tesorotools-python 0.0.6__py2.py3-none-any.whl → 0.0.7__py2.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.
Files changed (44) hide show
  1. {tesorotools_python-0.0.6.dist-info → tesorotools_python-0.0.7.dist-info}/METADATA +1 -1
  2. tesorotools_python-0.0.7.dist-info/RECORD +3 -0
  3. tesorotools/__init__.py +0 -0
  4. tesorotools/artists/__init__.py +0 -5
  5. tesorotools/artists/barh_plot.py +0 -310
  6. tesorotools/artists/line_plot.py +0 -114
  7. tesorotools/artists/table.py +0 -199
  8. tesorotools/artists/type_curve.py +0 -216
  9. tesorotools/assets/README.md +0 -5
  10. tesorotools/assets/fonts/README.md +0 -1
  11. tesorotools/assets/plots.yaml +0 -43
  12. tesorotools/assets/tesoro.mplstyle +0 -21
  13. tesorotools/convert.py +0 -93
  14. tesorotools/data_sources/README.md +0 -14
  15. tesorotools/data_sources/__init__.py +0 -0
  16. tesorotools/data_sources/debug.py +0 -26
  17. tesorotools/data_sources/lseg.py +0 -117
  18. tesorotools/database/__init__.py +0 -0
  19. tesorotools/database/push.py +0 -70
  20. tesorotools/dependencies/__init__.py +0 -0
  21. tesorotools/dependencies/functions.py +0 -11
  22. tesorotools/dependencies/node.py +0 -34
  23. tesorotools/dependencies/resolution.py +0 -118
  24. tesorotools/main.py +0 -37
  25. tesorotools/offsets/__init__.py +0 -0
  26. tesorotools/offsets/offsets.py +0 -439
  27. tesorotools/offsets/outliers.py +0 -15
  28. tesorotools/render/__init__.py +0 -11
  29. tesorotools/render/content/__init__.py +0 -0
  30. tesorotools/render/content/content.py +0 -17
  31. tesorotools/render/content/images.py +0 -147
  32. tesorotools/render/content/section.py +0 -53
  33. tesorotools/render/content/table.py +0 -284
  34. tesorotools/render/headline.py +0 -40
  35. tesorotools/render/introduction.py +0 -49
  36. tesorotools/render/report.py +0 -29
  37. tesorotools/utils/__init__.py +0 -0
  38. tesorotools/utils/config.py +0 -35
  39. tesorotools/utils/globals.py +0 -14
  40. tesorotools/utils/matplotlib.py +0 -38
  41. tesorotools/utils/series.py +0 -40
  42. tesorotools/utils/template.py +0 -126
  43. tesorotools_python-0.0.6.dist-info/RECORD +0 -43
  44. {tesorotools_python-0.0.6.dist-info → tesorotools_python-0.0.7.dist-info}/WHEEL +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: tesorotools-python
3
- Version: 0.0.6
3
+ Version: 0.0.7
4
4
  Requires-Dist: babel
5
5
  Requires-Dist: eikon
6
6
  Requires-Dist: lseg-data
