MatplotLibAPI 3.2.13__py3-none-any.whl → 3.2.14__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.
@@ -1,128 +1,342 @@
1
- # Hint for Visual Code Python Interactive window
2
- # %%
3
- from typing import Optional, Tuple
4
- import pandas as pd
5
- import matplotlib.pyplot as plt
6
- from matplotlib.figure import Figure
7
- from matplotlib.axes import Axes
8
- import seaborn as sns
1
+ """Timeserie plotting helpers."""
9
2
 
10
- from MatplotLibAPI.StyleTemplate import DynamicFuncFormatter, StyleTemplate, string_formatter, bmk_formatter, format_func, validate_dataframe
3
+ from typing import Dict, Optional, Tuple, cast
11
4
 
5
+ import matplotlib.pyplot as plt
6
+ import pandas as pd
7
+ import seaborn as sns
8
+ from matplotlib.axes import Axes
9
+ from matplotlib.figure import Figure
12
10
 
13
- TIMESERIE_STYLE_TEMPLATE = StyleTemplate(
14
- palette='rocket',
15
- format_funcs={"y": bmk_formatter, "label": string_formatter}
11
+ from .StyleTemplate import (
12
+ TIMESERIE_STYLE_TEMPLATE,
13
+ StyleTemplate,
14
+ bmk_formatter,
15
+ format_func,
16
+ string_formatter,
17
+ validate_dataframe,
18
+ DynamicFuncFormatter,
19
+ FormatterFunc,
16
20
  )
17
21
 
22
+
18
23
  # region Line
19
24
 
20
25
 
21
- def aplot_timeserie(pd_df: pd.DataFrame,
22
- label: str,
23
- x: str,
24
- y: str,
25
- title: Optional[str] = None,
26
- style: StyleTemplate = TIMESERIE_STYLE_TEMPLATE,
27
- max_values: int = 100,
28
- sort_by: Optional[str] = None,
29
- ascending: bool = False,
30
- std: bool = False,
31
- ax: Optional[Axes] = None) -> Axes:
26
+ def _prepare_timeserie_data(
27
+ pd_df: pd.DataFrame, label: str, x: str, y: str, sort_by: Optional[str]
28
+ ) -> pd.DataFrame:
29
+ """Prepare data for time series plotting.
32
30
 
33
- validate_dataframe(pd_df, cols=[label, x, y], sort_by=sort_by)
34
- style.format_funcs = format_func(style.format_funcs, label=label, x=x, y=y)
31
+ Parameters
32
+ ----------
33
+ pd_df : pd.DataFrame
34
+ Input DataFrame.
35
+ label : str
36
+ Column to group series by.
37
+ x : str
38
+ Column for x-axis values (time).
39
+ y : str
40
+ Column for y-axis values.
41
+ sort_by : Optional[str]
42
+ Column to sort by before plotting.
43
+
44
+ Returns
45
+ -------
46
+ pd.DataFrame
47
+ Prepared DataFrame with a datetime index.
35
48
 
36
- df = pd_df[[label, x, y]].sort_values(by=[label, x])
49
+ Raises
50
+ ------
51
+ AttributeError
52
+ If required columns are missing from the DataFrame.
53
+ """
54
+ validate_dataframe(pd_df, cols=[label, x, y], sort_by=sort_by)
55
+ df = pd_df[[label, x, y]].sort_values(by=[label, x]) # type: ignore
37
56
  df[x] = pd.to_datetime(df[x])
38
57
  df.set_index(x, inplace=True)
58
+ return df
39
59
 
40
- sns.set_palette(style.palette)
41
- # Colors for each group
42
- colors = sns.color_palette(n_colors=len(df.columns))
43
- if ax is None:
44
- ax = plt.gca()
45
60
 
61
+ def _plot_timeserie_lines(
62
+ ax: Axes,
63
+ df: pd.DataFrame,
64
+ label: str,
65
+ x: str,
66
+ y: str,
67
+ std: bool,
68
+ style: StyleTemplate,
69
+ format_funcs: Optional[Dict[str, Optional[FormatterFunc]]],
70
+ ) -> None:
71
+ """Plot the time series lines on the axes.
72
+
73
+ Parameters
74
+ ----------
75
+ ax : Axes
76
+ Matplotlib axes object.
77
+ df : pd.DataFrame
78
+ DataFrame with data for plotting.
79
+ label : str
80
+ Column used to group series.
81
+ x : str
82
+ Column for x-axis values.
83
+ y : str
84
+ Column for y-axis values.
85
+ std : bool
86
+ Whether to plot rolling standard deviation.
87
+ style : StyleTemplate
88
+ Styling for the plot.
89
+ format_funcs : Optional[Dict[str, Optional[FormatterFunc]]]
90
+ Functions to format labels and values.
91
+ """
92
+ sns.set_palette(style.palette)
46
93
  # Get unique dimension_types
47
94
  label_types = df[label].unique()
48
-
49
95
  # Colors for each group
50
96
  colors = sns.color_palette(n_colors=len(label_types))
51
97
 
52
98
  for label_type, color in zip(label_types, colors):
53
- temp_df = df[df[label] == label_type].sort_values(by=x)
99
+ temp_df = df[df[label] == label_type].sort_values(by=x) # type: ignore
54
100
 
55
- if style.format_funcs.get("label"):
56
- label_type = style.format_funcs.get("label")(label_type)
101
+ if format_funcs and (label_formatter := format_funcs.get("label")):
102
+ label_type = label_formatter(label_type, None)
57
103
  if std:
58
104
  ma = temp_df[y].rolling(window=7, min_periods=1).mean()
59
105
  std_dev = temp_df[y].rolling(window=7, min_periods=1).std()
60
106
  # Calculate the last moving average value to include in the legend
61
- last_ma_value = ma.iloc[-1]
107
+ last_ma_value = cast(pd.Series, ma).iloc[-1]
62
108
  # Dynamically creating the legend label
63
- label_str = f"{string_formatter(label_type)} (avg 7d: {style.format_funcs[y](last_ma_value)})"
109
+ if format_funcs and (y_formatter := format_funcs.get(y)):
110
+ label_str = f"{string_formatter(label_type)} (avg 7d: {y_formatter(last_ma_value, None)})"
111
+ else:
112
+ label_str = f"{string_formatter(label_type)} (avg 7d: {last_ma_value})"
64
113
  # Plot moving average and include the last MA value in the label for the legend
65
- ax.plot(temp_df.index, ma, color=color,
66
- linestyle='--', label=label_str)
114
+ ax.plot(temp_df.index, ma, color=color, linestyle="--", label=label_str)
67
115
 
68
- ax.fill_between(temp_df.index, ma - std_dev, ma +
69
- std_dev, color=color, alpha=0.2, label='_nolegend_')
116
+ ax.fill_between(
117
+ temp_df.index,
118
+ ma - std_dev,
119
+ ma + std_dev,
120
+ color=color,
121
+ alpha=0.2,
122
+ label="_nolegend_",
123
+ )
70
124
  else:
71
125
  label_str = f"{string_formatter(label_type)}"
72
126
  # Plot moving average and include the last MA value in the label for the legend
73
127
  ax.plot(temp_df.index, temp_df[y], color=color, label=label_str)
74
128
 
129
+
130
+ def _setup_timeserie_axes(
131
+ ax: Axes,
132
+ label: str,
133
+ x: str,
134
+ y: str,
135
+ style: StyleTemplate,
136
+ format_funcs: Optional[Dict[str, Optional[FormatterFunc]]],
137
+ ) -> None:
138
+ """Configure the axes for the time series plot.
139
+
140
+ Parameters
141
+ ----------
142
+ ax : Axes
143
+ Matplotlib axes object.
144
+ label : str
145
+ Column used for grouping and legend title.
146
+ x : str
147
+ Column for x-axis label.
148
+ y : str
149
+ Column for y-axis label.
150
+ style : StyleTemplate
151
+ Styling for the plot.
152
+ format_funcs : Optional[Dict[str, Optional[FormatterFunc]]]
153
+ Functions to format axis tick labels.
154
+ """
75
155
  ax.legend(
76
156
  title=label,
77
- fontsize=style.font_size-4,
157
+ fontsize=style.font_size - 4,
78
158
  title_fontsize=style.font_size,
79
- labelcolor='linecolor',
80
- facecolor=style.background_color)
159
+ labelcolor="linecolor",
160
+ facecolor=style.background_color,
161
+ )
81
162
 
