Public
Edited
Feb 14, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Swatches(d3.scaleOrdinal(["Wohnen", "Verkehr", "Industrie", "Landwirschaft", "WIKA", "WAKA", "PV", "ST", "BM", "UW", "Saldo"], ["#F39C12", "#5D6D7E", "#D7BDE2", "#D5F5E3", "#80DEEA", "#5DADE2", "#F4D03F", "#D4AC0D", "#43A047", "#A04000", "red"]), {
columns: "300px"
})
Insert cell
d3Chart4 = StackedBarChart(Gols2, {
x: (d) => d.wert,
y: (d) => d.begriff,
z: (d) => d.ruling,

xLabel: "← Verbrauch ··· Energie [MWh] ··· Erzeugung →",
yDomain: d3.groupSort(
Gols2,
(D) => d3.sum(D, (d) => -Math.max(0, d.wert)),
(d) => d.begriff,
),
zDomain: Gemeinde2.rulings2,
width,
marginLeft: 80,
marginRight: 80,
colors: ["#F39C12", "#5D6D7E", "#D7BDE2", "#D5F5E3", "#80DEEA", "#5DADE2", "#F4D03F", "#D4AC0D", "#43A047", "#A04000", "#F44336", "#F44336", "#F44336", "#F44336"]
})
Insert cell
map = {
const chartWidth = innerWidth;
const chartHeight = 500;
const backgroundColor = "#000000";
const landColor = "#555555";
const landStroke = "#000000";
const markerColor = "#FFCF00";
const projection = d3.geoMercator()
.scale([6000])
.center(markers[0].geometry.coordinates)
.translate([chartWidth / 1.2, chartHeight / 3])
;
const pathGenerator = d3.geoPath(projection);
const svg = d3.create('svg')
.attr("title", "map")
.attr('color', "#FFCF00")
.attr('width', chartWidth)
.attr('height', chartHeight)
svg.append("rect")
.attr("width", chartWidth)
.attr("height", chartHeight)
.attr('fill', backgroundColor);

svg.selectAll('path')
.data(gemeinden.features)
.join('path')
.attr('d', pathGenerator)
.attr('fill', landColor)
.attr('stroke', markerColor)
.attr("fill-opacity", 0.9)
.attr("stroke-opacity", 1)
.attr('stroke-width', 0.4);

svg.selectAll("circle")
.data(markers)
.join("circle")
.attr("cx", d => projection(d.geometry.coordinates)[0])
.attr("cy", d => projection(d.geometry.coordinates)[1])
.attr("r", 4)
.attr("fill-opacity", 0.5)
.attr("fill", markerColor)
.attr("stroke", markerColor);
return svg.node();
}

Insert cell
workbook = zielwertberechnung.sheet(0, { headers: true})
Insert cell
zielwertberechnung = FileAttachment("Zielwertberechnung.xlsx").xlsx()
Insert cell
Inputs.table(workbook)
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
excelJs = fetch('https://unpkg.com/@microsoft/office-js@1.1.10/dist/excel-web-16.00.js').then(response => response.text())
Insert cell
Excel = {
if (!window.Excel) {
(1, eval)('this').eval(excelJs);
}
return window.Excel;
}
Insert cell
Type JavaScript, then Shift-Enter. Ctrl-space for more options. Arrow ↑/↓ to switch modes.

