-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.py
More file actions
2565 lines (2376 loc) · 121 KB
/
Copy pathapp.py
File metadata and controls
2565 lines (2376 loc) · 121 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
"""
中国人口密度时空探索器 (2002-2020)
China Population Density Spatiotemporal Explorer
Spatiotemporal Explorer: Time + Map + Compare + Drill-down
Fixes applied:
1. Latitude-corrected pixel area (not fixed 25 km²)
2. National summary from raster (not province rollup)
3. Adaptive diff colorscale via p99
4. Mainland-only toggle
5. Independent year controls per tab
6. Map-click pixel drill-down
7. Bilingual Chinese/English UI
"""
import os
import json
import time as _time
import numpy as np
import pandas as pd
import rasterio
import streamlit as st
import folium
import plotly.express as px
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from matplotlib import cm
from matplotlib.colors import LogNorm, Normalize
from PIL import Image, ImageDraw
from scipy import stats as sp_stats
from streamlit_folium import st_folium
# ---------------------------------------------------------------------------
# Page config
# ---------------------------------------------------------------------------
st.set_page_config(
page_title="Population Agglomeration & Spatial Reallocation in China",
page_icon="",
layout="wide",
initial_sidebar_state="expanded",
)
st.markdown("""
<style>
/* Academic warm-tone base */
html, body, [class*="css"] {
font-family: 'Crimson Pro', 'Georgia', 'Noto Serif SC', serif;
}
.block-container {
padding-top: 3rem;
padding-bottom: 1rem;
max-width: 1200px;
background-color: #faf9f6;
}
/* Sidebar */
section[data-testid="stSidebar"] {
background: #f0efe9;
border-right: 1px solid #ddd8d0;
}
/* Nav buttons in sidebar */
section[data-testid="stSidebar"] button[kind="secondary"] {
background: #faf9f6 !important;
border: 1px solid #d5d0c8 !important;
border-radius: 6px !important;
padding: 9px 14px !important;
font-weight: 500 !important;
font-size: 0.9rem !important;
color: #3d3d3d !important;
transition: background 0.15s ease !important;
box-shadow: none !important;
margin-bottom: 2px !important;
}
section[data-testid="stSidebar"] button[kind="secondary"]:hover {
background: #eae8e1 !important;
border-color: #b8b2a6 !important;
box-shadow: none !important;
color: #1e3a5f !important;
}
/* KPI metric cards — quiet, academic */
[data-testid="stMetric"] {
background: #f5f4f0;
padding: 12px 16px;
border-radius: 6px;
border: 1px solid #ddd8d0;
}
[data-testid="stMetric"] label {
font-size: 0.78rem;
color: #6b6560;
letter-spacing: 0.02em;
}
/* Headers — weight + spacing, no underline */
h1 {
font-weight: 700;
color: #1e3a5f;
border: none !important;
padding-bottom: 0;
margin-bottom: 0.3rem;
}
h2 {
font-weight: 600;
color: #2d3748;
border: none !important;
padding-bottom: 0;
margin-bottom: 0.2rem;
}
h3 {
font-weight: 600;
color: #3d3d3d;
}
/* Hide Streamlit chrome */
#MainMenu {visibility: hidden;}
footer {visibility: hidden;}
/* Expander */
.streamlit-expanderHeader {
font-weight: 600;
font-size: 1rem;
color: #2d3748;
}
/* Captions */
.stCaption {
font-size: 0.82rem;
color: #8a8480;
}
/* Divider */
hr {
border-color: #ddd8d0;
}
/* Data tables */
[data-testid="stDataFrame"] {
border-radius: 6px;
overflow: hidden;
}
</style>
""", unsafe_allow_html=True)
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DATA_DIR = os.path.join(BASE_DIR, "data_5km")
GEOJSON_PATH = os.path.join(BASE_DIR, "china_provinces.geojson")
PROVINCE_STATS_PATH = os.path.join(DATA_DIR, "province_stats.json")
NATIONAL_STATS_PATH = os.path.join(DATA_DIR, "national_stats.json")
YEARS = list(range(2002, 2021))
VMIN, VMAX = 1, 10000
EXCLUDE_HMT = {"香港特别行政区", "澳门特别行政区", "台湾省"}
WORLDPOP_COLLECTION_URL = "https://hub.worldpop.org/Global1_2000-2020"
WORLDPOP_PROJECT_URL = "https://hub.worldpop.org/project/list"
WORLDPOP_CHINA_2002_URL = "https://hub.worldpop.org/geodata/summary?id=44816"
WORLDPOP_CHINA_2020_URL = "https://hub.worldpop.org/geodata/summary?id=44834"
WORLDPOP_DOI_URL = "https://doi.org/10.5258/SOTON/WP00675"
CC_BY_4_URL = "https://creativecommons.org/licenses/by/4.0/"
# --- Paper entry points (single source of truth) ---
# When SSRN is live, fill SSRN_URL; the site will auto-switch to it as canonical.
SSRN_URL = "https://papers.ssrn.com/sol3/papers.cfm?abstract_id=6569183"
PAPER_PDF_URL = "https://github.com/Li-Shen-Clark/CPDE/blob/main/main.pdf"
# Derived: prefer SSRN when available
PAPER_CANONICAL_URL = SSRN_URL or PAPER_PDF_URL
PAPER_IS_SSRN = bool(SSRN_URL)
CITATION_TEXT = (
'Shen, Li (2025). "Population Agglomeration and Spatial Reallocation in China." '
+ (f"Available at SSRN: {SSRN_URL}" if PAPER_IS_SSRN
else "Working Paper, Clark University.")
)
# ---------------------------------------------------------------------------
# Region classification (东/中/西/东北)
# ---------------------------------------------------------------------------
REGION_MAP = {
"北京市": "东部", "天津市": "东部", "河北省": "东部", "上海市": "东部",
"江苏省": "东部", "浙江省": "东部", "福建省": "东部", "山东省": "东部",
"广东省": "东部", "海南省": "东部",
"山西省": "中部", "安徽省": "中部", "江西省": "中部", "河南省": "中部",
"湖北省": "中部", "湖南省": "中部",
"内蒙古自治区": "西部", "广西壮族自治区": "西部", "重庆市": "西部",
"四川省": "西部", "贵州省": "西部", "云南省": "西部", "西藏自治区": "西部",
"陕西省": "西部", "甘肃省": "西部", "青海省": "西部", "宁夏回族自治区": "西部",
"新疆维吾尔自治区": "西部",
"辽宁省": "东北", "吉林省": "东北", "黑龙江省": "东北",
}
REGION_MAP_EN = {
"东部": "East",
"中部": "Central",
"西部": "West",
"东北": "Northeast",
}
PROVINCE_NAME_EN = {
"北京市": "Beijing", "天津市": "Tianjin", "河北省": "Hebei", "山西省": "Shanxi",
"内蒙古自治区": "Inner Mongolia", "辽宁省": "Liaoning", "吉林省": "Jilin",
"黑龙江省": "Heilongjiang", "上海市": "Shanghai", "江苏省": "Jiangsu",
"浙江省": "Zhejiang", "安徽省": "Anhui", "福建省": "Fujian", "江西省": "Jiangxi",
"山东省": "Shandong", "河南省": "Henan", "湖北省": "Hubei", "湖南省": "Hunan",
"广东省": "Guangdong", "广西壮族自治区": "Guangxi", "海南省": "Hainan",
"重庆市": "Chongqing", "四川省": "Sichuan", "贵州省": "Guizhou", "云南省": "Yunnan",
"西藏自治区": "Tibet", "陕西省": "Shaanxi", "甘肃省": "Gansu", "青海省": "Qinghai",
"宁夏回族自治区": "Ningxia", "新疆维吾尔自治区": "Xinjiang",
"香港特别行政区": "Hong Kong", "澳门特别行政区": "Macao", "台湾省": "Taiwan",
}
REGION_COLORS = {"东部": "#1e3a5f", "中部": "#c0392b", "西部": "#2d6a4f", "东北": "#64748b"}
# Modern Plotly layout defaults
PLOTLY_LAYOUT = dict(
template="plotly_white",
font=dict(family="Georgia, 'Noto Serif SC', serif", size=12, color="#3d3d3d"),
plot_bgcolor="#faf9f6",
paper_bgcolor="#faf9f6",
margin=dict(t=70, b=20, l=20, r=20),
hoverlabel=dict(bgcolor="#faf9f6", font_size=12, bordercolor="#ddd8d0"),
colorway=["#1e3a5f", "#c0392b", "#2d6a4f", "#b8860b", "#64748b", "#8b5e3c", "#5b7065", "#a0522d"],
)
# ---------------------------------------------------------------------------
# Bilingual helper
# ---------------------------------------------------------------------------
# lang is set in the sidebar section below; declared here so T() can reference it.
# We use a module-level sentinel; the real value is set after st.sidebar.radio().
_LANG_STRINGS = {
# Sidebar
"sidebar_title_zh": "论文交互附录",
"sidebar_title_en": "Working Paper Companion",
"sidebar_subtitle_zh": "中国人口密度 2002–2020",
"sidebar_subtitle_en": "China Population Density 2002–2020",
"mainland_toggle_zh": "仅中国大陆 (不含港澳台)",
"mainland_toggle_en": "Mainland China only (excl. HK/MO/TW)",
"opacity_slider_zh": "图层透明度",
"opacity_slider_en": "Layer Opacity",
"province_drilldown_zh": "##### 省份钻取",
"province_drilldown_en": "##### Province Drill-down",
"select_province_zh": "选择省份",
"select_province_en": "Select Province",
"all_national_zh": "(全国总览)",
"all_national_en": "(National Overview)",
"sidebar_data_info_zh": (
"<small>数据: WorldPop UN-adj 1km<br>"
"分辨率: ~5km 降采样<br>"
"人口: 纬度修正像元面积<br>"
"范围: {scope}</small>"
),
"sidebar_data_info_en": (
"<small>Data: WorldPop UN-adj 1km<br>"
"Resolution: ~5km downsampled<br>"
"Population: lat-corrected pixel area<br>"
"Scope: {scope}</small>"
),
"data_source_expander_zh": "数据来源与许可",
"data_source_expander_en": "Data Sources & License",
"data_source_md_zh": (
"- 官方来源: [WorldPop Global1 2000-2020]({col})\n"
"- 数据类型: [Population Density / UN-adjusted 1km]({proj})\n"
"- 中国页面示例: [2002]({c2002}) / [2020]({c2020})\n"
"- DOI: [{doi}]({doi})\n"
"- 许可: [CC BY 4.0]({cc})"
),
"data_source_md_en": (
"- Official source: [WorldPop Global1 2000-2020]({col})\n"
"- Data type: [Population Density / UN-adjusted 1km]({proj})\n"
"- China example pages: [2002]({c2002}) / [2020]({c2020})\n"
"- DOI: [{doi}]({doi})\n"
"- License: [CC BY 4.0]({cc})"
),
# Scope labels
"scope_mainland_zh": "中国大陆",
"scope_mainland_en": "Mainland China",
"scope_all_zh": "全国含港澳台",
"scope_all_en": "All incl. HK/MO/TW",
"scope_short_mainland_zh": "仅大陆",
"scope_short_mainland_en": "Mainland only",
"scope_short_all_zh": "含港澳台",
"scope_short_all_en": "Incl. HK/MO/TW",
# Tab names
"tab_summary_zh": "概览",
"tab_summary_en": "Overview",
"tab_national_zh": "主要发现",
"tab_national_en": "Main Findings",
"tab_spatial_zh": "空间格局",
"tab_spatial_en": "Maps",
"tab_hetero_zh": "省际证据",
"tab_hetero_en": "Provincial Evidence",
"tab_methods_zh": "数据与方法",
"tab_methods_en": "Data & Methods",
# Page title
"page_title_zh": "人口集聚与空间再配置:中国 2002-2020",
"page_title_en": "Population Agglomeration and Spatial Reallocation in China",
# ---- Tab 1: Summary (paper landing page) ----
"summary_header_zh": "人口集聚与空间再配置:中国",
"summary_header_en": "Population Agglomeration and Spatial Reallocation in China",
"summary_author_zh": "申丽 · 克拉克大学经济学系",
"summary_author_en": "Li Shen · Department of Economics, Clark University",
"summary_abstract_zh": (
"本研究利用 WorldPop 联合国校正 1 km 人口密度栅格数据(降采样至 ~5 km),"
"对 {y0}–{y1} 年间中国大陆人口的空间分布演变进行描述性分析。"
"我们从四个维度刻画空间格局:空间集聚指标(基尼系数与 Top-10% 集中度)、"
"像元层面的累积变化、人口重心轨迹以及省际 β/σ 收敛检验。"
"结果显示空间集聚在研究期内持续增强,但省际密度并未出现系统性收敛。"
),
"summary_abstract_en": (
"Using WorldPop UN-adjusted 1 km population density rasters (downsampled to ~5 km), "
"this paper provides a descriptive account of how the spatial distribution of China's population "
"evolved between {y0} and {y1}. We document four dimensions: spatial concentration (Gini and "
"top-decile share), pixel-level cumulative change, population centroid trajectory, and provincial "
"β/σ convergence. The results show that spatial concentration increased over the study period, "
"while interprovincial density exhibited no systematic convergence."
),
"summary_caption_zh": "Working Paper · 当前范围:{scope}",
"summary_caption_en": "Working Paper · Current scope: {scope}",
# --- Contributions section ---
"contrib_header_zh": "论文贡献",
"contrib_header_en": "Contributions",
"contrib_field_labels_zh": ["空间经济学", "区域科学", "中国区域发展"],
"contrib_field_labels_en": ["Spatial Economics", "Regional Science", "China Regional Development"],
"contrib_measurement_title_zh": "度量贡献",
"contrib_measurement_title_en": "Measurement",
"contrib_measurement_zh": (
"构建了一套基于栅格的人口空间分布度量框架:从 1 km WorldPop 栅格出发,"
"经纬度修正像元面积、P99 裁剪、降采样至 5 km,"
"直接从栅格计算空间基尼系数、Top-10% 集中度、人口重心等指标,"
"缓解了行政单元汇总带来的 MAUP 问题。"
),
"contrib_measurement_en": (
"Develops a raster-based measurement framework for population distribution: "
"starting from 1 km WorldPop grids, applying latitude-corrected pixel areas, P99 clipping, "
"and downsampling to 5 km, then computing spatial Gini, top-decile concentration, "
"and population centroid directly from the raster — mitigating MAUP concerns inherent "
"in administrative-unit aggregation."
),
"contrib_empirical_title_zh": "实证贡献",
"contrib_empirical_title_en": "Empirical",
"contrib_empirical_zh": (
"提供了 {y0}–{y1} 年中国人口空间再配置的系统性描述证据。"
"文献中关于中国人口分布的实证研究多依赖地级或省级截面数据;"
"本文在像元层面呈现了集聚增强、核心区扩展、重心东南漂移等事实,"
"并通过省际 β/σ 收敛检验刻画了省际密度的离散演化。"
),
"contrib_empirical_en": (
"Provides systematic descriptive evidence on China's population spatial reallocation "
"over {y0}–{y1}. Many existing studies on China's population "
"distribution rely on prefecture- or province-level cross-sections; "
"this paper documents rising concentration, core expansion, and southeastward centroid shift "
"at the pixel level, and characterizes interprovincial density dispersion through β/σ convergence tests."
),
"contrib_relevance_title_zh": "领域关联",
"contrib_relevance_title_en": "Relevance",
"contrib_relevance_zh": (
"**空间经济学**:为人口集聚的空间演化提供了像元层面的高分辨率证据,"
"补充了既有基于行政区划的集聚研究。"
"**区域科学**:β/σ 收敛检验揭示省际密度的追赶与分化特征,"
"对理解中国区域差异的演变具有参考价值。"
"**中国区域发展**:对高密度核心区的扩展路径、"
"人口重心的空间轨迹等提供了可重复的栅格证据。"
),
"contrib_relevance_en": (
"**Spatial economics**: provides high-resolution, pixel-level evidence on the spatial evolution "
"of population agglomeration, complementing existing studies based on administrative units. "
"**Regional science**: β/σ convergence tests reveal catch-up and dispersion patterns across provinces, "
"informing the understanding of China's evolving regional disparities. "
"**China regional development**: documents expansion paths of high-density cores "
"and the spatial trajectory of the population centroid with reproducible raster-based evidence."
),
# shift directions
"shift_ne_zh": "东北", "shift_ne_en": "Northeast",
"shift_nw_zh": "西北", "shift_nw_en": "Northwest",
"shift_se_zh": "东南", "shift_se_en": "Southeast",
"shift_sw_zh": "西南", "shift_sw_en": "Southwest",
"shift_n_zh": "北", "shift_n_en": "North",
"shift_s_zh": "南", "shift_s_en": "South",
"shift_e_zh": "东", "shift_e_en": "East",
"shift_w_zh": "西", "shift_w_en": "West",
# convergence words
"convergence_zh": "收敛(追赶效应)",
"convergence_en": "Convergence (catch-up effect)",
"divergence_zh": "发散",
"divergence_en": "Divergence",
"sig_zh": "显著", "sig_en": "significant",
"insig_zh": "不显著", "insig_en": "not significant",
# findings
"finding1_rise_zh": "升至", "finding1_rise_en": "rose to",
"finding1_fall_zh": "降至", "finding1_fall_en": "fell to",
"finding1_agg_zh": "表明空间集聚在研究期内持续增强",
"finding1_agg_en": "suggesting increased spatial agglomeration over the study period",
"finding1_disp_zh": "表明分散力有所增强",
"finding1_disp_en": "indicating dispersion forces have strengthened",
# KPI labels
"kpi_gini_zh": "空间基尼系数",
"kpi_gini_en": "Spatial Gini Coeff.",
"kpi_conc_zh": "Top10%人口占比",
"kpi_conc_en": "Top10% Pop. Share",
"kpi_wt_density_zh": "加权平均密度",
"kpi_wt_density_en": "Weighted Avg. Density",
"kpi_beta_zh": "β-收敛斜率",
"kpi_beta_en": "β-Conv. Slope",
"kpi_shift_zh": "重心漂移",
"kpi_shift_en": "Centroid Shift",
"convergence_label_zh": "收敛",
"convergence_label_en": "Converging",
"divergence_label_zh": "发散",
"divergence_label_en": "Diverging",
# Summary charts
"summary_chart_title_zh": "空间集聚指标({y0}–{y1})",
"summary_chart_title_en": "Spatial Concentration Indicators ({y0}–{y1})",
"gini_series_label_zh": "空间基尼系数",
"gini_series_label_en": "Spatial Gini Coeff.",
"conc_series_label_zh": "Top10%人口占比(%)",
"conc_series_label_en": "Top10% Pop. Share (%)",
"gini_yaxis_zh": "基尼系数",
"gini_yaxis_en": "Gini Coeff.",
"conc_yaxis_zh": "Top10% 占比 (%)",
"conc_yaxis_en": "Top10% Share (%)",
"diff_map_caption_zh": "{y0}→{y1} 空间再配置地图",
"diff_map_caption_en": "{y0}→{y1} Spatial Reallocation Map",
"diff_map_note_zh": "红色 = 人口流入区,蓝色 = 流出区。P99 对称色标 ±{p99:.0f} 人/km²,像元平均变化 {mean:+.1f}。",
"diff_map_note_en": "Red = population inflow, Blue = outflow. P99 symmetric colorscale ±{p99:.0f} ppl/km², pixel avg change {mean:+.1f}.",
# Beta convergence chart
"beta_chart_title_zh": "β-收敛检验:ln(初始密度) vs 年均增长率 (R²={r2:.3f})",
"beta_chart_title_en": "β-Convergence: ln(Initial Density) vs Annual Growth Rate (R²={r2:.3f})",
"beta_xaxis_zh": "ln({y0}年平均密度)",
"beta_xaxis_en": "ln({y0} avg. density)",
"beta_yaxis_zh": "年均增长率 (%)",
"beta_yaxis_en": "Annual Growth Rate (%)",
"ols_label_zh": "OLS (β={beta:.4f})",
"ols_label_en": "OLS (β={beta:.4f})",
# Top movers
"top_movers_zh": "**人口集聚最快的省份**",
"top_movers_en": "**Fastest Population Gaining Provinces**",
"top_losers_zh": "**人口流失最快的省份**",
"top_losers_en": "**Fastest Population Losing Provinces**",
# ---- Tab 2: National ----
"national_header_zh": "主要发现",
"national_header_en": "Main Findings",
"national_caption_zh": "展示 {y0}–{y1} 年人口密度的时间演变。上半部分为空间再配置动画(红色 = 相对基期人口增加,蓝色 = 减少),下半部分为集聚指标时间序列。",
"national_caption_en": "Displaying temporal evolution of population density {y0}–{y1}. Top: spatial reallocation animation (red = population gain relative to base year, blue = loss). Bottom: concentration indicator time series.",
"play_btn_zh": "播放累计变化",
"play_btn_en": "Play Cumulative Change",
"speed_label_zh": "速度",
"speed_label_en": "Speed",
"speed_fmt_zh": "{x}s/帧",
"speed_fmt_en": "{x}s/frame",
"year_slider_zh": "年份",
"year_slider_en": "Year",
"anim_frame_caption_zh": "{yr} 年累计变化(相对 {y0} 年)",
"anim_frame_caption_en": "{yr} cumulative change (relative to {y0})",
"anim_mean_change_zh": "均值变化",
"anim_mean_change_en": "Avg. Δ",
"anim_max_increase_zh": "最大增幅",
"anim_max_increase_en": "Max Δ",
"anim_increase_share_zh": "增长区占比",
"anim_increase_share_en": "Growth %",
"anim_decrease_share_zh": "下降区占比",
"anim_decrease_share_en": "Decline %",
"anim_stats_caption_zh": "当前总人口 {pop:.2f} 亿,加权平均密度 {wt:.1f} 人/km²;差值色标约为 ±{p99:.0f} 人/km²,裁剪 {clip:.1f}% 像素。",
"anim_stats_caption_en": "Current total pop. {pop:.2f}B, weighted avg. density {wt:.1f} ppl/km²; diff colorscale ≈±{p99:.0f} ppl/km², clipping {clip:.1f}% pixels.",
"agg_indicators_zh": "集聚指标时间序列",
"agg_indicators_en": "Concentration Indicator Time Series",
# Gini chart
"gini_chart_title_zh": "空间基尼系数",
"gini_chart_title_en": "Spatial Gini Coefficient",
"year_label_zh": "年份",
"year_label_en": "Year",
"gini_caption_zh": "基尼系数越高,人口在空间上越集中。",
"gini_caption_en": "Higher Gini = more spatially concentrated population.",
# Concentration chart
"conc_chart_title_zh": "Top 10% 人口集中度",
"conc_chart_title_en": "Top-10% Population Concentration",
"conc_yaxis2_zh": "占总人口比例 (%)",
"conc_yaxis2_en": "Share of Total Population (%)",
"conc_caption_zh": "该比例上升意味着更多人口集中在少数高密度区域。",
"conc_caption_en": "Rising share means more population is concentrated in a few high-density areas.",
# Market potential chart
"mp_chart_title_zh": "加权平均密度与高密度像元数",
"mp_chart_title_en": "Weighted Mean Density and High-Density Pixel Count",
"mp_trace1_zh": "加权平均密度",
"mp_trace1_en": "Weighted Avg. Density",
"mp_trace2_zh": "高密度像元数",
"mp_trace2_en": "High-Density Pixel Count",
"mp_yaxis1_zh": "人/km²",
"mp_yaxis1_en": "ppl/km²",
"mp_yaxis2_zh": "像元数",
"mp_yaxis2_en": "Pixel Count",
# Sigma convergence chart
"sigma_chart_title_zh": "σ-收敛:省际密度变异系数",
"sigma_chart_title_en": "σ-Convergence: Interprovincial Density CV",
"sigma_yaxis_zh": "变异系数",
"sigma_yaxis_en": "Coeff. of Variation",
"sigma_caption_zh": "CV 下降 = σ-收敛(省际差异缩小);CV 上升 = σ-发散(差异扩大)。",
"sigma_caption_en": "CV declining = σ-convergence (narrowing interprovincial gap); CV rising = σ-divergence (widening gap).",
# ---- Tab 3: Spatial ----
"spatial_header_zh": "空间格局与累积变化",
"spatial_header_en": "Spatial Patterns & Cumulative Change",
"spatial_sub_single_zh": "单年格局",
"spatial_sub_single_en": "Single Year",
"spatial_sub_compare_zh": "两期对比",
"spatial_sub_compare_en": "Two-Period Comparison",
"spatial_sub_centroid_zh": "人口重心与区域份额",
"spatial_sub_centroid_en": "Population Centroid & Regional Shares",
"year_slider2_zh": "年份",
"year_slider2_en": "Year",
"click_chart_title_zh": "点击位置 ({lat:.3f}, {lng:.3f}) 的历年密度",
"click_chart_title_en": "Density Time Series at Clicked Location ({lat:.3f}, {lng:.3f})",
"click_xaxis_zh": "年份",
"click_xaxis_en": "Year",
"density_unit_zh": "人/km²",
"density_unit_en": "ppl/km²",
"top15_title_zh": "省级密度排名 Top 15",
"top15_title_en": "Top 15 Provinces by Density",
"pixel_hist_title_zh": "像元密度分布(截取 P99.5)",
"pixel_hist_title_en": "Pixel Density Distribution (P99.5 truncated)",
"pixel_count_zh": "像元数",
"pixel_count_en": "Pixel Count",
"compare_start_zh": "起始年份",
"compare_start_en": "Start Year",
"compare_end_zh": "结束年份",
"compare_end_en": "End Year",
"compare_growth_zh": "增长区域",
"compare_growth_en": "Growth Area",
"compare_decline_zh": "下降区域",
"compare_decline_en": "Decline Area",
"compare_avg_change_zh": "平均变化",
"compare_avg_change_en": "Avg. Change",
"compare_p99_zh": "P99色标",
"compare_p99_en": "P99 Colorscale",
"compare_clip_note_zh": "超出裁剪: {n:,} 像素 ({pct:.1f}%)",
"compare_clip_note_en": "Clipped: {n:,} pixels ({pct:.1f}%)",
"prov_change_header_zh": "省级变化分析",
"prov_change_header_en": "Provincial Change Analysis",
"prov_diff_title_zh": "各省平均密度变化",
"prov_diff_title_en": "Provincial Avg. Density Change",
"pixel_change_hist_zh": "像元变化分布",
"pixel_change_hist_en": "Pixel Change Distribution",
"diff_warning_zh": "请选择两个不同年份。",
"diff_warning_en": "Please select two different years.",
# Centroid subtab
"centroid_header_zh": "人口重心轨迹",
"centroid_header_en": "Population Centroid Trajectory",
"centroid_caption_zh": "人口重心 = Σ(人口×坐标) / Σ人口。重心漂移方向与区域间相对人口增长的宏观格局一致。",
"centroid_caption_en": "Population centroid = Σ(pop×coord)/Σpop. Drift direction is consistent with macro patterns of relative population growth across regions.",
"centroid_hover_zh": "年份: %{text}<br>经度: %{lon:.4f}<br>纬度: %{lat:.4f}<extra></extra>",
"centroid_hover_en": "Year: %{text}<br>Lon: %{lon:.4f}<br>Lat: %{lat:.4f}<extra></extra>",
"centroid_chart_title_zh": "人口重心轨迹 ({y0}-{y1})",
"centroid_chart_title_en": "Population Centroid Trajectory ({y0}-{y1})",
"centroid_start_zh": "**起点** ({y0}): ({lat:.4f}°N, {lon:.4f}°E)",
"centroid_start_en": "**Start** ({y0}): ({lat:.4f}°N, {lon:.4f}°E)",
"centroid_end_zh": "**终点** ({y1}): ({lat:.4f}°N, {lon:.4f}°E)",
"centroid_end_en": "**End** ({y1}): ({lat:.4f}°N, {lon:.4f}°E)",
"centroid_dir_zh": "**漂移方向**: 向{dir}",
"centroid_dir_en": "**Drift Direction**: toward {dir}",
"centroid_dist_zh": "**漂移距离**: {km:.1f} km",
"centroid_dist_en": "**Drift Distance**: {km:.1f} km",
"centroid_lat_dir_zh": "- 纬度方向: {km:.1f} km ({dir})",
"centroid_lat_dir_en": "- Latitudinal: {km:.1f} km ({dir})",
"centroid_lon_dir_zh": "- 经度方向: {km:.1f} km ({dir})",
"centroid_lon_dir_en": "- Longitudinal: {km:.1f} km ({dir})",
"centroid_meaning_zh": "**说明**",
"centroid_meaning_en": "**Note**",
"centroid_meaning_text_zh": (
"人口重心的持续漂移与沿海和中南部省份的相对人口增长一致。"
),
"centroid_meaning_text_en": (
"The persistent centroid drift is consistent with relative population gains in coastal and south-central provinces."
),
"latlon_chart_title_zh": "重心坐标时间序列",
"latlon_chart_title_en": "Centroid Coordinate Time Series",
"lat_label_zh": "纬度",
"lat_label_en": "Latitude",
"lon_label_zh": "经度",
"lon_label_en": "Longitude",
"deg_n_zh": "°N", "deg_n_en": "°N",
"deg_e_zh": "°E", "deg_e_en": "°E",
"region_shares_header_zh": "四大区域人口份额演变",
"region_shares_header_en": "Four-Region Population Share Trends",
"region_shares_caption_zh": "东部/中部/西部/东北的人口份额变化。",
"region_shares_caption_en": "Population share changes across East/Central/West/Northeast.",
"region_shares_chart_title_zh": "四大区域人口份额",
"region_shares_chart_title_en": "Four-Region Population Shares",
"region_shares_yaxis_zh": "占总人口比例 (%)",
"region_shares_yaxis_en": "Share of Total Population (%)",
"region_shares_table_title_zh": "**区域份额对比**",
"region_shares_table_title_en": "**Regional Share Comparison**",
"region_col_zh": "区域",
"region_col_en": "Region",
"change_col_zh": "变化",
"change_col_en": "Change",
"region_interp_zh": "**说明**",
"region_interp_en": "**Note**",
"east_rise_zh": "东部份额上升 {d:+.2f} 个百分点,与人口持续向沿海高密度区域集中的趋势一致。",
"east_rise_en": "East's share rose {d:+.2f} pp, consistent with continued population concentration in coastal high-density areas.",
"east_fall_zh": "东部份额下降 {d:+.2f} 个百分点,中西部人口回流或就地城镇化趋势增强。",
"east_fall_en": "East's share fell {d:+.2f} pp, suggesting population return migration to inland regions or in-situ urbanization.",
# ---- Tab 4: Heterogeneity ----
"hetero_header_zh": "省际证据",
"hetero_header_en": "Provincial Evidence",
"hetero_caption_zh": "初始密度低的省份是否增长更快?省际密度差异在缩小还是扩大?",
"hetero_caption_en": "Do provinces with lower initial density grow faster? Is cross-provincial dispersion narrowing or widening?",
"subtab_beta_zh": "β-收敛",
"subtab_beta_en": "β-Convergence",
"subtab_sigma_zh": "σ-离散度",
"subtab_sigma_en": "σ-Dispersion",
"subtab_profile_zh": "省份剖面",
"subtab_profile_en": "Province Profile",
"subtab_compare_zh": "省际对比",
"subtab_compare_en": "Province Comparison",
"focus_province_zh": "焦点省份",
"focus_province_en": "Focus Province",
"compare_province_zh": "对照省份",
"compare_province_en": "Comparison Province",
"focus_year_zh": "焦点年份",
"focus_year_en": "Focus Year",
"scatter_mode_zh": "增长轨迹视图",
"scatter_mode_en": "Growth Trajectory View",
"scatter_endpoint_zh": "终点散点图",
"scatter_endpoint_en": "Endpoint Scatter",
"scatter_animation_zh": "按年份动态演变",
"scatter_animation_en": "Dynamic by Year",
"beta_scatter_title_zh": "β-收敛散点图:初始密度 vs 增长率(按区域着色)",
"beta_scatter_title_en": "β-Convergence Scatter: Initial Density vs Growth Rate (by Region)",
"beta_scatter_xaxis_zh": "2002年平均密度 (人/km², 对数坐标)",
"beta_scatter_xaxis_en": "2002 Avg. Density (ppl/km², log scale)",
"beta_scatter_yaxis_zh": "2002→2020 增长率 (%)",
"beta_scatter_yaxis_en": "2002→2020 Growth Rate (%)",
"focus_province_legend_zh": "焦点省份",
"focus_province_legend_en": "Focus Province",
"ols_trend_zh": "OLS趋势 (β={beta:.3f})",
"ols_trend_en": "OLS Trend (β={beta:.3f})",
"beta_caption_neg_zh": "负斜率表示低密度省份增速更快(收敛/追赶)",
"beta_caption_neg_en": "Negative slope: lower-density provinces grow faster (convergence/catch-up)",
"beta_caption_pos_zh": "正斜率表示高密度省份增速更快(发散/极化)",
"beta_caption_pos_en": "Positive slope: higher-density provinces grow faster (divergence/polarization)",
"beta_caption_full_zh": "OLS 斜率 β = {beta:.4f}:{direction}。区域着色揭示地理分组的收敛模式。",
"beta_caption_full_en": "OLS slope β = {beta:.4f}: {direction}. Regional coloring reveals geographic grouping convergence patterns.",
"anim_title_zh": "增长轨迹:按年份动态演变(相对 {y0} 年)",
"anim_title_en": "Growth Trajectories: Dynamic by Year (relative to {y0})",
"anim_xaxis_zh": "2002年平均密度 (人/km²)",
"anim_xaxis_en": "2002 Avg. Density (ppl/km²)",
"anim_yaxis_zh": "相对 {y0} 年增长率 (%)",
"anim_yaxis_en": "Growth Rate relative to {y0} (%)",
"abs_growth_label_zh": "绝对增长",
"abs_growth_label_en": "Absolute Growth",
"anim_caption_zh": "动画模式更适合观察轨迹与路径依赖;终点散点图仍然更适合做静态比较与标注。",
"anim_caption_en": "Animation mode is better for observing trajectories and path dependence; endpoint scatter is better for static comparison and annotation.",
"heatmap_metric_zh": "热力矩阵指标",
"heatmap_metric_en": "Heatmap Metric",
"heatmap_opt_mean_zh": "平均密度",
"heatmap_opt_mean_en": "Avg. Density",
"heatmap_opt_growth_zh": "相对2002年增长率%",
"heatmap_opt_growth_en": "Growth Rate vs 2002 %",
"heatmap_opt_yoy_zh": "逐年变化",
"heatmap_opt_yoy_en": "Year-on-Year Change",
"heatmap_bar_density_zh": "人/km²",
"heatmap_bar_density_en": "ppl/km²",
"heatmap_bar_pct_zh": "%",
"heatmap_bar_pct_en": "%",
"sigma_detail_header_zh": "σ-收敛检验:省际离散度的时间趋势",
"sigma_detail_header_en": "σ-Convergence Test: Temporal Trend of Interprovincial Dispersion",
"sigma_detail_trace1_zh": "省际标准差",
"sigma_detail_trace1_en": "Interprovincial Std. Dev.",
"sigma_detail_trace2_zh": "变异系数 CV",
"sigma_detail_trace2_en": "Coeff. of Variation CV",
"sigma_detail_title_zh": "σ-收敛:省际密度标准差与变异系数",
"sigma_detail_title_en": "σ-Convergence: Std. Dev. & CV of Interprovincial Density",
"sigma_yaxis1_zh": "标准差 (人/km²)",
"sigma_yaxis1_en": "Std. Dev. (ppl/km²)",
"cv_yaxis_zh": "CV",
"cv_yaxis_en": "CV",
"sigma_judgment_zh": "**σ-收敛判断**",
"sigma_judgment_en": "**σ-Convergence Assessment**",
"cv_converge_zh": "↓ 收敛",
"cv_converge_en": "↓ Converging",
"cv_diverge_zh": "↑ 发散",
"cv_diverge_en": "↑ Diverging",
"std_shrink_zh": "↓ 缩小",
"std_shrink_en": "↓ Shrinking",
"std_expand_zh": "↑ 扩大",
"std_expand_en": "↑ Expanding",
"sigma_meaning_zh": "**说明**",
"sigma_meaning_en": "**Note**",
"sigma_conv_text_zh": "CV 下降表明省际人口密度差异在缩小(σ-收敛),与劳动力流动降低区域间密度差距的假设一致。",
"sigma_conv_text_en": "Declining CV indicates narrowing interprovincial density differences (σ-convergence), consistent with labor mobility reducing regional density gaps.",
"sigma_div_text_zh": "CV 上升表明省际人口密度差异在扩大(σ-发散),高密度省份的人口份额持续上升。",
"sigma_div_text_en": "Rising CV indicates widening interprovincial density differences (σ-divergence), with high-density provinces continuing to gain population share.",
"focus_profile_zh": "{prov} · 深度剖面",
"focus_profile_en": "{prov} · In-Depth Profile",
"kpi_yr_density_zh": "{yr}年平均密度",
"kpi_yr_density_en": "{yr} Avg. Density",
"kpi_pop_est_zh": "估算人口",
"kpi_pop_est_en": "Est. Population",
"kpi_national_rank_zh": "全国排名",
"kpi_national_rank_en": "National Rank",
"kpi_rank_val_zh": "第 {rank} 名",
"kpi_rank_val_en": "Rank #{rank}",
"kpi_total_growth_zh": "总增长",
"kpi_total_growth_en": "Total Growth",
"kpi_growth_rate_zh": "增长率",
"kpi_growth_rate_en": "Growth Rate",
"province_trend_title_zh": "{prov} 历年趋势",
"province_trend_title_en": "{prov} Historical Trend",
"avg_density_trace_zh": "平均密度",
"avg_density_trace_en": "Avg. Density",
"pop_est_trace_zh": "估算人口(亿)",
"pop_est_trace_en": "Est. Pop. (100M)",
"hundred_million_zh": "亿",
"hundred_million_en": "100M",
"rank_chart_title_zh": "{prov} 排名变化",
"rank_chart_title_en": "{prov} Rank Change",
"rank_yaxis_zh": "排名",
"rank_yaxis_en": "Rank",
"stats_table_metrics_zh": ["平均密度", "中位数密度", "最大密度", "标准差", "估算人口(万)", "栅格像素数"],
"stats_table_metrics_en": ["Avg. Density", "Median Density", "Max Density", "Std. Dev.", "Est. Pop. (10k)", "Raster Pixels"],
"stats_value_col_zh": "值",
"stats_value_col_en": "Value",
"stats_metric_col_zh": "指标",
"stats_metric_col_en": "Metric",
"yoy_year_col_zh": "年份",
"yoy_year_col_en": "Period",
"yoy_change_col_zh": "变化",
"yoy_change_col_en": "Change",
"yoy_pct_col_zh": "变化率",
"yoy_pct_col_en": "Chg. Rate",
"compare_subplots_zh": ["平均密度", "估算人口(万)", "最大密度"],
"compare_subplots_en": ["Avg. Density", "Est. Pop. (10k)", "Max Density"],
# ---- Tab 6: Methods ----
"methods_header_zh": "数据与方法",
"methods_header_en": "Data & Methods",
"methods_caption_zh": "数据口径、处理流程与解释边界。",
"methods_caption_en": "Data scope, processing workflow, and interpretation boundaries.",
"methods_data_sources_zh": "数据来源",
"methods_data_sources_en": "Data Sources",
"methods_data_md_zh": (
"1. 官方来源:[{col}]({col})\n"
"2. 数据类型:WorldPop `UN-adjusted 1km Population Density`\n"
"3. 官方中国示例页:[2002]({c2002})、[2020]({c2020})\n"
"4. DOI:[{doi}]({doi})\n"
"5. 许可:[{cc}]({cc})"
),
"methods_data_md_en": (
"1. Official source: [{col}]({col})\n"
"2. Data type: WorldPop `UN-adjusted 1km Population Density`\n"
"3. China example pages: [2002]({c2002}), [2020]({c2020})\n"
"4. DOI: [{doi}]({doi})\n"
"5. License: [{cc}]({cc})"
),
"methods_sample_scope_zh": "样本范围",
"methods_sample_scope_en": "Sample Scope",
"methods_sample_md_zh": (
"1. 当前网页使用年份:{y0}-{y1}\n"
"2. 指标单位:人口密度,单位为人/km²\n"
"3. 当前展示数据经过 1km → 5km 平均降采样\n"
"4. 范围切换:当前可在\"{scope}\"与全国口径之间切换"
),
"methods_sample_md_en": (
"1. Years used on this page: {y0}-{y1}\n"
"2. Indicator unit: population density in ppl/km²\n"
"3. Data displayed after 1km → 5km average downsampling\n"
"4. Scope toggle: currently switchable between \"{scope}\" and national scope"
),
"methods_processing_zh": "处理流程",
"methods_processing_en": "Processing Workflow",
"methods_processing_md_zh": (
"1. 使用平均重采样把原始 1km 栅格降到约 5km,以降低前端负载。\n"
"2. 全国人口与全国均值直接由栅格计算,不通过省级统计反推。\n"
"3. 省级人口估算采用纬度修正后的像元面积,而不是固定 25 km²。\n"
"4. 变化图使用 P99 对称裁剪,避免少数极端像元压缩整体色阶。\n"
"5. 空间经济学指标(基尼系数、收敛检验、人口重心)直接由像元级栅格实时计算。"
),
"methods_processing_md_en": (
"1. Original 1km raster downsampled to ~5km using average resampling to reduce frontend load.\n"
"2. National population and national mean computed directly from raster, not back-calculated from provincial statistics.\n"
"3. Provincial population estimates use latitude-corrected pixel area rather than a fixed 25 km².\n"
"4. Change maps use P99 symmetric clipping to prevent a few extreme pixels from compressing the overall color scale.\n"
"5. Spatial economics indicators (Gini coefficient, convergence tests, population centroid) computed in real time directly from pixel-level rasters."
),
"methods_limits_zh": "解释边界",
"methods_limits_en": "Interpretation Boundaries",
"methods_limits_md_zh": (
"1. 本网页反映的是人口密度栅格估算,不等于官方行政统计口径。\n"
"2. 5km 降采样会平滑超高密度城市核心区。\n"
"3. UN-adjusted 表示全国总量与联合国人口估计保持一致。\n"
"4. 栅格密度差分作为迁移代理变量存在局限:无法区分自然增长与机械增长。\n"
"5. β/σ-收敛检验基于省级均值,省内异质性未被捕捉。\n"
"6. 页面不提供原始数据下载,仅提供分析性浏览。"
),
"methods_limits_md_en": (
"1. This page reflects population density raster estimates, not official administrative statistics.\n"
"2. 5km downsampling smooths ultra-high-density urban cores.\n"
"3. UN-adjusted means national totals are consistent with UN population estimates.\n"
"4. Raster density differencing as a migration proxy has limitations: cannot distinguish natural from mechanical growth.\n"
"5. β/σ-convergence tests are based on provincial means; within-province heterogeneity is not captured.\n"
"6. This page does not provide raw data download, only analytical browsing."
),
"methods_variables_zh": "变量口径",
"methods_variables_en": "Variable Definitions",
"methods_var_names_zh": ["估算总人口", "加权平均密度", "高密度像元数", "空间基尼系数", "Top10%集中度", "人口重心", "β-收敛斜率", "σ-收敛 (CV)", "区域人口份额", "省级平均密度", "增长率"],
"methods_var_names_en": ["Est. Total Pop.", "Weighted Avg. Density", "High-Density Pixels", "Spatial Gini Coeff.", "Top10% Concentration", "Population Centroid", "β-Conv. Slope", "σ-Conv. (CV)", "Regional Pop. Share", "Provincial Avg. Density", "Growth Rate"],
"methods_var_descs_zh": [
"按栅格密度 × 纬度修正像元面积汇总得到的总人口估算",
"按有效像元面积加权后的全国平均密度,可作为 market potential 代理指标",
"人口密度 > 1000 人/km² 的像元数量,代表核心区规模",
"基于像元人口(密度×面积)的洛伦兹曲线计算,衡量人口空间分布不平等度",
"最密 10% 像元的人口占总人口比例,衡量集聚程度",
"Σ(人口×坐标) / Σ人口,漂移方向反映区域间相对人口增长格局",
"ln(初始密度) vs 年均增长率的 OLS 斜率;负值 = 收敛(追赶),正值 = 发散",
"省际密度变异系数(标准差/均值);下降 = 省际差异缩小",
"东/中/西/东北四大区域的人口占比,基于省级估算人口汇总",
"省域内像元密度的算术平均",
"相对基期(2002 年)的百分比变化",
],
"methods_var_descs_en": [
"Total population estimate aggregated from raster density × latitude-corrected pixel area",
"National average density weighted by valid pixel area; serves as market potential proxy",
"Number of pixels with population density > 1000 ppl/km², representing core area scale",
"Computed from Lorenz curve of pixel-level population (density×area), measuring spatial inequality of population distribution",
"Share of total population living in the densest 10% of pixels, measuring agglomeration degree",
"Σ(pop×coord)/Σpop; drift direction reflects relative population growth across regions",
"OLS slope of ln(initial density) vs annual growth rate; negative = convergence (catch-up), positive = divergence",
"Interprovincial density coefficient of variation (std/mean); declining = narrowing interprovincial gap",
"Population shares of the four major regions (East/Central/West/Northeast), aggregated from provincial estimates",
"Arithmetic mean of pixel densities within a province",
"Percentage change relative to the base year (2002)",
],
"methods_var_col_zh": "变量",
"methods_var_col_en": "Variable",
"methods_desc_col_zh": "说明",
"methods_desc_col_en": "Description",
"methods_citation_zh": "建议引用",
"methods_citation_en": "Suggested Citation",
# Author info
"author_info_zh": "**Li Shen** · Department of Economics, Clark University",
"author_info_en": "**Li Shen** · Department of Economics, Clark University",
# Footer
"footer_zh": (
"<small>"
"中国人口密度时空探索器 ({scope}) | "
"Li Shen | Dept. of Economics, Clark University |"
"数据: WorldPop UN-adjusted 1km → 5km降采样 | "
"人口估算: 纬度修正像元面积 | 仅供趋势参考<br>"
"官方来源: <a href='{col}' target='_blank'>WorldPop Global1 2000-2020</a> | "
"DOI: <a href='{doi}' target='_blank'>10.5258/SOTON/WP00675</a> | "
"许可: <a href='{cc}' target='_blank'>CC BY 4.0</a> | "
"中国示例: <a href='{c2002}' target='_blank'>2002</a> / "
"<a href='{c2020}' target='_blank'>2020</a>"
"</small>"
),
"footer_en": (
"<small>"
"China Population Density Spatiotemporal Explorer ({scope}) | "
"Li Shen | Dept. of Economics, Clark University |"
"Data: WorldPop UN-adjusted 1km → 5km downsampled | "
"Pop. est.: lat-corrected pixel area | For trend reference only<br>"
"Official source: <a href='{col}' target='_blank'>WorldPop Global1 2000-2020</a> | "
"DOI: <a href='{doi}' target='_blank'>10.5258/SOTON/WP00675</a> | "
"License: <a href='{cc}' target='_blank'>CC BY 4.0</a> | "
"China examples: <a href='{c2002}' target='_blank'>2002</a> / "
"<a href='{c2020}' target='_blank'>2020</a>"
"</small>"
),
}
def T(key_zh, key_en=None, **kwargs):
"""Return Chinese or English string based on `lang`.
- T("key") → looks up _LANG_STRINGS["key_zh"] or ["key_en"]
- T("key_zh", "key_en", var=val) → format with kwargs
"""
global lang
if key_en is None:
# key_zh is a base key, append _zh or _en suffix
key = key_zh + ("_zh" if lang == "zh" else "_en")
text = _LANG_STRINGS.get(key, key_zh)
else:
# key_zh and key_en are explicit full keys
key = key_zh if lang == "zh" else key_en
text = _LANG_STRINGS.get(key, key)
if kwargs:
try:
text = text.format(**kwargs)
except (KeyError, IndexError):
pass
return text
def region_name(zh_name):
"""Return region name in current language."""
if lang == "en":
return REGION_MAP_EN.get(zh_name, zh_name)
return zh_name
def prov_name(zh_name):
"""Return province name in current language."""
if lang == "en":
return PROVINCE_NAME_EN.get(zh_name, zh_name)
return zh_name
# ---------------------------------------------------------------------------
# Cached data loaders
# ---------------------------------------------------------------------------
@st.cache_data
def load_year(year):
path = os.path.join(DATA_DIR, f"China_{year}_5km.tif")
with rasterio.open(path) as src:
data = src.read(1)
bounds = [[src.bounds.bottom, src.bounds.left],
[src.bounds.top, src.bounds.right]]
res_deg = src.res[0]
lat_top = src.bounds.top
height = src.height
data = data.astype(np.float64)
data[data < -1e30] = np.nan
data[data < 0] = np.nan
return data, bounds, res_deg, lat_top, height
@st.cache_data
def load_province_stats():
with open(PROVINCE_STATS_PATH, "r", encoding="utf-8") as f:
return json.load(f)
# [Fix 2] National summary directly from raster, with scope support
@st.cache_data
def load_national_stats(scope_key):
with open(NATIONAL_STATS_PATH, "r", encoding="utf-8") as f:
raw = json.load(f)
records = []
for y in YEARS:
year_payload = raw[str(y)]
d = year_payload.get(scope_key, year_payload)
records.append({
"年份": y,
"估算总人口(万)": d["est_pop_wan"],
"加权平均密度": d["weighted_mean_density"],
"平均密度": d["mean_density"],
"高密度像素数": d["high_density_pixels_1000"],
"有效像元数": d.get("total_valid_pixels"),
"有人口像元数": d.get("inhabited_pixels"),
})
return pd.DataFrame(records)
@st.cache_data
def load_geojson():
with open(GEOJSON_PATH, "r", encoding="utf-8") as f:
gj = json.load(f)
gj["features"] = [
feat for feat in gj["features"]
if feat["properties"].get("name", "") != ""
and "_" not in str(feat["properties"].get("adcode", ""))
]
return gj
@st.cache_data
def build_province_df(province_stats):
rows = []
for y in YEARS:
for p in province_stats[str(y)]:
rows.append({"年份": y, **p})
return pd.DataFrame(rows)
@st.cache_data
def compute_rank_history(province_stats, exclude_names):
rows = []
for y in YEARS:
provs = [p for p in province_stats[str(y)] if p["name"] not in exclude_names]
provs.sort(key=lambda x: x["mean"], reverse=True)
for rank, p in enumerate(provs, 1):
rows.append({"年份": y, "省份": p["name"], "排名": rank, "平均密度": p["mean"]})
return pd.DataFrame(rows)
# --- Image renderers ---
@st.cache_data
def raster_to_image(data):
norm = LogNorm(vmin=VMIN, vmax=VMAX, clip=True)
colormap = cm.get_cmap("inferno")
mask = np.isnan(data) | (data <= 0)
normalized = np.where(mask, 0, norm(data))
rgba = colormap(normalized)
rgba[mask, 3] = 0
return (rgba * 255).astype(np.uint8)
# [Fix 3] Adaptive diff colorscale using p99
@st.cache_data
def diff_to_image_adaptive(diff):
"""Coolwarm diverging colormap with p99-based symmetric bounds."""
colormap = cm.get_cmap("coolwarm")
valid = diff[~np.isnan(diff)]
if len(valid) == 0:
return np.zeros((*diff.shape, 4), dtype=np.uint8)
p99 = float(np.percentile(np.abs(valid), 99))
p99 = max(p99, 1.0)
clipped_count = int(np.sum(np.abs(valid) > p99))
norm = Normalize(vmin=-p99, vmax=p99, clip=True)
mask = np.isnan(diff)
normalized = np.where(mask, 0.5, norm(diff))
rgba = colormap(normalized)
rgba[mask, 3] = 0
return (rgba * 255).astype(np.uint8), p99, clipped_count, len(valid)