AeroViz 0.1.2__py3-none-any.whl → 0.1.3b0__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.

Potentially problematic release.


This version of AeroViz might be problematic. Click here for more details.

Files changed (112) hide show
  1. AeroViz/__init__.py +4 -4
  2. AeroViz/config/DEFAULT_DATA.csv +1417 -0
  3. AeroViz/config/DEFAULT_PNSD_DATA.csv +1417 -0
  4. AeroViz/dataProcess/Chemistry/__init__.py +38 -38
  5. AeroViz/dataProcess/Chemistry/_calculate.py +15 -15
  6. AeroViz/dataProcess/Chemistry/_isoropia.py +69 -68
  7. AeroViz/dataProcess/Chemistry/_mass_volume.py +158 -158
  8. AeroViz/dataProcess/Chemistry/_ocec.py +109 -109
  9. AeroViz/dataProcess/Chemistry/_partition.py +19 -18
  10. AeroViz/dataProcess/Chemistry/_teom.py +8 -11
  11. AeroViz/dataProcess/Optical/_IMPROVE.py +40 -39
  12. AeroViz/dataProcess/Optical/__init__.py +35 -35
  13. AeroViz/dataProcess/Optical/_absorption.py +35 -35
  14. AeroViz/dataProcess/Optical/_extinction.py +25 -24
  15. AeroViz/dataProcess/Optical/_mie.py +5 -6
  16. AeroViz/dataProcess/Optical/_mie_sd.py +89 -90
  17. AeroViz/dataProcess/Optical/_scattering.py +16 -16
  18. AeroViz/dataProcess/SizeDistr/__init__.py +37 -37
  19. AeroViz/dataProcess/SizeDistr/__merge.py +159 -158
  20. AeroViz/dataProcess/SizeDistr/_merge.py +155 -154
  21. AeroViz/dataProcess/SizeDistr/_merge_v1.py +162 -161
  22. AeroViz/dataProcess/SizeDistr/_merge_v2.py +153 -152
  23. AeroViz/dataProcess/SizeDistr/_merge_v3.py +326 -326
  24. AeroViz/dataProcess/SizeDistr/_merge_v4.py +272 -274
  25. AeroViz/dataProcess/SizeDistr/_size_distr.py +51 -51
  26. AeroViz/dataProcess/VOC/__init__.py +7 -7
  27. AeroViz/dataProcess/VOC/_potential_par.py +53 -55
  28. AeroViz/dataProcess/VOC/voc_par.json +464 -0
  29. AeroViz/dataProcess/__init__.py +4 -4
  30. AeroViz/dataProcess/core/__init__.py +59 -58
  31. AeroViz/plot/__init__.py +6 -1
  32. AeroViz/plot/bar.py +126 -0
  33. AeroViz/plot/box.py +68 -0
  34. AeroViz/plot/distribution/distribution.py +421 -427
  35. AeroViz/plot/meteorology/meteorology.py +240 -292
  36. AeroViz/plot/optical/__init__.py +0 -1
  37. AeroViz/plot/optical/optical.py +230 -230
  38. AeroViz/plot/pie.py +198 -0
  39. AeroViz/plot/regression.py +210 -0
  40. AeroViz/plot/scatter.py +99 -0
  41. AeroViz/plot/templates/__init__.py +0 -3
  42. AeroViz/plot/templates/contour.py +25 -25
  43. AeroViz/plot/templates/corr_matrix.py +86 -93
  44. AeroViz/plot/templates/diurnal_pattern.py +24 -24
  45. AeroViz/plot/templates/koschmieder.py +106 -106
  46. AeroViz/plot/templates/metal_heatmap.py +34 -34
  47. AeroViz/plot/timeseries/timeseries.py +53 -60
  48. AeroViz/plot/utils/__init__.py +2 -1
  49. AeroViz/plot/utils/_color.py +57 -57
  50. AeroViz/plot/utils/_unit.py +48 -48
  51. AeroViz/plot/utils/fRH.json +390 -0
  52. AeroViz/plot/utils/plt_utils.py +92 -0
  53. AeroViz/plot/utils/sklearn_utils.py +49 -0
  54. AeroViz/plot/utils/units.json +84 -0
  55. AeroViz/plot/violin.py +79 -0
  56. AeroViz/process/__init__.py +15 -15
  57. AeroViz/process/core/DataProc.py +9 -9
  58. AeroViz/process/core/SizeDist.py +81 -81
  59. AeroViz/process/method/PyMieScatt_update.py +488 -488
  60. AeroViz/process/method/mie_theory.py +231 -229
  61. AeroViz/process/method/prop.py +40 -40
  62. AeroViz/process/script/AbstractDistCalc.py +103 -103
  63. AeroViz/process/script/Chemical.py +166 -166
  64. AeroViz/process/script/IMPACT.py +40 -40
  65. AeroViz/process/script/IMPROVE.py +152 -152
  66. AeroViz/process/script/Others.py +45 -45
  67. AeroViz/process/script/PSD.py +26 -26
  68. AeroViz/process/script/PSD_dry.py +69 -70
  69. AeroViz/process/script/retrieve_RI.py +50 -51
  70. AeroViz/rawDataReader/__init__.py +57 -57
  71. AeroViz/rawDataReader/core/__init__.py +328 -326
  72. AeroViz/rawDataReader/script/AE33.py +18 -18
  73. AeroViz/rawDataReader/script/AE43.py +20 -20
  74. AeroViz/rawDataReader/script/APS_3321.py +30 -30
  75. AeroViz/rawDataReader/script/Aurora.py +23 -23
  76. AeroViz/rawDataReader/script/BC1054.py +40 -40
  77. AeroViz/rawDataReader/script/EPA_vertical.py +9 -9
  78. AeroViz/rawDataReader/script/GRIMM.py +21 -21
  79. AeroViz/rawDataReader/script/IGAC_TH.py +67 -67
  80. AeroViz/rawDataReader/script/IGAC_ZM.py +59 -59
  81. AeroViz/rawDataReader/script/MA350.py +39 -39
  82. AeroViz/rawDataReader/script/NEPH.py +74 -74
  83. AeroViz/rawDataReader/script/OCEC_LCRES.py +21 -21
  84. AeroViz/rawDataReader/script/OCEC_RES.py +16 -16
  85. AeroViz/rawDataReader/script/SMPS_TH.py +25 -25
  86. AeroViz/rawDataReader/script/SMPS_aim11.py +32 -32
  87. AeroViz/rawDataReader/script/SMPS_genr.py +31 -31
  88. AeroViz/rawDataReader/script/TEOM.py +28 -28
  89. AeroViz/rawDataReader/script/Table.py +12 -12
  90. AeroViz/rawDataReader/script/VOC_TH.py +16 -16
  91. AeroViz/rawDataReader/script/VOC_ZM.py +28 -28
  92. AeroViz/rawDataReader/script/__init__.py +20 -20
  93. AeroViz/rawDataReader/utils/config.py +161 -161
  94. AeroViz/tools/database.py +65 -65
  95. AeroViz/tools/dataclassifier.py +106 -106
  96. AeroViz/tools/dataprinter.py +51 -51
  97. AeroViz/tools/datareader.py +38 -38
  98. {AeroViz-0.1.2.dist-info → AeroViz-0.1.3b0.dist-info}/METADATA +5 -4
  99. AeroViz-0.1.3b0.dist-info/RECORD +110 -0
  100. AeroViz/config/__init__.py +0 -0
  101. AeroViz/plot/improve/__init__.py +0 -1
  102. AeroViz/plot/improve/improve.py +0 -240
  103. AeroViz/plot/optical/aethalometer.py +0 -77
  104. AeroViz/plot/templates/event_evolution.py +0 -65
  105. AeroViz/plot/templates/regression.py +0 -256
  106. AeroViz/plot/templates/scatter.py +0 -130
  107. AeroViz/plot/templates/templates.py +0 -398
  108. AeroViz/plot/utils/_decorator.py +0 -74
  109. AeroViz-0.1.2.dist-info/RECORD +0 -106
  110. {AeroViz-0.1.2.dist-info → AeroViz-0.1.3b0.dist-info}/LICENSE +0 -0
  111. {AeroViz-0.1.2.dist-info → AeroViz-0.1.3b0.dist-info}/WHEEL +0 -0
  112. {AeroViz-0.1.2.dist-info → AeroViz-0.1.3b0.dist-info}/top_level.txt +0 -0
