Utforsk utviklingen i åpen tilgang i Norge 2013–2025. Filtrer på sektor, fagområde og år – figuren og tabellen speiler hverandre.
Endret
23. september 2026
Datagrunnlaget dekker kun artikler som er rapportert i NVI-sammenheng og inkluderer ikke bøker, eller konferansebidrag i serier uten ISSN. Publikasjoner telles unikt innenfor valgt sektor og fagområde. En artikkel med forfattere fra flere sektorer telles derfor én gang i hver sektor, men bare én gang i totalen for hele Norge. Prosentberegningen av åpen andel baseres på andelen artikler som er åpent tilgjengelige (alle kategorier unntatt deponert og lukket). For å lese mer om utvalg og beregningsmåter, se metodebeskrivelsen.
Utforsk utviklingen
Filtrene styrer både figuren og tabellen. Hold musepekeren over søylene for detaljer.
oa = (newFunction("u","return import(u)"))(newURL("assets/js/oa-chart.js",document.baseURI).href)// typed: true makes d3 coerce year/total to numbers instead of stringscube =FileAttachment("data/oa_national_aggregated.csv").csv({typed:true})cubeYears = [...newSet(cube.map((d) => d.year))].sort((a, b) => a - b)// Filter options come from the data, not a hardcoded list, so a new sector or// discipline out of the pipeline appears by itself. `known` only fixes the// display order of the levels we already know; anything else is appended.sectorOptions = {const known = ["all","higher_education","institute","health","archives_libraries_museums"];const inData = [...newSet(cube.map((d) => d.sector))];return [...known.filter((s) => inData.includes(s)),...inData.filter((s) =>!known.includes(s)).sort()];}disciplineOptions = {const known = ["all","natural_sciences_engineering","health_sciences","social_science","humanities"];const inData = [...newSet(cube.map((d) => d.discipline))];return [...known.filter((s) => inData.includes(s)),...inData.filter((s) =>!known.includes(s)).sort()];}
// Filter inputs. Each `viewof` defines the named value used elsewhere on the// page; `format` keeps the English data values behind Norwegian labels.viewof natSector = Inputs.select(sectorOptions, {value:"all",label:"Sektor",format: oa.labelFor(oa.SECTOR_LABELS)})
// Absolute counts vs 100 % stacked shares. Drives the figure, the table cells// and the CSV export together, so the two always agree.viewof natMode = Inputs.radio(newMap([["Antall","abs"], ["Prosent","pct"]]), {value:"abs",label:"Visning"})
// Custom two-ended slider (Observable has no built-in range input). Bounds// follow the data, so the range extends by itself after an annual update.viewof natYears = oa.yearRangeInput({min: cubeYears[0],max: cubeYears.at(-1),label:"År"})
// Disabled for now. To re-enable: move this cell back inside the// ::: {.oa-controls} block above, uncomment the input and delete the// constant - the constant holds the input's former default.// viewof natLabels = Inputs.toggle({label: "Vis verdier", value: true})natLabels =true
// Disabled for now. To re-enable: move this cell back inside the// ::: {.oa-controls} block above, uncomment the input and delete the// constant - the constant holds the input's former default.// viewof natCats = Inputs.checkbox(oa.OA_ORDER, {// value: oa.OA_ORDER,// label: "Kategorier",// format: oa.labelFor(oa.OA_LABELS)// })natCats = oa.OA_ORDER
natRows = cube.filter((d) => d.sector=== natSector && d.discipline=== natDisc)// Subtitle names the active filters, omitting the ones left at "all"natSubtitle = [`NVI ${natYears[0]}–${natYears[1]}`, natSector ==="all"?null:`Sektor: ${oa.SECTOR_LABELS[natSector] ?? natSector}`, natDisc ==="all"?null:`Fagområde: ${oa.DISCIPLINE_LABELS[natDisc] ?? natDisc}`].filter(Boolean).join(" · ")
oa.oaChartCard(Plot, {data: natRows,mode: natMode,categories: natCats,yearFrom: natYears[0],yearTo: natYears[1],showLabels: natLabels,width:Math.min(width,960),title: natMode ==="pct"?"Distribusjon av åpen tilgang-artikler (%)":"Distribusjon av åpen tilgang-artikler",subtitle: natSubtitle})
Tabell
// The table mirrors the figure: same filters, same numbers, one row per year.// Pivots the long CSV rows (one per year x status) into one wide row per year.natTable = {const cats = oa.OA_ORDER.filter((c) => natCats.includes(c));const byYear =newMap();for (const d of natRows) {if (d.year< natYears[0] || d.year> natYears[1] ||!cats.includes(d.status)) continue;if (!byYear.has(d.year)) {const row = {year: d.year};for (const c of cats) row[c] =0; byYear.set(d.year, row); } byYear.get(d.year)[d.status] += d.total; }return [...byYear.values()].map((r) => {// "open" = every category except closed and deposited; deposited is a// waiting room (uploaded but not yet released), so it is not open accessconst total = cats.reduce((s, c) => s + r[c],0);const open = total - (r.closed??0) - (r.deposited??0);const out = {year: r.year};for (const c of cats) { out[c] = natMode ==="pct"? (total ?Math.round((r[c] / total) *1000) /10:0): r[c]; } out.total= total; out.open_share= total ? (open / total) *100:0;return out; }).sort((a, b) => a.year- b.year);}
// Exports exactly what the table currently shows (filters, year range and// Antall/Prosent all apply). Column names are English; see oa.downloadCsv.viewof natTblDownload = Inputs.button("Last ned CSV", {label:"Eksport",reduce: () => oa.downloadCsv( natTable, [ {key:"year",header:"year"},...oa.OA_ORDER.filter((c) => natCats.includes(c)).map((c) => ({key: c,header: natMode ==="pct"?`${c}_pct`: c,...(natMode ==="pct"? {value: (r) => r[c].toFixed(1).replace(".",",")}: {}) })), {key:"total",header:"total"}, {key:"open_share",header:"open_share_pct",value: (r) => r.open_share.toFixed(1).replace(".",",")}, ],`oa-barometer_national_${natYears[0]}-${natYears[1]}.csv` )})
// Keys stay English (they come from the data); `header` supplies the Norwegian// column names, and `format` renders each cell.Inputs.table(natTable, {columns: ["year",...oa.OA_ORDER.filter((c) => natCats.includes(c)),"total","open_share"],header: {year:"år",...Object.fromEntries(oa.OA_ORDER.map((c) => [c, oa.OA_LABELS[c]])),total:"totalt",open_share:"andel_åpen" },format: {year: (d) =>String(d),...Object.fromEntries(oa.OA_ORDER.map((c) => [ c, natMode ==="pct"? (d) =>`${oa.fmtPct1.format(d)} %`: oa.fmtNo.format ])),total: oa.fmtNo.format,open_share: (d) => oa.pctBarCell(d) },width: {open_share:110},sort:"year",rows:20,layout:"auto"})