AeroViz 0.1.3__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 (107) hide show
  1. AeroViz/__init__.py +4 -4
  2. AeroViz/dataProcess/Chemistry/__init__.py +38 -38
  3. AeroViz/dataProcess/Chemistry/_calculate.py +15 -15
  4. AeroViz/dataProcess/Chemistry/_isoropia.py +69 -68
  5. AeroViz/dataProcess/Chemistry/_mass_volume.py +158 -158
  6. AeroViz/dataProcess/Chemistry/_ocec.py +109 -109
  7. AeroViz/dataProcess/Chemistry/_partition.py +19 -18
  8. AeroViz/dataProcess/Chemistry/_teom.py +8 -11
  9. AeroViz/dataProcess/Optical/_IMPROVE.py +40 -39
  10. AeroViz/dataProcess/Optical/__init__.py +35 -35
  11. AeroViz/dataProcess/Optical/_absorption.py +35 -35
  12. AeroViz/dataProcess/Optical/_extinction.py +25 -24
  13. AeroViz/dataProcess/Optical/_mie.py +5 -6
  14. AeroViz/dataProcess/Optical/_mie_sd.py +89 -90
  15. AeroViz/dataProcess/Optical/_scattering.py +16 -16
  16. AeroViz/dataProcess/SizeDistr/__init__.py +37 -37
  17. AeroViz/dataProcess/SizeDistr/__merge.py +159 -158
  18. AeroViz/dataProcess/SizeDistr/_merge.py +155 -154
  19. AeroViz/dataProcess/SizeDistr/_merge_v1.py +162 -161
  20. AeroViz/dataProcess/SizeDistr/_merge_v2.py +153 -152
  21. AeroViz/dataProcess/SizeDistr/_merge_v3.py +326 -326
  22. AeroViz/dataProcess/SizeDistr/_merge_v4.py +272 -274
  23. AeroViz/dataProcess/SizeDistr/_size_distr.py +51 -51
  24. AeroViz/dataProcess/VOC/__init__.py +7 -7
  25. AeroViz/dataProcess/VOC/_potential_par.py +53 -55
  26. AeroViz/dataProcess/__init__.py +4 -4
  27. AeroViz/dataProcess/core/__init__.py +59 -58
  28. AeroViz/plot/__init__.py +6 -1
  29. AeroViz/plot/bar.py +126 -0
  30. AeroViz/plot/box.py +68 -0
  31. AeroViz/plot/distribution/distribution.py +421 -427
  32. AeroViz/plot/meteorology/meteorology.py +240 -292
  33. AeroViz/plot/optical/__init__.py +0 -1
  34. AeroViz/plot/optical/optical.py +230 -230
  35. AeroViz/plot/pie.py +198 -0
  36. AeroViz/plot/regression.py +210 -0
  37. AeroViz/plot/scatter.py +99 -0
  38. AeroViz/plot/templates/__init__.py +0 -3
  39. AeroViz/plot/templates/contour.py +25 -25
  40. AeroViz/plot/templates/corr_matrix.py +86 -93
  41. AeroViz/plot/templates/diurnal_pattern.py +24 -24
  42. AeroViz/plot/templates/koschmieder.py +106 -106
  43. AeroViz/plot/templates/metal_heatmap.py +34 -34
  44. AeroViz/plot/timeseries/timeseries.py +53 -60
  45. AeroViz/plot/utils/__init__.py +2 -1
  46. AeroViz/plot/utils/_color.py +57 -57
  47. AeroViz/plot/utils/_unit.py +48 -48
  48. AeroViz/plot/utils/plt_utils.py +92 -0
  49. AeroViz/plot/utils/sklearn_utils.py +49 -0
  50. AeroViz/plot/violin.py +79 -0
  51. AeroViz/process/__init__.py +15 -15
  52. AeroViz/process/core/DataProc.py +9 -9
  53. AeroViz/process/core/SizeDist.py +81 -81
  54. AeroViz/process/method/PyMieScatt_update.py +488 -488
  55. AeroViz/process/method/mie_theory.py +231 -229
  56. AeroViz/process/method/prop.py +40 -40
  57. AeroViz/process/script/AbstractDistCalc.py +103 -103
  58. AeroViz/process/script/Chemical.py +166 -166
  59. AeroViz/process/script/IMPACT.py +40 -40
  60. AeroViz/process/script/IMPROVE.py +152 -152
  61. AeroViz/process/script/Others.py +45 -45
  62. AeroViz/process/script/PSD.py +26 -26
  63. AeroViz/process/script/PSD_dry.py +69 -70
  64. AeroViz/process/script/retrieve_RI.py +50 -51
  65. AeroViz/rawDataReader/__init__.py +57 -57
  66. AeroViz/rawDataReader/core/__init__.py +328 -326
  67. AeroViz/rawDataReader/script/AE33.py +18 -18
  68. AeroViz/rawDataReader/script/AE43.py +20 -20
  69. AeroViz/rawDataReader/script/APS_3321.py +30 -30
  70. AeroViz/rawDataReader/script/Aurora.py +23 -23
  71. AeroViz/rawDataReader/script/BC1054.py +40 -40
  72. AeroViz/rawDataReader/script/EPA_vertical.py +9 -9
  73. AeroViz/rawDataReader/script/GRIMM.py +21 -21
  74. AeroViz/rawDataReader/script/IGAC_TH.py +67 -67
  75. AeroViz/rawDataReader/script/IGAC_ZM.py +59 -59
  76. AeroViz/rawDataReader/script/MA350.py +39 -39
  77. AeroViz/rawDataReader/script/NEPH.py +74 -74
  78. AeroViz/rawDataReader/script/OCEC_LCRES.py +21 -21
  79. AeroViz/rawDataReader/script/OCEC_RES.py +16 -16
  80. AeroViz/rawDataReader/script/SMPS_TH.py +25 -25
  81. AeroViz/rawDataReader/script/SMPS_aim11.py +32 -32
  82. AeroViz/rawDataReader/script/SMPS_genr.py +31 -31
  83. AeroViz/rawDataReader/script/TEOM.py +28 -28
  84. AeroViz/rawDataReader/script/Table.py +12 -12
  85. AeroViz/rawDataReader/script/VOC_TH.py +16 -16
  86. AeroViz/rawDataReader/script/VOC_ZM.py +28 -28
  87. AeroViz/rawDataReader/script/__init__.py +20 -20
  88. AeroViz/rawDataReader/utils/config.py +161 -161
  89. AeroViz/tools/database.py +65 -65
  90. AeroViz/tools/dataclassifier.py +106 -106
  91. AeroViz/tools/dataprinter.py +51 -51
  92. AeroViz/tools/datareader.py +38 -38
  93. {AeroViz-0.1.3.dist-info → AeroViz-0.1.3b0.dist-info}/METADATA +5 -4
  94. AeroViz-0.1.3b0.dist-info/RECORD +110 -0
  95. AeroViz/config/__init__.py +0 -0
  96. AeroViz/plot/improve/__init__.py +0 -1
  97. AeroViz/plot/improve/improve.py +0 -240
  98. AeroViz/plot/optical/aethalometer.py +0 -77
  99. AeroViz/plot/templates/event_evolution.py +0 -65
  100. AeroViz/plot/templates/regression.py +0 -256
  101. AeroViz/plot/templates/scatter.py +0 -130
  102. AeroViz/plot/templates/templates.py +0 -398
  103. AeroViz/plot/utils/_decorator.py +0 -74
  104. AeroViz-0.1.3.dist-info/RECORD +0 -111
  105. {AeroViz-0.1.3.dist-info → AeroViz-0.1.3b0.dist-info}/LICENSE +0 -0
  106. {AeroViz-0.1.3.dist-info → AeroViz-0.1.3b0.dist-info}/WHEEL +0 -0
  107. {AeroViz-0.1.3.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