bidviz 1.0.0__py3-none-any.whl → 1.1.1__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.
bidviz/__init__.py CHANGED
@@ -3,6 +3,8 @@ BidViz - Backend Visualization Data Transformation Library
3
3
 
4
4
  A powerful, configurable backend visualization data transformation library designed to bridge
5
5
  the gap between raw data and frontend charting libraries.
6
+
7
+ Supports both pandas and Polars backends for high-performance data transformation.
6
8
  """
7
9
 
8
10
  __version__ = "1.0.0"
@@ -0,0 +1,51 @@
1
+ """
2
+ BidViz Polars - High-performance chart data transformation using Polars.
3
+
4
+ This module provides Polars-based transformers for converting Polars DataFrames
5
+ into JSON-serializable formats optimized for frontend charting libraries.
6
+
7
+ Polars offers superior performance compared to pandas, especially for larger datasets,
8
+ with lazy evaluation, parallel processing, and memory efficiency.
9
+
10
+ Main Classes:
11
+ ChartTransformer: Facade for all Polars-based chart transformations
12
+ TransformationError: Exception for transformation failures
13
+ ValidationError: Exception for validation failures
14
+
15
+ Example:
16
+ >>> import polars as pl
17
+ >>> from bidviz.polars import ChartTransformer
18
+ >>>
19
+ >>> transformer = ChartTransformer()
20
+ >>> df = pl.DataFrame({'vendor': ['A', 'B'], 'revenue': [100, 200]})
21
+ >>> result = transformer.transform_to_bar_chart(df, 'vendor', 'revenue')
22
+ """
23
+
24
+ from bidviz.exceptions import TransformationError, ValidationError
25
+ from bidviz.polars.transformer import ChartTransformer
26
+ from bidviz.polars.utils import (
27
+ clean_dataframe,
28
+ dataframe_to_dicts,
29
+ format_label,
30
+ get_numeric_columns,
31
+ paginate_dataframe,
32
+ safe_convert_to_numeric,
33
+ safe_get_value,
34
+ validate_columns,
35
+ )
36
+
37
+ __version__ = "1.0.0"
38
+
39
+ __all__ = [
40
+ "ChartTransformer",
41
+ "TransformationError",
42
+ "ValidationError",
43
+ "clean_dataframe",
44
+ "dataframe_to_dicts",
45
+ "format_label",
46
+ "get_numeric_columns",
47
+ "paginate_dataframe",
48
+ "safe_convert_to_numeric",
49
+ "safe_get_value",
50
+ "validate_columns",
51
+ ]
@@ -0,0 +1,5 @@
1
+ """Core base classes for Polars transformers."""
2
+
3
+ from bidviz.polars.core.base import BaseChartTransformer
4
+
5
+ __all__ = ["BaseChartTransformer"]
@@ -0,0 +1,43 @@
1
+ """Base transformer class for all Polars chart transformations."""
2
+
3
+ from typing import Any, Dict
4
+
5
+ import polars as pl
6
+
7
+
8
+ class BaseChartTransformer:
9
+ """
10
+ Base class for Polars chart transformers.
11
+
12
+ All specific chart transformers should inherit from this class
13
+ and implement the transform method.
14
+ """
15
+
16
+ def transform(self, df: pl.DataFrame, **kwargs: Any) -> Dict[str, Any]:
17
+ """
18
+ Transform a Polars DataFrame into chart-ready format.
19
+
20
+ Args:
21
+ df: Input Polars DataFrame
22
+ **kwargs: Additional transformation parameters
23
+
24
+ Returns:
25
+ Dictionary containing chart data and metadata
26
+
27
+ Raises:
28
+ NotImplementedError: If not implemented by subclass
29
+ """
30
+ raise NotImplementedError("Subclasses must implement transform method")
31
+
32
+ def _validate_dataframe(self, df: pl.DataFrame) -> None:
33
+ """
34
+ Validate that DataFrame is not None and has data.
35
+
36
+ Args:
37
+ df: Polars DataFrame to validate
38
+
39
+ Raises:
40
+ ValueError: If DataFrame is None
41
+ """
42
+ if df is None:
43
+ raise ValueError("DataFrame cannot be None")
@@ -0,0 +1,337 @@
1
+ """
2
+ Core chart transformation service for Polars - facade for all chart transformers.
3
+
4
+ This module provides high-performance data transformations using Polars,
5
+ offering significantly better performance than pandas for larger datasets.
6
+ """
7
+
8
+ from typing import Any, Dict, List, Optional
9
+
10
+ import polars as pl
11
+
12
+ from bidviz.polars.transformers import (
13
+ BarChartTransformer,
14
+ CorrelationHeatmapTransformer,
15
+ DataTableTransformer,
16
+ FunnelChartTransformer,
17
+ HeatmapTransformer,
18
+ KPICardsTransformer,
19
+ LineChartTransformer,
20
+ MultiLineChartTransformer,
21
+ PieChartTransformer,
22
+ StackedBarChartTransformer,
23
+ )
24
+
25
+
26
+ class ChartTransformer:
27
+ """
28
+ Main facade for transforming Polars DataFrames into chart-ready data structures.
29
+
30
+ This class provides a unified interface to all chart transformers,
31
+ converting raw Polars DataFrames into JSON-serializable formats optimized
32
+ for various charting libraries (Chart.js, D3, Plotly, Recharts, etc.).
33
+
34
+ Polars provides superior performance compared to pandas through:
35
+ - Lazy evaluation and query optimization
36
+ - Parallel execution on all available cores
37
+ - Memory-efficient columnar storage
38
+ - Zero-copy operations where possible
39
+
40
+ The actual transformation logic is delegated to specialized transformer
41
+ classes for maintainability and modularity.
42
+
43
+ Supported chart types:
44
+ - KPI Cards
45
+ - Bar Chart
46
+ - Line Chart
47
+ - Multi-Line Chart
48
+ - Pie Chart
49
+ - Heatmap
50
+ - Funnel Chart
51
+ - Stacked Bar Chart
52
+ - Data Table (with pagination)
53
+ - Correlation Heatmap
54
+
55
+ Examples:
56
+ >>> import polars as pl
57
+ >>> transformer = ChartTransformer()
58
+ >>> df = pl.DataFrame({'vendor': ['A', 'B'], 'revenue': [100, 200]})
59
+ >>> result = transformer.transform_to_bar_chart(df, 'vendor', 'revenue')
60
+ >>> result['chart_type']
61
+ 'bar_chart'
62
+ """
63
+
64
+ def __init__(self) -> None:
65
+ """Initialize the chart transformer with all specialized transformers."""
66
+ self._kpi_transformer = KPICardsTransformer()
67
+ self._bar_transformer = BarChartTransformer()
68
+ self._line_transformer = LineChartTransformer()
69
+ self._multi_line_transformer = MultiLineChartTransformer()
70
+ self._pie_transformer = PieChartTransformer()
71
+ self._heatmap_transformer = HeatmapTransformer()
72
+ self._funnel_transformer = FunnelChartTransformer()
73
+ self._stacked_bar_transformer = StackedBarChartTransformer()
74
+ self._table_transformer = DataTableTransformer()
75
+ self._correlation_transformer = CorrelationHeatmapTransformer()
76
+
77
+ def transform_to_kpi_cards(self, df: pl.DataFrame) -> Dict[str, Any]:
78
+ """
79
+ Transform a single-row Polars DataFrame into KPI cards for dashboard metrics.
80
+
81
+ Args:
82
+ df: Single-row Polars DataFrame containing metrics
83
+
84
+ Returns:
85
+ Dict with chart_type='kpi_cards' and list of card data
86
+
87
+ Raises:
88
+ TransformationError: If DataFrame has more than one row
89
+
90
+ Examples:
91
+ >>> df = pl.DataFrame({'total_orders': [150], 'revenue': [45000.50]})
92
+ >>> result = transformer.transform_to_kpi_cards(df)
93
+ >>> len(result['data'])
94
+ 2
95
+ """
96
+ return self._kpi_transformer.transform(df)
97
+
98
+ def transform_to_bar_chart(
99
+ self,
100
+ df: pl.DataFrame,
101
+ x_column: str,
102
+ y_column: str,
103
+ label_column: Optional[str] = None,
104
+ ) -> Dict[str, Any]:
105
+ """
106
+ Transform Polars DataFrame into bar chart data structure.
107
+
108
+ Args:
109
+ df: Polars DataFrame containing the data
110
+ x_column: Column name for x-axis (categorical)
111
+ y_column: Column name for y-axis (numeric)
112
+ label_column: Optional column for custom labels
113
+
114
+ Returns:
115
+ Dict with chart_type='bar_chart', data points, and axis labels
116
+
117
+ Examples:
118
+ >>> df = pl.DataFrame({'vendor': ['A', 'B'], 'revenue': [1000, 1500]})
119
+ >>> result = transformer.transform_to_bar_chart(df, 'vendor', 'revenue')
120
+ >>> result['chart_type']
121
+ 'bar_chart'
122
+ """
123
+ return self._bar_transformer.transform(df, x_column, y_column, label_column)
124
+
125
+ def transform_to_line_chart(
126
+ self,
127
+ df: pl.DataFrame,
128
+ x_column: str,
129
+ y_column: str,
130
+ series_name: Optional[str] = None,
131
+ ) -> Dict[str, Any]:
132
+ """
133
+ Transform Polars DataFrame into line chart data for time series or trends.
134
+
135
+ Args:
136
+ df: Polars DataFrame containing the data
137
+ x_column: Column name for x-axis
138
+ y_column: Column name for y-axis
139
+ series_name: Optional custom name for the data series
140
+
141
+ Returns:
142
+ Dict with chart_type='line_chart', data points, and labels
143
+
144
+ Examples:
145
+ >>> df = pl.DataFrame({
146
+ ... 'date': ['2024-01-01', '2024-01-02', '2024-01-03'],
147
+ ... 'orders': [10, 15, 12]
148
+ ... })
149
+ >>> result = transformer.transform_to_line_chart(df, 'date', 'orders')
150
+ >>> result['series_name']
151
+ 'Orders'
152
+ """
153
+ return self._line_transformer.transform(df, x_column, y_column, series_name)
154
+
155
+ def transform_to_multi_line_chart(
156
+ self,
157
+ df: pl.DataFrame,
158
+ x_column: str,
159
+ y_columns: List[str],
160
+ series_names: Optional[List[str]] = None,
161
+ ) -> Dict[str, Any]:
162
+ """
163
+ Transform Polars DataFrame into multi-line chart for comparing multiple series.
164
+
165
+ Args:
166
+ df: Polars DataFrame containing the data
167
+ x_column: Column name for x-axis
168
+ y_columns: List of column names for y-axis
169
+ series_names: Optional custom names for each series
170
+
171
+ Returns:
172
+ Dict with chart_type='multi_line_chart' and series data
173
+
174
+ Examples:
175
+ >>> df = pl.DataFrame({
176
+ ... 'date': ['2024-01-01', '2024-01-02'],
177
+ ... 'vendor_a': [10, 15],
178
+ ... 'vendor_b': [12, 18]
179
+ ... })
180
+ >>> result = transformer.transform_to_multi_line_chart(
181
+ ... df, 'date', ['vendor_a', 'vendor_b'])
182
+ >>> len(result['series'])
183
+ 2
184
+ """
185
+ return self._multi_line_transformer.transform(df, x_column, y_columns, series_names)
186
+
187
+ def transform_to_pie_chart(
188
+ self, df: pl.DataFrame, label_column: str, value_column: str
189
+ ) -> Dict[str, Any]:
190
+ """
191
+ Transform Polars DataFrame into pie chart data for part-to-whole relationships.
192
+
193
+ Args:
194
+ df: Polars DataFrame containing the data
195
+ label_column: Column name for slice labels
196
+ value_column: Column name for slice values
197
+
198
+ Returns:
199
+ Dict with chart_type='pie_chart' and data points
200
+
201
+ Examples:
202
+ >>> df = pl.DataFrame({'category': ['A', 'B'], 'sales': [45000, 32000]})
203
+ >>> result = transformer.transform_to_pie_chart(df, 'category', 'sales')
204
+ >>> len(result['data'])
205
+ 2
206
+ """
207
+ return self._pie_transformer.transform(df, label_column, value_column)
208
+
209
+ def transform_to_heatmap(
210
+ self, df: pl.DataFrame, x_column: str, y_column: str, value_column: str
211
+ ) -> Dict[str, Any]:
212
+ """
213
+ Transform Polars DataFrame into heatmap data for 2D intensity visualization.
214
+
215
+ Args:
216
+ df: Polars DataFrame containing the data
217
+ x_column: Column name for x-axis
218
+ y_column: Column name for y-axis
219
+ value_column: Column name for cell values
220
+
221
+ Returns:
222
+ Dict with chart_type='heatmap', data points, and labels
223
+
224
+ Examples:
225
+ >>> df = pl.DataFrame({
226
+ ... 'hour': [0, 1],
227
+ ... 'day': ['Mon', 'Mon'],
228
+ ... 'count': [12, 8]
229
+ ... })
230
+ >>> result = transformer.transform_to_heatmap(df, 'hour', 'day', 'count')
231
+ >>> result['chart_type']
232
+ 'heatmap'
233
+ """
234
+ return self._heatmap_transformer.transform(df, x_column, y_column, value_column)
235
+
236
+ def transform_to_funnel_chart(
237
+ self, df: pl.DataFrame, stage_column: str, value_column: str
238
+ ) -> Dict[str, Any]:
239
+ """
240
+ Transform Polars DataFrame into funnel chart data for conversion pipelines.
241
+
242
+ Args:
243
+ df: Polars DataFrame containing the data
244
+ stage_column: Column name for funnel stages
245
+ value_column: Column name for stage values
246
+
247
+ Returns:
248
+ Dict with chart_type='funnel_chart' and data points
249
+
250
+ Examples:
251
+ >>> df = pl.DataFrame({
252
+ ... 'stage': ['Visits', 'Sign-ups'],
253
+ ... 'count': [1000, 300]
254
+ ... })
255
+ >>> result = transformer.transform_to_funnel_chart(df, 'stage', 'count')
256
+ >>> len(result['data'])
257
+ 2
258
+ """
259
+ return self._funnel_transformer.transform(df, stage_column, value_column)
260
+
261
+ def transform_to_stacked_bar_chart(
262
+ self,
263
+ df: pl.DataFrame,
264
+ x_column: str,
265
+ y_columns: List[str],
266
+ category_names: Optional[List[str]] = None,
267
+ ) -> Dict[str, Any]:
268
+ """
269
+ Transform Polars DataFrame into stacked bar chart for composed comparisons.
270
+
271
+ Args:
272
+ df: Polars DataFrame containing the data
273
+ x_column: Column name for x-axis
274
+ y_columns: List of column names for stacked values
275
+ category_names: Optional custom names for each stack
276
+
277
+ Returns:
278
+ Dict with chart_type='stacked_bar_chart' and data
279
+
280
+ Examples:
281
+ >>> df = pl.DataFrame({
282
+ ... 'month': ['Jan', 'Feb'],
283
+ ... 'product_a': [100, 150],
284
+ ... 'product_b': [200, 180]
285
+ ... })
286
+ >>> result = transformer.transform_to_stacked_bar_chart(
287
+ ... df, 'month', ['product_a', 'product_b'])
288
+ >>> len(result['categories'])
289
+ 2
290
+ """
291
+ return self._stacked_bar_transformer.transform(df, x_column, y_columns, category_names)
292
+
293
+ def transform_to_data_table(
294
+ self, df: pl.DataFrame, page: int = 1, page_size: int = 50
295
+ ) -> Dict[str, Any]:
296
+ """
297
+ Transform Polars DataFrame into paginated data table structure.
298
+
299
+ Args:
300
+ df: Polars DataFrame containing the data
301
+ page: Page number (1-indexed)
302
+ page_size: Number of rows per page
303
+
304
+ Returns:
305
+ Dict with chart_type='data_table', columns, rows, and pagination
306
+
307
+ Examples:
308
+ >>> df = pl.DataFrame({'id': [1, 2, 3], 'name': ['A', 'B', 'C']})
309
+ >>> result = transformer.transform_to_data_table(df, page=1, page_size=2)
310
+ >>> len(result['rows'])
311
+ 2
312
+ """
313
+ return self._table_transformer.transform(df, page, page_size)
314
+
315
+ def transform_to_correlation_heatmap(
316
+ self, df: pl.DataFrame, metrics: Optional[List[str]] = None
317
+ ) -> Dict[str, Any]:
318
+ """
319
+ Transform Polars DataFrame into correlation heatmap for statistical analysis.
320
+
321
+ Args:
322
+ df: Polars DataFrame containing numeric columns
323
+ metrics: Optional list of column names to correlate
324
+
325
+ Returns:
326
+ Dict with chart_type='heatmap' and correlation data
327
+
328
+ Examples:
329
+ >>> df = pl.DataFrame({
330
+ ... 'revenue': [100, 200, 150],
331
+ ... 'orders': [10, 20, 15]
332
+ ... })
333
+ >>> result = transformer.transform_to_correlation_heatmap(df)
334
+ >>> result['chart_type']
335
+ 'heatmap'
336
+ """
337
+ return self._correlation_transformer.transform(df, metrics)
@@ -0,0 +1,31 @@
1
+ """Chart transformers for Polars DataFrames."""
2
+
3
+ from bidviz.polars.transformers.bar import BarChartTransformer
4
+ from bidviz.polars.transformers.heatmap import (
5
+ CorrelationHeatmapTransformer,
6
+ HeatmapTransformer,
7
+ )
8
+ from bidviz.polars.transformers.kpi import KPICardsTransformer
9
+ from bidviz.polars.transformers.line import (
10
+ LineChartTransformer,
11
+ MultiLineChartTransformer,
12
+ )
13
+ from bidviz.polars.transformers.pie import PieChartTransformer
14
+ from bidviz.polars.transformers.table import DataTableTransformer
15
+ from bidviz.polars.transformers.other import (
16
+ FunnelChartTransformer,
17
+ StackedBarChartTransformer,
18
+ )
19
+
20
+ __all__ = [
21
+ "BarChartTransformer",
22
+ "LineChartTransformer",
23
+ "MultiLineChartTransformer",
24
+ "PieChartTransformer",
25
+ "KPICardsTransformer",
26
+ "HeatmapTransformer",
27
+ "CorrelationHeatmapTransformer",
28
+ "FunnelChartTransformer",
29
+ "StackedBarChartTransformer",
30
+ "DataTableTransformer",
31
+ ]
@@ -0,0 +1,68 @@
1
+ """Bar chart transformer for Polars DataFrames."""
2
+
3
+ from typing import Any, Dict, Optional
4
+
5
+ import polars as pl
6
+
7
+ from bidviz.exceptions import TransformationError
8
+ from bidviz.polars.core.base import BaseChartTransformer
9
+ from bidviz.polars.utils import format_label, safe_get_value, validate_columns
10
+
11
+
12
+ class BarChartTransformer(BaseChartTransformer):
13
+ """Transform Polars DataFrame into bar chart data."""
14
+
15
+ def transform(
16
+ self,
17
+ df: pl.DataFrame,
18
+ x_column: str,
19
+ y_column: str,
20
+ label_column: Optional[str] = None,
21
+ ) -> Dict[str, Any]:
22
+ """
23
+ Transform Polars DataFrame into bar chart data structure.
24
+
25
+ Args:
26
+ df: Polars DataFrame containing the data
27
+ x_column: Column name for x-axis (categorical)
28
+ y_column: Column name for y-axis (numeric)
29
+ label_column: Optional column for custom labels
30
+
31
+ Returns:
32
+ Dict with chart_type='bar_chart', data points, and axis labels
33
+
34
+ Raises:
35
+ TransformationError: If required columns are missing
36
+ """
37
+ try:
38
+ validate_columns(df, [x_column, y_column])
39
+ if label_column:
40
+ validate_columns(df, [label_column])
41
+ else:
42
+ label_column = x_column
43
+
44
+ data = []
45
+ for row in df.iter_rows(named=True):
46
+ data.append(
47
+ {
48
+ "x": str(safe_get_value(row[x_column])),
49
+ "y": safe_get_value(row[y_column]),
50
+ "label": str(safe_get_value(row[label_column])),
51
+ }
52
+ )
53
+
54
+ return {
55
+ "chart_type": "bar_chart",
56
+ "data": data,
57
+ "x_label": format_label(x_column),
58
+ "y_label": format_label(y_column),
59
+ }
60
+
61
+ except ValueError as e:
62
+ raise TransformationError(str(e), chart_type="bar_chart", df_shape=df.shape)
63
+ except Exception as e:
64
+ raise TransformationError(
65
+ f"Failed to transform bar chart: {str(e)}",
66
+ chart_type="bar_chart",
67
+ df_shape=df.shape,
68
+ )
@@ -0,0 +1,120 @@
1
+ """Heatmap transformers for Polars DataFrames."""
2
+
3
+ from typing import Any, Dict, List, Optional
4
+
5
+ import polars as pl
6
+
7
+ from bidviz.exceptions import TransformationError
8
+ from bidviz.polars.core.base import BaseChartTransformer
9
+ from bidviz.polars.utils import format_label, get_numeric_columns, safe_get_value, validate_columns
10
+
11
+
12
+ class HeatmapTransformer(BaseChartTransformer):
13
+ """Transform Polars DataFrame into heatmap data."""
14
+
15
+ def transform(
16
+ self, df: pl.DataFrame, x_column: str, y_column: str, value_column: str
17
+ ) -> Dict[str, Any]:
18
+ """
19
+ Transform Polars DataFrame into heatmap data for 2D intensity visualization.
20
+
21
+ Args:
22
+ df: Polars DataFrame containing the data
23
+ x_column: Column name for x-axis
24
+ y_column: Column name for y-axis
25
+ value_column: Column name for cell values
26
+
27
+ Returns:
28
+ Dict with chart_type='heatmap', data points, and labels
29
+ """
30
+ try:
31
+ validate_columns(df, [x_column, y_column, value_column])
32
+
33
+ data = []
34
+ for row in df.iter_rows(named=True):
35
+ data.append(
36
+ {
37
+ "x": str(safe_get_value(row[x_column])),
38
+ "y": str(safe_get_value(row[y_column])),
39
+ "value": safe_get_value(row[value_column]),
40
+ }
41
+ )
42
+
43
+ return {
44
+ "chart_type": "heatmap",
45
+ "data": data,
46
+ "x_label": format_label(x_column),
47
+ "y_label": format_label(y_column),
48
+ "value_label": format_label(value_column),
49
+ }
50
+
51
+ except ValueError as e:
52
+ raise TransformationError(str(e), chart_type="heatmap", df_shape=df.shape)
53
+ except Exception as e:
54
+ raise TransformationError(
55
+ f"Failed to transform heatmap: {str(e)}",
56
+ chart_type="heatmap",
57
+ df_shape=df.shape,
58
+ )
59
+
60
+
61
+ class CorrelationHeatmapTransformer(BaseChartTransformer):
62
+ """Transform Polars DataFrame into correlation heatmap."""
63
+
64
+ def transform(self, df: pl.DataFrame, metrics: Optional[List[str]] = None) -> Dict[str, Any]:
65
+ """
66
+ Transform Polars DataFrame into correlation heatmap for statistical analysis.
67
+
68
+ Args:
69
+ df: Polars DataFrame containing numeric columns
70
+ metrics: Optional list of column names to correlate
71
+
72
+ Returns:
73
+ Dict with chart_type='heatmap' and correlation data
74
+ """
75
+ try:
76
+ if metrics is None:
77
+ metrics = get_numeric_columns(df)
78
+
79
+ if len(metrics) < 2:
80
+ raise TransformationError(
81
+ "Need at least 2 numeric columns for correlation",
82
+ chart_type="correlation_heatmap",
83
+ df_shape=df.shape,
84
+ )
85
+
86
+ validate_columns(df, metrics)
87
+
88
+ # Polars uses corr() method on DataFrame
89
+ corr_matrix = df.select(metrics).corr()
90
+
91
+ data = []
92
+ for i, x_metric in enumerate(metrics):
93
+ for j, y_metric in enumerate(metrics):
94
+ # Access correlation value from the matrix
95
+ value = corr_matrix.row(j)[i]
96
+ data.append(
97
+ {
98
+ "x": x_metric,
99
+ "y": y_metric,
100
+ "value": safe_get_value(value),
101
+ }
102
+ )
103
+
104
+ return {
105
+ "chart_type": "heatmap",
106
+ "data": data,
107
+ "metrics": metrics,
108
+ "x_label": "Metrics",
109
+ "y_label": "Metrics",
110
+ "value_label": "Correlation Coefficient",
111
+ }
112
+
113
+ except ValueError as e:
114
+ raise TransformationError(str(e), chart_type="correlation_heatmap", df_shape=df.shape)
115
+ except Exception as e:
116
+ raise TransformationError(
117
+ f"Failed to transform correlation heatmap: {str(e)}",
118
+ chart_type="correlation_heatmap",
119
+ df_shape=df.shape,
120
+ )