like-sci-figures 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +56 -0
- package/README.md +93 -2
- package/cli.js +79 -0
- package/examples/area.json +9 -0
- package/examples/bar.json +15 -0
- package/examples/bland_altman.json +128 -0
- package/examples/bode.json +8 -0
- package/examples/box.json +8 -0
- package/examples/bubble.json +7 -0
- package/examples/contour.json +10 -0
- package/examples/corr_matrix.json +99 -0
- package/examples/dendrogram.json +5 -0
- package/examples/density.json +8 -0
- package/examples/dot_plot.json +8 -0
- package/examples/ecdf.json +377 -0
- package/examples/errorbar.json +7 -0
- package/examples/forest.json +12 -0
- package/examples/heatmap.json +10 -0
- package/examples/hexbin.json +6009 -0
- package/examples/histogram.json +6 -0
- package/examples/kaplan_meier.json +6 -0
- package/examples/line.json +11 -0
- package/examples/manhattan.json +7 -0
- package/examples/panels.json +28 -0
- package/examples/pca.json +12 -0
- package/examples/periodogram.json +7 -0
- package/examples/pie.json +4 -0
- package/examples/radar.json +7 -0
- package/examples/ridge.json +11 -0
- package/examples/roc.json +6 -0
- package/examples/sankey.json +9 -0
- package/examples/scatter3d.json +6 -0
- package/examples/slope.json +6 -0
- package/examples/stacked_bar.json +12 -0
- package/examples/surface.json +11 -0
- package/examples/taylor.json +9 -0
- package/examples/ternary.json +18 -0
- package/examples/venn.json +12 -0
- package/examples/violin.json +9 -0
- package/examples/volcano.json +7 -0
- package/examples/waterfall.json +5 -0
- package/examples/windrose.json +407 -0
- package/package.json +33 -4
- package/requirements.txt +9 -0
- package/scripts/add_chart.py +201 -0
- package/scripts/build_gallery.py +360 -0
- package/scripts/chart_plugin.py +153 -0
- package/scripts/data_loader.py +260 -0
- package/scripts/fig_3d.py +103 -0
- package/scripts/fig_area.py +57 -0
- package/scripts/fig_bar.py +117 -0
- package/scripts/fig_biomed.py +289 -0
- package/scripts/fig_box.py +60 -0
- package/scripts/fig_bubble.py +65 -0
- package/scripts/fig_core.py +195 -0
- package/scripts/fig_datasci.py +276 -0
- package/scripts/fig_distribution.py +59 -0
- package/scripts/fig_engineering.py +224 -0
- package/scripts/fig_environ.py +239 -0
- package/scripts/fig_errorbar.py +49 -0
- package/scripts/fig_forest.py +54 -0
- package/scripts/fig_heatmap.py +51 -0
- package/scripts/fig_line.py +39 -0
- package/scripts/fig_pca.py +101 -0
- package/scripts/fig_pie.py +52 -0
- package/scripts/fig_radar.py +32 -0
- package/scripts/fig_sankey.py +196 -0
- package/scripts/fig_scatter.py +44 -0
- package/scripts/fig_subplots.py +124 -0
- package/scripts/fig_taylor.py +80 -0
- package/scripts/fig_venn.py +80 -0
- package/scripts/fig_windrose.py +82 -0
- package/scripts/font_detector.py +85 -0
- package/scripts/gen_figure.py +583 -0
- package/scripts/generate_samples.py +322 -0
- package/scripts/palette_picker.py +244 -0
- package/scripts/palette_pref.py +179 -0
- package/scripts/palette_preview.py +334 -0
- package/scripts/palettes.py +461 -0
- package/scripts/registry.py +138 -0
- package/scripts/render_utils.py +233 -0
- package/scripts/showcase.py +179 -0
- package/scripts/style_manager.py +267 -0
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Palette library for LIKE Sci Figures.
|
|
4
|
+
|
|
5
|
+
A collection of 34 curated scientific color palettes, covering:
|
|
6
|
+
- 10 original 科研配色方案 poster series (wx01–wx10)
|
|
7
|
+
- 10 journal/medical series (wx11–wx20): Lancet, Nature, NEJM, Science, JAMA, JCO, BMJ, Cell, clinical status
|
|
8
|
+
- 3 colorblind-safe classics (wx21–wx23): Okabe-Ito, Paul Tol, Tableau10
|
|
9
|
+
- 4 perceptually-uniform continuous (wx24–wx27): Viridis, Magma, SciCo Tokyo, Cividis
|
|
10
|
+
- 2 finance series (wx28–wx29): Bloomberg Terminal, Financial Institutional
|
|
11
|
+
- 2 engineering/materials (wx30–wx31): IEEE/Springer, Advanced Materials
|
|
12
|
+
- 3 ColorBrewer classics (wx32–wx34): Set2, Spectral, Dark2
|
|
13
|
+
|
|
14
|
+
Each palette ships with:
|
|
15
|
+
- a slug (ASCII, for CLI use)
|
|
16
|
+
- a Chinese display name
|
|
17
|
+
- a "kind": qualitative | sequential | diverging
|
|
18
|
+
- a "domain": list of suitable academic fields
|
|
19
|
+
- an ordered list of hex colors
|
|
20
|
+
|
|
21
|
+
Usage from other modules:
|
|
22
|
+
from palettes import list_palettes, get_palette, palette_colormap
|
|
23
|
+
|
|
24
|
+
CLI:
|
|
25
|
+
--palette wx06_amber_navy # by slug
|
|
26
|
+
--palette p6 # by short id
|
|
27
|
+
--palette 6 # by index
|
|
28
|
+
--palette "#F26A1D,#1E5FA8" # raw comma-separated hex list
|
|
29
|
+
"""
|
|
30
|
+
import numpy as np
|
|
31
|
+
|
|
32
|
+
# ── The 34 palettes ─────────────────────────────────────────────────────
|
|
33
|
+
# Order matters: it defines the natural progression of the palette.
|
|
34
|
+
PALETTES = {
|
|
35
|
+
"wx01_blue_red": {
|
|
36
|
+
"zh": "01 深海蓝→中国红(蓝红发散)",
|
|
37
|
+
"kind": "diverging",
|
|
38
|
+
"domain": ["跨学科通用", "热力图", "相关性分析"],
|
|
39
|
+
"desc": "对称蓝红发散,适合热图/相关性矩阵/正负对比,也可作分组配色。",
|
|
40
|
+
"colors": [
|
|
41
|
+
"#104E8B", "#376B9E", "#5F89B1", "#AFC3D8", "#C9E9E3",
|
|
42
|
+
"#D7E1EB", "#F2DADA", "#E5B5B5", "#D89090", "#B22222",
|
|
43
|
+
],
|
|
44
|
+
},
|
|
45
|
+
"wx02_soft_pink": {
|
|
46
|
+
"zh": "02 柔粉灰(低饱和)",
|
|
47
|
+
"kind": "qualitative",
|
|
48
|
+
"domain": ["临床医学", "心理学", "社会科学研究"],
|
|
49
|
+
"desc": "低饱和粉/灰/奶油色,柔和高级,适合多组对比但不抢眼。",
|
|
50
|
+
"colors": ["#F4C7C7", "#E6ECF2", "#E57373", "#F29A8E", "#7FB3B0", "#FFF1D6"],
|
|
51
|
+
},
|
|
52
|
+
"wx03_sunset_blue": {
|
|
53
|
+
"zh": "03 暖橙→蓝紫(日落渐变)",
|
|
54
|
+
"kind": "sequential",
|
|
55
|
+
"domain": ["跨学科通用", "数据科学", "趋势分析"],
|
|
56
|
+
"desc": "暖到冷的连续渐变,适合折线/堆叠/热图,分组配色很有层次。",
|
|
57
|
+
"colors": [
|
|
58
|
+
"#F37252", "#F7935A", "#FCB461", "#FED297", "#FFF0DC",
|
|
59
|
+
"#E3F5F6", "#ABE0E4", "#7FC6D3", "#779FC6", "#6F78B9",
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
"wx04_macaron": {
|
|
63
|
+
"zh": "04 马卡龙(柔和多色)",
|
|
64
|
+
"kind": "qualitative",
|
|
65
|
+
"domain": ["生命科学", "环境科学", "生态学"],
|
|
66
|
+
"desc": "9 色柔和马卡龙,粉橙黄绿青蓝齐备,适合分类/花瓣图/多组散点。",
|
|
67
|
+
"colors": [
|
|
68
|
+
"#FEB8B4", "#FEB07A", "#FFEDAE", "#88D485", "#FFDBDB",
|
|
69
|
+
"#FFEBE4", "#D2F2ED", "#A6F6EE", "#B9D8F6",
|
|
70
|
+
],
|
|
71
|
+
},
|
|
72
|
+
"wx05_coral_blue": {
|
|
73
|
+
"zh": "05 珊瑚粉→钢蓝(红蓝发散·8色)",
|
|
74
|
+
"kind": "diverging",
|
|
75
|
+
"domain": ["跨学科通用", "统计学", "回归分析"],
|
|
76
|
+
"desc": "8 色红蓝发散,红端柔和、蓝端沉静,适合气泡/热图/回归。",
|
|
77
|
+
"colors": ["#FCE8E6", "#FFC6BC", "#F8B9B8", "#FFADA2",
|
|
78
|
+
"#D6DFEF", "#A5CDE2", "#5FA3CB", "#668FCA"],
|
|
79
|
+
},
|
|
80
|
+
"wx06_amber_navy": {
|
|
81
|
+
"zh": "06 琥珀橙→藏青(橙蓝对比)",
|
|
82
|
+
"kind": "sequential",
|
|
83
|
+
"domain": ["跨学科通用", "数据科学", "分布分析"],
|
|
84
|
+
"desc": "橙到深蓝的强对比渐变,主次分明,适合折线/堆叠/分布。",
|
|
85
|
+
"colors": ["#F26A1D", "#F7B891", "#FFF3E6", "#DCE6F2", "#6EA6D6", "#1E5FA8"],
|
|
86
|
+
},
|
|
87
|
+
"wx07_teal_blue_red": {
|
|
88
|
+
"zh": "07 青蓝→暖红(青蓝红)",
|
|
89
|
+
"kind": "qualitative",
|
|
90
|
+
"domain": ["跨学科通用", "热力图", "多面板组合"],
|
|
91
|
+
"desc": "青绿+蓝+红点缀,清爽专业,热图与多组图通用。",
|
|
92
|
+
"colors": ["#E8F2F2", "#C3DFDD", "#69BAA2", "#82C1D3", "#80B2C8", "#E79295", "#D55E57"],
|
|
93
|
+
},
|
|
94
|
+
"wx08_amber_indigo": {
|
|
95
|
+
"zh": "08 琥珀→靛蓝(暖冷渐变·8色)",
|
|
96
|
+
"kind": "sequential",
|
|
97
|
+
"domain": ["环境科学", "数据科学", "聚类分析"],
|
|
98
|
+
"desc": "8 色暖冷连续渐变,青蓝段过渡自然,适合堆叠/趋势/聚类热图。",
|
|
99
|
+
"colors": ["#F16D4E", "#FDB863", "#FDEBCF", "#E6F3F7",
|
|
100
|
+
"#B7E3EA", "#89CBD4", "#6E8FC7", "#6A6FBE"],
|
|
101
|
+
},
|
|
102
|
+
"wx09_pastel_mix": {
|
|
103
|
+
"zh": "09 柔彩综合(8色)",
|
|
104
|
+
"kind": "qualitative",
|
|
105
|
+
"domain": ["生物信息学", "统计学", "多面板分析"],
|
|
106
|
+
"desc": "黄绿粉青橙红综合柔和色,兼容火山图/热图/多面板。",
|
|
107
|
+
"colors": ["#E0ECCC", "#DACCE2", "#F1C0C0", "#E1E09C",
|
|
108
|
+
"#94C584", "#EEB56D", "#75C1D0", "#DC7C7D"],
|
|
109
|
+
},
|
|
110
|
+
"wx10_vivid_contrast": {
|
|
111
|
+
"zh": "10 高饱和对比(6色)",
|
|
112
|
+
"kind": "qualitative",
|
|
113
|
+
"domain": ["跨学科通用", "强调对比", "关键结果"],
|
|
114
|
+
"desc": "红橙青蓝紫深蓝,高饱和高区分度,适合强调关键结果的对比图。",
|
|
115
|
+
"colors": ["#D23918", "#E5A84B", "#5DA39D", "#4182A4", "#7B357D", "#354E6B"],
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
# ── Medical / Top-Journal series (ggsci-extracted) ────────────────────
|
|
119
|
+
"wx11_lancet_gradient": {
|
|
120
|
+
"zh": "11 Lancet 2024 渐变(蓝→绿→暖色·11色)",
|
|
121
|
+
"kind": "sequential",
|
|
122
|
+
"domain": ["临床医学", "流行病学", "公共卫生"],
|
|
123
|
+
"desc": "Lancet 2024 年最新配色,从蓝到暖色自然渐变,适合折线/堆叠/趋势图。",
|
|
124
|
+
"colors": [
|
|
125
|
+
"#7B95C6", "#49C2D9", "#A1D8E8", "#67A583", "#A2C986",
|
|
126
|
+
"#D0E2C0", "#FDED95", "#FFC1A6", "#F59C7C", "#F47254",
|
|
127
|
+
"#C85E62",
|
|
128
|
+
],
|
|
129
|
+
},
|
|
130
|
+
"wx12_lancet": {
|
|
131
|
+
"zh": "12 Lancet 经典(蓝红主调·9色)",
|
|
132
|
+
"kind": "qualitative",
|
|
133
|
+
"domain": ["临床医学", "流行病学", "卫生政策"],
|
|
134
|
+
"desc": "Lancet Oncology 经典配色,深蓝+正红为主,庄重大气,适合临床分组/流行病学。",
|
|
135
|
+
"colors": [
|
|
136
|
+
"#00468B", "#ED0000", "#42B540", "#0099B4", "#925E9F",
|
|
137
|
+
"#FDAF91", "#AD002A", "#ADB6B6", "#1B1919",
|
|
138
|
+
],
|
|
139
|
+
},
|
|
140
|
+
"wx13_nature_npg": {
|
|
141
|
+
"zh": "13 Nature 旗舰(NPG·10色)",
|
|
142
|
+
"kind": "qualitative",
|
|
143
|
+
"domain": ["自然科学通用", "生物医学", "地球科学"],
|
|
144
|
+
"desc": "Nature Publishing Group 旗舰配色,饱和稳重,多组对比通用首选。",
|
|
145
|
+
"colors": [
|
|
146
|
+
"#E64B35", "#4DBBD5", "#00A087", "#3C5488", "#F39B7F",
|
|
147
|
+
"#8491B4", "#91D1C2", "#DC0000", "#7E6148", "#B09C85",
|
|
148
|
+
],
|
|
149
|
+
},
|
|
150
|
+
"wx14_nejm": {
|
|
151
|
+
"zh": "14 NEJM 经典(红蓝层次·8色)",
|
|
152
|
+
"kind": "qualitative",
|
|
153
|
+
"domain": ["临床医学", "生存分析", "药物研发"],
|
|
154
|
+
"desc": "新英格兰医学杂志经典配色,红蓝层次分明,适合临床数据/生存分析曲线。",
|
|
155
|
+
"colors": [
|
|
156
|
+
"#BC3C29", "#0072B5", "#E18727", "#20854E",
|
|
157
|
+
"#7876B1", "#6F99AD", "#FFDC91", "#EE4C97",
|
|
158
|
+
],
|
|
159
|
+
},
|
|
160
|
+
"wx15_aaas_science": {
|
|
161
|
+
"zh": "15 AAAS/Science(偏暖·10色)",
|
|
162
|
+
"kind": "qualitative",
|
|
163
|
+
"domain": ["多学科通用", "物理学", "工程学"],
|
|
164
|
+
"desc": "Science 期刊配色,偏暖调,多学科对比通用。",
|
|
165
|
+
"colors": [
|
|
166
|
+
"#3B4992", "#EE0000", "#008B45", "#631879", "#008280",
|
|
167
|
+
"#BB0021", "#5F559B", "#A20056", "#808180", "#1B1919",
|
|
168
|
+
],
|
|
169
|
+
},
|
|
170
|
+
"wx16_jama": {
|
|
171
|
+
"zh": "16 JAMA 经典(冷暖平衡·7色)",
|
|
172
|
+
"kind": "qualitative",
|
|
173
|
+
"domain": ["医学统计", "临床对比", "循证医学"],
|
|
174
|
+
"desc": "美国医学会杂志配色,冷暖平衡,适合医学统计图/临床对比。",
|
|
175
|
+
"colors": [
|
|
176
|
+
"#374E55", "#DF8F44", "#00A1D5", "#B24745",
|
|
177
|
+
"#79AF97", "#6A6599", "#80796B",
|
|
178
|
+
],
|
|
179
|
+
},
|
|
180
|
+
"wx17_jco": {
|
|
181
|
+
"zh": "17 JCO 临床肿瘤(蓝黄对比·10色)",
|
|
182
|
+
"kind": "qualitative",
|
|
183
|
+
"domain": ["肿瘤学", "临床肿瘤", "色盲安全"],
|
|
184
|
+
"desc": "Journal of Clinical Oncology 配色,色盲安全,临床肿瘤数据首选。",
|
|
185
|
+
"colors": [
|
|
186
|
+
"#0073C2", "#EFC000", "#868686", "#CD534C", "#7AA6DC",
|
|
187
|
+
"#003C67", "#8F7700", "#3B3B3B", "#A73030", "#4A6990",
|
|
188
|
+
],
|
|
189
|
+
},
|
|
190
|
+
"wx18_bmj": {
|
|
191
|
+
"zh": "18 BMJ 简约(4色克制)",
|
|
192
|
+
"kind": "qualitative",
|
|
193
|
+
"domain": ["临床医学", "公共卫生", "少量分组"],
|
|
194
|
+
"desc": "BMJ 简约配色,仅 4 色,克制专业,适合少量分组对比。",
|
|
195
|
+
"colors": ["#C2D0EA", "#0070B8", "#00B3B0", "#D40D8C"],
|
|
196
|
+
},
|
|
197
|
+
"wx19_cell": {
|
|
198
|
+
"zh": "19 Cell 多彩(鲜艳·7色)",
|
|
199
|
+
"kind": "qualitative",
|
|
200
|
+
"domain": ["细胞生物学", "分子生物学", "发育生物学"],
|
|
201
|
+
"desc": "Cell Press 配色,鲜艳多彩,适合细胞/分子生物学可视化。",
|
|
202
|
+
"colors": [
|
|
203
|
+
"#85B373", "#FF9FA0", "#373737", "#367FBD",
|
|
204
|
+
"#BD324C", "#092DF1", "#FC2704",
|
|
205
|
+
],
|
|
206
|
+
},
|
|
207
|
+
"wx20_clinical_status": {
|
|
208
|
+
"zh": "20 临床状态(医学·5色)",
|
|
209
|
+
"kind": "qualitative",
|
|
210
|
+
"domain": ["临床医学", "患者管理", "不良反应分析"],
|
|
211
|
+
"desc": "医学临床状态配色:正常/监测/高危/未知/不适用,适合患者流程/不良反应图。",
|
|
212
|
+
"colors": ["#0072B2", "#E69F00", "#D55E00", "#999999", "#E6E6E6"],
|
|
213
|
+
},
|
|
214
|
+
|
|
215
|
+
# ── Colorblind-safe classics (international standards) ────────────────
|
|
216
|
+
"wx21_okabe_ito": {
|
|
217
|
+
"zh": "21 Okabe-Ito 色盲安全(8色·国际标准)",
|
|
218
|
+
"kind": "qualitative",
|
|
219
|
+
"domain": ["跨学科通用", "色盲安全", "Nature Methods推荐"],
|
|
220
|
+
"desc": "Okabe & Ito 2002 设计,色盲安全黄金标准,Nature Methods 推荐。",
|
|
221
|
+
"colors": [
|
|
222
|
+
"#000000", "#E69F00", "#56B4E9", "#009E73",
|
|
223
|
+
"#F0E442", "#0072B2", "#D55E00", "#CC79A7",
|
|
224
|
+
],
|
|
225
|
+
},
|
|
226
|
+
"wx22_paul_tol": {
|
|
227
|
+
"zh": "22 Paul Tol Bright(印刷安全·7色)",
|
|
228
|
+
"kind": "qualitative",
|
|
229
|
+
"domain": ["物理学", "天文学", "印刷出版"],
|
|
230
|
+
"desc": "Paul Tol 设计,CMYK 印刷安全,物理/天文领域广泛使用。",
|
|
231
|
+
"colors": [
|
|
232
|
+
"#4477AA", "#EE6677", "#228833", "#CCBB44",
|
|
233
|
+
"#66CCEE", "#AA3377", "#BBBBBB",
|
|
234
|
+
],
|
|
235
|
+
},
|
|
236
|
+
"wx23_tableau10": {
|
|
237
|
+
"zh": "23 Tableau10 现代默认(10色)",
|
|
238
|
+
"kind": "qualitative",
|
|
239
|
+
"domain": ["跨学科通用", "数据可视化", "Dashboard"],
|
|
240
|
+
"desc": "Tableau/Matplotlib 现代默认配色,广泛认知,dashboard 通用。",
|
|
241
|
+
"colors": [
|
|
242
|
+
"#1F77B4", "#FF7F0E", "#2CA02C", "#D62728", "#9467BD",
|
|
243
|
+
"#8C564B", "#E377C2", "#7F7F7F", "#BCBD22", "#17BECF",
|
|
244
|
+
],
|
|
245
|
+
},
|
|
246
|
+
|
|
247
|
+
# ── Perceptually-uniform continuous (heatmap/density) ─────────────────
|
|
248
|
+
"wx24_viridis": {
|
|
249
|
+
"zh": "24 Viridis 感知均匀(8色·热力图首选)",
|
|
250
|
+
"kind": "sequential",
|
|
251
|
+
"domain": ["数据科学", "跨学科通用", "热力图"],
|
|
252
|
+
"desc": "感知均匀色盲安全,matplotlib 默认,热力图/密度图最佳实践。",
|
|
253
|
+
"colors": [
|
|
254
|
+
"#440154", "#46327E", "#365C8D", "#277F8E",
|
|
255
|
+
"#1FA187", "#4AC16D", "#A0DA39", "#FDE725",
|
|
256
|
+
],
|
|
257
|
+
},
|
|
258
|
+
"wx25_magma": {
|
|
259
|
+
"zh": "25 Magma 暗紫→暖黄(8色)",
|
|
260
|
+
"kind": "sequential",
|
|
261
|
+
"domain": ["数据科学", "天文物理", "高端可视化"],
|
|
262
|
+
"desc": "暗紫到暖黄渐变,感知均匀,高端数据可视化。",
|
|
263
|
+
"colors": [
|
|
264
|
+
"#000004", "#1B0C41", "#4A0C6B", "#781C6D",
|
|
265
|
+
"#A52C60", "#CB4760", "#E87461", "#F59563",
|
|
266
|
+
],
|
|
267
|
+
},
|
|
268
|
+
"wx26_scico_tokyo": {
|
|
269
|
+
"zh": "26 SciCo Tokyo(Fabio Crameri·8色)",
|
|
270
|
+
"kind": "sequential",
|
|
271
|
+
"domain": ["地理信息", "气候科学", "地图学"],
|
|
272
|
+
"desc": "Fabio Crameri 设计,感知均匀,地图/热图/连续数据高端选择。",
|
|
273
|
+
"colors": [
|
|
274
|
+
"#3B445B", "#476C81", "#5892AB", "#71AEAB",
|
|
275
|
+
"#8FC29B", "#B6D485", "#DCE867", "#F7F799",
|
|
276
|
+
],
|
|
277
|
+
},
|
|
278
|
+
"wx27_cividis": {
|
|
279
|
+
"zh": "27 Cividis 色盲安全(8色)",
|
|
280
|
+
"kind": "sequential",
|
|
281
|
+
"domain": ["跨学科通用", "色盲安全", "连续数据"],
|
|
282
|
+
"desc": "色盲安全感知均匀,深蓝到暖黄,适合需要高对比的连续数据。",
|
|
283
|
+
"colors": [
|
|
284
|
+
"#00224E", "#123570", "#3B496C", "#5C5762",
|
|
285
|
+
"#7C6B5B", "#A3895A", "#D3A658", "#F6D771",
|
|
286
|
+
],
|
|
287
|
+
},
|
|
288
|
+
|
|
289
|
+
# ── Finance / Investment series ────────────────────────────────────────
|
|
290
|
+
"wx28_bloomberg": {
|
|
291
|
+
"zh": "28 Bloomberg 终端(深色·7色)",
|
|
292
|
+
"kind": "qualitative",
|
|
293
|
+
"domain": ["金融分析", "投资研究", "量化交易"],
|
|
294
|
+
"desc": "Bloomberg Terminal 风格,深底+琥珀+涨跌红绿,金融数据可视化专业级。",
|
|
295
|
+
"colors": [
|
|
296
|
+
"#0A0E1A", "#11172A", "#1A2138", "#FFA02F",
|
|
297
|
+
"#00B96B", "#F23645", "#5E6680",
|
|
298
|
+
],
|
|
299
|
+
},
|
|
300
|
+
"wx29_institutional": {
|
|
301
|
+
"zh": "29 金融机构(低明度高纯度·5色)",
|
|
302
|
+
"kind": "qualitative",
|
|
303
|
+
"domain": ["金融", "银行", "资产管理"],
|
|
304
|
+
"desc": "金融领域机构配色:海军蓝+板岩灰+香槟金+警示橙,权威专业。",
|
|
305
|
+
"colors": [
|
|
306
|
+
"#002366", "#708090", "#D4AF37", "#FF8C00", "#F0F8FF",
|
|
307
|
+
],
|
|
308
|
+
},
|
|
309
|
+
|
|
310
|
+
# ── Engineering / Materials Science ────────────────────────────────────
|
|
311
|
+
"wx30_ieee_springer": {
|
|
312
|
+
"zh": "30 IEEE/Springer(深蓝灰·4色)",
|
|
313
|
+
"kind": "qualitative",
|
|
314
|
+
"domain": ["工程学", "计算机科学", "工科论文"],
|
|
315
|
+
"desc": "IEEE/Springer 工程期刊配色,深蓝+深灰,低饱和稳重,工科论文首选。",
|
|
316
|
+
"colors": ["#1F497D", "#404040", "#1E1E1E", "#8FA0B8"],
|
|
317
|
+
},
|
|
318
|
+
"wx31_adv_mater": {
|
|
319
|
+
"zh": "31 Advanced Materials(丰富层次·12色)",
|
|
320
|
+
"kind": "qualitative",
|
|
321
|
+
"domain": ["材料科学", "纳米技术", "先进制造"],
|
|
322
|
+
"desc": "Advanced Materials 配色,12 色丰富层次,材料/工程/纳米领域。",
|
|
323
|
+
"colors": [
|
|
324
|
+
"#0A6DAF", "#A72061", "#926AAD", "#059244",
|
|
325
|
+
"#AC5326", "#848385", "#D4E5F4", "#FBB9BA",
|
|
326
|
+
"#F5EBF4", "#C2E3D0", "#F6E4D0", "#C9C9C9",
|
|
327
|
+
],
|
|
328
|
+
},
|
|
329
|
+
|
|
330
|
+
# ── ColorBrewer classics ───────────────────────────────────────────────
|
|
331
|
+
"wx32_set2": {
|
|
332
|
+
"zh": "32 ColorBrewer Set2(柔和·8色)",
|
|
333
|
+
"kind": "qualitative",
|
|
334
|
+
"domain": ["跨学科通用", "堆叠图", "饼图"],
|
|
335
|
+
"desc": "ColorBrewer 经典柔和色,大面积填充友好,适合堆叠/饼图。",
|
|
336
|
+
"colors": [
|
|
337
|
+
"#66C2A5", "#FC8D62", "#8DA0CB", "#E78AC3",
|
|
338
|
+
"#A6D854", "#FFD92F", "#E5C494", "#B3B3B3",
|
|
339
|
+
],
|
|
340
|
+
},
|
|
341
|
+
"wx33_spectral": {
|
|
342
|
+
"zh": "33 ColorBrewer Spectral(红蓝发散·11色)",
|
|
343
|
+
"kind": "diverging",
|
|
344
|
+
"domain": ["生物信息学", "差异表达分析", "正负对比"],
|
|
345
|
+
"desc": "ColorBrewer 红蓝双向发散,适合相关矩阵/正负值/差异表达分析。",
|
|
346
|
+
"colors": [
|
|
347
|
+
"#9E0142", "#D53E4F", "#F46D43", "#FDAE61", "#FEE08B",
|
|
348
|
+
"#FFFFBF", "#E6F598", "#ABDDA4", "#66C2A5", "#3288BD",
|
|
349
|
+
"#5E4FA2",
|
|
350
|
+
],
|
|
351
|
+
},
|
|
352
|
+
"wx34_dark2": {
|
|
353
|
+
"zh": "34 ColorBrewer Dark2(深色系·8色)",
|
|
354
|
+
"kind": "qualitative",
|
|
355
|
+
"domain": ["跨学科通用", "高密度数据", "小标记图表"],
|
|
356
|
+
"desc": "ColorBrewer 深色系,适合细线条/小标记/高密度数据。",
|
|
357
|
+
"colors": [
|
|
358
|
+
"#1B9E77", "#D95F02", "#7570B3", "#E7298A",
|
|
359
|
+
"#66A61E", "#E6AB02", "#A6761D", "#666666",
|
|
360
|
+
],
|
|
361
|
+
},
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
# Short aliases: index and pN and wxN
|
|
365
|
+
_ALIASES = {}
|
|
366
|
+
for _i, _slug in enumerate(PALETTES.keys(), start=1):
|
|
367
|
+
_ALIASES[str(_i)] = _slug
|
|
368
|
+
_ALIASES[f"p{_i}"] = _slug
|
|
369
|
+
_ALIASES[f"wx{_i}"] = _slug
|
|
370
|
+
_ALIASES[f"wx{_i:02d}"] = _slug
|
|
371
|
+
_ALIASES[_slug] = _slug
|
|
372
|
+
_ALIASES[_slug.split("_", 1)[0]] = _slug # e.g. "wx01"
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
def _is_hex_list(text):
|
|
376
|
+
parts = [p.strip() for p in text.split(",") if p.strip()]
|
|
377
|
+
if len(parts) < 2:
|
|
378
|
+
return None
|
|
379
|
+
for p in parts:
|
|
380
|
+
if not (p.startswith("#") and len(p) in (4, 7)):
|
|
381
|
+
return None
|
|
382
|
+
return parts
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
def _sample(colors, n):
|
|
386
|
+
"""Evenly sample n colors across the palette (endpoints included)."""
|
|
387
|
+
if n is None or n <= 0 or n >= len(colors):
|
|
388
|
+
return list(colors)
|
|
389
|
+
idx = np.linspace(0, len(colors) - 1, n).round().astype(int)
|
|
390
|
+
out = []
|
|
391
|
+
for i in idx:
|
|
392
|
+
c = colors[i]
|
|
393
|
+
if c not in out: # avoid duplicates on tiny palettes
|
|
394
|
+
out.append(c)
|
|
395
|
+
return out
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
def list_palettes():
|
|
399
|
+
"""Return the list of palette slugs."""
|
|
400
|
+
return list(PALETTES.keys())
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
def palette_info(name):
|
|
404
|
+
"""Return the metadata dict for a palette (or None)."""
|
|
405
|
+
slug = _ALIASES.get(str(name).lower().strip())
|
|
406
|
+
if slug is None:
|
|
407
|
+
return None
|
|
408
|
+
info = dict(PALETTES[slug])
|
|
409
|
+
info["slug"] = slug
|
|
410
|
+
return info
|
|
411
|
+
|
|
412
|
+
|
|
413
|
+
def get_palette(name, n=None):
|
|
414
|
+
"""
|
|
415
|
+
Resolve a palette name to a list of hex colors.
|
|
416
|
+
|
|
417
|
+
Args:
|
|
418
|
+
name: slug ("wx06_amber_navy"), alias ("p6", "6", "wx06"),
|
|
419
|
+
or a raw comma-separated hex list.
|
|
420
|
+
n: optional number of colors to evenly sample from the palette.
|
|
421
|
+
Returns:
|
|
422
|
+
list[str] of hex colors (raises ValueError if name is unknown).
|
|
423
|
+
"""
|
|
424
|
+
raw = _is_hex_list(str(name))
|
|
425
|
+
if raw:
|
|
426
|
+
return _sample(raw, n)
|
|
427
|
+
|
|
428
|
+
slug = _ALIASES.get(str(name).lower().strip())
|
|
429
|
+
if slug is None:
|
|
430
|
+
raise ValueError(
|
|
431
|
+
f"Unknown palette '{name}'. Available: {', '.join(list_palettes())} "
|
|
432
|
+
f"(aliases: 1-{len(PALETTES)}, p1-p{len(PALETTES)}, wx1-wx{len(PALETTES)})"
|
|
433
|
+
)
|
|
434
|
+
return _sample(PALETTES[slug]["colors"], n)
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
def palette_colormap(name):
|
|
438
|
+
"""
|
|
439
|
+
Build a matplotlib Colormap from a palette (for heatmap/contour/surface).
|
|
440
|
+
Returns None if the palette name is unknown / not a hex list.
|
|
441
|
+
"""
|
|
442
|
+
from matplotlib.colors import LinearSegmentedColormap
|
|
443
|
+
try:
|
|
444
|
+
colors = get_palette(name)
|
|
445
|
+
except ValueError:
|
|
446
|
+
return None
|
|
447
|
+
return LinearSegmentedColormap.from_list("sf_" + str(name), colors, N=256)
|
|
448
|
+
|
|
449
|
+
|
|
450
|
+
def print_palette_table():
|
|
451
|
+
"""Pretty-print all palettes with their hex codes (for docs / --list-palettes)."""
|
|
452
|
+
lines = []
|
|
453
|
+
for slug, meta in PALETTES.items():
|
|
454
|
+
domain_str = "/".join(meta.get("domain", []))
|
|
455
|
+
lines.append(f"{slug} [{meta['kind']}] {meta['zh']} 适用:{domain_str}")
|
|
456
|
+
lines.append(" " + " ".join(meta["colors"]))
|
|
457
|
+
return "\n".join(lines)
|
|
458
|
+
|
|
459
|
+
|
|
460
|
+
if __name__ == "__main__":
|
|
461
|
+
print(print_palette_table())
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Central chart-type registry for like-sci-figures.
|
|
3
|
+
|
|
4
|
+
Why this exists
|
|
5
|
+
---------------
|
|
6
|
+
Before this file existed, the mapping "chart type -> example file" and the
|
|
7
|
+
Chinese display names were duplicated across five places:
|
|
8
|
+
|
|
9
|
+
gen_figure.py EXAMPLE_MAP
|
|
10
|
+
palette_picker.py EXAMPLES + ZH_NAME
|
|
11
|
+
showcase.py CHART_EXAMPLES + ZH_NAME
|
|
12
|
+
tests/test_examples.py CHART_EXAMPLES
|
|
13
|
+
SKILL.md chart-type table
|
|
14
|
+
|
|
15
|
+
Every new chart type required editing four Python files plus the docs. This
|
|
16
|
+
module is the single source of truth: one entry per chart type, and every
|
|
17
|
+
other script imports from here. Adding a new chart type is now a three-step
|
|
18
|
+
task (generator module + GENERATORS entry in gen_figure.py + one line here).
|
|
19
|
+
|
|
20
|
+
Fields per entry
|
|
21
|
+
----------------
|
|
22
|
+
type canonical slug used by --type
|
|
23
|
+
zh Chinese display name
|
|
24
|
+
example filename inside examples/ (None if no standalone example)
|
|
25
|
+
kind statistical | relational | specialized (grouping for docs)
|
|
26
|
+
aliases other slugs that resolve to this canonical type
|
|
27
|
+
|
|
28
|
+
Public API
|
|
29
|
+
----------
|
|
30
|
+
from registry import CHART_EXAMPLES, ZH_NAME, CHART_TYPES, ALIASES
|
|
31
|
+
|
|
32
|
+
CHART_EXAMPLES = {"bar": "bar.json", ...} # for --verify-all / tests
|
|
33
|
+
ZH_NAME = {"bar": "柱状图", ...} # for posters / docs
|
|
34
|
+
CHART_TYPES = ["area", "bar", ...] # sorted canonical list
|
|
35
|
+
ALIASES = {"grouped_bar": "bar", ...} # alias -> canonical
|
|
36
|
+
resolve(t) -> canonical type (follows aliases)
|
|
37
|
+
example_path(t) -> absolute path under examples/ or None
|
|
38
|
+
"""
|
|
39
|
+
import os
|
|
40
|
+
|
|
41
|
+
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
42
|
+
EXAMPLES_DIR = os.path.join(SCRIPT_DIR, "..", "examples")
|
|
43
|
+
|
|
44
|
+
# ── Canonical registry ─────────────────────────────────────────────────────
|
|
45
|
+
# One row per chart type. Order is irrelevant; CHART_TYPES is sorted on load.
|
|
46
|
+
_REGISTRY = [
|
|
47
|
+
# (type, zh, example, kind, aliases)
|
|
48
|
+
("bar", "柱状图", "bar.json", "statistics", ("grouped_bar",)),
|
|
49
|
+
("stacked_bar", "堆叠柱状图", "stacked_bar.json", "statistics", ("stacked",)),
|
|
50
|
+
("heatmap", "热力图", "heatmap.json", "relational", ()),
|
|
51
|
+
("scatter", "散点图", "scatter.csv", "relational", ()),
|
|
52
|
+
("line", "折线图", "line.json", "relational", ()),
|
|
53
|
+
("box", "箱线图", "box.json", "statistics", ("boxplot",)),
|
|
54
|
+
("violin", "小提琴图", "violin.json", "statistics", ()),
|
|
55
|
+
("forest", "森林图", "forest.json", "statistics", ()),
|
|
56
|
+
("histogram", "直方图", "histogram.json", "statistics", ()),
|
|
57
|
+
("density", "密度图", "density.json", "statistics", ()),
|
|
58
|
+
("pie", "饼图", "pie.json", "relational", ("donut",)),
|
|
59
|
+
("radar", "雷达图", "radar.json", "relational", ()),
|
|
60
|
+
("surface", "3D曲面", "surface.json", "relational", ()),
|
|
61
|
+
("contour", "等高线", "contour.json", "relational", ()),
|
|
62
|
+
("scatter3d", "3D散点", "scatter3d.json", "relational", ()),
|
|
63
|
+
("bubble", "气泡图", "bubble.json", "statistics", ()),
|
|
64
|
+
("area", "面积图", "area.json", "statistics", ()),
|
|
65
|
+
("errorbar", "误差棒图", "errorbar.json", "statistics", ()),
|
|
66
|
+
("venn", "韦恩图", "venn.json", "specialized", ()),
|
|
67
|
+
("pca", "PCA双标图", "pca.json", "specialized", ()),
|
|
68
|
+
("windrose", "风玫瑰图", "windrose.json", "specialized", ()),
|
|
69
|
+
("taylor", "Taylor图", "taylor.json", "specialized", ()),
|
|
70
|
+
("sankey", "桑基图", "sankey.json", "specialized", ()),
|
|
71
|
+
("subplots", "子图组合", "panels.json", "specialized", ()),
|
|
72
|
+
("volcano", "火山图", "volcano.json", "statistics", ()),
|
|
73
|
+
("manhattan", "曼哈顿图", "manhattan.json", "specialized", ()),
|
|
74
|
+
("kaplan_meier", "KM生存曲线", "kaplan_meier.json", "statistics", ()),
|
|
75
|
+
("roc", "ROC曲线", "roc.json", "statistics", ()),
|
|
76
|
+
("ridge", "岭图", "ridge.json", "statistics", ()),
|
|
77
|
+
("ternary", "三元相图", "ternary.json", "specialized", ()),
|
|
78
|
+
("dot_plot", "点图", "dot_plot.json", "statistics", ()),
|
|
79
|
+
("dendrogram", "树状图", "dendrogram.json", "specialized", ()),
|
|
80
|
+
("slope", "斜率图", "slope.json", "relational", ()),
|
|
81
|
+
("waterfall", "瀑布图", "waterfall.json", "statistics", ()),
|
|
82
|
+
("bode", "博德图", "bode.json", "specialized", ()),
|
|
83
|
+
("periodogram", "周期图", "periodogram.json", "specialized", ()),
|
|
84
|
+
("corr_matrix", "相关矩阵", "corr_matrix.json", "relational", ()),
|
|
85
|
+
("hexbin", "六边形分箱密度图", "hexbin.json", "relational", ()),
|
|
86
|
+
("ecdf", "经验累积分布", "ecdf.json", "statistics", ()),
|
|
87
|
+
("bland_altman", "Bland-Altman图", "bland_altman.json", "statistics", ()),
|
|
88
|
+
]
|
|
89
|
+
|
|
90
|
+
# ── Derived lookups ────────────────────────────────────────────────────────
|
|
91
|
+
CHART_EXAMPLES = {row[0]: row[2] for row in _REGISTRY if row[2]}
|
|
92
|
+
ZH_NAME = {row[0]: row[1] for row in _REGISTRY}
|
|
93
|
+
CHART_TYPES = sorted(row[0] for row in _REGISTRY)
|
|
94
|
+
ALIASES = {}
|
|
95
|
+
for _t, _zh, _ex, _kind, _aliases in _REGISTRY:
|
|
96
|
+
for _a in _aliases:
|
|
97
|
+
ALIASES[_a] = _t
|
|
98
|
+
|
|
99
|
+
_KIND = {row[0]: row[3] for row in _REGISTRY}
|
|
100
|
+
_KNOWN = {row[0] for row in _REGISTRY} | set(ALIASES)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def resolve(type_name):
|
|
104
|
+
"""Resolve a chart type name (alias or canonical) to its canonical slug.
|
|
105
|
+
|
|
106
|
+
Returns the canonical slug if the name is known, or the input unchanged
|
|
107
|
+
(so unknown custom types still pass through to GENERATORS for validation).
|
|
108
|
+
"""
|
|
109
|
+
if type_name in _KNOWN:
|
|
110
|
+
return ALIASES.get(type_name, type_name)
|
|
111
|
+
return type_name
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def kind_of(type_name):
|
|
115
|
+
"""Return the category (statistics / relational / specialized) or None."""
|
|
116
|
+
return _KIND.get(resolve(type_name))
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def example_path(type_name):
|
|
120
|
+
"""Absolute path to the example file for this chart type, or None."""
|
|
121
|
+
fname = CHART_EXAMPLES.get(resolve(type_name))
|
|
122
|
+
if not fname:
|
|
123
|
+
return None
|
|
124
|
+
return os.path.abspath(os.path.join(EXAMPLES_DIR, fname))
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def example_name(type_name):
|
|
128
|
+
"""Bare filename of the example for this chart type, or None."""
|
|
129
|
+
return CHART_EXAMPLES.get(resolve(type_name))
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def example_types():
|
|
133
|
+
"""Sorted list of chart types that have an example file."""
|
|
134
|
+
return sorted(t for t, ex in CHART_EXAMPLES.items() if ex)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def __repr__():
|
|
138
|
+
return "registry(%d types, %d aliases)" % (len(_REGISTRY), len(ALIASES))
|