82
163
  ax.set_xlabel(string_formatter(x), color=style.font_color)
83
- if style.format_funcs.get("x"):
84
- ax.xaxis.set_major_formatter(
85
- DynamicFuncFormatter(style.format_funcs.get("x")))
86
- ax.tick_params(axis='x', colors=style.font_color,
87
- labelrotation=45, labelsize=style.font_size-4)
164
+ if format_funcs and (x_formatter := format_funcs.get("x")):
165
+ ax.xaxis.set_major_formatter(DynamicFuncFormatter(x_formatter))
166
+ ax.tick_params(
167
+ axis="x",
168
+ colors=style.font_color,
169
+ labelrotation=45,
170
+ labelsize=style.font_size - 4,
171
+ )
88
172
 
89
173
  ax.set_ylabel(string_formatter(y), color=style.font_color)
90
- if style.format_funcs.get("y"):
91
- ax.yaxis.set_major_formatter(
92
- DynamicFuncFormatter(style.format_funcs.get("y")))
93
- ax.tick_params(axis='y', colors=style.font_color,
94
- labelsize=style.font_size-4)
174
+ if format_funcs and (y_formatter := format_funcs.get("y")):
175
+ ax.yaxis.set_major_formatter(DynamicFuncFormatter(y_formatter))
176
+ ax.tick_params(axis="y", colors=style.font_color, labelsize=style.font_size - 4)
95
177
  ax.set_facecolor(style.background_color)