@@ -0,0 +1,3 @@
1
+ tesorotools_python-0.0.7.dist-info/METADATA,sha256=3rD3qrljFgGk0QKP5gHOwvI-dx3jL5w8vtjQwnSmH1o,323
2
+ tesorotools_python-0.0.7.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
3
+ tesorotools_python-0.0.7.dist-info/RECORD,,
tesorotools/__init__.py DELETED
File without changes
@@ -1,5 +0,0 @@
1
- import matplotlib.style
2
-
3
- from ..utils.globals import STYLE_SHEET
4
-
5
- matplotlib.style.use(STYLE_SHEET)
@@ -1,310 +0,0 @@
1
- from enum import Enum
2
- from pathlib import Path
3
- from typing import Any
4
-
5
- import matplotlib.pyplot as plt
6
- import pandas as pd
7
- from matplotlib.container import BarContainer
8
- from matplotlib.ticker import FuncFormatter
9
-
10
- from tesorotools.offsets.offsets import Difference, FloatingOffset, Stat
11
- from tesorotools.offsets.outliers import flag_outliers
12
- from tesorotools.utils.globals import DEBUG
13
- from tesorotools.utils.matplotlib import (
14
- PLOT_CONFIG,
15
- format_annotation,
16
- load_fonts,
17
- )
18
-
19
- BARH_CONFIG: dict[str, Any] = PLOT_CONFIG["barh"]
20
- AX_CONFIG: dict[str, Any] = PLOT_CONFIG["ax"]
21
- FIG_CONFIG: dict[str, Any] = PLOT_CONFIG["figure"]
22
-
23
- load_fonts()
24
-
25
-
26
- class Column(Enum):
27
- VALUE = "value"
28
- AXIS = "axis"
29
- DEVIATION = "deviation"
30
- COLOR = "color"
31
- ALPHA = "alpha"
32
-
33
-
34
- def _style_spines(
35
- ax: plt.Axes,
36
- decimals: int,
37
- units: str,
38
- *,
39
- color: str,
40
- linewidth: str,
41
- ):
42
- ax.grid(visible=True, axis="x")
43
- for spine in ax.spines.values():
44
- spine.set_color(color)
45
- spine.set_linewidth(linewidth)
46
- ax.xaxis.set_major_formatter(
47
- FuncFormatter(lambda x, _: format_annotation(x, decimals, units))
48
- )
49
- ax.tick_params(axis="both", which="major")
50
- for tick in ax.get_xticklines():
51
- tick.set_markeredgecolor(color)
52
- for tick in ax.get_yticklines():
53
- tick.set_markeredgecolor(color)
54
-
55
-
56
- def _style_baseline(ax: plt.Axes, **baseline_config):
57
- color: str = baseline_config["color"]
58
- left_lim, right_lim = ax.get_xlim()
59
- ax.set_xlim(left=min(0, left_lim), right=max(0, right_lim))
60
- left_lim, right_lim = ax.get_xlim()
61
- if left_lim == 0:
62
- ax.spines["left"].set_edgecolor(color)
63
- elif right_lim == 0:
64
- ax.spines["right"].set_edgecolor(color)
65
- else:
66
- ax.axvline(x=0, **baseline_config)
67
-
68
-
69
- def _collect_series(
70
- blocks: dict[str, Any] | None, series: dict[str, str] | None
71
- ) -> dict[str, str]:
72
- if series is None and blocks is None:
73
- raise ValueError("blocks and series cannot be both missing")
74
- if series is None and blocks is not None:
75
- return _collect_block_series(blocks)
76
- else:
77
- return series
78
-
79
-
80
- def _collect_block_series(blocks: dict[str, Any]) -> dict[str, str]:
81
- series = {}
82
- for _, block_cfg in blocks.items():
83
- series = series | block_cfg["series"]
84
- return series
85
-
86
-
87
- def _infer_colors(
88
- value_series: pd.Series, blocks: dict[str, Any] | None
89
- ) -> pd.Series:
90
- color_series: pd.Series = pd.Series(
91
- index=value_series.index, name=Column.COLOR.value, dtype=str
92
- )
93
- if blocks is not None:
94
- for idx, block_cfg in enumerate(blocks.values()):
95
- block_series: dict[str, str] = block_cfg["series"]
96
- color_series.loc[block_series.keys()] = f"C{idx}"
97
- else:
98
- color_series[value_series >= 0] = "C0"
99
- color_series[value_series < 0] = "C1"
100
- return color_series
101
-
102
-
103
- def _highlight_series(
104
- alias: dict[str, str], value_series: pd.Series
105
- ) -> pd.Series:
106
- alpha_series: pd.Series = pd.Series(
107
- index=value_series.index, name=Column.ALPHA.value
108
- )
109
- alpha_series.loc[:] = 1
110
- high_series = [k for k, v in alias.items() if v.endswith("*")]
111
- alpha_series.loc[high_series] = BARH_CONFIG["highlight_factor"]
112
- return alpha_series
113
-
114
-
115
- def _format_yaxis(
116
- alias: dict[str, str],
117
- axis_format: dict[str, Any],
118
- value_series: pd.Series,
119
- axis_series: pd.Series | None,
120
- ) -> pd.Series:
121
- # format y axis ticker labels
122
- renamer = {_: label.replace("*", "") for _, label in alias.items()}
123
- value_series = value_series.rename(renamer)
124
- if axis_format is not None:
125
- decimals: int = axis_format["decimals"]
126
- units: str = axis_format["units"]
127
- axis_series: pd.Series = axis_series.rename(renamer).apply(
128
- lambda x: format_annotation(x, decimals, units)
129
- )
130
- value_series = value_series.rename(
131
- lambda x: f"{x} ({axis_series.loc[x]})"
132
- )
133
- return value_series
134
-
135
-
136
- def _annotate(
137
- fig: plt.Figure,
138
- ax: plt.Axes,
139
- bar_container: BarContainer,
140
- *,
141
- decimals: int,
142
- units: str,
143
- ):
144
- # annotate
145
- labels = ax.bar_label(
146
- container=bar_container,
147
- fmt=lambda x: format_annotation(x, decimals, units),
148
- padding=BARH_CONFIG["padding"],
149
- )
150
-
151
- # rescale
152
- fig.canvas.draw_idle()
153
- for label in labels:
154
- bbox = label.get_window_extent()
155
- bbox_data = bbox.transformed(ax.transData.inverted())
156
- ax.update_datalim(bbox_data.corners())
157
- ax.autoscale_view()
158
-
159
-
160
- def _plot_barh_chart(
161
- out_file: Path,
162
- standard_dict: dict[Column, pd.Series | None],
163
- alias: dict[str, str],
164
- sorted: bool,
165
- format: dict,
166
- annot_format: dict,
167
- axis_format: dict | None = None,
168
- blocks: dict | None = None,
169
- **kwargs,
170
- ):
171
- # infer colors
172
- value_series: pd.Series = standard_dict[Column.VALUE]
173
- color_series: pd.Series = _infer_colors(value_series, blocks)
174
- alpha_series: pd.Series = _highlight_series(alias, value_series)
175
-
176
- # format y axis ticker labels
177
- axis_series = standard_dict[Column.AXIS]
178
- value_series = _format_yaxis(alias, axis_format, value_series, axis_series)
179
- color_series.index = value_series.index
180
- alpha_series.index = value_series.index
181
-
182
- data: pd.DataFrame = pd.concat(
183
- [value_series, color_series, alpha_series], axis=1
184
- )
185
-
186
- # sort if required
187
- if sorted:
188
- data = data.sort_values(by=Column.VALUE.value)
189
-
190
- # plot
191
- fig = plt.figure(**FIG_CONFIG)
192
- ax = fig.add_subplot()
193
-
194
- bar_container: BarContainer = ax.barh(
195
- y=data.index,
196
- width=data[Column.VALUE.value],
197
- color=data[Column.COLOR.value],
198
- )
199
- for bar, alpha in zip(bar_container, data[Column.ALPHA.value]):
200
- bar.set_alpha(alpha)
201
-
202
- _annotate(fig, ax, bar_container, **annot_format)
203
- _style_spines(ax, **format, **AX_CONFIG["spines"])
204
- _style_baseline(ax, **AX_CONFIG["baseline"])
205
-
206
- fig.savefig(out_file)
207
-
208
-
209
- def _normalize_from_flash(
210
- flash: pd.DataFrame,
211
- axis: bool,
212
- *,
213
- date: str | pd.Timestamp | None,
214
- offset: str,
215
- difference: str,
216
- deviations: bool,
217
- units_bar: str,
218
- units_axis: str,
219
- ) -> dict[Column, pd.Series | None]:
220
-
221
- # format parameters
222
- date: pd.Timestamp = (
223
- flash.index.get_level_values(level=0).max()
224
- if date is None
225
- else pd.to_datetime(date)
226
- )
227
- offset: FloatingOffset = FloatingOffset(offset)
228
- difference: Difference = Difference(difference)
229
-
230
- # value column
231
- values_series: pd.Series = flash.loc[
232
- (date, offset.value, difference.value, Stat.VALUE.value),
233
- :,
234
- ].copy()
235
- values_series.name = Column.VALUE.value
236
- values_series = (
237
- values_series * 100 if difference is Difference.REL else values_series
238
- )
239
- values_series = (
240
- values_series * 100
241
- if (difference is Difference.ABS and units_bar == "p.b.")
242
- else values_series
243
- )
244
-
245
- # axis column
246
- if axis:
247
- axis_series: pd.Series = flash.loc[
248
- (
249
- date,
250
- FloatingOffset.NO.value,
251
- Difference.NO.value,
252
- Stat.VALUE.value,
253
- ),
254
- :,
255
- ].copy()
256
- axis_series = (
257
- axis_series * 100
258
- if (difference is Difference.ABS and units_axis == "p.b.")
259
- else axis_series
260
- )
261
-
262
- axis_series.name = Column.AXIS.value
263
- else:
264
- axis_series = None
265
-
266
- # deviations column
267
- if deviations:
268
- deviations_df: pd.DataFrame = flash.loc[
269
- (
270
- date,
271
- offset.value,
272
- difference.value,
273
- [Stat.VALUE.value, Stat.ROLL_AVG.value, Stat.ROLL_STD._value_],
274
- ),
275
- :,
276
- ].T.copy()
277
- deviations_df.columns = deviations_df.columns.get_level_values(level=-1)
278
- deviations_df.columns.name = None
279
- deviations_series: pd.Series = flag_outliers(deviations_df)
280
- deviations_series.name = Column.DEVIATION.value
281
- else:
282
- deviations_series = None
283
-
284
- return {
285
- Column.VALUE: values_series,
286
- Column.AXIS: axis_series,
287
- Column.DEVIATION: deviations_series,
288
- }
289
-
290
-
291
- def plot_barh_charts_from_flash(
292
- flash: pd.DataFrame, config_dicts: dict[str, dict]
293
- ):
294
- for name, config in config_dicts.items():
295
- blocks: dict[str, Any] = config.get("blocks", None)
296
- series: dict[str, str] | None = config.get("series", None)
297
- alias = _collect_series(blocks, series)
298
- trimmed_flash: pd.DataFrame = flash.loc[:, alias.keys()]
299
- flash_config: dict[str, Any] = config["flash"]
300
- axis_format: dict[str, Any] = config.get("axis_format", None)
301
- axis = axis_format is not None
302
- standard_dict: dict[Column, pd.Series | None] = _normalize_from_flash(
303
- trimmed_flash,
304
- axis,
305
- **flash_config,
306
- units_bar=config["format"]["units"],
307
- units_axis=config.get("axis_format", {"units": ""})["units"],
308
- )
309
- out_file = Path(DEBUG / "barh" / f"{name}.png")
310
- _plot_barh_chart(out_file, standard_dict, alias, **config)
@@ -1,114 +0,0 @@
1
- import locale
2
- from pathlib import Path
3
- from typing import Any
4
-
5
- import matplotlib.pyplot as plt
6
- import pandas as pd
7
- from matplotlib.ticker import FuncFormatter
8
-
9
- locale.setlocale(locale.LC_ALL, "")
10
-
11
- from tesorotools.utils.globals import DEBUG
12
- from tesorotools.utils.matplotlib import (
13
- PLOT_CONFIG,
14
- format_annotation,
15
- load_fonts,
16
- )
17
-
18
- load_fonts()
19
-
20
- LINE_PLOT_CONFIG: dict[str, Any] = PLOT_CONFIG["line"]
21
- AX_CONFIG: dict[str, Any] = PLOT_CONFIG["ax"]
22
- FIG_CONFIG: dict[str, Any] = PLOT_CONFIG["figure"]
23
-
24
-
25
- def _style_spines(
26
- ax: plt.Axes,
27
- decimals: int,
28
- units: str,
29
- *,
30
- color: str,
31
- linewidth: str,
32
- ):
33
- ax.grid(visible=True, axis="y")
34
- for spine in ax.spines.values():
35
- spine.set_color(color)
36
- spine.set_linewidth(linewidth)
37
- ax.yaxis.tick_right()
38
- ax.yaxis.set_major_formatter(
39
- FuncFormatter(lambda y, _: format_annotation(y, decimals, units))
40
- )
41
- ax.set_xlabel("")
42
-
43
- ax.tick_params(which="minor", size=0, width=0)
44
- ax.tick_params(axis="both", which="major")
45
- for tick in ax.get_xticklines():
46
- tick.set_markeredgecolor(color)
47
- for tick in ax.get_yticklines():
48
- tick.set_markeredgecolor(color)
49
-
50
-
51
- def _style_baseline(ax: plt.Axes, reference: float = 0, **baseline_config):
52
- color: str = baseline_config["color"]
53
- bottom_lim, top_lim = ax.get_ylim()
54
- ax.set_ylim(bottom=min(reference, bottom_lim), top=max(reference, top_lim))
55
- bottom_lim, top_lim = ax.get_ylim()
56
- if bottom_lim == reference:
57
- ax.spines["bottom"].set_edgecolor(color)
58
- elif top_lim == reference:
59
- ax.spines["top"].set_edgecolor(color)
60
- else:
61
- ax.axhline(y=reference, **baseline_config)
62
-
63
-
64
- def plot_line_chart(
65
- out_name: Path,
66
- data: pd.DataFrame,
67
- *,
68
- base_100: bool,
69
- annotate: bool,
70
- format: dict[str, Any],
71
- **kwargs,
72
- ):
73
- if base_100:
74
- data = data / data.iloc[0, :] * 100
75
- if format["units"] == "p.b.":
76
- data = data * 100
77
- fig = plt.figure(**FIG_CONFIG)
78
- ax = fig.add_subplot()
79
- data.plot(ax=ax)
80
- if annotate:
81
- pass
82
-
83
- reference = 100 if base_100 else 0
84
- _style_spines(ax, **format, **AX_CONFIG["spines"])
85
- _style_baseline(ax, reference, **AX_CONFIG["baseline"])
86
- ax.legend(
87
- loc="upper center",
88
- bbox_to_anchor=(0.5, LINE_PLOT_CONFIG["legend_sep"]),
89
- ncol=(
90
- kwargs["legend"]["ncol"]
91
- if kwargs is not None and kwargs.get("legend", None) is not None
92
- else LINE_PLOT_CONFIG["ncol"]
93
- ),
94
- )
95
-
96
- fig.savefig(out_name)
97
-
98
-
99
- def plot_line_charts(data: pd.DataFrame, config_dicts: dict[str, Any]):
100
- for name, config in config_dicts.items():
101
- start_date: pd.Timestamp = pd.to_datetime(config["start_date"])
102
- end_date_str: str | None = config["end_date"]
103
- end_date: pd.Timestamp = (
104
- data.index.max()
105
- if end_date_str is None
106
- else pd.to_datetime(end_date_str)
107
- )
108
- series: dict[str, str] = config["series"]
109
- trimmed_data: pd.DataFrame = data.loc[
110
- slice(start_date, end_date), series.keys()
111
- ]
112
- trimmed_data = trimmed_data.rename(columns=series)
113
- out_name: Path = DEBUG / "line" / f"{name}.png"
114
- plot_line_chart(out_name, trimmed_data, **config)
@@ -1,199 +0,0 @@
1
- from math import floor
2
- from typing import Any
3
-
4
- import pandas as pd
5
-
6
- from tesorotools.dependencies.resolution import collect_series
7
- from tesorotools.offsets.outliers import flag_outliers
8
- from tesorotools.utils.globals import DEBUG
9
- from tesorotools.utils.matplotlib import format_annotation, is_zero
10
-
11
- # this file is by far the worst and most spaghettified, must be rewritten
12
-
13
- # to global config
14
- GOOD: str = "00c800"
15
- BAD: str = "c80000"
16
- THRESHOLD: float = 1
17
- SHADE_LEVELS = 2
18
-
19
-
20
- def _shade_intensity(
21
- ratio: float, shade_levels: int = 2, continuous: bool = False
22
- ) -> str:
23
- # intensity may vary from 150 (highest) to 255 (lowest), a grand difference of 105
24
- # there are SHADE_LEVELS levels, so increments will be of 105/SHADE_LEVELS
25
- corrected_ratio: float = min(ratio, shade_levels)
26
- corrected_ratio: float = (
27
- floor(corrected_ratio) if not continuous else corrected_ratio
28
- )
29
- increment: float = (corrected_ratio - 1) * (105 / shade_levels)
30
- intensity: float = 255 - increment
31
- intensity_hex: str = f"{int(intensity):x}"
32
- return intensity_hex
33
-
34
-
35
- def _generate_column(
36
- column_data: pd.Series,
37
- column_cfg: dict[str, Any],
38
- outliers_flags: pd.Series | None = None,
39
- ):
40
- # TODO: factor out
41
- # data
42
- if column_cfg["show_units_in_title"]:
43
- column_data.name = f"{column_cfg["name"]} ({column_cfg["unit"]})"
44
- else:
45
- column_data.name = column_cfg["name"]
46
- column_cfg["formatted_name"] = column_data.name
47
-
48
- unit = (
49
- column_cfg["unit"]
50
- if column_cfg["show_units_in_cell"] and column_cfg["unit"] is not None
51
- else ""
52
- )
53
- scaled_data: pd.Series = column_data * column_cfg["scale"]
54
- formatted_data = scaled_data.apply(
55
- lambda x: format_annotation(
56
- x, decimals=column_cfg["decimals"], units=unit
57
- )
58
- )
59
- zeros: pd.Series = scaled_data.apply(
60
- lambda x: is_zero(x, decimals=column_cfg["decimals"])
61
- )
62
- positives: pd.Series = scaled_data > 0
63
- negatives: pd.Series = scaled_data < 0
64
-
65
- # colors
66
- colors_cfg: bool = column_cfg["colors"]
67
- color_data: pd.Series = pd.Series(
68
- index=formatted_data.index, name=column_data.name, dtype=str
69
- )
70
- if colors_cfg:
71
- positive_good: bool = column_cfg["positive_good"]
72
- color_data[positives] = GOOD if positive_good else BAD
73
- color_data.loc[negatives] = BAD if positive_good else GOOD
74
- color_data.loc[zeros.values] = pd.NA
75
-
76
- # shades
77
- shade_data: pd.Series = pd.Series(
78
- index=formatted_data.index, name=column_data.name, dtype=str
79
- )
80
- if outliers_flags is not None:
81
- thresholds: pd.Series = abs(outliers_flags / THRESHOLD)
82
- intensities: pd.Series = thresholds.apply(
83
- lambda x: _shade_intensity(x, SHADE_LEVELS)
84
- )
85
- shade_data[(thresholds >= 1) & (outliers_flags > 0)] = intensities[
86
- (thresholds >= 1) & (outliers_flags > 0)
87
- ].apply(lambda x: f"00{x}00" if positive_good else f"{x}0000")
88
- shade_data[(thresholds >= 1) & (outliers_flags < 0)] = intensities[
89
- (thresholds >= 1) & (outliers_flags < 0)
90
- ].apply(lambda x: f"{x}0000" if positive_good else f"00{x}00")
91
-
92
- return formatted_data, color_data, shade_data
93
-
94
-
95
- def _generate_block(block_data: pd.DataFrame, block_cfg: dict[str, Any]):
96
- columns: dict[str, Any] = block_cfg["columns"]
97
- formatted_columns: list[pd.Series] = []
98
- color_columns: list[pd.Series] = []
99
- shade_columns: list[pd.Series] = []
100
- sort_idx: pd.Index | None = None
101
- for column_name, column_cfg in columns.items():
102
- last_date: pd.Timestamp = block_data.index.get_level_values(
103
- level=0
104
- ).max()
105
- block_data = block_data.rename(columns=block_cfg["series"])
106
- offset: str = column_cfg["offset"]
107
- difference: str = column_cfg["difference"]
108
- stat: str = column_cfg["stat"]
109
- outliers: bool = column_cfg["outliers"]
110
-
111
- stat_data = block_data.loc[
112
- (last_date, offset, difference, slice(None)), :
113
- ]
114
- stat_data.index = stat_data.index.get_level_values(level=-1)
115
-
116
- outliers_flags: pd.Series | None = None
117
- if outliers:
118
- outliers_flags = flag_outliers(stat_data.T)
119
-
120
- column_data: pd.Series = stat_data.loc[stat, :]
121
- # sort capability
122
- sort: str = block_cfg.get("sort", None)
123
- if sort is not None and column_name == sort:
124
- column_data: pd.Series = column_data.sort_values(ascending=False)
125
- sort_idx = column_data.index
126
- formatted_column, color_column, shade_column = _generate_column(
127
- column_data, column_cfg, outliers_flags
128
- )
129
- formatted_columns.append(formatted_column)
130
- color_columns.append(color_column)
131
- shade_columns.append(shade_column)
132
-
133
- if sort_idx is not None:
134
- formatted_columns = [s.reindex(sort_idx) for s in formatted_columns]
135
- color_columns = [s.reindex(sort_idx) for s in color_columns]
136
- shade_columns = [s.reindex(sort_idx) for s in shade_columns]
137
-
138
- formatted_block: pd.DataFrame = pd.concat(formatted_columns, axis=1)
139
- color_block: pd.DataFrame = pd.concat(color_columns, axis=1)
140
- shade_block: pd.DataFrame = pd.concat(shade_columns, axis=1)
141
-
142
- formatted_block.columns.name = block_cfg["title"]
143
- color_block.columns.name = block_cfg["title"]
144
- shade_block.columns.name = block_cfg["title"]
145
- return formatted_block, color_block, shade_block
146
-
147
-
148
- def generate_table(table_data: pd.DataFrame, table_cfg: dict[str, Any]):
149
- blocks: dict[str, dict] = table_cfg["blocks"]
150
- formatted_blocks: list[pd.DataFrame] = []
151
- color_blocks: list[pd.DataFrame] = []
152
- shade_blocks: list[pd.DataFrame] = []
153
- axis = 0 if table_cfg["axis"] == "vertical" else 1
154
- # sorting capabilities
155
- for block_name, block_cfg in blocks.items():
156
- series_dict: dict[str, str] = block_cfg["series"]
157
- block_data: pd.DataFrame = table_data.loc[:, series_dict.keys()]
158
- formatted_block, color_block, shade_block = _generate_block(
159
- block_data, block_cfg
160
- )
161
- formatted_blocks.append(formatted_block)
162
- color_blocks.append(color_block)
163
- shade_blocks.append(shade_block)
164
- formatted_table = pd.concat(
165
- formatted_blocks,
166
- axis=axis,
167
- keys=[
168
- formatted_block.columns.name for formatted_block in formatted_blocks
169
- ],
170
- )
171
- color_table = pd.concat(
172
- color_blocks,
173
- axis=axis,
174
- keys=[
175
- formatted_block.columns.name for formatted_block in formatted_blocks
176
- ],
177
- )
178
- shade_table = pd.concat(
179
- shade_blocks,
180
- axis=axis,
181
- keys=[
182
- formatted_block.columns.name for formatted_block in formatted_blocks
183
- ],
184
- )
185
- return formatted_table, color_table, shade_table
186
-
187
-
188
- def generate_tables_from_flash(
189
- flash: pd.DataFrame, config_dicts: dict[str, dict]
190
- ):
191
- for table_name, table_cfg in config_dicts.items():
192
- series: list[str] = list(collect_series(table_cfg))
193
- table_data: pd.DataFrame = flash.loc[:, series]
194
- formatted_table, color_table, shade_table = generate_table(
195
- table_data, table_cfg
196
- )
197
- formatted_table.to_feather(DEBUG / "table" / f"{table_name}.feather")
198
- color_table.to_feather(DEBUG / "table" / f"{table_name}_color.feather")
199
- shade_table.to_feather(DEBUG / "table" / f"{table_name}_shade.feather")