Insert cell
chart = Choropleth(getDataset(), {
id: d => d.ISO.toString(),
value: d => d[getKey(auswahl)], // which data column to display
//range: d3.interpolateReds,
features: gemeinden,
featureId: f => f.properties.iso,
borders: gemeinden,
height: width/1.95,
width: width,
projection: d3.geoMercator()
.scale([width*3])
.center(markers[0].geometry.coordinates)
.translate([width*0.8, width/3.1])
})
Insert cell
function getDataset(name) { //how to get the columns?????
{return Zielwertberechnung}
}
Insert cell
viewof auswahl = Inputs.select([null].concat(names.labels), {label: "Zielwert", value:names.labels[14]})
Insert cell
viewof quantil = rangeSlider({
min: 0.0,
max: 1,
step:0.01,
value: this ? this.value: [0.00,0.95],
title: "",
label: "Darzustellender Wertebereich",
})
Insert cell
names = ({
keys: [
"EE_WAKA","EE_WIKA","EE_PV","EE_Biomasse","EE_Solartherm","EE_Umweltw","B_WuD","B_Mob","B_IuG","B_LuF","EE_e","EE_t","B_e","B_t","Saldo_e","Saldo_t"],
labels: [
"Ausbau Wasserkraft","Ausbau Windkraft","Ausbau PV","Ausbau Biomasse","Ausbau Solarthermie","Ausbau Umweltwärme","Reduktion Wohnen und Dienstleistungen","Reduktion Mobilität","Reduktion Industrie und Gewerbe","Reduktion Land- und Forstwirtschaft","Ausbauziel elektrisch","Ausbauziel thermisch","Bedarfsreduktion elektrisch","Bedarfsreduktion thermisch","Handlungsbedarf elektrisch (Einsparungen und Ausbau)","Handlungsbedarf thermisch (Einsparungen und Ausbau)"]
})
Insert cell
// Copyright 2021 Observable, Inc.
// Released under the ISC license.
// https://observablehq.com/@d3/choropleth
function Choropleth(data, {
id = d => d.ISO, // given d in data, returns the feature id
value, // given d in data, returns the quantitative value
title, // given a feature f and possibly a datum d, returns the hover text
format, // optional format specifier for the title
scale = d3.scaleSequentialSqrt, // type of color scale
domain, // [min, max] values; input of color scale
range = d3.interpolateGnBu, // output of color scale
width, // outer width, in pixels
height, // outer height, in pixels
projection, // a D3 projection; null for pre-projected geometry
features, // a GeoJSON feature collection
featureId, // given a feature, returns its id
borders, // a GeoJSON object for stroking borders
outline = projection && projection.rotate ? {type: "Sphere"} : null, // a GeoJSON object for the background
unknown = "#AA0000", // fill color for missing data
fill = "white", // fill color for outline
stroke = "#EEE",//"#E26F99", // stroke color for borders
strokeLinecap = "round", // stroke line cap for borders
strokeLinejoin = "round", // stroke line join for borders
strokeWidth = 0.15, // stroke width for borders
strokeOpacity = 1, // stroke opacity for borders
backgroundColor = "#AAA",
landColor = "#444444",
landStroke = "#000000",
markerColor = "#E26F99",
} = {}) {
// Compute values.
const N = d3.map(data, id); // one-dimensional array with all IDs
const V = d3.map(data, value).map(d => d == null ? NaN : +d); // one-dimensional array with all values
const Im = new d3.InternMap(N.map((id, i) => [id, i])); // 1dim map ISO string as key, and index i as result: Im("10101") = 0
const If = d3.map(features.features, featureId);
console.log(N)

// Compute default domains.
if (domain === undefined) domain = [d3.quantile(V,quantil[0]), d3.quantile(V, quantil[1])];//d3.extent(V);

// Construct scales.
const color = scale(domain, range);
if (color.unknown && unknown !== undefined) color.unknown(unknown);

// Compute titles.
if (title === undefined) {
format = color.tickFormat(100, format);
title = (d, i) => `${auswahl}\n${d.properties.name}\n${format(V[i])}`;
} else if (title !== null) {
const T = title;
const O = d3.map(data, d => d);
title = (f, i) => T(f, O[i]);
}

// Compute the default height. If an outline object is specified, scale the projection to fit
// the width, and then compute the corresponding height.
if (height === undefined) {
if (outline === undefined) {
height = width/2;
} else {
const [[x0, y0], [x1, y1]] = d3.geoPath(projection.fitWidth(width, outline)).bounds(outline);
const dy = Math.ceil(y1 - y0), l = Math.min(Math.ceil(x1 - x0), dy);
projection.scale(projection.scale() * (l - 1) / l).precision(0.2);
height = dy;
}
}

// Construct a path generator.
const path = d3.geoPath(projection);

const svg = d3.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [0, 0, width, height])
.attr("style", "width: 100%; height: auto; height: intrinsic;");


