wbgapi360 0.3.0__py3-none-any.whl → 0.3.1__py3-none-any.whl
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.
- wbgapi360/_version.py +2 -2
- wbgapi360/visual/charts.py +90 -28
- {wbgapi360-0.3.0.dist-info → wbgapi360-0.3.1.dist-info}/METADATA +1 -1
- {wbgapi360-0.3.0.dist-info → wbgapi360-0.3.1.dist-info}/RECORD +8 -8
- {wbgapi360-0.3.0.dist-info → wbgapi360-0.3.1.dist-info}/WHEEL +0 -0
- {wbgapi360-0.3.0.dist-info → wbgapi360-0.3.1.dist-info}/entry_points.txt +0 -0
- {wbgapi360-0.3.0.dist-info → wbgapi360-0.3.1.dist-info}/licenses/LICENSE +0 -0
- {wbgapi360-0.3.0.dist-info → wbgapi360-0.3.1.dist-info}/top_level.txt +0 -0
wbgapi360/_version.py
CHANGED
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '0.3.
|
|
32
|
-
__version_tuple__ = version_tuple = (0, 3,
|
|
31
|
+
__version__ = version = '0.3.1'
|
|
32
|
+
__version_tuple__ = version_tuple = (0, 3, 1)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
wbgapi360/visual/charts.py
CHANGED
|
@@ -46,8 +46,38 @@ REGION_BBOX = {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
class Visualizer:
|
|
49
|
+
# Reference figsize for default font sizes (FT standard)
|
|
50
|
+
REF_FIGSIZE = (10, 6)
|
|
51
|
+
REF_FONTS = {
|
|
52
|
+
'title': 18,
|
|
53
|
+
'subtitle': 12,
|
|
54
|
+
'axis_label': 10,
|
|
55
|
+
'tick': 9,
|
|
56
|
+
'source': 8,
|
|
57
|
+
'legend': 9,
|
|
58
|
+
'annotation': 9
|
|
59
|
+
}
|
|
60
|
+
|
|
49
61
|
def __init__(self):
|
|
50
|
-
|
|
62
|
+
self._current_figsize = self.REF_FIGSIZE
|
|
63
|
+
|
|
64
|
+
def _get_scaled_fonts(self, figsize=None):
|
|
65
|
+
"""Calculate font sizes scaled proportionally to figsize."""
|
|
66
|
+
fs = figsize or self._current_figsize
|
|
67
|
+
# Scale factor based on width (primary driver of text readability)
|
|
68
|
+
scale = fs[0] / self.REF_FIGSIZE[0]
|
|
69
|
+
# Clamp scale between 0.6 and 1.2 to avoid extreme sizes
|
|
70
|
+
scale = max(0.6, min(1.2, scale))
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
'title': int(self.REF_FONTS['title'] * scale),
|
|
74
|
+
'subtitle': int(self.REF_FONTS['subtitle'] * scale),
|
|
75
|
+
'axis_label': int(self.REF_FONTS['axis_label'] * scale),
|
|
76
|
+
'tick': int(self.REF_FONTS['tick'] * scale),
|
|
77
|
+
'source': int(self.REF_FONTS['source'] * scale),
|
|
78
|
+
'legend': int(self.REF_FONTS['legend'] * scale),
|
|
79
|
+
'annotation': int(self.REF_FONTS['annotation'] * scale)
|
|
80
|
+
}
|
|
51
81
|
|
|
52
82
|
def _apply_theme_context(self):
|
|
53
83
|
"""Configura el estilo FT explícitamente."""
|
|
@@ -103,19 +133,26 @@ class Visualizer:
|
|
|
103
133
|
ax.xaxis.set_major_formatter(ticker.FuncFormatter(ft_formatter))
|
|
104
134
|
|
|
105
135
|
def _finalize_chart(self, fig, ax, title, subtitle, save_path, source="World Bank Data360", is_regional_map=False):
|
|
106
|
-
#
|
|
136
|
+
# Get scaled font sizes based on current figsize
|
|
137
|
+
fonts = self._get_scaled_fonts()
|
|
138
|
+
|
|
139
|
+
# Main title (Serif, Dark, scaled)
|
|
107
140
|
ax.text(x=0, y=1.15, s=title, transform=ax.transAxes,
|
|
108
|
-
fontsize=
|
|
141
|
+
fontsize=fonts['title'], weight='semibold', color=FT_TITLE_COLOR, ha='left',
|
|
109
142
|
fontfamily='serif')
|
|
110
143
|
|
|
111
|
-
# Subtitle (Sans, Medium grey,
|
|
144
|
+
# Subtitle (Sans, Medium grey, scaled)
|
|
112
145
|
if subtitle:
|
|
113
146
|
ax.text(x=0, y=1.06, s=subtitle, transform=ax.transAxes,
|
|
114
|
-
fontsize=
|
|
147
|
+
fontsize=fonts['subtitle'], color=FT_SUBTITLE_COLOR, ha='left')
|
|
115
148
|
|
|
116
149
|
# Source note
|
|
117
150
|
plt.figtext(0.05, 0.01, f"Source: {source}",
|
|
118
|
-
fontsize=
|
|
151
|
+
fontsize=fonts['source'], color=FT_SOURCE_COLOR, ha='left', va='bottom')
|
|
152
|
+
|
|
153
|
+
# Scale tick labels
|
|
154
|
+
ax.tick_params(axis='both', labelsize=fonts['tick'])
|
|
155
|
+
|
|
119
156
|
|
|
120
157
|
# Adjust layout based on map type
|
|
121
158
|
if is_regional_map:
|
|
@@ -220,7 +257,9 @@ class Visualizer:
|
|
|
220
257
|
var_name='INDICATOR', value_name='OBS_VALUE')
|
|
221
258
|
df = df.rename(columns={t_col: 'TIME_PERIOD'})
|
|
222
259
|
|
|
223
|
-
|
|
260
|
+
actual_figsize = figsize or DEFAULT_FIGSIZE
|
|
261
|
+
self._current_figsize = actual_figsize
|
|
262
|
+
fig, ax = plt.subplots(figsize=actual_figsize)
|
|
224
263
|
|
|
225
264
|
hue_col = 'REF_AREA'
|
|
226
265
|
if 'REF_AREA' in df.columns and df['REF_AREA'].nunique() == 1 and 'INDICATOR' in df.columns:
|
|
@@ -311,26 +350,24 @@ class Visualizer:
|
|
|
311
350
|
|
|
312
351
|
return self._finalize_chart(fig, ax, title, subtitle, save_path=save_path)
|
|
313
352
|
|
|
314
|
-
|
|
315
353
|
def plot_bar(self, df, title="", subtitle="", save_path=None, figsize=None):
|
|
316
354
|
self._apply_theme_context()
|
|
317
355
|
df, val_label = self._prepare_data(df, auto_rename=True)
|
|
318
|
-
|
|
356
|
+
actual_figsize = figsize or (8, 6)
|
|
357
|
+
self._current_figsize = actual_figsize # Store for font scaling
|
|
358
|
+
fig, ax = plt.subplots(figsize=actual_figsize)
|
|
319
359
|
|
|
320
360
|
df_sorted = df.sort_values('OBS_VALUE', ascending=False)
|
|
321
|
-
|
|
322
|
-
# Color logic: One dominant category? Usually bars are same category compared.
|
|
323
|
-
# Use Main Blue for all, or Palette if 'hue' exists?
|
|
324
|
-
# "Para múltiples categorías... paleta desaturada"
|
|
325
|
-
# We'll use color cycling if there is a 'category' column distinguishable?
|
|
326
|
-
# Usually barplot is 1 measure across countries. All same color (Blue or Petrol).
|
|
361
|
+
fonts = self._get_scaled_fonts()
|
|
327
362
|
|
|
328
363
|
sns.barplot(
|
|
329
364
|
data=df_sorted, x='OBS_VALUE', y='REF_AREA',
|
|
330
365
|
color=FT_BLUE, ax=ax, edgecolor=None
|
|
331
|
-
# Note: Using simple color=FT_BLUE for sobriety unless strictly multi-category variable
|
|
332
366
|
)
|
|
333
367
|
|
|
368
|
+
# Scale y-axis labels (country names)
|
|
369
|
+
ax.tick_params(axis='y', labelsize=fonts['axis_label'])
|
|
370
|
+
|
|
334
371
|
ax.xaxis.grid(True, color=FT_GRID_COLOR)
|
|
335
372
|
ax.yaxis.grid(False)
|
|
336
373
|
ax.set_xlabel("")
|
|
@@ -338,10 +375,13 @@ class Visualizer:
|
|
|
338
375
|
self._format_axis(ax, 'x')
|
|
339
376
|
self._finalize_chart(fig, ax, title, subtitle, save_path)
|
|
340
377
|
|
|
378
|
+
|
|
341
379
|
def plot_column(self, df, title="", subtitle="", save_path=None, figsize=None):
|
|
342
380
|
self._apply_theme_context()
|
|
343
381
|
df, val_label = self._prepare_data(df, auto_rename=True)
|
|
344
|
-
|
|
382
|
+
actual_figsize = figsize or DEFAULT_FIGSIZE
|
|
383
|
+
self._current_figsize = actual_figsize
|
|
384
|
+
fig, ax = plt.subplots(figsize=actual_figsize)
|
|
345
385
|
|
|
346
386
|
sns.barplot(
|
|
347
387
|
data=df, x='REF_AREA', y='OBS_VALUE',
|
|
@@ -358,7 +398,9 @@ class Visualizer:
|
|
|
358
398
|
def plot_scatter(self, df, title="", subtitle="", save_path=None, figsize=None):
|
|
359
399
|
self._apply_theme_context()
|
|
360
400
|
df, val_label = self._prepare_data(df)
|
|
361
|
-
|
|
401
|
+
actual_figsize = figsize or DEFAULT_FIGSIZE
|
|
402
|
+
self._current_figsize = actual_figsize
|
|
403
|
+
fig, ax = plt.subplots(figsize=actual_figsize)
|
|
362
404
|
|
|
363
405
|
numeric_cols = df.select_dtypes(include=['number']).columns.tolist()
|
|
364
406
|
cols = [c for c in numeric_cols if c != 'TIME_PERIOD']
|
|
@@ -448,7 +490,9 @@ class Visualizer:
|
|
|
448
490
|
df_wide = df.pivot_table(index='TIME_PERIOD', columns='REF_AREA', values='OBS_VALUE', aggfunc='sum')
|
|
449
491
|
df_wide = df_wide.fillna(0)
|
|
450
492
|
|
|
451
|
-
|
|
493
|
+
actual_figsize = figsize or DEFAULT_FIGSIZE
|
|
494
|
+
self._current_figsize = actual_figsize
|
|
495
|
+
fig, ax = plt.subplots(figsize=actual_figsize)
|
|
452
496
|
|
|
453
497
|
# Clean Palette for stack
|
|
454
498
|
# FT uses muted colors for composition.
|
|
@@ -532,7 +576,9 @@ class Visualizer:
|
|
|
532
576
|
|
|
533
577
|
world_data = world.merge(df_map, left_on=iso_world_col, right_on=merge_col, how='left')
|
|
534
578
|
|
|
535
|
-
|
|
579
|
+
actual_figsize = figsize or DEFAULT_FIGSIZE_MAP
|
|
580
|
+
self._current_figsize = actual_figsize
|
|
581
|
+
fig, ax = plt.subplots(figsize=actual_figsize)
|
|
536
582
|
|
|
537
583
|
# Base world map (light neutral background)
|
|
538
584
|
world.plot(ax=ax, color='#F6F6F6', edgecolor='#E0E0E0', linewidth=0.3)
|
|
@@ -632,7 +678,9 @@ class Visualizer:
|
|
|
632
678
|
iso_world_col = 'ISO_A3' if 'ISO_A3' in world.columns else 'iso_a3'
|
|
633
679
|
world_data = world.merge(df_map, left_on=iso_world_col, right_on=merge_col, how='inner')
|
|
634
680
|
|
|
635
|
-
|
|
681
|
+
actual_figsize = figsize or DEFAULT_FIGSIZE_MAP
|
|
682
|
+
self._current_figsize = actual_figsize
|
|
683
|
+
fig, ax = plt.subplots(figsize=actual_figsize)
|
|
636
684
|
world.plot(ax=ax, color='#F6F6F6', edgecolor='#E0E0E0', linewidth=0.3)
|
|
637
685
|
|
|
638
686
|
if not world_data.empty:
|
|
@@ -700,7 +748,9 @@ class Visualizer:
|
|
|
700
748
|
iso_world_col = 'ISO_A3' if 'ISO_A3' in world.columns else 'iso_a3'
|
|
701
749
|
world_data = world.merge(df_map, left_on=iso_world_col, right_on=merge_col, how='left')
|
|
702
750
|
|
|
703
|
-
|
|
751
|
+
actual_figsize = figsize or DEFAULT_FIGSIZE_MAP
|
|
752
|
+
self._current_figsize = actual_figsize
|
|
753
|
+
fig, ax = plt.subplots(figsize=actual_figsize)
|
|
704
754
|
world.plot(ax=ax, color='#F6F6F6', edgecolor='#E0E0E0', linewidth=0.3)
|
|
705
755
|
|
|
706
756
|
if not world_data.dropna(subset=[value_col]).empty:
|
|
@@ -789,7 +839,9 @@ class Visualizer:
|
|
|
789
839
|
iso_world_col = 'ISO_A3' if 'ISO_A3' in world.columns else 'iso_a3'
|
|
790
840
|
world_data = world.merge(df_map, left_on=iso_world_col, right_on=merge_col, how='left')
|
|
791
841
|
|
|
792
|
-
|
|
842
|
+
actual_figsize = figsize or DEFAULT_FIGSIZE_MAP
|
|
843
|
+
self._current_figsize = actual_figsize
|
|
844
|
+
fig, ax = plt.subplots(figsize=actual_figsize)
|
|
793
845
|
world.plot(ax=ax, color='#F6F6F6', edgecolor='#E0E0E0', linewidth=0.3)
|
|
794
846
|
|
|
795
847
|
if not world_data.dropna(subset=[value_col]).empty:
|
|
@@ -894,7 +946,9 @@ class Visualizer:
|
|
|
894
946
|
# Handle duplicates
|
|
895
947
|
df_pivot = df.pivot_table(index='TIME_PERIOD', columns='REF_AREA', values='OBS_VALUE', aggfunc='mean')
|
|
896
948
|
|
|
897
|
-
|
|
949
|
+
actual_figsize = figsize or DEFAULT_FIGSIZE
|
|
950
|
+
self._current_figsize = actual_figsize
|
|
951
|
+
fig, ax = plt.subplots(figsize=actual_figsize)
|
|
898
952
|
|
|
899
953
|
df_pivot.plot(kind='bar', stacked=True, ax=ax, width=0.8, color=FT_PALETTE, edgecolor='white', linewidth=0.5)
|
|
900
954
|
|
|
@@ -923,7 +977,9 @@ class Visualizer:
|
|
|
923
977
|
except ValueError:
|
|
924
978
|
df_pivot = df.pivot_table(index='TIME_PERIOD', columns='REF_AREA', values='OBS_VALUE', aggfunc='mean')
|
|
925
979
|
|
|
926
|
-
|
|
980
|
+
actual_figsize = figsize or DEFAULT_FIGSIZE
|
|
981
|
+
self._current_figsize = actual_figsize
|
|
982
|
+
fig, ax = plt.subplots(figsize=actual_figsize)
|
|
927
983
|
|
|
928
984
|
df_pivot.plot(kind='area', stacked=True, ax=ax, alpha=0.9, color=FT_PALETTE, linewidth=0)
|
|
929
985
|
|
|
@@ -956,7 +1012,9 @@ class Visualizer:
|
|
|
956
1012
|
top_entities = df[df['TIME_PERIOD'] == latest_year].nsmallest(top_n, 'Rank')['REF_AREA'].unique()
|
|
957
1013
|
df_filtered = df[df['REF_AREA'].isin(top_entities)]
|
|
958
1014
|
|
|
959
|
-
|
|
1015
|
+
actual_figsize = figsize or DEFAULT_FIGSIZE
|
|
1016
|
+
self._current_figsize = actual_figsize
|
|
1017
|
+
fig, ax = plt.subplots(figsize=actual_figsize)
|
|
960
1018
|
|
|
961
1019
|
# Invert Y axis for Rank 1 at top
|
|
962
1020
|
ax.invert_yaxis()
|
|
@@ -990,7 +1048,9 @@ class Visualizer:
|
|
|
990
1048
|
else:
|
|
991
1049
|
return
|
|
992
1050
|
|
|
993
|
-
|
|
1051
|
+
actual_figsize = figsize or (6, 6)
|
|
1052
|
+
self._current_figsize = actual_figsize
|
|
1053
|
+
fig, ax = plt.subplots(figsize=actual_figsize)
|
|
994
1054
|
|
|
995
1055
|
colors = [FT_BLUE, FT_GREEN, FT_MUSTARD, FT_RED, FT_PURPLE, FT_NEUTRAL_DARK, FT_NEUTRAL_LIGHT]
|
|
996
1056
|
|
|
@@ -1065,7 +1125,9 @@ class Visualizer:
|
|
|
1065
1125
|
|
|
1066
1126
|
rects = recursive_split(normed, 0, 0, 100, 100)
|
|
1067
1127
|
|
|
1068
|
-
|
|
1128
|
+
actual_figsize = figsize or DEFAULT_FIGSIZE
|
|
1129
|
+
self._current_figsize = actual_figsize
|
|
1130
|
+
fig, ax = plt.subplots(figsize=actual_figsize)
|
|
1069
1131
|
ax.set_xlim(0, 100)
|
|
1070
1132
|
ax.set_ylim(0, 100)
|
|
1071
1133
|
ax.set_axis_off()
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
wbgapi360/__init__.py,sha256=4ur1kFtjN56mR_xprSejHy2FJb7oleiEJaK4nGSiTvg,1750
|
|
2
|
-
wbgapi360/_version.py,sha256=
|
|
2
|
+
wbgapi360/_version.py,sha256=gGLpQUQx-ty9SEy9PYw9OgJWWzJLBnCpfJOfzL7SjlI,704
|
|
3
3
|
wbgapi360/api.py,sha256=kA9kCicFVwwph8wYOsr7uafuRFpfEY2p5SbQy1JVF74,10430
|
|
4
4
|
wbgapi360/cli.py,sha256=4Y4GXl8rsxfiDUDNCqVSjtC_bgGNOGedfZBN0UWNowg,3034
|
|
5
5
|
wbgapi360/config.py,sha256=Se0_l6H6C6BHRRNW93GitE9DNzqvVwQIxJW0uHvUQj4,1652
|
|
@@ -16,10 +16,10 @@ wbgapi360/metadata/iso_mapping.py,sha256=Cma8snXlYTVm7k0SA7j25hnsfrS7Vwdcyu0NMkI
|
|
|
16
16
|
wbgapi360/metadata/resolver.py,sha256=VgdcCk2CUg7RD55UenAGcfhtvup89JUxYgbBEI90T1M,4821
|
|
17
17
|
wbgapi360/search/engine.py,sha256=TCAwabUfyC0PtxK97FNlS3xWKddLQOWocl57Oo-Gvsg,5827
|
|
18
18
|
wbgapi360/visual/__init__.py,sha256=FQxrEU8OEBzz9-rLwdGqrLTSPSvcaKVlAm9-xTY4SKM,24
|
|
19
|
-
wbgapi360/visual/charts.py,sha256=
|
|
20
|
-
wbgapi360-0.3.
|
|
21
|
-
wbgapi360-0.3.
|
|
22
|
-
wbgapi360-0.3.
|
|
23
|
-
wbgapi360-0.3.
|
|
24
|
-
wbgapi360-0.3.
|
|
25
|
-
wbgapi360-0.3.
|
|
19
|
+
wbgapi360/visual/charts.py,sha256=BzlLIOoz0nXrjqoQm44nkNwojrt9gldcob16SCcRFFw,48513
|
|
20
|
+
wbgapi360-0.3.1.dist-info/licenses/LICENSE,sha256=g-9qOC69nvvAJ8dr4_i3yJsz0iPpL8gswkrLj3-je7o,1071
|
|
21
|
+
wbgapi360-0.3.1.dist-info/METADATA,sha256=JBRIiYyhS_sbEZT82KFJWBvZE7ZzRQM1KEu3JCPG5yo,8495
|
|
22
|
+
wbgapi360-0.3.1.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
23
|
+
wbgapi360-0.3.1.dist-info/entry_points.txt,sha256=9nNopsIlKEKw9rNe_6zW-ERL6fWu6eXymmKLBIZzzqI,49
|
|
24
|
+
wbgapi360-0.3.1.dist-info/top_level.txt,sha256=q3vycsvqQsLZqAFyCzrPw392QV6wAYbVamr39Z-n2MQ,10
|
|
25
|
+
wbgapi360-0.3.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|