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
AeroViz/plot/pie.py ADDED
@@ -0,0 +1,198 @@
1
+ from typing import Literal
2
+
3
+ import matplotlib.pyplot as plt
4
+ import numpy as np
5
+ import pandas as pd
6
+ from matplotlib.pyplot import Figure, Axes
7
+ from pandas import DataFrame
8
+
9
+ from AeroViz.plot.utils import *
10
+
11
+ __all__ = [
12
+ 'pie',
13
+ 'donuts'
14
+ ]
15
+
16
+
17
+ @set_figure(fw='bold')
18
+ def pie(data_set: DataFrame | dict,
19
+ labels: list[str],
20
+ unit: str,
21
+ style: Literal["pie", 'donut'],
22
+ ax: Axes | None = None,
23
+ symbol: bool = True,
24
+ **kwargs) -> tuple[Figure, Axes]:
25
+ """
26
+ Create a pie or donut chart based on the provided data.
27
+
28
+ Parameters
29
+ ----------
30
+ data_set : pd.DataFrame | dict
31
+ A pandas DataFrame or dictionary mapping category names to a list of species.
32
+ If a DataFrame is provided, the index represents the categories, and each column contains species data.
33
+ If a dictionary is provided, it maps category names to lists of species data.
34
+ It is assumed that all lists or DataFrame columns contain the same number of entries as the *labels* list.
35
+ labels : list of str
36
+ The labels for each category.
37
+ unit : str
38
+ The unit to display in the center of the donut chart.
39
+ style : Literal["pie", 'donut']
40
+ The style of the chart, either 'pie' for a standard pie chart or 'donut' for a donut chart.
41
+ ax : plt.Axes or None, optional
42
+ The Axes object to plot the chart onto. If None, a new figure and Axes will be created.
43
+ symbol : bool, optional
44
+ Whether to display values for each species in the chart.
45
+ **kwargs
46
+ Additional keyword arguments to be passed to the plotting function.
47
+
48
+ Returns
49
+ -------
50
+ matplotlib.axes.Axes
51
+ The Axes object containing the violin plot.
52
+
53
+ Notes
54
+ -----
55
+ - If *data_set* is a dictionary, it should contain lists of species that correspond to each category in *labels*.
56
+ - The length of each list in *data_set* or the number of columns in the DataFrame should match the length of the *labels* list.
57
+
58
+ Examples
59
+ --------
60
+ >>> data_set = {'Category 1': [10, 20, 30], 'Category 2': [15, 25, 35]}
61
+ >>> labels = ['Species 1', 'Species 2', 'Species 3']
62
+ >>> pie(data_set, labels, unit='kg', style='pie', symbol=True)
63
+ """
64
+ if isinstance(data_set, DataFrame):
65
+ category_names = list(data_set.index)
66
+ data = data_set.to_numpy()
67
+
68
+ pies, species = data.shape
69
+
70
+ elif isinstance(data_set, dict):
71
+ category_names = list(data_set.keys())
72
+ data = np.array(list(data_set.values()))
73
+
74
+ pies, species = data.shape
75
+
76
+ else:
77
+ raise ValueError('data_set must be a DataFrame or a dictionary.')
78
+
79
+ colors = kwargs.get('colors') or (Color.colors1 if species == 6 else Color.getColor(num=species))
80
+
81
+ radius = 4
82
+ width = 4 if style == 'pie' else 1
83
+
84
+ text = [''] * pies if style == 'pie' else [Unit(unit) + '\n\n' + '{:.2f}'.format(x) for x in data.sum(axis=1)]
85
+ pct_distance = 0.6 if style == 'pie' else 0.88
86
+
87
+ fig, ax = plt.subplots(1, pies, figsize=((pies * 2) + 1, 2)) if ax is None else (ax.get_figure(), ax)
88
+
89
+ if pies == 1:
90
+ ax = [ax]
91
+
92
+ for i in range(pies):
93
+ ax[i].pie(data[i], labels=None, colors=colors, textprops=None,
94
+ autopct=lambda pct: auto_label_pct(pct, symbol=symbol, include_pct=True),
95
+ pctdistance=pct_distance, radius=radius, wedgeprops=dict(width=width, edgecolor='w'))
96
+
97
+ ax[i].pie(data[i], labels=None, colors=colors, textprops=None,
98
+ autopct=lambda pct: auto_label_pct(pct, symbol=symbol, ignore='outer', include_pct=True),
99
+ pctdistance=1.3, radius=radius, wedgeprops=dict(width=width, edgecolor='w'))
100
+ ax[i].axis('equal')
101
+ ax[i].text(0, 0, text[i], ha='center', va='center')
102
+ ax[i].set_title(category_names[i])
103
+
104
+ ax[-1].legend(labels, loc='center left', prop={'size': 8, 'weight': 'normal'}, bbox_to_anchor=(1, 0, 1.15, 1))
105
+
106
+ # fig.savefig(f"pie_{style}_{title}")
107
+
108
+ plt.show()
109
+
110
+ return fig, ax
111
+
112
+
113
+ @set_figure(fw='bold')
114
+ def donuts(data_set: DataFrame | dict,
115
+ labels: list[str],
116
+ unit: str,
117
+ ax: Axes | None = None,
118
+ symbol=True,
119
+ **kwargs) -> tuple[Figure, Axes]:
120
+ """
121
+ Plot a donut chart based on the data set.
122
+
123
+ Parameters
124
+ ----------
125
+ data_set : pd.DataFrame | dict
126
+ A pandas DataFrame or a dictionary mapping category names to a list of species.
127
+ If a DataFrame is provided, the index represents the categories, and each column contains species data.
128
+ If a dictionary is provided, it maps category names to lists of species data.
129
+ It is assumed that all lists or DataFrame columns contain the same number of entries as the *labels* list.
130
+ labels : list of str
131
+ The category labels.
132
+ unit : str
133
+ The unit to be displayed in the center of the donut chart.
134
+ ax : matplotlib.axes.Axes, optional
135
+ The axes to plot on. If None, the current axes will be used (default).
136
+ symbol : bool, optional
137
+ Whether to display values for each species (default is True).
138
+ **kwargs : dict, optional
139
+ Additional keyword arguments to pass to the matplotlib pie chart function.
140
+
141
+ Returns
142
+ -------
143
+ matplotlib.axes.Axes
144
+ The axes containing the donut chart.
145
+ """
146
+
147
+ if isinstance(data_set, DataFrame):
148
+ category_names = list(data_set.index)
149
+ data = data_set.to_numpy()
150
+
151
+ pies, species = data.shape
152
+
153
+ elif isinstance(data_set, dict):
154
+ category_names = list(data_set.keys())
155
+ data = np.array(list(data_set.values()))
156
+
157
+ pies, species = data.shape
158
+
159
+ else:
160
+ raise ValueError('data_set must be a DataFrame or a dictionary.')
161
+
162
+ colors1 = kwargs.get('colors') or (Color.colors1 if species == 6 else Color.getColor(num=species))
163
+ colors2 = Color.adjust_opacity(colors1, 0.8)
164
+ colors3 = Color.adjust_opacity(colors1, 0.6)
165
+
166
+ fig, ax = plt.subplots(**kwargs.get('fig_kws', {})) if ax is None else (ax.get_figure(), ax)
167
+
168
+ ax.pie(data[2], labels=None, colors=colors1, textprops=None,
169
+ autopct=lambda pct: auto_label_pct(pct, symbol=symbol, include_pct=True),
170
+ pctdistance=0.9, radius=14, wedgeprops=dict(width=3, edgecolor='w'))
171
+
172
+ ax.pie(data[1], labels=None, colors=colors2, textprops=None,
173
+ autopct=lambda pct: auto_label_pct(pct, symbol=symbol, include_pct=True),
174
+ pctdistance=0.85, radius=11, wedgeprops=dict(width=3, edgecolor='w'))
175
+
176
+ ax.pie(data[0], labels=None, colors=colors3, textprops=None,
177
+ autopct=lambda pct: auto_label_pct(pct, symbol=symbol, include_pct=True),
178
+ pctdistance=0.80, radius=8, wedgeprops=dict(width=3, edgecolor='w'))
179
+
180
+ text = (Unit(f'{unit}') + '\n\n' +
181
+ 'Event : ' + "{:.2f}".format(np.sum(data[2])) + '\n' +
182
+ 'Transition : ' + "{:.2f}".format(np.sum(data[1])) + '\n' +
183
+ 'Clean : ' + "{:.2f}".format(np.sum(data[0])))
184
+
185
+ ax.text(0, 0, text, ha='center', va='center')
186
+ ax.axis('equal')
187
+
188
+ ax.set_title(kwargs.get('title', ''))
189
+
190
+ ax.legend(labels, loc='center', prop={'size': 8}, title_fontproperties={'weight': 'bold'},
191
+ title=f'Outer : {category_names[2]}' + '\n' + f'Middle : {category_names[1]}' + '\n' + f'Inner : {category_names[0]}',
192
+ bbox_to_anchor=(0.8, 0, 0.5, 1))
193
+
194
+ # fig.savefig(f"donuts_{title}")
195
+
196
+ plt.show()
197
+
198
+ return fig, ax
@@ -0,0 +1,210 @@
1
+ import matplotlib.pyplot as plt
2
+ import numpy as np
3
+ import pandas as pd
4
+ from matplotlib.pyplot import Figure, Axes
5
+
6
+ from AeroViz.plot.utils import *
7
+
8
+ __all__ = [
9
+ 'linear_regression',
10
+ 'multiple_linear_regression',
11
+ ]
12
+
13
+
14
+ @set_figure
15
+ def linear_regression(df: pd.DataFrame,
16
+ x: str | list[str],
17
+ y: str | list[str],
18
+ labels: str | list[str] = None,
19
+ ax: Axes | None = None,
20
+ diagonal=False,
21
+ positive: bool = True,
22
+ fit_intercept: bool = True,
23
+ **kwargs
24
+ ) -> tuple[Figure, Axes]:
25
+ """
26
+ Create a scatter plot with multiple regression lines for the given data.
27
+
28
+ Parameters
29
+ ----------
30
+ df : DataFrame
31
+ Input DataFrame containing the data.
32
+
33
+ x : str or list of str
34
+ Column name(s) for the x-axis variable(s).
35
+
36
+ y : str or list of str
37
+ Column name(s) for the y-axis variable(s).
38
+
39
+ labels : str or list of str, optional
40
+ Labels for the y-axis variable(s). If None, column names are used as labels. Default is None.
41
+
42
+ ax : AxesSubplot, optional
43
+ Matplotlib AxesSubplot to use for the plot. If None, a new subplot is created. Default is None.
44
+
45
+ diagonal : bool, optional
46
+ If True, a diagonal line (1:1 line) is added to the plot. Default is False.
47
+
48
+ positive : bool, optional
49
+ Whether to let coefficient positive. Default is True.
50
+
51
+ fit_intercept: bool, optional
52
+ Whether to fit intercept. Default is True.
53
+
54
+ **kwargs
55
+ Additional keyword arguments to customize the plot.
56
+
57
+ Returns
58
+ -------
59
+ AxesSubplot
60
+ Matplotlib AxesSubplot containing the scatter plot.
61
+
62
+ Notes
63
+ -----
64
+ - The function creates a scatter plot with the option to include multiple regression lines.
65
+ - If regression is True, regression lines are fitted for each y variable.
66
+ - Additional customization can be done using the **kwargs.
67
+
68
+ Example
69
+ -------
70
+ >>> linear_regression(df, x='X', y=['Y1', 'Y2'], labels=['Label1', 'Label2'],
71
+ ... regression=True, diagonal=True, xlim=(0, 10), ylim=(0, 20),
72
+ ... xlabel="X-axis", ylabel="Y-axis", title="Scatter Plot with Regressions")
73
+ """
74
+ fig, ax = plt.subplots(**kwargs.get('fig_kws', {})) if ax is None else (ax.get_figure(), ax)
75
+
76
+ if not isinstance(x, str):
77
+ x = x[0]
78
+
79
+ if not isinstance(y, list):
80
+ y = [y]
81
+
82
+ if labels is None:
83
+ labels = y
84
+
85
+ df = df.dropna(subset=[x, *y])
86
+ x_array = df[[x]].to_numpy()
87
+
88
+ color_cycle = Color.linecolor
89
+
90
+ handles, text_list = [], []
91
+
92
+ for i, y_var in enumerate(y):
93
+ y_array = df[[y_var]].to_numpy()
94
+
95
+ color = color_cycle[i % len(color_cycle)]
96
+
97
+ scatter = ax.scatter(x_array, y_array, s=25, color=color['face'], edgecolors=color['edge'], alpha=0.8,
98
+ label=labels[i])
99
+ handles.append(scatter)
100
+
101
+ text, y_predict, slope = linear_regression_base(x_array, y_array,
102
+ columns=labels[i],
103
+ positive=positive,
104
+ fit_intercept=fit_intercept)
105
+
106
+ text_list.append(f'{labels[i]}:\n{text}')
107
+ plt.plot(x_array, y_predict, linewidth=3, color=color['line'], alpha=1, zorder=3)
108
+
109
+ ax.set(xlim=kwargs.get('xlim'), ylim=kwargs.get('ylim'), xlabel=Unit(x), ylabel=Unit(y[0]),
110
+ title=kwargs.get('title'))
111
+
112
+ # Add regression info to the legend
113
+ leg = plt.legend(handles=handles, labels=text_list, loc='upper left', prop={'weight': 'bold'})
114
+
115
+ for text, color in zip(leg.get_texts(), [color['line'] for color in color_cycle]):
116
+ text.set_color(color)
117
+
118
+ if diagonal:
119
+ ax.axline((0, 0), slope=1., color='k', lw=2, ls='--', alpha=0.5, label='1:1')
120
+ plt.text(0.97, 0.97, r'$\bf 1:1\ Line$', color='k', ha='right', va='top', transform=ax.transAxes)
121
+
122
+ plt.show()
123
+
124
+ return fig, ax
125
+
126
+
127
+ @set_figure
128
+ def multiple_linear_regression(df: pd.DataFrame,
129
+ x: str | list[str],
130
+ y: str | list[str],
131
+ labels: str | list[str] = None,
132
+ ax: Axes | None = None,
133
+ diagonal=False,
134
+ positive: bool = True,
135
+ fit_intercept: bool = True,
136
+ **kwargs
137
+ ) -> tuple[Figure, Axes]:
138
+ """
139
+ Perform multiple linear regression analysis and plot the results.
140
+
141
+ Parameters
142
+ ----------
143
+ df : pandas.DataFrame
144
+ Input DataFrame containing the data.
145
+
146
+ x : str or list of str
147
+ Column name(s) for the independent variable(s). Can be a single string or a list of strings.
148
+
149
+ y : str or list of str
150
+ Column name(s) for the dependent variable(s). Can be a single string or a list of strings.
151
+
152
+ labels : str or list of str, optional
153
+ Labels for the dependent variable(s). If None, column names are used as labels. Default is None.
154
+
155
+ ax : matplotlib.axes.Axes or None, optional
156
+ Matplotlib Axes object to use for the plot. If None, a new subplot is created. Default is None.
157
+
158
+ diagonal : bool, optional
159
+ Whether to include a diagonal line (1:1 line) in the plot. Default is False.
160
+
161
+ positive : bool, optional
162
+ Whether to let coefficient positive. Default is True.
163
+
164
+ fit_intercept: bool, optional
165
+ Whether to fit intercept. Default is True.
166
+
167
+ **kwargs
168
+ Additional keyword arguments to customize the plot.
169
+
170
+ Returns
171
+ -------
172
+ matplotlib.axes.Axes
173
+ Matplotlib Axes object containing the regression plot.
174
+
175
+ Notes
176
+ -----
177
+ This function performs multiple linear regression analysis using the input DataFrame.
178
+ It supports multiple independent variables and can plot the regression results.
179
+
180
+ Example
181
+ -------
182
+ >>> multiple_linear_regression(df, x=['X1', 'X2'], y='Y', labels=['Y1', 'Y2'],
183
+ ... diagonal=True, add_constant=True,
184
+ ... xlabel="X-axis", ylabel="Y-axis", title="Multiple Linear Regression Plot")
185
+ """
186
+ fig, ax = plt.subplots(**kwargs.get('fig_kws', {})) if ax is None else (ax.get_figure(), ax)
187
+
188
+ if not isinstance(x, list):
189
+ x = [x]
190
+
191
+ if not isinstance(y, str):
192
+ y = y[0]
193
+
194
+ if labels is None:
195
+ labels = x
196
+
197
+ df = df[[*x, y]].dropna()
198
+ x_array = df[[*x]].to_numpy()
199
+ y_array = df[[y]].to_numpy()
200
+
201
+ text, y_predict, coefficients = linear_regression_base(x_array, y_array,
202
+ columns=labels,
203
+ positive=positive,
204
+ fit_intercept=fit_intercept)
205
+
206
+ df = pd.DataFrame(np.concatenate([y_array, y_predict], axis=1), columns=['y_actual', 'y_predict'])
207
+
208
+ linear_regression(df, x='y_actual', y='y_predict', ax=ax, regression=True, diagonal=diagonal)
209
+
210
+ return fig, ax
@@ -0,0 +1,99 @@
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.utils import *
10
+
11
+ __all__ = ['scatter']
12
+
13
+
14
+ @set_figure(figsize=(5, 4))
15
+ def scatter(df: pd.DataFrame,
16
+ x: str,
17
+ y: str,
18
+ c: str | None = None,
19
+ s: str | None = None,
20
+ cmap='jet',
21
+ regression=False,
22
+ diagonal=False,
23
+ ax: Axes | None = None,
24
+ **kwargs) -> tuple[Figure, Axes]:
25
+ fig, ax = plt.subplots(**kwargs.get('fig_kws', {})) if ax is None else (ax.get_figure(), ax)
26
+
27
+ if c is not None and s is not None:
28
+ df_ = df.dropna(subset=[x, y, c, s]).copy()
29
+ x_data, y_data, c_data, s_data = df_[x].to_numpy(), df_[y].to_numpy(), df_[c].to_numpy(), df_[s].to_numpy()
30
+
31
+ scatter = ax.scatter(x_data, y_data, c=c_data,
32
+ norm=Normalize(vmin=np.percentile(c_data, 10), vmax=np.percentile(c_data, 90)),
33
+ cmap=cmap, s=50 * (s_data / s_data.max()) ** 1.5, alpha=0.7, edgecolors=None)
34
+ colorbar = True
35
+
36
+ dot = np.linspace(s_data.min(), s_data.max(), 6).round(-1)
37
+
38
+ for dott in dot[1:-1]:
39
+ plt.scatter([], [], c='k', alpha=0.8, s=50 * (dott / s_data.max()) ** 1.5, label='{:.0f}'.format(dott))
40
+
41
+ plt.legend(title=Unit(s))
42
+
43
+ elif c is not None:
44
+ df_ = df.dropna(subset=[x, y, c]).copy()
45
+ x_data, y_data, c_data = df_[x].to_numpy(), df_[y].to_numpy(), df_[c].to_numpy()
46
+
47
+ scatter = ax.scatter(x_data, y_data, c=c_data, vmin=c_data.min(), vmax=np.percentile(c_data, 90), cmap=cmap,
48
+ alpha=0.7,
49
+ edgecolors=None)
50
+ colorbar = True
51
+
52
+ elif s is not None:
53
+ df_ = df.dropna(subset=[x, y, s]).copy()
54
+ x_data, y_data, s_data = df_[x].to_numpy(), df_[y].to_numpy(), df_[s].to_numpy()
55
+
56
+ scatter = ax.scatter(x_data, y_data, s=50 * (s_data / s_data.max()) ** 1.5, color='#7a97c9', alpha=0.7,
57
+ edgecolors='white')
58
+ colorbar = False
59
+
60
+ # dealing
61
+ dot = np.linspace(s_data.min(), s_data.max(), 6).round(-1)
62
+
63
+ for dott in dot[1:-1]:
64
+ plt.scatter([], [], c='k', alpha=0.8, s=50 * (dott / s_data.max()) ** 1.5, label='{:.0f}'.format(dott))
65
+
66
+ plt.legend(title=Unit(s))
67
+
68
+ else:
69
+ df_ = df.dropna(subset=[x, y]).copy()
70
+ x_data, y_data = df_[x].to_numpy(), df_[y].to_numpy()
71
+
72
+ scatter = ax.scatter(x_data, y_data, s=30, color='#7a97c9', alpha=0.7, edgecolors='white')
73
+ colorbar = False
74
+
75
+ ax.set(xlim=kwargs.get('xlim', (x_data.min(), x_data.max())),
76
+ ylim=kwargs.get('ylim', (y_data.min(), y_data.max())),
77
+ xlabel=kwargs.get('xlabel', Unit(x)),
78
+ ylabel=kwargs.get('ylabel', Unit(y)),
79
+ title=kwargs.get('title', ''))
80
+
81
+ if colorbar:
82
+ plt.colorbar(scatter, extend='both', label=Unit(c))
83
+
84
+ if regression:
85
+ text, y_predict, slope = linear_regression_base(x_data, y_data)
86
+ ax.plot(x_data, y_predict, linewidth=3, color=sns.xkcd_rgb["denim blue"], alpha=1, zorder=3)
87
+ plt.text(0.05, 0.95, text, fontdict={'weight': 'bold'}, color=sns.xkcd_rgb["denim blue"],
88
+ ha='left', va='top', transform=ax.transAxes)
89
+
90
+ if diagonal:
91
+ ax.axline((0, 0), slope=1., color='k', lw=2, ls='--', alpha=0.5, label='1:1')
92
+ plt.text(0.91, 0.97, r'$\bf 1:1\ Line$', color='k', ha='right', va='top', transform=ax.transAxes)
93
+
94
+ ax.xaxis.set_major_formatter(ScalarFormatter())
95
+ ax.yaxis.set_major_formatter(ScalarFormatter())
96
+
97
+ plt.show()
98
+
99
+ return fig, ax
@@ -3,6 +3,3 @@ from .corr_matrix import corr_matrix
3
3
  from .diurnal_pattern import *