if (outline != null) svg.append("path")
.attr("fill", fill)
.attr("stroke", "currentColor")
.attr("d", path(outline));

svg.append("rect")
.attr("width", width)
.attr("height", height)
.attr('fill', backgroundColor);
svg.append("g")
.selectAll("path")
.data(features.features)
.join("path")
.attr("fill", (d, i) => color(V[Im.get(If[i])]))
.attr("d", path)
.append("title")
.text((d, i) => title(d, Im.get(If[i])));

if (borders != null) svg.append("path")
.attr("pointer-events", "none")
.attr("fill", "none")
.attr("stroke", stroke)
.attr("stroke-linecap", strokeLinecap)
.attr("stroke-linejoin", strokeLinejoin)
.attr("stroke-width", strokeWidth)
.attr("stroke-opacity", strokeOpacity)
.attr("d", path(borders));

const key = Legend(color, { // https://observablehq.com/@d3/choropleth
title: auswahl+" ",
width: width/2,
size:100,
})
svg.append("g")
.attr("transform", "translate("+width/50+","+width/50+")")
.append(() => key);
return Object.assign(svg.node(), {scales: {color}});
}
Insert cell
markers = [
{
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
16.37250,
48.20833
]
}
}
]
Insert cell
topo2 = FileAttachment("gemeinden_topo (2).txt").json()
Insert cell
at = FileAttachment("STATISTIK_AUSTRIA_GEM_20220101.json").json()
//at = FileAttachment("gemeinden95.geo.json.txt").json() zu groß, 100 punkte pro polygon
//at = FileAttachment("gemeinden_95_topo.json").json()
Insert cell
top = FileAttachment("STATISTIK_AUSTRIA_GEM_20220101@1.txt").json()
Insert cell
gemeinden = topojson.feature(topo2, topo2.objects.gemeinden)
Insert cell
STATISTIK_AUSTRIA_GEM_20220101 = topojson.feature(top, top.objects.STATISTIK_AUSTRIA_GEM_20220101)
Insert cell
reflist_ort = FileAttachment("Reflist_Ort@1.xlsx").xlsx()
Insert cell
PLZtoGZ = reflist_ort.sheet(0, { headers: true})
Insert cell
Insert cell
gols2 = FileAttachment("Gols2@4.xlsx").xlsx()
Insert cell
Gols2 = gols2.sheet(0, { headers: true})
Insert cell
Inputs.table(Gols2)
Insert cell
colours = ({
keys: ["#F39C12", "#5D6D7E", "#D7BDE2", "#D5F5E3", "#80DEEA", "#5DADE2", "#F4D03F", "#D4AC0D", "#43A047", "#A04000", "#F44336", "#F44336", "#F44336", "#F44336", "#F44336", "black"],
labels: ["WuD","Mob","IuG","LuF","WIKa", "WAKA", "PV", "Solartherm", "Biomasse", "Umweltw","WuDe","Mobe","IuG_e","LuF_e", "Saldo_e","Saldo_t"]
})
Insert cell
Gemeinde2 = {

const rulings2 = {
"wud": {name: "WuD", sign: -1},
"mob": {name: "Mob", sign: -1},
"iug": {name: "IuG", sign: -1},
"luf": {name: "LuF", sign: -1},
"wika": {name: "WIKA", sign: 1},
"waka": {name: "WAKA", sign: 1},
"pv": {name: "PV", sign: 1},
"st": {name: "Solartherm", sign: 1},
"bm": {name: "Biomasse", sign: 1},
"uw": {name: "Umweltw", sign: 1},
"wude": {name: "WuDe", sign: -1},
"mobe": {name: "Mobe", sign: -1},
"iuge": {name: "IuG_e", sign: -1},
"lufe": {name: "LuF_e", sign: -1},
"wudt": {name: "WuDt", sign: -1},
"mobt": {name: "Mobt", sign: -1},
"iugt": {name: "IuG_t", sign: -1},
"luft": {name: "LuF_t", sign: -1},
"eee": {name: "EE_e", sign: 1},
"eet": {name: "EE_t", sign: 1},
"seee": {name: "sEE_e", sign: -1},
"seet": {name: "sEE_t", sign: -1},
"espe": {name: "Einsp_e", sign: -1},
"espt": {name: "Einsp_t", sign: -1},
"gese": {name: "Saldo_e", sign: -1},
"gest": {name: "Saldo_t", sign: -1},
};
const Gemeinde2 = Gols2.filter(d => d.ruling in rulings2);

const total = d3.rollup(Gols2, D => d3.sum(D, d => d.wert), d => d.begriff);

return Object.assign(Gemeinde2.map(d => ({
begriff: d.begriff,
ruling: rulings2[d.ruling].name,
wert: d.wert * rulings2[d.ruling].sign,
colors: ["#F39C12", "#5D6D7E", "#D7BDE2", "#D5F5E3", "#80DEEA", "#5DADE2", "#F4D03F", "#D4AC0D", "#43A047", "#A04000", "#F44336", "#F44336", "#F44336"],
})), {
rulings2: [...d3.union(Object.values(rulings2).map(d => d.name))]
});
}
Insert cell
Insert cell
steyr = FileAttachment("Steyr-9.xlsx").xlsx()
Insert cell
Steyr = steyr.sheet(0, { headers: true})

