From 2a4466cb827def7d94dd0af0bfe9eae8d6b3ea9b Mon Sep 17 00:00:00 2001 From: Stan Runge Date: Sun, 25 Oct 2026 21:22:20 +0000 Subject: [PATCH] =?UTF-8?q?stats:=20/stats/countries=20comparison=20and=20?= =?UTF-8?q?/stats/countries/[iso3]=20profiles=20(Cura=C3=A7ao=20via=20Worl?= =?UTF-8?q?d=20Bank),=20more=20WB=20indicators,=20Countries=20+=20Cura?= =?UTF-8?q?=C3=A7ao=20cards,=20nav/sitemap/start=20links?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/stats/worldbank.ts | 54 ++- src/lib/projects.ts | 6 + src/lib/server/stats.ts | 19 +- src/lib/stats/countries.ts | 130 ++++++ src/lib/stats/regions.ts | 5 +- src/routes/sitemap.xml/+server.ts | 2 + src/routes/start/+page.svelte | 4 +- src/routes/stats/+page.svelte | 18 +- src/routes/stats/countries/+page.server.ts | 29 ++ src/routes/stats/countries/+page.svelte | 174 +++++++ .../stats/countries/[iso3]/+page.server.ts | 23 + .../stats/countries/[iso3]/+page.svelte | 428 ++++++++++++++++++ 12 files changed, 887 insertions(+), 5 deletions(-) create mode 100644 src/lib/stats/countries.ts create mode 100644 src/routes/stats/countries/+page.server.ts create mode 100644 src/routes/stats/countries/+page.svelte create mode 100644 src/routes/stats/countries/[iso3]/+page.server.ts create mode 100644 src/routes/stats/countries/[iso3]/+page.svelte diff --git a/scripts/stats/worldbank.ts b/scripts/stats/worldbank.ts index c0e4abe..b9f875a 100644 --- a/scripts/stats/worldbank.ts +++ b/scripts/stats/worldbank.ts @@ -49,7 +49,59 @@ export const WB_INDICATORS: { id: string; title: string; unit: string; theme: st theme: 'budget' }, { id: 'GC.XPN.TOTL.GD.ZS', title: 'Government expense', unit: '% of GDP', theme: 'budget' }, - { id: 'GC.DOD.TOTL.GD.ZS', title: 'Central government debt', unit: '% of GDP', theme: 'budget' } + { id: 'GC.DOD.TOTL.GD.ZS', title: 'Central government debt', unit: '% of GDP', theme: 'budget' }, + // Country profiles (/stats/countries/[iso3]); most of these also cover Curaçao. + { + id: 'NY.GNP.PCAP.CD', + title: 'GNI per capita (Atlas)', + unit: 'current USD', + theme: 'countries' + }, + { + id: 'SL.UEM.TOTL.ZS', + title: 'Unemployment (ILO modelled)', + unit: '% of labour force', + theme: 'countries' + }, + { id: 'SP.DYN.LE00.IN', title: 'Life expectancy at birth', unit: 'years', theme: 'countries' }, + { id: 'SP.DYN.TFRT.IN', title: 'Fertility rate', unit: 'births per woman', theme: 'countries' }, + { + id: 'SP.POP.65UP.TO.ZS', + title: 'Population aged 65+', + unit: '% of population', + theme: 'countries' + }, + { + id: 'NE.EXP.GNFS.ZS', + title: 'Exports of goods and services', + unit: '% of GDP', + theme: 'countries' + }, + { + id: 'NE.IMP.GNFS.ZS', + title: 'Imports of goods and services', + unit: '% of GDP', + theme: 'countries' + }, + { id: 'NV.SRV.TOTL.ZS', title: 'Services, value added', unit: '% of GDP', theme: 'countries' }, + { + id: 'ST.INT.ARVL', + title: 'International tourism, arrivals', + unit: 'arrivals', + theme: 'countries' + }, + { + id: 'ST.INT.RCPT.CD', + title: 'International tourism, receipts', + unit: 'current USD', + theme: 'countries' + }, + { + id: 'EG.ELC.RNEW.ZS', + title: 'Renewable electricity output', + unit: '% of electricity', + theme: 'energy' + } ]; type WbRow = { diff --git a/src/lib/projects.ts b/src/lib/projects.ts index f97becf..cdb98f2 100644 --- a/src/lib/projects.ts +++ b/src/lib/projects.ts @@ -51,6 +51,12 @@ export const statsPages = [ subtitle: 'population, housing and neighbourhoods in Gouda', href: '/stats/gouda', external: false + }, + { + name: 'countries', + subtitle: 'the Netherlands, Curaçao, the US, Korea, China and more side by side', + href: '/stats/countries', + external: false } ] as const; diff --git a/src/lib/server/stats.ts b/src/lib/server/stats.ts index 69e9c3f..beebb1c 100644 --- a/src/lib/server/stats.ts +++ b/src/lib/server/stats.ts @@ -25,6 +25,8 @@ export type StatSeries = { region: string | null; sourceId: string; points: StatPoint[]; + /** First forecast year (IMF WEO vintages); points from that year on are projections. */ + forecastFrom?: number; }; export type SeriesRequest = { id: string; @@ -48,8 +50,10 @@ export async function loadSeries( freq: string; region_code: string | null; source_id: string; + forecast_from: string | null; }[] - >`select series_id, title, unit, freq, region_code, source_id from stats.series + >`select series_id, title, unit, freq, region_code, source_id, meta->>'forecastFrom' as forecast_from + from stats.series where series_id = any(${reqs.map((r) => r.id)})`; const out: Record = {}; await Promise.all( @@ -72,6 +76,7 @@ export async function loadSeries( freq: m.freq, region: m.region_code, sourceId: m.source_id, + ...(m.forecast_from ? { forecastFrom: Number(m.forecast_from) } : {}), points: rows.map((r) => [r.period, Math.round(r.value * 1e6) / 1e6]) }; }) @@ -181,3 +186,15 @@ export async function loadCbsCross( } return [...byCode.values()].sort((a, b) => a.code.localeCompare(b.code)); } + +export type LatestValue = { period: string; value: number }; +/** Latest observed (non-forecast) value per series; missing ids are absent. */ +export async function loadLatest(ids: string[]): Promise> { + if (!ids.length) return {}; + const rows = await client<{ series_id: string; period: string; value: number }[]>` + select distinct on (series_id) series_id, to_char(period, 'YYYY-MM-DD') as period, value + from stats.obs + where series_id = any(${ids}) and value is not null and status is distinct from 'forecast' + order by series_id, period desc`; + return Object.fromEntries(rows.map((r) => [r.series_id, { period: r.period, value: r.value }])); +} diff --git a/src/lib/stats/countries.ts b/src/lib/stats/countries.ts new file mode 100644 index 0000000..53a0f93 --- /dev/null +++ b/src/lib/stats/countries.ts @@ -0,0 +1,130 @@ +// Country profiles for /stats/countries and /stats/countries/[iso3]: which regions get a page, +// and which normalised series (World Bank, IMF WEO) feed each indicator. IMF first where it +// exists (it has forecasts); the World Bank fills in for places the IMF skips, like Curaçao. + +export const COUNTRY_PAGES = [ + 'NLD', + 'CUW', + 'USA', + 'KOR', + 'CHN', + 'DEU', + 'FRA', + 'BEL', + 'GBR', + 'JPN', + 'IND', + 'BRA', + 'RUS', + 'EU27', + 'WLD' +] as const; +export type CountryCode = (typeof COUNTRY_PAGES)[number]; +export const isCountryPage = (code: string): code is CountryCode => + (COUNTRY_PAGES as readonly string[]).includes(code); + +export const FLAG: Record = { + NLD: '🇳🇱', + CUW: '🇨🇼', + USA: '🇺🇸', + KOR: '🇰🇷', + CHN: '🇨🇳', + DEU: '🇩🇪', + FRA: '🇫🇷', + BEL: '🇧🇪', + GBR: '🇬🇧', + JPN: '🇯🇵', + IND: '🇮🇳', + BRA: '🇧🇷', + RUS: '🇷🇺', + EU27: '🇪🇺', + WLD: '🌍' +}; + +export const COUNTRY_COLOR: Record = { + NLD: '#f97316', + CUW: '#06b6d4', + USA: '#3b82f6', + KOR: '#e11d48', + CHN: '#eab308', + DEU: '#64748b', + FRA: '#6366f1', + BEL: '#a16207', + GBR: '#a855f7', + JPN: '#ec4899', + IND: '#10b981', + BRA: '#84cc16', + RUS: '#0d9488', + EU27: '#1d4ed8', + WLD: '#94a3b8' +}; + +/** Comparison columns: series id candidates in order of preference ({c} = region code). */ +export const COMPARE_COLUMNS = [ + { key: 'pop', label: 'Population', ids: ['wb:SP.POP.TOTL:{c}'], fmt: 'compact' }, + { key: 'gdppc', label: 'GDP/cap PPP', ids: ['wb:NY.GDP.PCAP.PP.KD:{c}'], fmt: 'usd' }, + { + key: 'growth', + label: 'Growth', + ids: ['imf:NGDP_RPCH:{c}', 'wb:NY.GDP.MKTP.KD.ZG:{c}'], + fmt: 'pct' + }, + { + key: 'infl', + label: 'Inflation', + ids: ['imf:PCPIPCH:{c}', 'wb:FP.CPI.TOTL.ZG:{c}'], + fmt: 'pct' + }, + { + key: 'unemp', + label: 'Unemployment', + ids: ['imf:LUR:{c}', 'wb:SL.UEM.TOTL.ZS:{c}'], + fmt: 'pct' + }, + { + key: 'debt', + label: 'Gov. debt', + ids: ['imf:GGXWDG_NGDP:{c}', 'wb:GC.DOD.TOTL.GD.ZS:{c}'], + fmt: 'pct' + }, + { key: 'life', label: 'Life exp.', ids: ['wb:SP.DYN.LE00.IN:{c}'], fmt: 'years' } +] as const; + +export const seriesIds = (c: string, ids: readonly string[]) => ids.map((i) => i.replace('{c}', c)); + +/** Indicators shown on a country page (World Bank ids unless prefixed). */ +export const PROFILE_SERIES = [ + 'wb:SP.POP.TOTL', + 'wb:SM.POP.NETM', + 'wb:SP.DYN.LE00.IN', + 'wb:SP.DYN.TFRT.IN', + 'wb:SP.POP.65UP.TO.ZS', + 'wb:NY.GDP.PCAP.KD', + 'wb:NY.GDP.PCAP.PP.KD', + 'wb:NY.GNP.PCAP.CD', + 'wb:NY.GDP.MKTP.CD', + 'wb:NY.GDP.MKTP.KD.ZG', + 'wb:FP.CPI.TOTL.ZG', + 'wb:SL.UEM.TOTL.ZS', + 'wb:NE.TRD.GNFS.ZS', + 'wb:NE.EXP.GNFS.ZS', + 'wb:NE.IMP.GNFS.ZS', + 'wb:NV.SRV.TOTL.ZS', + 'wb:ST.INT.ARVL', + 'wb:ST.INT.RCPT.CD', + 'wb:EG.IMP.CONS.ZS', + 'wb:EG.ELC.RNEW.ZS', + 'wb:TM.TAX.MRCH.WM.AR.ZS', + 'wb:GC.REV.XGRT.GD.ZS', + 'wb:GC.XPN.TOTL.GD.ZS', + 'wb:GC.DOD.TOTL.GD.ZS', + 'imf:NGDP_RPCH', + 'imf:NGDPDPC', + 'imf:PPPPC', + 'imf:PCPIPCH', + 'imf:LUR', + 'imf:GGXWDG_NGDP', + 'imf:GGXCNL_NGDP', + 'imf:GGR_G01_GDP_PT', + 'imf:G_X_G01_GDP_PT' +]; diff --git a/src/lib/stats/regions.ts b/src/lib/stats/regions.ts index da43d03..e336d41 100644 --- a/src/lib/stats/regions.ts +++ b/src/lib/stats/regions.ts @@ -31,5 +31,8 @@ export const COUNTRY: Record = { BEL: 'Belgium', GBR: 'United Kingdom', JPN: 'Japan', - IND: 'India' + IND: 'India', + BRA: 'Brazil', + RUS: 'Russia', + EU27: 'European Union' }; diff --git a/src/routes/sitemap.xml/+server.ts b/src/routes/sitemap.xml/+server.ts index 9b7705c..9c3eb05 100644 --- a/src/routes/sitemap.xml/+server.ts +++ b/src/routes/sitemap.xml/+server.ts @@ -18,6 +18,8 @@ const staticPaths = [ '/stats/economy', '/stats/energy', '/stats/gouda', + '/stats/countries', + '/stats/countries/CUW', '/trackers/books', '/trackers/spotting', '/trackers/cars', diff --git a/src/routes/start/+page.svelte b/src/routes/start/+page.svelte index 15cd46c..d349981 100644 --- a/src/routes/start/+page.svelte +++ b/src/routes/start/+page.svelte @@ -51,7 +51,9 @@ { name: 'Stats', href: '/stats' }, { name: 'Stats: economy', href: '/stats/economy' }, { name: 'Stats: energy', href: '/stats/energy' }, - { name: 'Stats: Gouda', href: '/stats/gouda' } + { name: 'Stats: Gouda', href: '/stats/gouda' }, + { name: 'Stats: countries', href: '/stats/countries' }, + { name: 'Stats: Curaçao', href: '/stats/countries/CUW' } ]; const host = $derived(data.host); diff --git a/src/routes/stats/+page.svelte b/src/routes/stats/+page.svelte index 4072529..ac7b807 100644 --- a/src/routes/stats/+page.svelte +++ b/src/routes/stats/+page.svelte @@ -7,6 +7,8 @@ import Landmark from 'lucide-svelte/icons/landmark'; import Flame from 'lucide-svelte/icons/flame'; import House from 'lucide-svelte/icons/house'; + import Globe from 'lucide-svelte/icons/globe'; + import Palmtree from 'lucide-svelte/icons/tree-palm'; import ArrowRight from 'lucide-svelte/icons/arrow-right'; let { data } = $props(); @@ -62,6 +64,20 @@ icon: House, grad: 'linear-gradient(135deg,#10b981,#06b6d4)', text: 'Population since 1942, house prices, housing stock, municipal levies and neighbourhoods, next to the surrounding towns.' + }, + { + href: '/stats/countries', + title: 'Countries', + icon: Globe, + grad: 'linear-gradient(135deg,#a855f7,#ec4899)', + text: 'The Netherlands, Curaçao, the US, South Korea, China and more side by side: income, growth, inflation, debt and life expectancy.' + }, + { + href: '/stats/countries/CUW', + title: 'Curaçao', + icon: Palmtree, + grad: 'linear-gradient(135deg,#06b6d4,#3b82f6)', + text: 'Population, income, inflation, tourism, trade and government finances of Curaçao.' } ] as const; @@ -164,7 +180,7 @@
{#each SECTIONS as sec (sec.href)} {@const Icon = sec.icon} - + {sec.title} diff --git a/src/routes/stats/countries/+page.server.ts b/src/routes/stats/countries/+page.server.ts new file mode 100644 index 0000000..829f1c4 --- /dev/null +++ b/src/routes/stats/countries/+page.server.ts @@ -0,0 +1,29 @@ +import { cached, loadLatest, loadSeries } from '#lib/server/stats.js'; +import { COMPARE_COLUMNS, COUNTRY_PAGES, seriesIds } from '#lib/stats/countries.js'; +import type { PageServerLoad } from './$types'; + +export const load: PageServerLoad = async () => + cached('stats:countries', async () => { + const ids = COUNTRY_PAGES.flatMap((c) => + COMPARE_COLUMNS.flatMap((col) => seriesIds(c, col.ids)) + ); + const [latest, series] = await Promise.all([ + loadLatest(ids), + loadSeries( + COUNTRY_PAGES.flatMap((c) => [ + { id: `wb:NY.GDP.PCAP.PP.KD:${c}` }, + { id: `wb:SP.DYN.LE00.IN:${c}`, from: '1960-01-01' } + ]) + ) + ]); + const rows = COUNTRY_PAGES.map((c) => ({ + code: c, + values: Object.fromEntries( + COMPARE_COLUMNS.map((col) => { + const id = seriesIds(c, col.ids).find((i) => latest[i]); + return [col.key, id ? { ...latest[id], source: id.split(':')[0] } : null]; + }) + ) + })); + return { rows, series }; + }); diff --git a/src/routes/stats/countries/+page.svelte b/src/routes/stats/countries/+page.svelte new file mode 100644 index 0000000..7f9eeeb --- /dev/null +++ b/src/routes/stats/countries/+page.svelte @@ -0,0 +1,174 @@ + + + + countries · stats · Stan Runge + + + +
+ stats / countries +

Countries

+

+ The places I compare most, side by side. Latest actual values (no forecasts) from the World Bank + and the IMF World Economic Outlook; the IMF is used where it covers a country. Click a country + for its full profile. +

+
+ +
+ + + + + {#each COMPARE_COLUMNS as col (col.key)}{/each} + + + + {#each data.rows as r (r.code)} + + + {#each COMPARE_COLUMNS as col (col.key)} + {@const v = r.values[col.key]} + + {/each} + + {/each} + +
Country{col.label}
+ {FLAG[r.code]}{name(r.code)} + {show(v, col.fmt)}{v ? ` '${v.period.slice(2, 4)}` : ''}
+
+

+ Small numbers after each value are the year it refers to. GDP per capita in constant 2021 + international dollars (PPP). Growth, inflation, unemployment and debt from the IMF where + available, otherwise the World Bank. +

+ +
+ barRankOption(t, rank('gdppc'), { decimals: 0, unit: '$', color: '#10b981' })} + /> + barRankOption(t, rank('life'), { decimals: 1, unit: 'yr', color: '#a855f7' })} + /> + lineOption(t, gdpLines, { unit: '$', decimals: 0 })} + /> + lineOption(t, lifeLines, { unit: 'years', decimals: 1, min: 'dataMin' })} + /> + barRankOption(t, rank('debt'), { decimals: 0, unit: '%', color: '#e11d48' })} + /> + barRankOption(t, rank('infl'), { decimals: 1, unit: '%', color: '#f97316' })} + /> +
+ + diff --git a/src/routes/stats/countries/[iso3]/+page.server.ts b/src/routes/stats/countries/[iso3]/+page.server.ts new file mode 100644 index 0000000..d5ea01c --- /dev/null +++ b/src/routes/stats/countries/[iso3]/+page.server.ts @@ -0,0 +1,23 @@ +import { error, redirect } from '@sveltejs/kit'; +import { cached, loadSeries } from '#lib/server/stats.js'; +import { isCountryPage, PROFILE_SERIES } from '#lib/stats/countries.js'; +import type { PageServerLoad } from './$types'; + +export const load: PageServerLoad = async ({ params, url }) => { + const code = params.iso3.toUpperCase(); + if (code !== params.iso3 && isCountryPage(code)) + redirect(308, `/stats/countries/${code}${url.search}`); + if (!isCountryPage(code)) error(404, 'Not Found'); + const series = await cached(`stats:country:${code}`, () => + loadSeries([ + ...PROFILE_SERIES.map((id) => `${id}:${code}`), + // Benchmarks for the "next to the Netherlands and the world" lines. + ...['NLD', 'WLD'].flatMap((c) => [ + `wb:NY.GDP.PCAP.PP.KD:${c}`, + `wb:SP.DYN.LE00.IN:${c}`, + `wb:FP.CPI.TOTL.ZG:${c}` + ]) + ]) + ); + return { code, series }; +}; diff --git a/src/routes/stats/countries/[iso3]/+page.svelte b/src/routes/stats/countries/[iso3]/+page.svelte new file mode 100644 index 0000000..14ce7c0 --- /dev/null +++ b/src/routes/stats/countries/[iso3]/+page.svelte @@ -0,0 +1,428 @@ + + + + {name} · countries · stats · Stan Runge + + + +
+ countries + stats / countries / {c} +

{FLAG[c]} {name}

+

+ {#if c === 'CUW'} + Curaçao has been a country within the Kingdom of the Netherlands since 2010, with about + 150,000 inhabitants. The IMF's World Economic Outlook doesn't cover it, so the headline + numbers here come from the World Bank; detailed CBS Curaçao and central bank series are on + their way. + {:else} + {name} at a glance, from the World Bank's development indicators and the IMF World Economic Outlook{imfCovered + ? ' (dashed lines are IMF forecasts)' + : ''}. + {/if} +

+
+ +
+ + + + + {#if kUnemp} + + {/if} + {#if kDebt} + + {/if} + + {#if kTour} + + {/if} +
+ +

People

+
+ + lineOption( + t, + [ + { name: 'Population', points: pts('wb:SP.POP.TOTL'), color, kind: 'area' }, + { + name: 'Net migration', + points: pts('wb:SM.POP.NETM'), + color: '#64748b', + kind: 'bar', + right: true + } + ], + { decimals: 0, min: 'dataMin', rightUnit: 'people' } + )} + /> + + lineOption( + t, + [ + { name, points: pts('wb:SP.DYN.LE00.IN'), color }, + ...(c !== 'NLD' + ? [ + { + name: 'Netherlands', + points: pts('wb:SP.DYN.LE00.IN', 'NLD'), + color: '#f97316', + dashed: true + } + ] + : []), + ...(c !== 'WLD' + ? [ + { + name: 'World', + points: pts('wb:SP.DYN.LE00.IN', 'WLD'), + color: '#94a3b8', + dashed: true + } + ] + : []) + ], + { unit: 'years', decimals: 1, min: 'dataMin' } + )} + /> + + lineOption( + t, + [ + { name: 'Fertility rate', points: pts('wb:SP.DYN.TFRT.IN'), color: '#ec4899' }, + { + name: 'Aged 65+ (%)', + points: pts('wb:SP.POP.65UP.TO.ZS'), + color: '#64748b', + right: true + } + ], + { unit: 'births', rightUnit: '%', decimals: 2 } + )} + /> +
+ +

Economy

+
+ + lineOption( + t, + [ + { name, points: pts('wb:NY.GDP.PCAP.PP.KD'), color }, + ...(c !== 'NLD' + ? [ + { + name: 'Netherlands', + points: pts('wb:NY.GDP.PCAP.PP.KD', 'NLD'), + color: '#f97316', + dashed: true + } + ] + : []), + ...(c !== 'WLD' + ? [ + { + name: 'World', + points: pts('wb:NY.GDP.PCAP.PP.KD', 'WLD'), + color: '#94a3b8', + dashed: true + } + ] + : []) + ], + { unit: '$', decimals: 0 } + )} + /> + + lineOption( + t, + has('imf:NGDP_RPCH') + ? imfLines('imf:NGDP_RPCH', 'Growth', '#3b82f6') + : [ + { name: 'Growth', points: pts('wb:NY.GDP.MKTP.KD.ZG'), color: '#3b82f6', kind: 'bar' } + ], + { unit: '%', decimals: 1, legend: has('imf:NGDP_RPCH') } + )} + /> + + lineOption( + t, + [ + ...(has('imf:PCPIPCH') + ? imfLines('imf:PCPIPCH', name, '#e11d48') + : [{ name, points: pts('wb:FP.CPI.TOTL.ZG'), color: '#e11d48' }]), + ...(c !== 'NLD' + ? [ + { + name: 'Netherlands', + points: pts('wb:FP.CPI.TOTL.ZG', 'NLD'), + color: '#f97316', + dashed: true + } + ] + : []) + ], + { unit: '%', decimals: 1 } + )} + /> + {#if has('imf:LUR') || has('wb:SL.UEM.TOTL.ZS')} + + lineOption( + t, + has('imf:LUR') + ? imfLines('imf:LUR', 'Unemployment', '#a855f7') + : [{ name: 'Unemployment', points: pts('wb:SL.UEM.TOTL.ZS'), color: '#a855f7' }], + { unit: '%', decimals: 1 } + )} + /> + {/if} + {#if has('wb:NE.EXP.GNFS.ZS') || has('wb:NE.TRD.GNFS.ZS')} + + lineOption( + t, + [ + { name: 'Exports', points: pts('wb:NE.EXP.GNFS.ZS'), color: '#10b981' }, + { name: 'Imports', points: pts('wb:NE.IMP.GNFS.ZS'), color: '#e11d48' }, + { + name: 'Services value added', + points: pts('wb:NV.SRV.TOTL.ZS'), + color: '#64748b', + dashed: true + } + ], + { unit: '% GDP', decimals: 1 } + )} + /> + {/if} + {#if has('wb:ST.INT.ARVL') || has('wb:ST.INT.RCPT.CD')} + + lineOption( + t, + [ + { name: 'Arrivals', points: pts('wb:ST.INT.ARVL'), color: '#eab308', kind: 'bar' }, + { name: 'Receipts', points: pts('wb:ST.INT.RCPT.CD'), color: '#06b6d4', right: true } + ], + { decimals: 0, rightUnit: 'US$' } + )} + /> + {/if} +
+ +

Government and energy

+
+ + lineOption( + t, + has('imf:GGXWDG_NGDP') + ? [ + ...imfLines('imf:GGXWDG_NGDP', 'Debt', '#e11d48'), + ...imfLines('imf:GGR_G01_GDP_PT', 'Revenue', '#10b981'), + ...imfLines('imf:G_X_G01_GDP_PT', 'Spending', '#3b82f6') + ] + : [ + { name: 'Debt', points: pts('wb:GC.DOD.TOTL.GD.ZS'), color: '#e11d48' }, + { name: 'Revenue', points: pts('wb:GC.REV.XGRT.GD.ZS'), color: '#10b981' }, + { name: 'Expense', points: pts('wb:GC.XPN.TOTL.GD.ZS'), color: '#3b82f6' } + ], + { unit: '% GDP', decimals: 1 } + )} + note={!has('imf:GGXWDG_NGDP') && !has('wb:GC.DOD.TOTL.GD.ZS') + ? 'No government finance data for this country yet.' + : ''} + /> + + lineOption( + t, + [ + { name: 'Net energy imports', points: pts('wb:EG.IMP.CONS.ZS'), color: '#64748b' }, + { name: 'Renewable electricity', points: pts('wb:EG.ELC.RNEW.ZS'), color: '#10b981' } + ], + { unit: '%', decimals: 1 } + )} + /> +
+ +