nais jeg har råd til bolig på vinje
Sondov Engen (@sen)1 point8d ago·permalink

One thing worth exploring is to change the projection from Mercator to something like Albers Equal Area Conic projection (EPSG:9822).

It will reduce the size of Finnmark somewhat and bring it in line with the rest of the country. It can also be fun to experiment with some of the options.

Here are some AI suggestions, but I have no verified or tested it.

  • Central Meridian: 15.0° E (Centers the projection along Norway's longitudinal axis).
  • Standard Parallel 1: 59.0° N (Focuses on Southern Norway).
  • Standard Parallel 2: 69.0° N (Focuses on Northern Norway).
  • Latitude of Origin: 63.0° N (The approximate geographic center).
  • False Easting: 0.0
  • False Northing: 0.0
Thanks for the tip! I'll have to check that out!
Martin Myrseth (@mmy)2 points8d ago·permalink
Really nice with the elaborate description here Filip Floberg Jensen!
Thank you for the kind words Martin :D
Sondov Engen (@sen)1 point8d ago·permalink
Yeah, both good looking and informative!
Thank you Sondov :D
Sondov Engen (@sen)15d ago·permalink
Wow, this is really cool. How did you get all the country geo data in there?

Description

The below description is supplied in free-text by the user

Interaktivt koroplettkart over Norge med gjennomsnittlig boligpris per m² for alle kommuner. Data hentes automatisk fra SSB og oppdateres via en Novem-jobb.

Pek på en kommune for å se navn og pris. Klikk for å flytte zoom-utsnittet til den valgte kommunen.


Datainnhenting

Data hentes av fetch_data.py fra to SSB-endepunkter:

  • SSB tabell 06035 (PxWebAPI) — gjennomsnittlig kvadratmeterpris per kommune, siste tilgjengelige kvartal
  • SSB KLASS 131 (KLASS API) — kommunenavn på bokmål

Spørringen bruker JSON-stat2-formatet og henter alle 4-sifrede kommunekoder samtidig:

query = {
    "query": [
        {"code": "Region",       "selection": {"filter": "item", "values": all_codes}},
        {"code": "Boligtype",    "selection": {"filter": "item", "values": [alle_code]}},
        {"code": "ContentsCode", "selection": {"filter": "item", "values": [price_code]}},
        {"code": "Tid",          "selection": {"filter": "item", "values": [latest_tid]}},
    ],
    "response": {"format": "json-stat2"}
}

Kommunegrenser som SVG-stier

Grensedataene kommer fra kommuner_S.topojson (Kartverket/GeoNorge). I stedet for å prosessere TopoJSON i nettleseren, er alle grensene forhånds-projisert til SVG-stier av generate_municipality_paths.py.

Koordinatene dekodes fra delta-kodet TopoJSON og projiseres til et 760×900 px referanserom med Web Mercator:

def project(lon, lat):
    x = (lon - LON_MIN) / (LON_MAX - LON_MIN) * REF_W
    y = (1 - (merc_y(lat) - Y_MIN) / (Y_MAX - Y_MIN)) * REF_H
    return round(x), round(y)

fetch_data.py slår sammen SVG-stier, kommunenavn og SSB-priser til én CSV som pushes til plottet:

Kolonne Eksempel
name Oslo
kommunenummer 0301
pris_kr_m2 72 850
svg_path M180 777L181 776…Z

Rendering (D3.js)

Siden SVG-stiene allerede er projisert, skaleres de bare til tilgjengelig plass i nettleseren — ingen re-projeksjon nødvendig:

const scale = Math.min(plotW / REF_W, plotH / REF_H);
const mapG  = svg.append("g")
  .attr("transform", `translate(${offsetX},${offsetY}) scale(${scale})`);

mapG.selectAll("path")
  .data(pathData)
  .join("path")
    .attr("d", d => d[2])                        // SVG-sti direkte fra CSV
    .attr("fill", d => colorScale(priceMap.get(d[0])));

Fargene bruker kvadratrot-normalisering for å gi bedre kontrast i det vanlige prisintervallet:

function colorScale(price) {
  const t = (Math.sqrt(price) - sqrtMin) / (sqrtMax - sqrtMin);
  return interp(Math.max(0.08, Math.min(1, t)));
}

Klikk på en kommune beregner midtpunktet til <path>-elementet og animerer zoom-utsnittet dit:

.on("click", function(event, d) {
  const bbox = this.getBBox();
  const cx = bbox.x + bbox.width / 2;
  const cy = bbox.y + bbox.height / 2;
  zoomG.transition().duration(450)
    .attr("transform", `translate(${ZOOM_SIZE/2 - cx * ZOOM_DEFAULT},
                                  ${ZOOM_SIZE/2 - cy * ZOOM_DEFAULT})
                        scale(${ZOOM_DEFAULT})`);
});

Tilpasning via CSS

Farger og størrelser styres av CSS-variabler i custom.css — ingen endringer i JS nødvendig:

--color-scheme-light:  blues;    /* blues, plasma, viridis, inferno … */
--color-scheme-dark:   plasma;
--zoom-level:          3;
--bg-light:            #ffffff;
--bg-dark:             #0d1117;

Datakilder: SSB PxWebAPI (tabell 06035) · SSB KLASS (klassifikasjon 131) · Kartverket/GeoNorge via AnalyseABO