4
4
  from .koschmieder import *
5
5
  from .metal_heatmap import metal_heatmaps, process_data
6
- from .regression import *
7
- from .scatter import *
8
- from .templates import *
@@ -10,38 +10,38 @@ __all__ = ['contour']
10
10
 
11
11
  @set_figure
12
12
  def contour(df, ax: Axes | None = None, **kwargs) -> tuple[Figure, Axes]:
13
- fig, ax = plt.subplots(**kwargs.get('fig_kws', {})) if ax is None else (ax.get_figure(), ax)
13
+ fig, ax = plt.subplots(**kwargs.get('fig_kws', {})) if ax is None else (ax.get_figure(), ax)
14
14
 
15
- npoints = 1000
16
- xreg = np.linspace(df.PM25.min(), df.PM25.max(), 83)
17
- yreg = np.linspace(df.gRH.min(), df.gRH.max(), 34)
18
- X, Y = np.meshgrid(xreg, yreg)
15
+ npoints = 1000
16
+ xreg = np.linspace(df.PM25.min(), df.PM25.max(), 83)
17
+ yreg = np.linspace(df.gRH.min(), df.gRH.max(), 34)
18
+ X, Y = np.meshgrid(xreg, yreg)
19
19
 
20
- d_f = df.copy()
21
- df['gRH'] = d_f['gRH'].round(2)
22
- df['PM25'] = d_f['PM25'].round(2)
20
+ d_f = df.copy()
21
+ df['gRH'] = d_f['gRH'].round(2)
22
+ df['PM25'] = d_f['PM25'].round(2)
23
23
 