@@ -1,130 +0,0 @@
1
- import matplotlib.pyplot as plt
2
- import numpy as np
3
- import pandas as pd
4
- import seaborn as sns
5
- from matplotlib.colors import Normalize
6
- from matplotlib.pyplot import Figure, Axes
7
- from matplotlib.ticker import ScalarFormatter
8
-
9
- from AeroViz.plot.templates.regression import _linear_regression
10
- from AeroViz.plot.utils import *
11
-
12
- __all__ = ['scatter']
13
-
14
-
15
- @set_figure
16
- def scatter(df: pd.DataFrame,
17
- x: str,
18
- y: str,
19
- c: str | None = None,
20
- s: str | None = None,
21
- cmap='jet',
22
- regression=False,
23
- diagonal=False,
24
- box=False,
25
- ax: Axes | None = None,
26
- **kwargs) -> tuple[Figure, Axes]:
27
- fig, ax = plt.subplots(**kwargs.get('fig_kws', {})) if ax is None else (ax.get_figure(), ax)
28
-
29
- if c is not None and s is not None:
30
- df_ = df.dropna(subset=[x, y, c, s]).copy()
31
- x_data, y_data, c_data, s_data = df_[x].to_numpy(), df_[y].to_numpy(), df_[c].to_numpy(), df_[s].to_numpy()
32
-
33
- scatter = ax.scatter(x_data, y_data, c=c_data,
34
- norm=Normalize(vmin=np.percentile(c_data, 10), vmax=np.percentile(c_data, 90)),
35
- cmap=cmap, s=50 * (s_data / s_data.max()) ** 1.5, alpha=0.7, edgecolors=None)
36
- colorbar = True
37
-
38
- dot = np.linspace(s_data.min(), s_data.max(), 6).round(-1)
39
-
40
- for dott in dot[1:-1]:
41
- plt.scatter([], [], c='k', alpha=0.8, s=50 * (dott / s_data.max()) ** 1.5, label='{:.0f}'.format(dott))
42
-
43
- plt.legend(title=Unit(s))
44
-
45
- elif c is not None:
46
- df_ = df.dropna(subset=[x, y, c]).copy()
47
- x_data, y_data, c_data = df_[x].to_numpy(), df_[y].to_numpy(), df_[c].to_numpy()
48
-
49
- scatter = ax.scatter(x_data, y_data, c=c_data, vmin=c_data.min(), vmax=np.percentile(c_data, 90), cmap=cmap,
50
- alpha=0.7,
51
- edgecolors=None)
52
- colorbar = True
53
-
54
- elif s is not None:
55
- df_ = df.dropna(subset=[x, y, s]).copy()
56
- x_data, y_data, s_data = df_[x].to_numpy(), df_[y].to_numpy(), df_[s].to_numpy()
57
-
58
- scatter = ax.scatter(x_data, y_data, s=50 * (s_data / s_data.max()) ** 1.5, color='#7a97c9', alpha=0.7,
59
- edgecolors='white')
60
- colorbar = False
61
-
62
- # dealing
63
- dot = np.linspace(s_data.min(), s_data.max(), 6).round(-1)
64
-
65
- for dott in dot[1:-1]:
66
- plt.scatter([], [], c='k', alpha=0.8, s=50 * (dott / s_data.max()) ** 1.5, label='{:.0f}'.format(dott))
67
-
68
- plt.legend(title=Unit(s))
69
-
70
- else:
71
- df_ = df.dropna(subset=[x, y]).copy()
72
- x_data, y_data = df_[x].to_numpy(), df_[y].to_numpy()
73
-
74
- scatter = ax.scatter(x_data, y_data, s=30, color='#7a97c9', alpha=0.7, edgecolors='white')
75
- colorbar = False
76
-
77
- xlim = kwargs.get('xlim', (x_data.min(), x_data.max()))
78
- ylim = kwargs.get('ylim', (y_data.min(), y_data.max()))
79
- xlabel = kwargs.get('xlabel', Unit(x))
80
- ylabel = kwargs.get('ylabel', Unit(y))
81
- title = kwargs.get('title', '')
82
- ax.set(xlim=xlim, ylim=ylim, xlabel=xlabel, ylabel=ylabel, title=title)
83
-
84
- # color_bar
85
- if colorbar:
86
- color_bar = plt.colorbar(scatter, extend='both')
87
- color_bar.set_label(label=Unit(c), size=14)
88
-
89
- if regression:
90
- text, y_predict, slope = _linear_regression(x_data, y_data)
91
- plt.plot(x_data, y_predict, linewidth=3, color=sns.xkcd_rgb["denim blue"], alpha=1, zorder=3)
92
-
93
- plt.text(0.05, 0.95, f'{text}', fontdict={'weight': 'bold'}, color=sns.xkcd_rgb["denim blue"],
94
- ha='left', va='top', transform=ax.transAxes)
95
-
96
- if diagonal:
97
- ax.axline((0, 0), slope=1., color='k', lw=2, ls='--', alpha=0.5, label='1:1')
98
- plt.text(0.91, 0.97, r'$\bf 1:1\ Line$', color='k', ha='right', va='top', transform=ax.transAxes)
99
-
100
- if box:
101
- bins = np.linspace(x_data.min(), x_data.max(), 11, endpoint=True)
102
- wid = (bins + (bins[1] - bins[0]) / 2)[0:-1]
103
-
104
- df[x + '_bin'] = pd.cut(x=x_data, bins=bins, labels=wid)
105
-
106
- group = x + '_bin'
107
- column = y
108
- grouped = df.groupby(group, observed=False)
109
-
110
- names, vals = [], []
111
-
112
- for i, (name, subdf) in enumerate(grouped):
113
- names.append('{:.0f}'.format(name))
114
- vals.append(subdf[column].dropna().values)
115
-
116
- plt.boxplot(vals, labels=names, positions=wid, widths=(bins[1] - bins[0]) / 3,
117
- showfliers=False, showmeans=True, meanline=True, patch_artist=True,
118
- boxprops=dict(facecolor='#f2c872', alpha=.7),
119
- meanprops=dict(color='#000000', ls='none'),
120
- medianprops=dict(ls='-', color='#000000'))
121
-
122
- plt.xlim(x_data.min(), x_data.max())
123
- ax.set_xticks(bins, labels=bins.astype(int))
124
-
125
- ax.xaxis.set_major_formatter(ScalarFormatter())
126
- ax.yaxis.set_major_formatter(ScalarFormatter())
127
-
128
- plt.show()
129
-
130
- return fig, ax
@@ -1,398 +0,0 @@
1
- from typing import Literal
2
-
3
- import matplotlib.pyplot as plt
4
- import numpy as np
5
- import pandas as pd
6
- import seaborn as sns
7
- from matplotlib.pyplot import Figure, Axes
8
- from pandas import DataFrame
9
-
10
- from AeroViz.plot.utils import *
11
-
12
- __all__ = [
13
- 'pie',
14
- 'donuts',
15
- 'violin',
16
- 'bar',
17
- ]
18
-
19
-
20
- def _auto_label_pct(pct,
21
- symbol: bool = True,
22
- include_pct: bool = False,
23
- ignore: Literal["inner", "outer"] = 'inner',
24
- value: float = 2):
25
- if not symbol:
26
- return ''
27
- cond = pct <= value if ignore == 'inner' else pct > value
28
- label = '' if cond else '{:.1f}'.format(pct)
29
- return '' if label == '' else label + '%' if include_pct else label
30
-
31
-
32
- @set_figure(fs=8, fw='bold')
33
- def pie(data_set: DataFrame | dict,
34
- labels: list[str],
35
- unit: str,
36
- style: Literal["pie", 'donut'],
37
- ax: Axes | None = None,
38
- symbol: bool = True,
39
- **kwargs) -> tuple[Figure, Axes]:
40
- """
41
- Create a pie or donut chart based on the provided data.
42
-
43
- Parameters
44
- ----------
45
- data_set : pd.DataFrame | dict
46
- A pandas DataFrame or dictionary mapping category names to a list of species.
47
- If a DataFrame is provided, the index represents the categories, and each column contains species data.
48
- If a dictionary is provided, it maps category names to lists of species data.
49
- It is assumed that all lists or DataFrame columns contain the same number of entries as the *labels* list.
50
- labels : list of str
51
- The labels for each category.
52
- unit : str
53
- The unit to display in the center of the donut chart.
54
- style : Literal["pie", 'donut']
55
- The style of the chart, either 'pie' for a standard pie chart or 'donut' for a donut chart.
56
- ax : plt.Axes or None, optional
57
- The Axes object to plot the chart onto. If None, a new figure and Axes will be created.
58
- symbol : bool, optional
59
- Whether to display values for each species in the chart.
60
- **kwargs
61
- Additional keyword arguments to be passed to the plotting function.
62
-
63
- Returns
64
- -------
65
- matplotlib.axes.Axes
66
- The Axes object containing the violin plot.
67
-
68
- Notes
69
- -----
70
- - If *data_set* is a dictionary, it should contain lists of species that correspond to each category in *labels*.
71
- - The length of each list in *data_set* or the number of columns in the DataFrame should match the length of the *labels* list.
72
-
73
- Examples
74
- --------
75
- >>> data_set = {'Category 1': [10, 20, 30], 'Category 2': [15, 25, 35]}
76
- >>> labels = ['Species 1', 'Species 2', 'Species 3']
77
- >>> pie(data_set, labels, unit='kg', style='pie', symbol=True)
78
- """
79
- if isinstance(data_set, DataFrame):
80
- category_names = list(data_set.index)
81
- data = data_set.to_numpy()
82
-
83
- pies, species = data.shape
84
-
85
- elif isinstance(data_set, dict):
86
- category_names = list(data_set.keys())
87
- data = np.array(list(data_set.values()))
88
-
89
- pies, species = data.shape
90
-
91
- else:
92
- raise ValueError('data_set must be a DataFrame or a dictionary.')
93
-
94
- colors = kwargs.get('colors') or (Color.colors1 if species == 6 else Color.getColor(num=species))
95
-
96
- radius = 4
97
- width = 4 if style == 'pie' else 1
98
-
99
- text = [''] * pies if style == 'pie' else [Unit(unit) + '\n\n' + '{:.2f}'.format(x) for x in data.sum(axis=1)]
100
- pct_distance = 0.6 if style == 'pie' else 0.88
101
-
102
- fig, ax = plt.subplots(1, pies, figsize=((pies * 2) + 1, 2)) if ax is None else (ax.get_figure(), ax)
103
-
104
- if pies == 1:
105
- ax = [ax]
106
-
107
- for i in range(pies):
108
- ax[i].pie(data[i], labels=None, colors=colors, textprops=None,
109
- autopct=lambda pct: _auto_label_pct(pct, symbol=symbol, include_pct=True),
110
- pctdistance=pct_distance, radius=radius, wedgeprops=dict(width=width, edgecolor='w'))
111
-
112
- ax[i].pie(data[i], labels=None, colors=colors, textprops=None,
113
- autopct=lambda pct: _auto_label_pct(pct, symbol=symbol, ignore='outer', include_pct=True),
114
- pctdistance=1.3, radius=radius, wedgeprops=dict(width=width, edgecolor='w'))
115
- ax[i].axis('equal')
116
- ax[i].text(0, 0, text[i], ha='center', va='center')
117
- ax[i].set_title(category_names[i])
118
-
119
- ax[-1].legend(labels, loc='center left', prop={'weight': 'bold'}, bbox_to_anchor=(1, 0, 1.15, 1))
120
-
121
- # fig.savefig(f"pie_{style}_{title}")
122
-
123
- plt.show()
124
-
125
- return fig, ax
126
-
127
-
128
- @set_figure(fs=8, fw='bold')
129
- def donuts(data_set: DataFrame | dict,
130
- labels: list[str],
131
- unit: str,
132
- ax: Axes | None = None,
133
- symbol=True,
134
- **kwargs) -> tuple[Figure, Axes]:
135
- """
136
- Plot a donut chart based on the data set.
137
-
138
- Parameters
139
- ----------
140
- data_set : pd.DataFrame | dict
141
- A pandas DataFrame or a dictionary mapping category names to a list of species.
142
- If a DataFrame is provided, the index represents the categories, and each column contains species data.
143
- If a dictionary is provided, it maps category names to lists of species data.
144
- It is assumed that all lists or DataFrame columns contain the same number of entries as the *labels* list.
145
- labels : list of str
146
- The category labels.
147
- unit : str
148
- The unit to be displayed in the center of the donut chart.
149
- ax : matplotlib.axes.Axes, optional
150
- The axes to plot on. If None, the current axes will be used (default).
151
- symbol : bool, optional
152
- Whether to display values for each species (default is True).
153
- **kwargs : dict, optional
154
- Additional keyword arguments to pass to the matplotlib pie chart function.
155
-
156
- Returns
157
- -------
158
- matplotlib.axes.Axes
159
- The axes containing the donut chart.
160
- """
161
-
162
- if isinstance(data_set, DataFrame):
163
- category_names = list(data_set.index)
164
- data = data_set.to_numpy()
165
-
166
- pies, species = data.shape
167
-
168
- elif isinstance(data_set, dict):
169
- category_names = list(data_set.keys())
170
- data = np.array(list(data_set.values()))
171
-
172
- pies, species = data.shape
173
-
174
- else:
175
- raise ValueError('data_set must be a DataFrame or a dictionary.')
176
-
177
- colors1 = kwargs.get('colors') or (Color.colors1 if species == 6 else Color.getColor(num=species))
178
- colors2 = Color.adjust_opacity(colors1, 0.8)
179
- colors3 = Color.adjust_opacity(colors1, 0.6)
180
-
181
- fig, ax = plt.subplots(**kwargs.get('fig_kws', {})) if ax is None else (ax.get_figure(), ax)
182
-
183
- ax.pie(data[2], labels=None, colors=colors1, textprops=None,
184
- autopct=lambda pct: _auto_label_pct(pct, symbol=symbol, include_pct=True),
185
- pctdistance=0.9, radius=14, wedgeprops=dict(width=3, edgecolor='w'))
186
-
187
- ax.pie(data[1], labels=None, colors=colors2, textprops=None,
188
- autopct=lambda pct: _auto_label_pct(pct, symbol=symbol, include_pct=True),
189
- pctdistance=0.85, radius=11, wedgeprops=dict(width=3, edgecolor='w'))
190
-
191
- ax.pie(data[0], labels=None, colors=colors3, textprops=None,
192
- autopct=lambda pct: _auto_label_pct(pct, symbol=symbol, include_pct=True),
193
- pctdistance=0.80, radius=8, wedgeprops=dict(width=3, edgecolor='w'))
194
-
195
- text = (Unit(f'{unit}') + '\n\n' +
196
- 'Event : ' + "{:.2f}".format(np.sum(data[2])) + '\n' +
197
- 'Transition : ' + "{:.2f}".format(np.sum(data[1])) + '\n' +
198
- 'Clean : ' + "{:.2f}".format(np.sum(data[0])))
199
-
200
- ax.text(0, 0, text, ha='center', va='center')
201
- ax.axis('equal')
202
-
203
- ax.set_title(kwargs.get('title', ''))
204
-
205
- ax.legend(labels, loc='center', prop={'weight': 'bold'}, title_fontproperties={'weight': 'bold'},
206
- title=f'Outer : {category_names[2]}' + '\n' + f'Middle : {category_names[1]}' + '\n' + f'Inner : {category_names[0]}',
207
- bbox_to_anchor=(0.8, 0, 0.5, 1))
208
-
209
- # fig.savefig(f"donuts_{title}")
210
-
211
- plt.show()
212
-
213
- return fig, ax
214
-
215
-
216
- @set_figure(figsize=(5, 4))
217
- def bar(data_set: DataFrame | dict,
218
- data_std: DataFrame | None,
219
- labels: list[str],
220
- unit: str,
221
- style: Literal["stacked", "dispersed"] = "dispersed",
222
- orientation: Literal["va", "ha"] = 'va',
223
- ax: Axes | None = None,
224
- symbol=True,
225
- **kwargs
226
- ) -> tuple[Figure, Axes]:
227
- """
228
- Parameters
229
- ----------
230
- data_set : pd.DataFrame or dict
231
- A mapping from category names to a list of species mean or a DataFrame with columns as categories and values as means.
232
- data_std : pd.DataFrame or None
233
- A DataFrame with standard deviations corresponding to data_set, or None if standard deviations are not provided.
234
- labels : list of str
235
- The species names.
236
- unit : str
237
- The unit for the values.
238
- style : {'stacked', 'dispersed'}, default 'dispersed'
239
- Whether to display the bars stacked or dispersed.
240
- orientation : {'va', 'ha'}, default 'va'
241
- The orientation of the bars, 'va' for vertical and 'ha' for horizontal.
242
- ax : plt.Axes or None, default None
243
- The Axes object to plot on. If None, a new figure and Axes are created.
244
- symbol : bool, default True
245
- Whether to display values for each bar.
246
- kwargs : dict
247
- Additional keyword arguments passed to the barplot function.
248
-
249
- Returns
250
- -------
251
- matplotlib.Axes
252
- The Axes object containing the plot.
253
-
254
- """
255
- # data process
256
- data = data_set.values
257
-
258
- if data_std is None:
259
- data_std = np.zeros(data.shape)
260
- else:
261
- data_std = data_std.values
262
-
263
- groups, species = data.shape
264
- groups_arr = np.arange(groups)
265
- species_arr = np.arange(species)
266
-
267
- total = np.array([data.sum(axis=1), ] * species).T
268
-
269
- pct_data = data / total * 100
270
- data_cum = pct_data.cumsum(axis=1)
271
-
272
- # figure info
273
- category_names = kwargs.get('ticks') or list(data_set.index)
274
- title = kwargs.get('title', '')
275
- colors = kwargs.get('colors') or (Color.colors1 if species == 6 else Color.getColor(num=species))
276
-
277
- fig, ax = plt.subplots(**kwargs.get('fig_kws', {})) if ax is None else (ax.get_figure(), ax)
278
-
279
- if style == "stacked":
280
- for i in range(species):
281
- widths = pct_data[:, i]
282
- starts = data_cum[:, i] - pct_data[:, i]
283
-
284
- if orientation == 'va':
285
- _ = ax.bar(groups_arr, widths, bottom=starts, width=0.7, color=colors[i], label=labels[i],
286
- edgecolor=None, capsize=None)
287
- if orientation == 'ha':
288
- _ = ax.barh(groups_arr, widths, left=starts, height=0.7, color=colors[i], label=labels[i],
289
- edgecolor=None, capsize=None)
290
- if symbol:
291
- ax.bar_label(_, fmt=_auto_label_pct, label_type='center', padding=0, fontsize=10, weight='bold')
292
-
293
- if style == "dispersed":
294
- width = 0.1
295
- block = width / 4
296
-
297
- for i in range(species):
298
- val = data[:, i]
299
- std = (0,) * groups, data_std[:, i]
300
- if orientation == 'va':
301
- _ = ax.bar(groups_arr + (i + 1) * (width + block), val, yerr=std, width=width, color=colors[i],
302
- edgecolor=None, capsize=None)
303
- if orientation == 'ha':
304
- _ = ax.barh(groups_arr + (i + 1) * (width + block), val, xerr=std, height=width, color=colors[i],
305
- edgecolor=None, capsize=None)
306
- if symbol:
307
- ax.bar_label(_, fmt=_auto_label_pct, label_type='center', padding=0, fontsize=8, weight='bold')
308
-
309
- if orientation == 'va':
310
- xticks = groups_arr + (species / 2 + 0.5) * (width + block) if style == "dispersed" else groups_arr
311
- ax.set_xticks(xticks, category_names, weight='bold')
312
- ax.set_ylabel(Unit(unit) if style == "dispersed" else '$Contribution (\\%)$')
313
- ax.set_ylim(0, None if style == "dispersed" else 100)
314
- ax.legend(labels, bbox_to_anchor=(1, 1), loc='upper left', prop={'size': 12})
315
-
316
- if orientation == 'ha':
317
- ax.invert_yaxis()
318
- yticks = groups_arr + 3.5 * (width + block) if style == "dispersed" else groups_arr
319
- ax.set_yticks(yticks, category_names, weight='bold')
320
- ax.set_xlabel(Unit(unit) if style == "dispersed" else '$Contribution (\\%)$')
321
- ax.set_xlim(0, None if style == "dispersed" else 100)
322
- ax.legend(labels, bbox_to_anchor=(1, 1), loc='upper left', prop={'size': 12})
323
-
324
- # fig.savefig(f"Barplot_{title}")
325
-
326
- plt.show()
327
-
328
- return fig, ax
329
-
330
-
331
- @set_figure
332
- def violin(data_set: DataFrame | dict,
333
- unit: str,
334
- ax: Axes | None = None,
335
- **kwargs
336
- ) -> tuple[Figure, Axes]:
337
- """
338
- Generate a violin plot for multiple data sets.
339
-
340
- Parameters
341
- ----------
342
- data_set : pd.DataFrame or dict
343
- A mapping from category names to pandas DataFrames containing the data.
344
- unit : str
345
- The unit for the data being plotted.
346
- ax : matplotlib.axes.Axes, optional
347
- The Axes object to draw the plot onto. If not provided, a new figure will be created.
348
- **kwargs : dict
349
- Additional keyword arguments to be passed to the violinplot function.
350
-
351
- Returns
352
- -------
353
- matplotlib.axes.Axes
354
- The Axes object containing the violin plot.
355
-
356
- """
357
- fig, ax = plt.subplots(**kwargs.get('fig_kws', {})) if ax is None else (ax.get_figure(), ax)
358
-
359
- data = data_set.to_numpy()
360
-
361
- data = data[~np.isnan(data).any(axis=1)]
362
-
363
- grps = data.shape[1]
364
-
365
- width = 0.6
366
- block = width / 2
367
- x_position = np.arange(grps)
368
-
369
- plt.boxplot(data, positions=x_position, widths=0.15,
370
- showfliers=False, showmeans=True, meanline=False, patch_artist=True,
371
- capprops=dict(linewidth=0),
372
- whiskerprops=dict(linewidth=1.5, color='k', alpha=1),
373
- boxprops=dict(linewidth=1.5, color='k', facecolor='#4778D3', alpha=1),
374
- meanprops=dict(marker='o', markeredgecolor='black', markerfacecolor='white', markersize=6),
375
- medianprops=dict(linewidth=1.5, ls='-', color='k', alpha=1))
376
-
377
- sns.violinplot(data=data, density_norm='area', color='#4778D3', inner=None)
378
-
379
- for violin, alpha in zip(ax.collections[:], [0.5] * len(ax.collections[:])):
380
- violin.set_alpha(alpha)
381
- violin.set_edgecolor(None)
382
-
383
- plt.scatter(x_position, data.mean(), marker='o', facecolor='white', edgecolor='k', s=10)
384
-
385
- xlim = kwargs.get('xlim') or (x_position[0] - (width / 2 + block), x_position[-1] + (width / 2 + block))
386
- ylim = kwargs.get('ylim') or (0, None)
387
- xlabel = kwargs.get('xlabel') or ''
388
- ylabel = kwargs.get('ylabel') or Unit(unit)
389
- xticks = kwargs.get('xticks') or [x.replace('-', '\n') for x in list(data_set.keys())]
390
-
391
- ax.set(xlim=xlim, ylim=ylim, xlabel=xlabel, ylabel=ylabel, title=kwargs.get('title'))
392
- ax.set_xticks(x_position, xticks, fontweight='bold', fontsize=12)
393
-
394
- # fig.savefig(f'Violin_{unit}')
395
-
396
- plt.show()
397
-
398
- return fig, ax
@@ -1,74 +0,0 @@
1
- from functools import wraps
2
-
3
- import matplotlib.pyplot as plt
4
-
5
- __all__ = ['set_figure']
6
-
7
-
8
- # For more details please see https://matplotlib.org/stable/users/explain/customizing.html
9
-
10
-
11
- def set_figure(func=None,
12
- *,
13
- figsize: tuple | None = None,
14
- fs: int | None = None,
15
- fw: str = None,
16
- autolayout: bool = True
17
- ):
18
- def decorator(_func):
19
- @wraps(_func)
20
- def wrapper(*args, **kwargs):
21
- print(f'\t\t Plot: \033[96m{_func.__name__}\033[0m')
22
-
23
- plt.rcParams['mathtext.fontset'] = 'custom'
24
- plt.rcParams['mathtext.rm'] = 'Times New Roman'
25
- plt.rcParams['mathtext.it'] = 'Times New Roman: italic'
26
- plt.rcParams['mathtext.bf'] = 'Times New Roman: bold'
27
- plt.rcParams['mathtext.default'] = 'regular'
28
-
29
- # The font properties used by `text.Text`.
30
- # The text, annotate, label, title, ticks, are used to create text
31
- plt.rcParams['font.family'] = 'Times New Roman'
32
- plt.rcParams['font.weight'] = fw or 'normal'
33
- plt.rcParams['font.size'] = fs or 8
34
-
35
- plt.rcParams['axes.titlesize'] = 'large'
36
- plt.rcParams['axes.titleweight'] = 'bold'
37
- plt.rcParams['axes.labelweight'] = 'bold'
38
-
39
- # color
40
- plt.rcParams['axes.prop_cycle'] = plt.cycler(color=['b', 'g', 'r', 'c', 'm', 'y', 'k'])
41
-
42
- plt.rcParams['xtick.labelsize'] = 'medium'
43
- plt.rcParams['ytick.labelsize'] = 'medium'
44
-
45
- # matplotlib.font_manager.FontProperties ---> matplotlib.rcParams
46
- plt.rcParams['legend.loc'] = 'best'
47
- plt.rcParams['legend.frameon'] = False
48
- plt.rcParams['legend.fontsize'] = 'small'
49
- plt.rcParams['legend.title_fontsize'] = 'medium'
50
- plt.rcParams['legend.handlelength'] = 1.5
51
- plt.rcParams['legend.labelspacing'] = 0.7
52
-
53
- plt.rcParams['figure.figsize'] = figsize or (5, 4)
54
- plt.rcParams['figure.dpi'] = 200
55
- plt.rcParams['figure.autolayout'] = autolayout
56
-
57
- if ~autolayout:
58
- plt.rcParams['figure.subplot.left'] = 0.1
59
- plt.rcParams['figure.subplot.right'] = 0.875
60
- plt.rcParams['figure.subplot.top'] = 0.875
61
- plt.rcParams['figure.subplot.bottom'] = 0.125
62
-
63
- # plt.rcParams['figure.constrained_layout.use'] = True
64
-
65
- plt.rcParams['savefig.transparent'] = True
66
-
67
- return _func(*args, **kwargs)
68
-
69
- return wrapper
70
-
71
- if func is None:
72
- return decorator
73
-
74
- return decorator(func)