96
178
  ax.grid(True)
179
+
180
+
181
+ def aplot_timeserie(
182
+ pd_df: pd.DataFrame,
183
+ label: str,
184
+ x: str,
185
+ y: str,
186
+ title: Optional[str] = None,
187
+ style: StyleTemplate = TIMESERIE_STYLE_TEMPLATE,
188
+ max_values: int = 100,
189
+ sort_by: Optional[str] = None,
190
+ ascending: bool = False,
191
+ std: bool = False,
192
+ ax: Optional[Axes] = None,
193
+ ) -> Axes:
194
+ """Plot a time series on the provided axes.
195
+
196
+ Parameters
197
+ ----------
198
+ pd_df : pd.DataFrame
199
+ DataFrame containing the data to plot.
200
+ label : str
201
+ Column used to group series.
202
+ x : str
203
+ Column for the x-axis values.
204
+ y : str
205
+ Column for the y-axis values.
206
+ title : str, optional
207
+ Plot title.
208
+ style : StyleTemplate, optional
209
+ Style configuration. The default is `TIMESERIE_STYLE_TEMPLATE`.
210
+ max_values : int, optional
211
+ Maximum number of rows to plot. The default is 100.
212
+ sort_by : str, optional
213
+ Column used to sort the data.
214
+ ascending : bool, optional
215
+ Sort order for the data. The default is `False`.
216
+ std : bool, optional
217
+ Whether to plot rolling standard deviation. The default is `False`.
218
+ ax : Axes, optional
219
+ Axes to draw on.
220
+
221
+ Returns
222
+ -------
223
+ Axes
224
+ Matplotlib axes with the time series plot.
225
+
226
+ Raises
227
+ ------
228
+ AttributeError
229
+ If required columns are not in the DataFrame.
230
+
231
+ Examples
232
+ --------
233
+ >>> import pandas as pd
234
+ >>> import matplotlib.pyplot as plt
235
+ >>> from MatplotLibAPI.Timeserie import aplot_timeserie
236
+ >>> data = {
237
+ ... 'date': pd.to_datetime(['2023-01-01', '2023-01-02', '2023-01-01', '2023-01-02']),
238
+ ... 'category': ['A', 'A', 'B', 'B'],
239
+ ... 'value': [10, 12, 15, 13]
240
+ ... }
241
+ >>> df = pd.DataFrame(data)
242
+ >>> fig, ax = plt.subplots()
243
+ >>> aplot_timeserie(df, label='category', x='date', y='value', ax=ax)
244
+ """
245
+ if ax is None:
246
+ ax = cast(Axes, plt.gca())
247
+
248
+ df = _prepare_timeserie_data(pd_df, label, x, y, sort_by)
249
+
250
+ format_funcs = format_func(style.format_funcs, label=label, x=x, y=y)
251
+
252
+ _plot_timeserie_lines(ax, df, label, x, y, std, style, format_funcs)
253
+
254
+ _setup_timeserie_axes(ax, label, x, y, style, format_funcs)
255
+
97
256
  if title:
