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

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more