Insert cell
Inputs.table(Steyr)
Insert cell
import { StackedBarChart } from "@d3/diverging-stacked-bar-chart"
Insert cell
d3Chart2 = StackedBarChart(Steyr, {
x: (d) => d.wert,
y: (d) => d.name,
z: (d) => d.ruling,

xLabel: "← Verbrauch ··· Energie [MWh] ··· Erzeugung →",
yDomain: d3.groupSort(
Steyr,
(D) => d3.sum(D, (d) => -Math.max(0, d.wert)),
(d) => d.name,
),
zDomain: Gemeinde.rulings,
width,
marginLeft: 80,
marginRight: 80,
colors: d => d[getKey(colours)]
})

Insert cell
function getKey(label) {
let index = colours.labels.indexOf(label);
if(index !== -1) return colours.keys[index];
else return 'Key not found'
}
Insert cell
gols = FileAttachment("Gols.xlsx").xlsx()
Insert cell
Gols = gols.sheet(0, { headers: true})
Insert cell
d3Chart3 = StackedBarChart(Gols, {
x: (d) => d.wert,
y: (d) => d.name,
z: (d) => d.ruling,

xLabel: "← Verbrauch ··· Energie [MWh] ··· Erzeugung →",
yDomain: d3.groupSort(
Gols,
(D) => d3.sum(D, (d) => -Math.max(0, d.wert)),
(d) => d.name,
),
zDomain: Test.rulings,
width,
marginLeft: 80,
marginRight: 80,
colors: ["#F39C12", "#5D6D7E", "#D7BDE2", "#D5F5E3", "#80DEEA", "#5DADE2", "#F4D03F", "#D4AC0D", "#43A047", "#A04000"]
})

