Cities with Internet: India by state, "ever used the internet", women and men
Country-level internet data is not good enough for India. This adds the first sub-national layer, from the one open, machine-readable source verified for it: NFHS-5 (2019-21, IIPS / MoHFW), "women / men aged 15-49 who have ever used the internet (%)", urban / rural / total, for every state and UT (CSV transcription of the state fact sheets, CC BY 4.0; SPEC-GRANULAR-INTERNET.md). - data/internet/: the two NFHS-5 internet rows (with provenance, licence and upstream commit), plus a strict crosswalk from source names to the shipped gb-IND-ADM1 shapeNames. - plugin-designs/cities-internet/scripts/build-adm1-internet.mjs (`bun run internet:adm1`) writes data/tables/internet-by-adm1.json. It is GENERIC, one row per iso3 x adm1 x measure x sex x area, with meta naming measures, sources, boundary files and the national figures, so go-int and other plugins can reuse it. It fails on an unmatched name or a value outside 0-100: a name is never guessed. - The map draws India's states in a blue ramp (0-25-40-55-70%+), leading with women, with a Women / Men toggle. A tapped state shows both halves, urban / rural / total. Its own legend block names the measure, survey, years and ages, and says it counts people, not subscriptions, so it is never read as the World Bank country bands. India's national band is taken out under its states. - The shipped boundary file is the UPG-100 partition (34 of 36 units): Mizoram and Nagaland have data but no geometry. They stay in the table and the legend names them. - 8 new strings under connectivity.adm1, in all 11 locales (library change: consumers need rebuilding). Headless: build and tree OK, and the table and gb-IND-ADM1 are staged under assets/. The fill expression validates with maplibre-gl-style-spec, and all 34 shipped states get a colour (e.g. Bihar women 20.6 -> 0-25, Delhi men 85.2 -> 70+). A crosswalk poisoned to a wrong shapeName fails the generator. Passing: universal-props, no-free-identifiers, i18n-parity, i18n-never-translated, profiles-mount, composites-mount, no-orphan-gates, script-flags, quoted-scripts. Not rendered in a browser.
This commit is contained in:
parent
fc2fa2e4bf
commit
47a69fa1ce
18 changed files with 3014 additions and 1 deletions
23
data/internet/README.md
Normal file
23
data/internet/README.md
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# data/internet/ — internet use below the country level
|
||||
|
||||
Source files for `data/tables/internet-by-adm1.json`, which
|
||||
`plugin-designs/cities-internet/scripts/build-adm1-internet.mjs` writes. Edit the sources here and
|
||||
re-run the script; never edit the table by hand.
|
||||
|
||||
## nfhs5-internet-by-state.csv
|
||||
- **What:** India, National Family Health Survey 5 (NFHS-5, 2019–21, IIPS / Ministry of Health and
|
||||
Family Welfare), indicators 18 and 19: *Women / Men (age 15–49) who have ever used the internet (%)*,
|
||||
by state/UT, urban / rural / total (plus the NFHS-4 total).
|
||||
- **From:** the two internet rows of `NFHS-5-States.csv` in https://github.com/pratapvardhan/NFHS-5 at
|
||||
commit `93c67fed2403c8e533d178d293c5ba0411892b1e`, a CSV transcription of the official state fact sheets
|
||||
(http://rchiips.org/nfhs/). The transcriber notes that quality checks were minimal; the figures
|
||||
here were spot-checked against the national fact sheet (India: women 33.3%, men 57.1%).
|
||||
- **Licence:** the CSV is **CC BY 4.0**. Attribution: "NFHS-5 (IIPS/MoHFW) state fact sheets, via
|
||||
pratapvardhan/NFHS-5 (CC BY 4.0)".
|
||||
- **Measure:** a SURVEY SHARE OF PEOPLE (0–100%): has this person ever used the internet. It is
|
||||
not a subscription count (TRAI's "subscribers per 100" is a different measure and can exceed 100).
|
||||
|
||||
## adm1-crosswalk-IND.json
|
||||
Source state names → the `shapeName` of `plugin-designs/my-upg-100-list/data/gb-IND-ADM1.geojson`
|
||||
(served as `assets/boundaries/gb-IND-ADM1.geojson`). Every source name must appear here, with either
|
||||
the boundary name or `null` plus a reason. The build fails on anything else, never guesses.
|
||||
120
data/internet/adm1-crosswalk-IND.json
Normal file
120
data/internet/adm1-crosswalk-IND.json
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
{
|
||||
"_about": "NFHS-5 state name -> gb-IND-ADM1.geojson shapeName. null = no geometry to draw it on, with the reason. Checked by build-adm1-internet.mjs.",
|
||||
"map": {
|
||||
"Andaman & Nicobar Islands": {
|
||||
"adm1": "Andaman and Nicobar Islands"
|
||||
},
|
||||
"Andhra Pradesh": {
|
||||
"adm1": "Andhra Pradesh"
|
||||
},
|
||||
"Arunachal Pradesh": {
|
||||
"adm1": "Arunāchal Pradesh"
|
||||
},
|
||||
"Assam": {
|
||||
"adm1": "Assam"
|
||||
},
|
||||
"Bihar": {
|
||||
"adm1": "Bihār"
|
||||
},
|
||||
"Chandigarh": {
|
||||
"adm1": "Chandīgarh"
|
||||
},
|
||||
"Chhattisgarh": {
|
||||
"adm1": "Chhattīsgarh"
|
||||
},
|
||||
"Dadra & Nagar Haveli and Daman & Diu": {
|
||||
"adm1": "Dādra and Nagar Haveli and Damān and Diu"
|
||||
},
|
||||
"Goa": {
|
||||
"adm1": "Goa"
|
||||
},
|
||||
"Gujarat": {
|
||||
"adm1": "Gujarāt"
|
||||
},
|
||||
"Haryana": {
|
||||
"adm1": "Haryāna"
|
||||
},
|
||||
"Himachal Pradesh": {
|
||||
"adm1": "Himāchal Pradesh"
|
||||
},
|
||||
"India": {
|
||||
"adm1": null,
|
||||
"national": true,
|
||||
"reason": "the national row, kept as the national reference"
|
||||
},
|
||||
"Jammu & Kashmir": {
|
||||
"adm1": "Jammu and Kashmīr"
|
||||
},
|
||||
"Jharkhand": {
|
||||
"adm1": "Jhārkhand"
|
||||
},
|
||||
"Karnataka": {
|
||||
"adm1": "Karnātaka"
|
||||
},
|
||||
"Kerala": {
|
||||
"adm1": "Kerala"
|
||||
},
|
||||
"Ladakh": {
|
||||
"adm1": "Ladākh"
|
||||
},
|
||||
"Lakshadweep": {
|
||||
"adm1": "Lakshadweep"
|
||||
},
|
||||
"Madhya Pradesh": {
|
||||
"adm1": "Madhya Pradesh"
|
||||
},
|
||||
"Maharashtra": {
|
||||
"adm1": "Mahārāshtra"
|
||||
},
|
||||
"Manipur": {
|
||||
"adm1": "Manipur"
|
||||
},
|
||||
"Meghalaya": {
|
||||
"adm1": "Meghālaya"
|
||||
},
|
||||
"Mizoram": {
|
||||
"adm1": null,
|
||||
"reason": "excluded from the shipped boundary file, which is the UPG-100 partition (my-upg-100-list/data/source-boundaries.mjs: 36 units upstream, 34 on disk)"
|
||||
},
|
||||
"NCT Delhi": {
|
||||
"adm1": "Delhi"
|
||||
},
|
||||
"Nagaland": {
|
||||
"adm1": null,
|
||||
"reason": "excluded from the shipped boundary file, which is the UPG-100 partition (my-upg-100-list/data/source-boundaries.mjs: 36 units upstream, 34 on disk)"
|
||||
},
|
||||
"Odisha": {
|
||||
"adm1": "Odisha"
|
||||
},
|
||||
"Puducherry": {
|
||||
"adm1": "Puducherry"
|
||||
},
|
||||
"Punjab": {
|
||||
"adm1": "Punjab"
|
||||
},
|
||||
"Rajasthan": {
|
||||
"adm1": "Rājasthān"
|
||||
},
|
||||
"Sikkim": {
|
||||
"adm1": "Sikkim"
|
||||
},
|
||||
"Tamil Nadu": {
|
||||
"adm1": "Tamil Nādu"
|
||||
},
|
||||
"Telangana": {
|
||||
"adm1": "Telangāna"
|
||||
},
|
||||
"Tripura": {
|
||||
"adm1": "Tripura"
|
||||
},
|
||||
"Uttar Pradesh": {
|
||||
"adm1": "Uttar Pradesh"
|
||||
},
|
||||
"Uttarakhand": {
|
||||
"adm1": "Uttarākhand"
|
||||
},
|
||||
"West Bengal": {
|
||||
"adm1": "West Bengal"
|
||||
}
|
||||
}
|
||||
}
|
||||
75
data/internet/nfhs5-internet-by-state.csv
Normal file
75
data/internet/nfhs5-internet-by-state.csv
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
state,state_code,indicator,nfhs5_urban,nfhs5_rural,nfhs5_total,nfhs4_total
|
||||
India,,18. Women who have ever used the internet (%),51.8,24.6,33.3,
|
||||
India,,19. Men who have ever used the internet (%),72.5,48.7,57.1,
|
||||
Andaman & Nicobar Islands,AN,18. Women who have ever used the internet (%),44.1,27.9,34.8,
|
||||
Andaman & Nicobar Islands,AN,19. Men who have ever used the internet (%),54.6,41.1,46.5,
|
||||
Andhra Pradesh,AP,18. Women who have ever used the internet (%),33.9,15.4,21.0,
|
||||
Andhra Pradesh,AP,19. Men who have ever used the internet (%),65.1,41.5,48.8,
|
||||
Arunachal Pradesh,AR,18. Women who have ever used the internet (%),70.0,49.6,52.9,
|
||||
Arunachal Pradesh,AR,19. Men who have ever used the internet (%),86.9,68.5,71.6,
|
||||
Assam,AS,18. Women who have ever used the internet (%),49.0,24.4,28.2,
|
||||
Assam,AS,19. Men who have ever used the internet (%),67.4,37.8,42.3,
|
||||
Bihar,BR,18. Women who have ever used the internet (%),38.4,17.0,20.6,
|
||||
Bihar,BR,19. Men who have ever used the internet (%),58.4,39.4,43.6,
|
||||
Chandigarh,CH,18. Women who have ever used the internet (%),75.2,,75.2,
|
||||
Chandigarh,CH,19. Men who have ever used the internet (%),91.9,,91.9,
|
||||
Chhattisgarh,CT,18. Women who have ever used the internet (%),44.5,20.8,26.7,
|
||||
Chhattisgarh,CT,19. Men who have ever used the internet (%),75.4,50.4,56.3,
|
||||
Dadra & Nagar Haveli and Daman & Diu,DD,18. Women who have ever used the internet (%),49.4,23.8,36.7,
|
||||
Dadra & Nagar Haveli and Daman & Diu,DD,19. Men who have ever used the internet (%),76.2,61.3,68.3,
|
||||
NCT Delhi,DL,18. Women who have ever used the internet (%),63.7,69.2,63.8,
|
||||
NCT Delhi,DL,19. Men who have ever used the internet (%),85.1,87.4,85.2,
|
||||
Goa,GA,18. Women who have ever used the internet (%),78.1,68.3,73.7,
|
||||
Goa,GA,19. Men who have ever used the internet (%),86.1,76.6,82.9,
|
||||
Gujarat,GJ,18. Women who have ever used the internet (%),48.9,17.5,30.8,
|
||||
Gujarat,GJ,19. Men who have ever used the internet (%),72.9,48.0,58.9,
|
||||
Himachal Pradesh,HP,18. Women who have ever used the internet (%),78.9,45.2,49.7,
|
||||
Himachal Pradesh,HP,19. Men who have ever used the internet (%),83.7,65.1,67.9,
|
||||
Haryana,HR,18. Women who have ever used the internet (%),60.2,42.8,48.4,
|
||||
Haryana,HR,19. Men who have ever used the internet (%),79.7,68.8,72.4,
|
||||
Jharkhand,JH,18. Women who have ever used the internet (%),57.8,22.7,31.4,
|
||||
Jharkhand,JH,19. Men who have ever used the internet (%),70.8,53.2,58.0,
|
||||
Jammu & Kashmir,JK,18. Women who have ever used the internet (%),55.0,38.9,43.3,
|
||||
Jammu & Kashmir,JK,19. Men who have ever used the internet (%),79.4,68.8,72.0,
|
||||
Karnataka,KA,18. Women who have ever used the internet (%),50.1,24.8,35.0,
|
||||
Karnataka,KA,19. Men who have ever used the internet (%),71.5,55.6,62.4,
|
||||
Kerala,KL,18. Women who have ever used the internet (%),64.9,57.5,61.1,
|
||||
Kerala,KL,19. Men who have ever used the internet (%),78.3,74.2,76.1,
|
||||
Lakshadweep,LD,18. Women who have ever used the internet (%),61.8,36.0,56.4,
|
||||
Lakshadweep,LD,19. Men who have ever used the internet (%),81.5,77.0,80.3,
|
||||
Ladakh,LH,18. Women who have ever used the internet (%),66.5,54.0,56.4,
|
||||
Ladakh,LH,19. Men who have ever used the internet (%),82.9,64.3,67.8,
|
||||
Maharashtra,MH,18. Women who have ever used the internet (%),54.3,23.7,38.0,
|
||||
Maharashtra,MH,19. Men who have ever used the internet (%),76.8,47.2,61.5,
|
||||
Meghalaya,ML,18. Women who have ever used the internet (%),57.8,28.0,34.7,
|
||||
Meghalaya,ML,19. Men who have ever used the internet (%),59.2,38.5,42.1,
|
||||
Manipur,MN,18. Women who have ever used the internet (%),50.8,40.4,44.8,
|
||||
Manipur,MN,19. Men who have ever used the internet (%),81.5,68.2,73.9,
|
||||
Madhya Pradesh,MP,18. Women who have ever used the internet (%),46.5,20.1,26.9,
|
||||
Madhya Pradesh,MP,19. Men who have ever used the internet (%),72.7,49.3,55.7,
|
||||
Mizoram,MZ,18. Women who have ever used the internet (%),83.8,48.0,67.6,
|
||||
Mizoram,MZ,19. Men who have ever used the internet (%),92.7,63.9,79.7,
|
||||
Nagaland,NL,18. Women who have ever used the internet (%),66.5,40.3,49.9,
|
||||
Nagaland,NL,19. Men who have ever used the internet (%),81.0,55.2,64.6,
|
||||
Odisha,OR,18. Women who have ever used the internet (%),39.7,21.3,24.9,
|
||||
Odisha,OR,19. Men who have ever used the internet (%),64.2,47.2,50.7,
|
||||
Punjab,PB,18. Women who have ever used the internet (%),64.1,48.8,54.8,
|
||||
Punjab,PB,19. Men who have ever used the internet (%),85.6,73.0,78.2,
|
||||
Puducherry,PY,18. Women who have ever used the internet (%),66.9,50.4,61.9,
|
||||
Puducherry,PY,19. Men who have ever used the internet (%),85.1,69.4,80.7,
|
||||
Rajasthan,RJ,18. Women who have ever used the internet (%),56.1,30.8,36.9,
|
||||
Rajasthan,RJ,19. Men who have ever used the internet (%),81.7,59.4,65.2,
|
||||
Sikkim,SK,18. Women who have ever used the internet (%),90.0,68.1,76.7,
|
||||
Sikkim,SK,19. Men who have ever used the internet (%),94.2,69.5,78.2,
|
||||
Telangana,TG,18. Women who have ever used the internet (%),43.9,15.8,26.5,
|
||||
Telangana,TG,19. Men who have ever used the internet (%),72.3,46.7,57.4,
|
||||
Tamil Nadu,TN,18. Women who have ever used the internet (%),55.8,39.2,46.9,
|
||||
Tamil Nadu,TN,19. Men who have ever used the internet (%),76.1,64.9,70.2,
|
||||
Tripura,TR,18. Women who have ever used the internet (%),36.6,17.7,22.9,
|
||||
Tripura,TR,19. Men who have ever used the internet (%),47.0,45.2,45.7,
|
||||
Uttar Pradesh,UP,18. Women who have ever used the internet (%),50.2,24.5,30.6,
|
||||
Uttar Pradesh,UP,19. Men who have ever used the internet (%),72.4,54.2,59.1,
|
||||
Uttarakhand,UT,18. Women who have ever used the internet (%),58.4,39.4,45.1,
|
||||
Uttarakhand,UT,19. Men who have ever used the internet (%),82.1,71.2,74.6,
|
||||
West Bengal,WB,18. Women who have ever used the internet (%),48.1,14.0,25.5,
|
||||
West Bengal,WB,19. Men who have ever used the internet (%),64.6,38.3,46.7,
|
||||
|
2449
data/tables/internet-by-adm1.json
Normal file
2449
data/tables/internet-by-adm1.json
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -54,5 +54,15 @@
|
|||
"messaging": "تطبيقات المراسلة"
|
||||
},
|
||||
"loading": "جارٍ تحميل {name}…"
|
||||
},
|
||||
"adm1": {
|
||||
"title": "الهند حسب الولاية: سبق لهم استخدام الإنترنت",
|
||||
"women": "النساء",
|
||||
"men": "الرجال",
|
||||
"total": "الإجمالي",
|
||||
"urban": "الحضر",
|
||||
"rural": "الريف",
|
||||
"source": "المسح NFHS-5 (2019–2021)، الأشخاص من 15 إلى 49 عامًا: نسبة من سبق لهم استخدام الإنترنت. مسح للأشخاص، لا عدد للاشتراكات.",
|
||||
"missing": "لا توجد بعد حدود ولاية لـ {names}: أرقامها موجودة في البيانات، لا على الخريطة."
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,5 +54,15 @@
|
|||
"messaging": "Messenger"
|
||||
},
|
||||
"loading": "{name} wird geladen…"
|
||||
},
|
||||
"adm1": {
|
||||
"title": "Indien nach Bundesstaat: haben das Internet schon genutzt",
|
||||
"women": "Frauen",
|
||||
"men": "Männer",
|
||||
"total": "Gesamt",
|
||||
"urban": "Stadt",
|
||||
"rural": "Land",
|
||||
"source": "NFHS-5 (2019–21), Personen im Alter von 15–49 Jahren: Anteil derer, die das Internet schon einmal genutzt haben. Eine Befragung von Menschen, keine Zählung von Anschlüssen.",
|
||||
"missing": "Noch keine Staatsgrenze für {names}: Ihre Werte stehen in den Daten, nicht auf der Karte."
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,5 +54,15 @@
|
|||
"messaging": "Messaging Apps"
|
||||
},
|
||||
"loading": "Loading {name}…"
|
||||
},
|
||||
"adm1": {
|
||||
"title": "India by state: ever used the internet",
|
||||
"women": "Women",
|
||||
"men": "Men",
|
||||
"total": "Total",
|
||||
"urban": "Urban",
|
||||
"rural": "Rural",
|
||||
"source": "NFHS-5 (2019–21), people aged 15–49: the share who have ever used the internet. A survey of people, not a count of subscriptions.",
|
||||
"missing": "No state boundary yet for {names}: their figures are in the data, not on the map."
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,5 +54,15 @@
|
|||
"messaging": "Mensajería"
|
||||
},
|
||||
"loading": "Cargando {name}…"
|
||||
},
|
||||
"adm1": {
|
||||
"title": "India por estado: han usado internet alguna vez",
|
||||
"women": "Mujeres",
|
||||
"men": "Hombres",
|
||||
"total": "Total",
|
||||
"urban": "Urbano",
|
||||
"rural": "Rural",
|
||||
"source": "NFHS-5 (2019–21), personas de 15 a 49 años: proporción que ha usado internet alguna vez. Una encuesta a personas, no un recuento de suscripciones.",
|
||||
"missing": "Aún no hay límite estatal para {names}: sus cifras están en los datos, no en el mapa."
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,5 +54,15 @@
|
|||
"messaging": "Messageries"
|
||||
},
|
||||
"loading": "Chargement de {name}…"
|
||||
},
|
||||
"adm1": {
|
||||
"title": "Inde par État : ont déjà utilisé Internet",
|
||||
"women": "Femmes",
|
||||
"men": "Hommes",
|
||||
"total": "Total",
|
||||
"urban": "Urbain",
|
||||
"rural": "Rural",
|
||||
"source": "NFHS-5 (2019–21), personnes de 15 à 49 ans : part de celles qui ont déjà utilisé Internet. Une enquête auprès des personnes, pas un décompte d’abonnements.",
|
||||
"missing": "Pas encore de limite d’État pour {names} : leurs chiffres figurent dans les données, pas sur la carte."
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,5 +54,15 @@
|
|||
"messaging": "मैसेजिंग ऐप"
|
||||
},
|
||||
"loading": "{name} लोड हो रहा है…"
|
||||
},
|
||||
"adm1": {
|
||||
"title": "भारत राज्य अनुसार: कभी इंटरनेट का उपयोग किया",
|
||||
"women": "महिलाएँ",
|
||||
"men": "पुरुष",
|
||||
"total": "कुल",
|
||||
"urban": "शहरी",
|
||||
"rural": "ग्रामीण",
|
||||
"source": "NFHS-5 (2019–21), 15–49 वर्ष के लोग: जिन्होंने कभी इंटरनेट का उपयोग किया है उनका प्रतिशत। यह लोगों का सर्वेक्षण है, सब्सक्रिप्शन की गिनती नहीं।",
|
||||
"missing": "{names} की राज्य सीमा अभी उपलब्ध नहीं है: उनके आँकड़े डेटा में हैं, नक्शे पर नहीं।"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,5 +54,15 @@
|
|||
"messaging": "Messaggistica"
|
||||
},
|
||||
"loading": "Caricamento di {name}…"
|
||||
},
|
||||
"adm1": {
|
||||
"title": "India per Stato: hanno mai usato internet",
|
||||
"women": "Donne",
|
||||
"men": "Uomini",
|
||||
"total": "Totale",
|
||||
"urban": "Urbano",
|
||||
"rural": "Rurale",
|
||||
"source": "NFHS-5 (2019–21), persone di 15–49 anni: quota di chi ha mai usato internet. Un’indagine sulle persone, non un conteggio di abbonamenti.",
|
||||
"missing": "Ancora nessun confine statale per {names}: i loro dati sono nel dataset, non sulla mappa."
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,5 +54,15 @@
|
|||
"messaging": "Mensagens"
|
||||
},
|
||||
"loading": "A carregar {name}…"
|
||||
},
|
||||
"adm1": {
|
||||
"title": "Índia por estado: já usaram a internet",
|
||||
"women": "Mulheres",
|
||||
"men": "Homens",
|
||||
"total": "Total",
|
||||
"urban": "Urbano",
|
||||
"rural": "Rural",
|
||||
"source": "NFHS-5 (2019–21), pessoas de 15 a 49 anos: proporção que já usou a internet. Uma pesquisa com pessoas, não uma contagem de assinaturas.",
|
||||
"missing": "Ainda não há limite estadual para {names}: os números estão nos dados, não no mapa."
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,5 +54,15 @@
|
|||
"messaging": "Aplicații de mesagerie"
|
||||
},
|
||||
"loading": "Se încarcă {name}…"
|
||||
},
|
||||
"adm1": {
|
||||
"title": "India pe state: au folosit vreodată internetul",
|
||||
"women": "Femei",
|
||||
"men": "Bărbați",
|
||||
"total": "Total",
|
||||
"urban": "Urban",
|
||||
"rural": "Rural",
|
||||
"source": "NFHS-5 (2019–21), persoane de 15–49 de ani: ponderea celor care au folosit vreodată internetul. Un sondaj despre oameni, nu o numărătoare de abonamente.",
|
||||
"missing": "Încă nu există limită de stat pentru {names}: cifrele lor sunt în date, nu pe hartă."
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,5 +54,15 @@
|
|||
"messaging": "Мессенджеры"
|
||||
},
|
||||
"loading": "Загрузка: {name}…"
|
||||
},
|
||||
"adm1": {
|
||||
"title": "Индия по штатам: когда-либо пользовались интернетом",
|
||||
"women": "Женщины",
|
||||
"men": "Мужчины",
|
||||
"total": "Всего",
|
||||
"urban": "Город",
|
||||
"rural": "Село",
|
||||
"source": "NFHS-5 (2019–21), люди 15–49 лет: доля тех, кто когда-либо пользовался интернетом. Опрос людей, а не подсчёт подписок.",
|
||||
"missing": "Для {names} ещё нет границы штата: их данные есть в таблице, но не на карте."
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,5 +54,15 @@
|
|||
"messaging": "即时通讯"
|
||||
},
|
||||
"loading": "正在加载{name}…"
|
||||
},
|
||||
"adm1": {
|
||||
"title": "印度各邦:曾经使用过互联网",
|
||||
"women": "女性",
|
||||
"men": "男性",
|
||||
"total": "合计",
|
||||
"urban": "城市",
|
||||
"rural": "农村",
|
||||
"source": "NFHS-5(2019–21),15–49 岁人群:曾经使用过互联网的比例。这是对人的调查,而不是订阅数统计。",
|
||||
"missing": "{names} 尚无邦界:其数据在数据集中,但未显示在地图上。"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -202,6 +202,7 @@
|
|||
"gallery": "node internal/generate-gallery.mjs",
|
||||
"gates:post": "node internal/run-parallel.mjs --label=post -- check:drop check:parse verify check:sri check:public-hygiene check:label-joins check:facet-cascade check:facet-one-field check:heartbeat check:kpi-unit check:composite-reg check:descriptions check:no-abs-paths check:no-codename check:dep-names check:composite-srcs check:embed-targets check:nested-token check:i18n-parity check:tabs-localized check:packets-all check:packet-strings-parity check:zone-census check:share-policy check:library-index check:csv-shape check:capability-citations check:catalog-identity check:no-orphan-gates check:quoted-scripts check:done-evidence check:script-flags check:backlog-status check:capability-exemplars check:packet-fixture check:packet-browser check:provider-switch check:locale-reachable check:url-resolver check:manifest-covers check:one-palette check:pin-dim-slider check:legend-source check:backlog-refs check:clustering-modes check:composite-embed-knobs check:composite-locale-leaks check:linked-vocabulary check:wp-embed check:dashboard-geocoder-provider check:leaf-engine-per-provider check:map-props-unit check:composites-mount check:composite-interop check:no-free-identifiers check:map-fly-reduced-motion check:mst-clustering check:list-prop-unit check:profiles-mount check:cdn-pins check:no-eval check:popup-escaping check:i18n-treeshake check:pinned-umd check:one-palette:self-test",
|
||||
"gates:pre": "node internal/run-parallel.mjs --label=pre -- check:template-literal check:mjs-parse check:sfc-parse check:tab-radius check:synced-css check:doc-scripts",
|
||||
"internet:adm1": "node plugin-designs/cities-internet/scripts/build-adm1-internet.mjs",
|
||||
"library-index": "node internal/generate-library-index.mjs",
|
||||
"lists": "node library/scripts/people-groups/build-lists.mjs",
|
||||
"packet-fixture": "node internal/generate-packet-fixture.mjs",
|
||||
|
|
@ -360,6 +361,7 @@
|
|||
"check:zone-census": "every zone a USER CAN SELECT must have a poster (asks the LEGEND, not clusters.json — two collapsed deaf lists are unreachable and not a gap). CONDITIONAL: SKIPs without out/posters/, which is gitignored — run `bun run posters` first. It cannot be fixtured like check:packets-all, because it asserts COVERAGE of real generated output and a fixture would only assert the fixture is complete.",
|
||||
"deploy:dev": "destination + allowlist come from vite.doxa-maps-build-config.json (dropin.dest / dropin.include); DOXA_DROPIN_DEST=<dir> overrides the destination",
|
||||
"gallery": "writes public/__gallery/index.html — the ARCHIVED bundle-index gallery, from public/doxa-maps/manifest.json. It is NO LONGER the root page: as of 2026-09-22 `/` mounts <plugin-studio> in BOTH trees (the built root page is written by `bun run tree`), and the gallery is the opt-in index at /__gallery. Archived, not deleted — the dev server imports renderGallery()/readBuildConfig() from this module.",
|
||||
"internet:adm1": "regenerate data/tables/internet-by-adm1.json (internet use by first-level area; India from NFHS-5 2019-21, CC BY 4.0) from data/internet/ through a strict name crosswalk to the shipped gb-IND-ADM1 boundaries. Fails on an unmatched name, never guesses. Generic rows (iso3, adm1, measure, sex, area, value, source, year) so other plugins and go-int can reuse it.",
|
||||
"library-index": "regenerate documentation/reference-library-index.md — the DERIVED menu of the 84 reusable library pieces an author can import instead of rebuilding. Was UNREACHABLE, and the index did not exist at all: its header promised 'can't drift from the code' while nothing ever ran it.",
|
||||
"lists": "regenerate data/people-groups/lists/<id>.json, the DOXA slugs in each people-group list of library/lists/lists.json, from the IMB CSV and the DOXA snapshot. Re-run after either changes.",
|
||||
"packet-fixture": "regenerate the committed records subset (smallest zone, image_url stripped) that lets CI build a packet at all — out/ is gitignored, so a clean checkout has neither the records cache nor any packet.",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,10 @@ const rows = ref([])
|
|||
const selected = ref(null)
|
||||
const aiNoticeOpen = ref(true) // dismissible AI-research disclaimer in the detail sheet
|
||||
const err = ref(null)
|
||||
// India by state (data/tables/internet-by-adm1.json, NFHS-5): the one country with sub-national data.
|
||||
const adm1 = shallowRef(null) // { meta, byArea: { [adm1]: { name, women: {total,urban,rural}, men: {…} } } }
|
||||
const adm1Sex = ref('women') // which half of the survey the fill shows; both are in the sheet
|
||||
const selectedAdm1 = ref(null)
|
||||
|
||||
// ── People-group dots (Driver: "red dots on the map to show me where the people groups are")
|
||||
// The DOXA list from pray-tools, the same list Prayer Progress draws. It carries the slug the
|
||||
|
|
@ -264,12 +268,76 @@ function paint(map, adm0) {
|
|||
// A tap on a people-group dot belongs to the dot, not the country under it.
|
||||
if (map.getLayer('ci-pg-dots') && map.queryRenderedFeatures(e.point, { layers: ['ci-pg-dots'] }).length) return
|
||||
const iso = e.features?.[0]?.properties?.iso3
|
||||
if (iso && byIso.value[iso]) { uiStore?.selectPeopleGroup(null); selected.value = byIso.value[iso] }
|
||||
if (iso && byIso.value[iso]) { uiStore?.selectPeopleGroup(null); selectedAdm1.value = null; selected.value = byIso.value[iso] }
|
||||
})
|
||||
map.on('mouseenter', 'ci-fill', () => { map.getCanvas().style.cursor = 'pointer' })
|
||||
map.on('mouseleave', 'ci-fill', () => { map.getCanvas().style.cursor = '' })
|
||||
}
|
||||
|
||||
// ── INDIA BY STATE: "ever used the internet", NFHS-5 2019–21, women and men asked separately ─────
|
||||
// A share of PEOPLE (0–100%), so it gets its own ramp and its own legend block, never the country
|
||||
// bands: the bands are World Bank national "internet users", a different measure and source.
|
||||
// Blues, so no state can be read as one of the band colours.
|
||||
const ADM1_STEPS = [
|
||||
{ from: 0, color: '#deebf7' },
|
||||
{ from: 25, color: '#9ecae1' },
|
||||
{ from: 40, color: '#6baed6' },
|
||||
{ from: 55, color: '#3182bd' },
|
||||
{ from: 70, color: '#08519c' },
|
||||
]
|
||||
const adm1Fill = (sex) => ['case', ['==', ['typeof', ['get', sex]], 'number'],
|
||||
['step', ['get', sex], ...ADM1_STEPS.flatMap((st, i) => (i === 0 ? [st.color] : [st.from, st.color]))],
|
||||
'rgba(0,0,0,0)']
|
||||
|
||||
async function loadAdm1() {
|
||||
const [table, geo] = await Promise.all([
|
||||
fetch(`${assetsBase.value}/tables/internet-by-adm1.json`).then((r) => { if (!r.ok) throw new Error('internet-by-adm1 ' + r.status); return r.json() }),
|
||||
fetch(`${assetsBase.value}/boundaries/gb-IND-ADM1.geojson`).then((r) => { if (!r.ok) throw new Error('gb-IND-ADM1 ' + r.status); return r.json() }),
|
||||
])
|
||||
const byArea = {}
|
||||
for (const r of table.rows || []) {
|
||||
if (r.iso3 !== 'IND' || r.measure !== 'ever_used_internet' || !r.adm1) continue
|
||||
const a = (byArea[r.adm1] ??= { name: r.adm1_name || r.adm1, women: {}, men: {} })
|
||||
a[r.sex][r.area] = r.value
|
||||
}
|
||||
adm1.value = markRaw({ meta: table.meta || {}, byArea })
|
||||
return geo
|
||||
}
|
||||
|
||||
function paintAdm1(map, geo) {
|
||||
const byArea = adm1.value.byArea
|
||||
const fc = { type: 'FeatureCollection', features: (geo.features || []).map((f) => {
|
||||
const a = byArea[f.properties?.shapeName]
|
||||
return { type: 'Feature', geometry: f.geometry,
|
||||
properties: { adm1: f.properties?.shapeName, women: a?.women.total ?? null, men: a?.men.total ?? null } }
|
||||
}) }
|
||||
// Under the people-group dots, which stay tappable on top.
|
||||
const before = map.getLayer('ci-pg-dots') ? 'ci-pg-dots' : undefined
|
||||
map.addSource('ci-adm1-src', { type: 'geojson', data: fc })
|
||||
map.addLayer({ id: 'ci-adm1-fill', type: 'fill', source: 'ci-adm1-src',
|
||||
paint: { 'fill-color': adm1Fill(adm1Sex.value), 'fill-opacity': 0.85 } }, before)
|
||||
map.addLayer({ id: 'ci-adm1-line', type: 'line', source: 'ci-adm1-src',
|
||||
paint: { 'line-color': 'rgba(255,255,255,0.8)', 'line-width': 0.6 } }, before)
|
||||
// India's national band would sit under its states and show through the two with no geometry
|
||||
// (Mizoram, Nagaland) as if it were their figure. Take India out of the country layer.
|
||||
if (map.getLayer('ci-fill')) map.setFilter('ci-fill', ['!=', ['get', 'iso3'], 'IND'])
|
||||
map.on('click', 'ci-adm1-fill', (e) => {
|
||||
if (map.getLayer('ci-pg-dots') && map.queryRenderedFeatures(e.point, { layers: ['ci-pg-dots'] }).length) return
|
||||
const key = e.features?.[0]?.properties?.adm1
|
||||
const a = key && byArea[key]
|
||||
if (a) { uiStore?.selectPeopleGroup(null); selected.value = null; selectedAdm1.value = { key, ...a } }
|
||||
})
|
||||
map.on('mouseenter', 'ci-adm1-fill', () => { map.getCanvas().style.cursor = 'pointer' })
|
||||
map.on('mouseleave', 'ci-adm1-fill', () => { map.getCanvas().style.cursor = '' })
|
||||
}
|
||||
|
||||
function showAdm1Sex(sex) {
|
||||
adm1Sex.value = sex
|
||||
const map = mapRef.value
|
||||
if (map?.getLayer('ci-adm1-fill')) map.setPaintProperty('ci-adm1-fill', 'fill-color', adm1Fill(sex))
|
||||
}
|
||||
const adm1Missing = computed(() => (adm1.value?.meta?.boundaries?.IND?.missing || []).join(', '))
|
||||
|
||||
// ── HONOUR THE PROVIDER SWITCH: this profile builds its map RAW ─────────────
|
||||
// Every bundle that goes through useMapInstance gets the switch for free. This one calls
|
||||
// `new gl.Map` directly, so it was invisible to it — MEASURED by sweeping all 16 isMap leaves:
|
||||
|
|
@ -293,6 +361,8 @@ onMounted(async () => {
|
|||
try {
|
||||
// The dots are a second layer, not a precondition: if the list fails, the map still shades.
|
||||
const groupsLoaded = loadGroups().catch((e) => { console.warn('[connectivity-map] people groups:', e?.message || e) })
|
||||
// India by state is a third layer, and optional like the dots: without it India keeps its band.
|
||||
const adm1Loaded = loadAdm1().catch((e) => { console.warn('[connectivity-map] India by state:', e?.message || e); return null })
|
||||
const adm0 = await load()
|
||||
// The pane can unmount during the awaits above (a tab switch mid-load). Building a map
|
||||
// into a container that no longer exists throws; this is the raw-map twin of the
|
||||
|
|
@ -325,6 +395,8 @@ onMounted(async () => {
|
|||
selectedPin.initialize()
|
||||
await groupsLoaded
|
||||
paintGroups(map)
|
||||
const geo = await adm1Loaded
|
||||
if (geo && !unmounted) paintAdm1(map, geo)
|
||||
})
|
||||
} catch (e) { err.value = String(e.message || e) }
|
||||
})
|
||||
|
|
@ -367,6 +439,16 @@ useShadowStyles(
|
|||
'.gm-key{display:flex;align-items:center;gap:5px;font-size:11px;white-space:nowrap}' +
|
||||
'.gm-sw{width:12px;height:12px;border-radius:3px;flex:none}' +
|
||||
'.gm-caveat{margin-top:5px;font-size:10.5px;opacity:.72;line-height:1.4}' +
|
||||
'.gm-adm1{margin-top:8px;padding-top:7px;border-top:1px solid rgba(0,0,0,.12)}' +
|
||||
'.gm-adm1-h{font-weight:600;font-size:12px;margin-bottom:5px}' +
|
||||
'.gm-seg{display:inline-flex;border:1px solid rgba(0,0,0,.2);border-radius:6px;overflow:hidden;margin-bottom:6px}' +
|
||||
'.gm-seg button{font:inherit;font-size:11px;padding:3px 10px;border:0;background:transparent;color:inherit;cursor:pointer}' +
|
||||
'.gm-seg button.on{background:#08519c;color:#fff}' +
|
||||
'.gm-adm1-t{width:100%;border-collapse:collapse;font-size:12px;margin:4px 0 6px}' +
|
||||
'.gm-adm1-t th,.gm-adm1-t td{padding:3px 4px;text-align:end}' +
|
||||
'.gm-adm1-t th:first-child{text-align:start}' +
|
||||
'.is-dark .gm-adm1{border-top-color:rgba(255,255,255,.15)}' +
|
||||
'.is-dark .gm-seg{border-color:rgba(255,255,255,.3)}' +
|
||||
// DETAIL: a bottom sheet on a phone, a corner card on desktop.
|
||||
'.gm-sheet{position:absolute;left:0;right:0;bottom:0;z-index:6;max-height:62%;overflow-y:auto;' +
|
||||
'background:#fff;color:#0f1419;border-radius:14px 14px 0 0;padding:14px 16px 22px;' +
|
||||
|
|
@ -426,6 +508,21 @@ useShadowStyles(
|
|||
<div class="gm-caveat">
|
||||
{{ t('connectivity.caveat') }}
|
||||
</div>
|
||||
<!-- India by state: a different measure and source, so its own block and its own ramp. -->
|
||||
<div v-if="adm1" class="gm-adm1">
|
||||
<div class="gm-adm1-h">{{ t('connectivity.adm1.title') }}</div>
|
||||
<div class="gm-seg" role="group" :aria-label="t('connectivity.adm1.title')">
|
||||
<button type="button" :class="{ on: adm1Sex === 'women' }" :aria-pressed="adm1Sex === 'women'" @click="showAdm1Sex('women')">{{ t('connectivity.adm1.women') }}</button>
|
||||
<button type="button" :class="{ on: adm1Sex === 'men' }" :aria-pressed="adm1Sex === 'men'" @click="showAdm1Sex('men')">{{ t('connectivity.adm1.men') }}</button>
|
||||
</div>
|
||||
<div class="gm-keys">
|
||||
<span v-for="(st, i) in ADM1_STEPS" :key="st.from" class="gm-key">
|
||||
<i class="gm-sw" :style="{ background: st.color }"></i>{{ i + 1 < ADM1_STEPS.length ? st.from + '–' + ADM1_STEPS[i + 1].from + '%' : st.from + '%+' }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="gm-caveat">{{ t('connectivity.adm1.source') }}</div>
|
||||
<div v-if="adm1Missing" class="gm-caveat">{{ t('connectivity.adm1.missing', { names: adm1Missing }) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="err" class="gm-err">{{ err }}</div>
|
||||
|
|
@ -438,6 +535,25 @@ useShadowStyles(
|
|||
<LegendMobile legend-type="prayer" popup-action="pray" :is-dark="isDark" />
|
||||
</div>
|
||||
|
||||
<!-- Tap an Indian state: the same sheet, with both halves of the survey. -->
|
||||
<div v-if="selectedAdm1" class="gm-sheet">
|
||||
<div class="gm-sh-head">
|
||||
<span class="gm-sh-name">{{ selectedAdm1.name }}</span>
|
||||
<button type="button" class="gm-x" @click="selectedAdm1 = null">{{ t('connectivity.sheet.close') }}</button>
|
||||
</div>
|
||||
<div class="gm-list-h">{{ t('connectivity.adm1.title') }}</div>
|
||||
<table class="gm-adm1-t">
|
||||
<thead><tr><th></th><th>{{ t('connectivity.adm1.total') }}</th><th>{{ t('connectivity.adm1.urban') }}</th><th>{{ t('connectivity.adm1.rural') }}</th></tr></thead>
|
||||
<tbody>
|
||||
<tr v-for="sex in ['women', 'men']" :key="sex">
|
||||
<th>{{ t('connectivity.adm1.' + sex) }}</th>
|
||||
<td v-for="area in ['total', 'urban', 'rural']" :key="area">{{ selectedAdm1[sex][area] != null ? selectedAdm1[sex][area] + '%' : '—' }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="gm-note">{{ t('connectivity.adm1.source') }}</p>
|
||||
</div>
|
||||
|
||||
<!-- Tap a country: bottom sheet on mobile, corner card on desktop. -->
|
||||
<div v-if="selected" class="gm-sheet">
|
||||
<div class="gm-sh-head">
|
||||
|
|
|
|||
118
plugin-designs/cities-internet/scripts/build-adm1-internet.mjs
Normal file
118
plugin-designs/cities-internet/scripts/build-adm1-internet.mjs
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
#!/usr/bin/env node
|
||||
/**
|
||||
* build-adm1-internet.mjs — internet use by first-level administrative area (ADM1), from data.
|
||||
*
|
||||
* node plugin-designs/cities-internet/scripts/build-adm1-internet.mjs
|
||||
*
|
||||
* READS data/internet/nfhs5-internet-by-state.csv India, NFHS-5 2019–21 (see data/internet/README.md)
|
||||
* data/internet/adm1-crosswalk-IND.json source names -> boundary shapeName (strict)
|
||||
* plugin-designs/my-upg-100-list/data/gb-IND-ADM1.geojson the boundary file the map draws
|
||||
* WRITES data/tables/internet-by-adm1.json served as assets/tables/internet-by-adm1.json
|
||||
*
|
||||
* THE TABLE IS GENERIC ON PURPOSE (other plugins and go-int reuse it). One row per
|
||||
* (iso3, adm1, measure, sex, area): no India-specific shape, so a second country or a second
|
||||
* measure is more rows, not a new format. `meta.boundaries[iso3]` names the geometry file and the
|
||||
* property its `adm1` joins on; `meta.measures` and `meta.sources` say what each number is.
|
||||
*
|
||||
* STRICT. The run FAILS when a source name is missing from the crosswalk, when a crosswalk target
|
||||
* is not a shapeName in the boundary file, or when a value is not a number in 0–100. A name is
|
||||
* never guessed. Source rows that have no geometry (crosswalk `adm1: null`) are KEPT, keyed by
|
||||
* their source name, and listed in meta.boundaries[iso3].missing, so nothing is silently dropped.
|
||||
*/
|
||||
import { readFileSync, writeFileSync } from 'node:fs'
|
||||
import { resolve, dirname, join } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '../../..')
|
||||
const CSV = join(ROOT, 'data/internet/nfhs5-internet-by-state.csv')
|
||||
const CROSSWALK = join(ROOT, 'data/internet/adm1-crosswalk-IND.json')
|
||||
const BOUNDARY = join(ROOT, 'plugin-designs/my-upg-100-list/data/gb-IND-ADM1.geojson')
|
||||
const OUT = join(ROOT, 'data/tables/internet-by-adm1.json')
|
||||
|
||||
const fail = (msg) => { console.error('build-adm1-internet: FAIL — ' + msg); process.exit(1) }
|
||||
|
||||
// A quoted-field CSV reader (the NFHS file quotes names that contain commas).
|
||||
function parseCsv(text) {
|
||||
const rows = []; let row = []; let f = ''; let q = false
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
const c = text[i]
|
||||
if (q) { if (c === '"') { if (text[i + 1] === '"') { f += '"'; i++ } else q = false } else f += c }
|
||||
else if (c === '"') q = true
|
||||
else if (c === ',') { row.push(f); f = '' }
|
||||
else if (c === '\n') { row.push(f); rows.push(row); row = []; f = '' }
|
||||
else if (c !== '\r') f += c
|
||||
}
|
||||
if (f || row.length) { row.push(f); rows.push(row) }
|
||||
const head = rows.shift()
|
||||
return rows.filter((r) => r.length === head.length).map((r) => Object.fromEntries(head.map((h, i) => [h, r[i]])))
|
||||
}
|
||||
|
||||
const src = parseCsv(readFileSync(CSV, 'utf8'))
|
||||
const crosswalk = JSON.parse(readFileSync(CROSSWALK, 'utf8')).map
|
||||
const shapeNames = new Set(JSON.parse(readFileSync(BOUNDARY, 'utf8')).features.map((f) => f.properties.shapeName))
|
||||
|
||||
const SEX = { 'Women who have ever used the internet (%)': 'women', 'Men who have ever used the internet (%)': 'men' }
|
||||
const AREAS = { total: 'nfhs5_total', urban: 'nfhs5_urban', rural: 'nfhs5_rural' }
|
||||
|
||||
const rows = []
|
||||
const national = []
|
||||
const missing = new Set()
|
||||
for (const r of src) {
|
||||
const sex = SEX[r.indicator.replace(/^\d+\.\s*/, '')]
|
||||
if (!sex) fail(`unexpected indicator "${r.indicator}"`)
|
||||
const cw = crosswalk[r.state]
|
||||
if (!cw) fail(`"${r.state}" is not in data/internet/adm1-crosswalk-IND.json`)
|
||||
if (cw.adm1 && !shapeNames.has(cw.adm1)) fail(`crosswalk maps "${r.state}" to "${cw.adm1}", which is not a shapeName in gb-IND-ADM1.geojson`)
|
||||
if (!cw.adm1 && !cw.reason) fail(`crosswalk entry for "${r.state}" has no adm1 and no reason`)
|
||||
for (const [area, col] of Object.entries(AREAS)) {
|
||||
const raw = String(r[col] ?? '').trim()
|
||||
if (raw === '' || raw === '*' || raw === 'na') continue // not reported for this cell
|
||||
const value = Number(raw)
|
||||
if (!Number.isFinite(value) || value < 0 || value > 100) fail(`"${r.state}" ${sex} ${area}: "${raw}" is not a share in 0–100`)
|
||||
const row = { iso3: 'IND', measure: 'ever_used_internet', sex, area, value, source: 'nfhs5', year: '2019-21' }
|
||||
if (cw.national) { national.push(row); continue }
|
||||
if (!cw.adm1) missing.add(r.state)
|
||||
rows.push({ ...row, adm1: cw.adm1 || null, adm1_name: r.state })
|
||||
}
|
||||
}
|
||||
if (!rows.length) fail('no rows (vacuous run)')
|
||||
|
||||
const out = {
|
||||
meta: {
|
||||
title: 'Internet use by first-level administrative area',
|
||||
grain: 'one row per iso3 x adm1 x measure x sex x area',
|
||||
measures: {
|
||||
ever_used_internet: {
|
||||
label: 'Ever used the internet',
|
||||
unit: '%',
|
||||
population: 'people aged 15–49, women and men asked separately',
|
||||
note: 'A survey SHARE OF PEOPLE (0–100). Not a subscription count: never put it on one scale with subscriptions per 100.',
|
||||
},
|
||||
},
|
||||
sources: {
|
||||
nfhs5: {
|
||||
name: 'National Family Health Survey 5 (NFHS-5), IIPS / Ministry of Health and Family Welfare, India',
|
||||
year: '2019-21',
|
||||
url: 'http://rchiips.org/nfhs/',
|
||||
via: 'https://github.com/pratapvardhan/NFHS-5 (CSV transcription of the state fact sheets)',
|
||||
licence: 'CC BY 4.0',
|
||||
attribution: 'NFHS-5 (IIPS/MoHFW) state fact sheets, via pratapvardhan/NFHS-5 (CC BY 4.0)',
|
||||
},
|
||||
},
|
||||
boundaries: {
|
||||
IND: {
|
||||
file: 'boundaries/gb-IND-ADM1.geojson',
|
||||
key: 'shapeName',
|
||||
licence: 'geoBoundaries gbOpen, India ADM1: CC BY 2.5 IN (datameet)',
|
||||
missing: [...missing].sort(),
|
||||
missing_reason: 'no geometry in the shipped boundary file (the UPG-100 partition: 34 of 36 units)',
|
||||
},
|
||||
},
|
||||
national,
|
||||
generated_by: 'plugin-designs/cities-internet/scripts/build-adm1-internet.mjs',
|
||||
},
|
||||
rows,
|
||||
}
|
||||
writeFileSync(OUT, JSON.stringify(out, null, 1) + '\n')
|
||||
const drawn = new Set(rows.filter((r) => r.adm1).map((r) => r.adm1)).size
|
||||
console.log(`build-adm1-internet: ${rows.length} rows · IND ${drawn} ADM1 areas drawn · ${missing.size} without geometry (${[...missing].join(', ') || 'none'}) · national ${national.length} rows`)
|
||||
Loading…
Reference in a new issue