98
- ax.set_title(title, color=style.font_color, fontsize=style.font_size+4)
257
+ ax.set_title(title, color=style.font_color, fontsize=style.font_size + 4)
99
258
  return ax
100
259
 
101
260
 
102
- def fplot_timeserie(pd_df: pd.DataFrame,
103
- label: str,
104
- x: str,
105
- y: str,
106
- title: Optional[str] = None,
107
- style: StyleTemplate = TIMESERIE_STYLE_TEMPLATE,
108
- max_values: int = 100,
109
- sort_by: Optional[str] = None,
110
- ascending: bool = False,
111
- std: bool = False,
112
- figsize: Tuple[float, float] = (19.2, 10.8)) -> Figure:
113
- fig = plt.figure(figsize=figsize)
261
+ def fplot_timeserie(
262
+ pd_df: pd.DataFrame,
263
+ label: str,
264
+ x: str,
265
+ y: str,
266
+ title: Optional[str] = None,
267
+ style: StyleTemplate = TIMESERIE_STYLE_TEMPLATE,
268
+ max_values: int = 100,
269
+ sort_by: Optional[str] = None,
270
+ ascending: bool = False,
271
+ std: bool = False,
272
+ figsize: Tuple[float, float] = (19.2, 10.8),
273
+ ) -> Figure:
274
+ """Return a figure plotting the time series.
275
+
276
+ Parameters
277
+ ----------
278
+ pd_df : pd.DataFrame
279
+ DataFrame containing the data to plot.
280
+ label : str
281
+ Column used to group series.
282
+ x : str
283
+ Column for the x-axis values.
284
+ y : str
285
+ Column for the y-axis values.
286
+ title : str, optional
287
+ Plot title.
288
+ style : StyleTemplate, optional
289
+ Style configuration. The default is `TIMESERIE_STYLE_TEMPLATE`.
290
+ max_values : int, optional
291
+ Maximum number of rows to plot. The default is 100.
292
+ sort_by : str, optional
293
+ Column used to sort the data.
294
+ ascending : bool, optional
295
+ Sort order for the data. The default is `False`.
296
+ std : bool, optional
297
+ Whether to plot rolling standard deviation. The default is `False`.
298
+ figsize : tuple[float, float], optional
299
+ Size of the created figure. The default is (19.2, 10.8).
300
+
301
+ Returns
302
+ -------
303
+ Figure
304
+ Matplotlib figure containing the time series plot.
305
+
306
+ Raises
307
+ ------
308
+ AttributeError
309
+ If required columns are not in the DataFrame.
310
+
311
+ Examples
312
+ --------
313
+ >>> import pandas as pd
314
+ >>> from MatplotLibAPI.Timeserie import fplot_timeserie
315
+ >>> data = {
316
+ ... 'date': pd.to_datetime(['2023-01-01', '2023-01-02', '2023-01-01', '2023-01-02']),
317
+ ... 'category': ['A', 'A', 'B', 'B'],
318
+ ... 'value': [10, 12, 15, 13]
319
+ ... }
320
+ >>> df = pd.DataFrame(data)
321
+ >>> fig = fplot_timeserie(df, label='category', x='date', y='value')
322
+ """
323
+ fig = cast(Figure, plt.figure(figsize=figsize))
114
324
  fig.patch.set_facecolor(style.background_color)
115
325
  ax = fig.add_subplot()
116
- ax = aplot_timeserie(pd_df=pd_df,
117
- label=label,
118
- x=x,
119
- y=y,
120
- title=title,
121
- style=style,
122
- max_values=max_values,
123
- std=std,
124
- sort_by=sort_by,
125
- ascending=ascending,
126
- ax=ax)
326
+ ax = aplot_timeserie(
327
+ pd_df=pd_df,
328
+ label=label,
329
+ x=x,
330
+ y=y,
331
+ title=title,
332
+ style=style,
333
+ max_values=max_values,
334
+ std=std,
335
+ sort_by=sort_by,
336
+ ascending=ascending,
337
+ ax=ax,
338
+ )
127
339
  return fig
340
+
341
+
128
342
  # endregion
