processed_flyttdata = {
if (flyttningsvisning === "Flyttningar totalt") {
return inrikesflyttdata.filter(d => d.Region === selectedRegionFlyttningar);
} else {
// Definiera de år du vill visa - alla från 2010
const yearsToShow = [2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, 2020, 2021, 2022, 2023, 2024, 2025];
// Hämta data för de valda åren
const regionData = inflyttkommun.filter(d =>
d.Region === selectedRegionFlyttningar &&
d.Variabel === "Inrikes flyttningsöverskott" &&
yearsToShow.includes(d.År)
);
// Definiera den korrekta ordningen för åldersgrupper
const ageOrder = [
"0-4 år", "5-9 år", "10-14 år", "15-19 år", "20-24 år", "25-29 år",
"30-34 år", "35-39 år", "40-44 år", "45-49 år", "50-54 år", "55-59 år",
"60-64 år", "65-69 år", "70-74 år", "75-79 år", "80-84 år", "85-89 år",
"90-94 år", "95-99 år", "100+ år"
];
// Bearbeta datan: lägg till ÅlderIndex och konvertera År till sträng
const processedData = regionData.map(d => ({
Ålder: d.Ålder,
ÅlderIndex: ageOrder.indexOf(d.Ålder), // VIKTIGT: Index för x-axeln
År: d.År.toString(), // VIKTIGT: Sträng för gruppering
Värde: parseFloat(d.Värde),
isLatest: d.År === 2025, // Markera om det är senaste året
strokeColor: d.År === 2025 ? "#005A4D" : "#999999", // 2025 får mörkgrön färg, resten grå
fillColor: d.År === 2025 ? "#005A4D" : "#999999" // 2025 får mörkgrön färg, resten grå
})).filter(d => d.ÅlderIndex > -1 && !isNaN(d.Värde)); // Filtrera bort ogiltiga rader
console.log("Processed age index data:", processedData);
return processedData;
}
}
// Beräkna label offsets för sista årets data om vi visar totala flyttningar
lastYearData = flyttningsvisning === "Flyttningar totalt"
? processed_flyttdata.filter(d => d.År === Math.max(...processed_flyttdata.map(d => d.År)))
: [];
// Använd dynamisk offset-beräkning
labelOffsets = flyttningsvisning === "Flyttningar totalt"
? calculateLabelOffsets(lastYearData, {
minDistancePercent: 0.08 // 5% av värdeområdet
})
: new Map();
// Rita graf för inrikes flyttningar
Plot.plot({
width: 700,
height: 400,
x: {
label: null,
grid: false,
line: "#005A4D",
tickSize: 6,
...(flyttningsvisning === "Flyttningar totalt" && {
tickFormat: d => d.toString()
}),
...(flyttningsvisning === "Flyttnetto per åldersgrupp" && {
tickFormat: (d) => {
const ageOrder = [
"0-4 år", "5-9 år", "10-14 år", "15-19 år", "20-24 år", "25-29 år",
"30-34 år", "35-39 år", "40-44 år", "45-49 år", "50-54 år", "55-59 år",
"60-64 år", "65-69 år", "70-74 år", "75-79 år", "80-84 år", "85-89 år",
"90-94 år", "95-99 år", "100+ år"
];
return ageOrder[d] || "";
},
tickRotate: -45
})
},
y: {
label: "Antal personer",
grid: "#797d7f",
line: "#005A4D",
nice: true,
tickSize: 6,
tickFormat: d => formatNumber(d),
labelOffset: 0,
labelArrow: "none",
textAnchor: "end"
},
color: {
legend: false, // Ingen legend
...(flyttningsvisning === "Flyttningar totalt" && {
domain: ["Inrikes inflyttade", "Inrikes utflyttade", "Inrikes flyttnetto"],
range: ["#005A4D", "#B33D4A", "#004C70"]
}),
...(flyttningsvisning === "Flyttnetto per åldersgrupp" && {
scheme: "Tableau10"
})
},
marginLeft: 70,
marginRight: 120,
marginBottom: flyttningsvisning === "Flyttnetto per åldersgrupp" ? 60 : 40,
style: {
fontSize: "12.5px",
color: "#002b1f"
},
marks: [
// Olika grafer beroende på visningstyp
...(flyttningsvisning === "Flyttningar totalt" ? [
// Vertikal referenslinje som följer musen
Plot.ruleX(processed_flyttdata, Plot.pointerX({
x: "År",
stroke: "#999",
strokeWidth: 1,
strokeDasharray: "3,3"
})),
// Nolllinje
Plot.ruleY([0], {stroke: "#005A4D", strokeWidth: 1}),
// Framskrivningsmarkering (ljus bakgrund för framskrivningsår)
Plot.rect([{x1: 2025.5, x2: 2040}], {
x1: "x1",
x2: "x2",
fill: "#E5F2E5",
fillOpacity: 0.3
}),
// Text för framskrivningsperiod
Plot.text(["Framskrivningsperiod"], {
x: 2032.25,
frameAnchor: "top",
dy: -10,
textAnchor: "middle",
fill: "#555",
fontSize: 13,
fontStyle: "italic"
}),
// Linjer för varje variabel
Plot.line(processed_flyttdata, {
x: "År",
y: "Värde",
stroke: "Variabel",
strokeWidth: 3
}),
// Punkter för alla år utom sista
Plot.dot(processed_flyttdata.filter(d => d.År < Math.max(...processed_flyttdata.map(d => d.År))), {
x: "År",
y: "Värde",
fill: "Variabel",
r: 3.5,
fillOpacity: 0.6
}),
// Större punkter för sista året
Plot.dot(processed_flyttdata.filter(d => d.År === Math.max(...processed_flyttdata.map(d => d.År))), {
x: "År",
y: "Värde",
fill: "Variabel",
r: 4.5
}),
// Linjer från punkter till etiketter om de flyttats
Plot.link(lastYearData.filter(d => Math.abs(labelOffsets.get(d.Variabel) || 0) > 1), {
x1: "År",
y1: "Värde",
x2: "År",
y2: d => d.Värde + (labelOffsets.get(d.Variabel) || 0),
stroke: "Variabel",
strokeWidth: 1,
strokeOpacity: 0.3,
strokeDasharray: "2,2",
dx1: 6, // Start från punktens kant
dx2: 6 // Slut vid etikettens kant
}),
// Etiketter för sista värdet med dynamisk positionering
Plot.text(lastYearData, {
x: "År",
y: d => d.Värde + (labelOffsets.get(d.Variabel) || 0), // Justera y-position baserat på beräknade offsets
text: "Variabel",
fill: "Variabel",
dx: 8,
textAnchor: "start",
fontSize: 12.5,
fontWeight: "600"
}),
// Tooltip
Plot.tip(processed_flyttdata, Plot.pointerX({
x: "År",
y: "Värde",
title: d => `${d.Variabel}\nÅr: ${d.År}\nAntal: ${formatNumber(d.Värde)}`,
fontSize: 14,
lineHeight: 1.5,
frameAnchor: "bottom"
}))
] : [
// Grafer för åldersklassdata
// Nolllinje
Plot.ruleY([0], {stroke: "#005A4D", strokeWidth: 1}),
// Linjer för alla år (både grå och 2025)
Plot.line(processed_flyttdata, {
x: "ÅlderIndex", // Använd numeriskt index för position
y: "Värde",
stroke: d => d.strokeColor, // Använd färg från data
strokeWidth: d => d.isLatest ? 3 : 1, // Tjockare linje för 2025, tunnare för resten
strokeOpacity: d => d.isLatest ? 1 : 0.4, // Genomskinliga gråa linjer
z: "År" // Gruppera på år för separata linjer
}),
// Punkter endast för 2025 (ritas sist så de hamnar överst)
Plot.dot(processed_flyttdata.filter(d => d.isLatest), {
x: "ÅlderIndex",
y: "Värde",
fill: d => d.fillColor,
r: 3.5,
stroke: d => d.strokeColor,
strokeWidth: 1
}),
// Annotation som förklarar att grön linje är 2025
Plot.text(["Grön linje: 2025"], {
x: 15, // Placera i mitten av grafen
y: Math.max(...processed_flyttdata.map(d => d.Värde)) * 0.8, // Nära toppen
text: d => d,
fill: "#005A4D",
fontSize: 11,
fontWeight: "600",
textAnchor: "middle"
}),
// Tooltip som använder index
Plot.tip(processed_flyttdata, Plot.pointer({
x: "ÅlderIndex", // Använd index för position
y: "Värde",
title: d => `År: ${d.År}\nÅldersgrupp: ${d.Ålder}\nFlyttnetto: ${formatNumber(d.Värde)}`,
fontSize: 14,
lineHeight: 1.5
}))
])
]
})