24
- def func(data, *params):
25
- return params[0] * data ** (params[1])
24
+ def func(data, *params):
25
+ return params[0] * data ** (params[1])
26
26
 
27
- initial_guess = [1.0, 1.0]
27
+ initial_guess = [1.0, 1.0]
28
28
 
29
- fit_df = df[['PM25', 'gRH', 'Extinction']].dropna()
30
- popt, pcov = curve_fit(func, xdata=(fit_df['PM25'] * fit_df['gRH']), ydata=fit_df['Extinction'], p0=initial_guess,
31
- maxfev=2000000, method='trf')
29
+ fit_df = df[['PM25', 'gRH', 'Extinction']].dropna()
30
+ popt, pcov = curve_fit(func, xdata=(fit_df['PM25'] * fit_df['gRH']), ydata=fit_df['Extinction'], p0=initial_guess,
31
+ maxfev=2000000, method='trf')
32
32
 
33
- x, y = df.PM25, df.gRH
33
+ x, y = df.PM25, df.gRH
34
34
 
35
- # pcolor = ax.pcolormesh(X, Y, (X * 4.5 * Y ** (1 / 3)), cmap='jet', shading='auto', vmin=0, vmax=843, alpha=0.8)
36
- Z = func(X * Y, *popt)
37
- cont = ax.contour(X, Y, Z, colors='black', levels=5, vmin=0, vmax=Z.max())
38
- conf = ax.contourf(X, Y, Z, cmap='YlGnBu', levels=100, vmin=0, vmax=Z.max())
39
- ax.clabel(cont, colors=['black'], fmt=lambda s: f"{s:.0f} 1/Mm")
40
- ax.set(xlabel=Unit('PM25'), ylabel=Unit('gRH'), xlim=(x.min(), x.max()), ylim=(y.min(), y.max()))
35
+ # pcolor = ax.pcolormesh(X, Y, (X * 4.5 * Y ** (1 / 3)), cmap='jet', shading='auto', vmin=0, vmax=843, alpha=0.8)
36
+ Z = func(X * Y, *popt)
37
+ cont = ax.contour(X, Y, Z, colors='black', levels=5, vmin=0, vmax=Z.max())
38
+ conf = ax.contourf(X, Y, Z, cmap='YlGnBu', levels=100, vmin=0, vmax=Z.max())
39
+ ax.clabel(cont, colors=['black'], fmt=lambda s: f"{s:.0f} 1/Mm")
40
+ ax.set(xlabel=Unit('PM25'), ylabel=Unit('gRH'), xlim=(x.min(), x.max()), ylim=(y.min(), y.max()))
41
41
 
42
- color_bar = plt.colorbar(conf, pad=0.02, fraction=0.05, label='Extinction (1/Mm)')
43
- color_bar.ax.set_xticklabels(color_bar.ax.get_xticks().astype(int))
42
+ color_bar = plt.colorbar(conf, pad=0.02, fraction=0.05, label='Extinction (1/Mm)')
43
+ color_bar.ax.set_xticklabels(color_bar.ax.get_xticks().astype(int))
44
44
 
45
- plt.show()
45
+ plt.show()
46
46
 
47
- return fig, ax
47
+ return fig, ax