MatplotLibAPI/Treemap.py CHANGED
@@ -1,87 +1,150 @@
1
- # Hint for Visual Code Python Interactive window
2
- # %%
1
+ """Treemap plotting utilities."""
2
+
3
3
  from typing import Optional
4
+
4
5
  import pandas as pd
5
- from pandas import CategoricalDtype, BooleanDtype
6
6
  import plotly.graph_objects as go
7
+ from pandas import BooleanDtype, CategoricalDtype
7
8
 
8
- from MatplotLibAPI.StyleTemplate import StyleTemplate, string_formatter, percent_formatter, validate_dataframe
9
+ from .StyleTemplate import (
10
+ TREEMAP_STYLE_TEMPLATE,
11
+ StyleTemplate,
12
+ percent_formatter,
13
+ string_formatter,
14
+ validate_dataframe,
15
+ )
9
16
 
10
17
 
11
- TREEMAP_STYLE_TEMPLATE = StyleTemplate(
12
- background_color='black',
13
- fig_border='darkgrey',
14
- font_color='white',
15
- palette='magma',
16
- format_funcs={"y": percent_formatter,
17
- "label": string_formatter}
18
- )
18
+ def aplot_treemap(
19
+ pd_df: pd.DataFrame,
20
+ path: str,
21
+ values: str,
22
+ style: StyleTemplate = TREEMAP_STYLE_TEMPLATE,
23
+ title: Optional[str] = None,
24
+ color: Optional[str] = None,
25
+ sort_by: Optional[str] = None,
26
+ ascending: bool = False,
27
+ max_values: int = 100,
28
+ ) -> go.Trace:
29
+ """Create a treemap trace from the data frame.
19
30
 
31
+ Parameters
32
+ ----------
33
+ pd_df : pd.DataFrame
34
+ DataFrame containing the data to plot.
35
+ path : str
36
+ Column representing hierarchical path.
37
+ values : str
38
+ Column containing values for each treemap block.
39
+ style : StyleTemplate, optional
40
+ Style configuration. The default is `TREEMAP_STYLE_TEMPLATE`.
41
+ title : str, optional
42
+ Plot title.
43
+ color : str, optional
44
+ Column used for coloring.
45
+ sort_by : str, optional
46
+ Column used to sort data.
47
+ ascending : bool, optional
48
+ Sort order for the data. The default is `False`.
49
+ max_values : int, optional
50
+ Maximum number of rows to plot. The default is 100.
20
51
 
21
- def aplot_treemap(pd_df: pd.DataFrame,
22
- path: str,
23
- values: str,
24
- style: StyleTemplate = TREEMAP_STYLE_TEMPLATE,
25
- title: Optional[str] = None,
26
- color: Optional[str] = None,
27
- sort_by: Optional[str] = None,
28
- ascending: bool = False,
29
- max_values: int = 100) -> go.Trace:
52
+ Returns
53
+ -------
54
+ go.Trace
55
+ Plotly treemap trace.
56
+ """
30
57
  cols = [path, values]
31
58
  if color:
32
59
  cols.append(color)
33
60
  validate_dataframe(pd_df, cols=cols, sort_by=sort_by)
34
61
  if not sort_by:
35
62
  sort_by = values
36
- df = pd_df.sort_values(by=sort_by, ascending=ascending)[
37
- cols].head(max_values)
38
- data = {"labels": df[path],
39
- "parents": [""] * len(df),
40
- "values": df[values],
41
- "textinfo": "label",
42
- "name": title,
43
- "textfont":
44
- {"family": style.font_name,
45
- "size": style.font_size,
46
- "color": style.font_color}
47
- }
63
+ df = pd_df.sort_values(by=sort_by, ascending=ascending)[cols].head(max_values)
64
+ data = {
65
+ "labels": df[path],
66
+ "parents": [""] * len(df),
67
+ "values": df[values],
68
+ "textinfo": "label",
69
+ "name": title,
70
+ "textfont": {
71
+ "family": style.font_name,
72
+ "size": style.font_size,
73
+ "color": style.font_color,
74
+ },
75
+ }
48
76
 
49
77
  if color and color in pd_df.columns:
50
78
  color_data = pd_df[color]