Insert cell
G2 = require("@antv/g2@3")
Insert cell
Gemeinde = {

const rulings = {
"sq_wud": {name: "SQ_WuD", sign: -1,},
"sq_mob": {name: "SQ_Mob", sign: -1,},
"sq_iug": {name: "SQ_IuG", sign: -1,},
"sq_luf": {name: "SQ_LuF", sign: -1},
"sq_wika": {name: "SQ_EE_WIKA", sign: 1},
"sq_waka": {name: "SQ_EE_WAKA", sign: 1},
"sq_pv": {name: "SQ_EE_PV", sign: 1},
"sq_st": {name: "SQ_EE_Solartherm", sign: 1},
"sq_bm": {name: "SQ_EE_Biomasse", sign: 1},
"sq_uw": {name: "SQ_EE_Umweltw", sign: 1},
};

const Gemeinde = Steyr.filter(d => d.ruling in rulings);

// Compute the total number of rulings for each speaker.
const total = d3.rollup(Steyr, D => d3.sum(D, d => d.wert), d => d.begriff);

return Object.assign(Gemeinde.map(d => ({
begriff: d.begriff,
ruling: rulings[d.ruling].name,
wert: d.wert * rulings[d.ruling].sign*total.get(d.begriff),
colors: ["#F39C12", "#5D6D7E", "#D7BDE2", "#D5F5E3", "#80DEEA", "#5DADE2", "#F4D03F", "#D4AC0D", "#43A047", "#A04000"],
})), {
rulings: [...d3.union(Object.values(rulings).map(d => d.name))]
});
}
Insert cell
https://observablehq.com/@d3/diverging-stacked-bar-chart
https://observablehq.com/@douglyuckling/diverging-stacked-bar-chart
https://observablehq.com/@pearmini/g2-bar-chart-groupedg2-stacked-bar-chart-diverging
Insert cell
Test = {
const options = {
type: "view",
coorindates: [{ type: "transpose" }],
children: [
{
type: "interval",
data: Gols,
trasnform: [{ type: "stackY", orderBy: "series", diverging: true }], //+
scale: {
x: { display: false },
color: {
range: d3.schemeSpectral[Gols.rulings],
domain: Gols.rulings
},
y: { formatter: "~%", position: "top", tickCount: 15 }
},
encode: {
x: "name",
y: "wert",
color: "ruling"
},
labels: [
{
text: "name",
textAnchor: "end",
dx: -5,
dy: -5,
transform: [
{
type: "selectY",
selector: "min",
groupBy: "name"
}
]
}
]
},
{ type: "annotaion.lineY", data: [0] },
{
type: "text",
data: [0, 0, "← Bedarf · Energie · Erzeugung →"],
scale: { x: { type: "identity" } },
style: { dy: -30 }
}
]

};

return md`A better spec...`;
}
Insert cell
// Copyright 2021, Observable Inc.
// Released under the ISC license.
// https://observablehq.com/@d3/color-legend
function Swatches(color, {
columns = null,
format,
unknown: formatUnknown,
swatchSize = 15,
swatchWidth = swatchSize,
swatchHeight = swatchSize,
marginLeft = 0
} = {}) {
const id = `-swatches-${Math.random().toString(16).slice(2)}`;
const unknown = formatUnknown == null ? undefined : color.unknown();
const unknowns = unknown == null || unknown === d3.scaleImplicit ? [] : [unknown];
const domain = color.domain().concat(unknowns);
if (format === undefined) format = x => x === unknown ? formatUnknown : x;

function entity(character) {
return `&#${character.charCodeAt(0).toString()};`;
}

if (columns !== null) return htl.html`<div style="display: flex; align-items: center; margin-left: ${+marginLeft}px; min-height: 33px; font: 10px sans-serif;">
<style>

.${id}-item {
break-inside: avoid;
display: flex;
align-items: center;
padding-bottom: 1px;
}

.${id}-label {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: calc(100% - ${+swatchWidth}px - 0.5em);
}

.${id}-swatch {
width: ${+swatchWidth}px;
height: ${+swatchHeight}px;
margin: 0 0.5em 0 0;
}

</style>
<div style=${{width: "100%", columns}}>${domain.map(value => {
const label = `${format(value)}`;
return htl.html`<div class=${id}-item>
<div class=${id}-swatch style=${{background: color(value)}}></div>
<div class=${id}-label title=${label}>${label}</div>
</div>`;
})}
</div>
</div>`;

return htl.html`<div style="display: flex; align-items: center; min-height: 33px; margin-left: ${+marginLeft}px; font: 10px sans-serif;">
<style>

.${id} {
display: inline-flex;
align-items: center;
margin-right: 1em;
}

.${id}::before {
content: "";
width: ${+swatchWidth}px;
height: ${+swatchHeight}px;
margin-right: 0.5em;
background: var(--color);
}

</style>
<div>${domain.map(value => htl.html`<span class="${id}" style="--color: ${color(value)}">${format(value)}</span>`)}</div>`;
}
Insert cell
import {Legend} from "@d3/color-legend"
Insert cell
import {rangeSlider, themes} from '@mootari/range-slider'
Insert cell
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more