Public
Edited
May 15
1 fork
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
viewof regionSelector = Inputs.radio(region.reverse(), {
label: "Region ändern",
value: "Kanton Zürich"
})
Insert cell
viewof industrySelector = Inputs.select(branche, {
label: "Branche wählen",
value: "Alle Branchen"
})
Insert cell
Insert cell
viewof lineChart = {
const dimensions = lineChartDimensions;
const svg = d3
.create("svg")
.attr("viewBox", [0, 0, dimensions.width, dimensions.height])
.attr("aria-hidden", "true")
.style("display", "block");

svg.call(xAxis);

svg.call(yAxis);
svg.call(yAxisLabel);

const updateLines = createLines(svg);

svg.call(createMarker);

return Object.assign(svg.node(), {
update: (...args) => {
updateLines(...args);
}
});
}
Insert cell
Insert cell
viewof lineChartTooltip = {
const dimensions = lineChartDimensions;
const visible = highlightedYear !== null;

const year = visible ? highlightedYear : defaultYear;
const x = xScale(highlightedYear) + dimensions.margin.left;

/* Not all of the selected regions have data for this specific year */
const regions = selectedRegions.filter(
(region) => !isNaN(region.valuesByYear[year])
);

// If the tooltip hangs to the right: Highest x value before the tooltip will be cut off
const maxXRight = width - tooltipMaxWidth;

// If the tooltip hangs to the left: Lowest x value before the tooltip will be cut off
const minXLeft = tooltipMaxWidth;

const xPos =
x > width / 2
? `${Math.max(minXLeft, x)}px - 100%`
: `${Math.min(maxXRight, x)}px`;

const dataPoints = regions
.sort((a, b) => b.valuesByYear[year] - a.valuesByYear[year])
.map((region, i) => ({
label: region.year,
value: isNaN(region.valuesByYear[year])
? "keine Daten"
: valueFormat(region.valuesByYear[year]),
symbol: getRegionColor(region.year)
}));

return createTooltip(
{
dataPoints: [{ label: "Datum", value: dateFormat(year) }, ...dataPoints],
visible,
x: `calc(${xPos})`,
y: `calc(${dimensions.margin.top}px - 100% - .25rem)`
},
this
);
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
xScale = d3
.scaleTime()
.domain([new Date(dummyYear, 0, 1), new Date(dummyYear, 11, 31)])
.nice()
.range([0, lineChartDimensions.boundedWidth])
Insert cell
Insert cell
Insert cell
yAxis = (svg) => {
const dimensions = lineChartDimensions;
const numOfTicks = yScale.domain()[1];

const axisHeight = dimensions.boundedHeight;
const pixelsPerTick = 50;
const numberOfTicksTarget = Math.max(
1,
Math.floor(axisHeight / pixelsPerTick)
);

svg
.append("g")
.attr("transform", `translate(0 ${dimensions.margin.top})`)
.call(
d3
.axisRight(yScale)
.tickSize(dimensions.margin.left + dimensions.boundedWidth)
.tickFormat((d) => d.toLocaleString("de-CH"))
.ticks(numberOfTicksTarget)
)
.call((g) =>
g
.selectAll(".tick text")
.attr("x", 0)
.attr("dy", -4)
.attr("fill", ZHColors.axis.ticklabel)
)
.call((g) => {
g.selectAll(".tick line").attr("stroke", ZHColors.axis.gridline);
})
.call((g) => {
g.selectAll(".domain").remove();
});
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
viewof leuDropdown = htl.html`<leu-dropdown label="Download">
<leu-icon slot="icon" name="download"></leu-icon>
<leu-menu>
<leu-menu-item href="${dataPath}">Daten als CSV herunterladen</leu-menu-item>
<leu-menu-item href="https://www.zh.ch/de/politik-staat/statistik-daten/datenkatalog.html#/datasets/1742@statistisches-amt-kanton-zuerich">Daten im Open-Data-Katalog anzeigen</leu-menu-item>
<leu-menu-item onclick=${() =>
createPNG({
containerId: contentId.id,
padding: "10px",
filename: `ZEFIX_${titel}.png`
})}>Grafik als PNG herunterladen</leu-menu-item>
</leu-dropdown>
`
Insert cell
leuTheme = theme
Insert cell
leuFonts = fonts
Insert cell
leuElements = {
import(`https://esm.sh/@statistikzh/leu@${version}/leu-dropdown.js`);
import(`https://esm.sh/@statistikzh/leu@${version}/leu-menu.js`);
import(`https://esm.sh/@statistikzh/leu@${version}/leu-menu-item.js`);
import(`https://esm.sh/@statistikzh/leu@${version}/leu-icon.js`);
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
/*
* Group by Gebiet and rename properties
*/
selectedRegions = summedData
.filter(
(d) =>
d.location === regionSelector && d.br_abschnitt_red === industrySelector
)
.reduce((groups, d) => {
const group = groups.find((g) => g.year === d.year);

const currentValue = {
value: d.cumsum,
date: d.date
};

if (group) {
group.values.push(currentValue);
group.valuesByYear[currentValue.date] = currentValue.value;
} else {
groups.push({
year: d.year,
values: [currentValue],
valuesByYear: {
[currentValue.date]: currentValue.value
}
});
}

return groups;
}, [])
.map((group) => ({
...group,
values: group.values.sort((a, b) => b.year - a.year)
}))
Insert cell
Insert cell
Insert cell
// getRegionColor = (name) => {
// return colors.year[name];
// }

getRegionColor = (year) => {
return colors[selectedRegions.findIndex((region) => region.year === year)];
}
Insert cell
// getRegionSymbol = (name) => {
// return symbols.year[name];
// }

getRegionSymbol = (year) => {
return symbols?.[selectedRegions.findIndex((r) => r.year === year)];
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
localeDeCH = {
const res = await fetch(
"https://cdn.jsdelivr.net/npm/d3-format@3/locale/de-CH.json"
);
const data = await res.json();
return d3.formatLocale(data);
}
Insert cell
valueFormat = (v) => lit.html`${v.toLocaleString("de-CH")}`
Insert cell
dateFormat = (d) => lit.html`${d3.timeFormat("%d.%m.")(d)}`
Insert cell
dateParse = (d) => localeDeCH.timeFormat("%b")(d)
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
contentId = DOM.uid("zhstat-content")
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// only the last 5 years are displayed
startTimeRange = 4
Insert cell
Insert cell
fetchedData = d3.csv(dataPath, (d) => ({
...d,
value: Number.parseFloat(d.value),
year: new Date(d.date).getFullYear(),
// make all dates have the same year so that they can use the same time scale.
date: d3.timeParse("%Y-%m-%d")(`${dummyYear}-${d.date.slice(5)}`), //(`${dummyYear}-${d.date.slice(5)}`),
location: d.location === "CH" ? "Schweiz" : "Kanton Zürich"
}))
Insert cell
summedData = tidy(
// Calculation of the cumulative daily values for all years, all industries and the two areas, Switzerland and Canton Zurich
fetchedData.filter((d) => d.year >= yearExtent[1] - startTimeRange),
groupBy(
["location", "br_abschnitt_red", "year"],
mutateWithSummary({ cumsum: cumsum("value") })
)
)
Insert cell
branche = [...new Set(summedData.map((d) => d.br_abschnitt_red))]
Insert cell
Insert cell
titel = "Konkurseröffnungen im Handelsregister"
// {
// const years = [yearExtent[1] - startTimeRange, yearExtent[1]];

// return `Anzahl Konkurseröffnungen, ${years.join(" bis ")}`;
// }
Insert cell
untertitel = "Seit Jahresbeginn summierte Tageswerte (kumulierte Tageswerte)" // "Für den Kanton Zürich und die Schweiz kumulierte Tageswerte nach Branchen"
Insert cell
Insert cell
anmerkung = "Seit Jahresbeginn aufsummierte Konkurseröffnungen. Ohne Privatkonkurse und ohne formelle Konkurse von bereits inaktiven Unternehmen. Branchenklassifikation nach NOGA2008 (Wirtschaftsabschnitte)."
Insert cell
Insert cell
yearExtent = d3.extent(fetchedData, (d) => d.year)
Insert cell
years = [...new Set(d3.map(summedData, (d) => d.date))]
Insert cell
dateExtent = [...new Set(summedData.map((d) => d.date))]
Insert cell
Insert cell
import {
colors as ZHColors,
fonts as ZHFonts
} from "@statistikzh/common-styles"
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
lit = import(`https://esm.run/lit-html@3`) // import("lit-html@3.2.1")
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