51
- if isinstance(color_data, CategoricalDtype) or pd.api.types.is_object_dtype(color_data):
52
- color_data = color_data.astype('category').cat.codes
53
- elif isinstance(color_data, BooleanDtype):
79
+ if isinstance(
80
+ color_data.dtype, CategoricalDtype
81
+ ) or pd.api.types.is_object_dtype(color_data.dtype):
82
+ color_data = color_data.astype("category").cat.codes
83
+ elif isinstance(color_data.dtype, BooleanDtype):
54
84
  color_data = color_data.astype(int)
55
- data['marker'] = dict(colorscale="Viridis",
56
- colors=color_data.to_list())
57
-
58
- g = go.Treemap(data,
59
- root_color=style.background_color
60
- )
61
-
62
- return g
63
-
64
-
65
- def fplot_treemap(pd_df: pd.DataFrame,
66
- path: str,
67
- values: str,
68
- style: StyleTemplate = TREEMAP_STYLE_TEMPLATE,
69
- title: Optional[str] = None,
70
- color: Optional[str] = None,
71
- sort_by: Optional[str] = None,
72
- ascending: bool = False,
73
- max_values: int = 100,
74
- fig: Optional[go.Figure] = None) -> go.Figure:
75
-
76
- g = aplot_treemap(pd_df=pd_df,
77
- path=path,
78
- values=values,
79
- title=title,
80
- style=style,
81
- color=color,
82
- sort_by=sort_by,
83
- ascending=ascending,
84
- max_values=max_values)
85
+ data["marker"] = dict(colorscale="Viridis", colors=color_data.to_list())
86
+
87
+ g = go.Treemap(
88
+ data,
89
+ root_color=style.background_color,
90
+ )
91
+
92
+ return g # type: ignore
93
+
94
+
95
+ def fplot_treemap(
96
+ pd_df: pd.DataFrame,
97
+ path: str,
98
+ values: str,
99
+ style: StyleTemplate = TREEMAP_STYLE_TEMPLATE,
100
+ title: Optional[str] = None,
101
+ color: Optional[str] = None,
102
+ sort_by: Optional[str] = None,
103
+ ascending: bool = False,
104
+ max_values: int = 100,
105
+ fig: Optional[go.Figure] = None,
106
+ ) -> go.Figure:
107
+ """Return a figure containing the treemap plot.
108
+
109
+ Parameters
110
+ ----------
111
+ pd_df : pd.DataFrame
112
+ DataFrame containing the data to plot.
113
+ path : str
114
+ Column representing hierarchical path.
115
+ values : str
116
+ Column containing values for each treemap block.
117
+ style : StyleTemplate, optional
118
+ Style configuration. The default is `TREEMAP_STYLE_TEMPLATE`.
119
+ title : str, optional
120
+ Plot title.
121
+ color : str, optional
122
+ Column used for coloring.
123
+ sort_by : str, optional
124
+ Column used to sort data.
125
+ ascending : bool, optional
126
+ Sort order for the data. The default is `False`.
127
+ max_values : int, optional
128
+ Maximum number of rows to plot. The default is 100.
129
+ fig : go.Figure, optional
130
+ Existing figure to add the treemap to.
131
+
132
+ Returns
133
+ -------
134
+ go.Figure
135
+ Figure containing the treemap plot.
136
+ """
137
+ g = aplot_treemap(
138
+ pd_df=pd_df,
139
+ path=path,
140
+ values=values,
141
+ title=title,
142
+ style=style,
143
+ color=color,
144
+ sort_by=sort_by,
145
+ ascending=ascending,
146
+ max_values=max_values,
147
+ )
85
148
 
86
149
  if not fig:
87
150
  fig = go.Figure(g)
@@ -92,16 +155,11 @@ def fplot_treemap(pd_df: pd.DataFrame,
92
155
  title=title,
93
156
  plot_bgcolor=style.background_color,
94
157
  paper_bgcolor=style.background_color,
95
- font=dict(
96
- family=style.font_name,
97
- size=style.font_size,
98
- color=style.font_color
99
- ),
100
- showlegend=style.legend if style else True)
158
+ font=dict(family=style.font_name, size=style.font_size, color=style.font_color),
159
+ showlegend=style.legend if style else True,
160
+ )
101
161
 
102
162
  # Apply color scale
103
- fig.update_traces(
104
- marker=dict(colorscale=style.palette)
105
- )
163
+ fig.update_traces(marker=dict(colorscale=style.palette))
106
164
 
107
165
  return fig