Spaces:
Sleeping
Sleeping
Download backend/visual_notebook/viz/boxplot.py from Sid-WC121/visual-notebook: direct link, hf CLI and curl.
- Browser
- Download file 3.5 kB
-
https://huggingface.co/spaces/Sid-WC121/visual-notebook/resolve/main/backend/visual_notebook/viz/boxplot.py
- Command line
-
hf download hf://spaces/Sid-WC121/visual-notebook/backend/visual_notebook/viz/boxplot.py
-
curl -L -o boxplot.py https://huggingface.co/spaces/Sid-WC121/visual-notebook/resolve/main/backend/visual_notebook/viz/boxplot.py
3.5 kB
| """Boxplot chart generation.""" | |
| from __future__ import annotations | |
| from typing import Any | |
| import duckdb | |
| from visual_notebook.viz._common import ( | |
| PALETTE, axis_style, base_chart, title, tooltip_style, | |
| ) | |
| def compute_boxplot( | |
| con: duckdb.DuckDBPyConnection, | |
| table_name: str, | |
| column: str, | |
| group_col: str | None = None, | |
| ) -> dict[str, Any]: | |
| """Compute boxplot data and return ECharts spec.""" | |
| if group_col: | |
| # Get unique groups | |
| groups = con.execute(f""" | |
| SELECT DISTINCT "{group_col}" as grp | |
| FROM "{table_name}" | |
| WHERE "{column}" IS NOT NULL AND "{group_col}" IS NOT NULL | |
| ORDER BY grp | |
| """).fetchall() | |
| group_names = [] | |
| box_data = [] | |
| for row in groups: | |
| grp = row[0] | |
| stats = con.execute(f""" | |
| SELECT | |
| MIN("{column}") as min_val, | |
| PERCENTILE_CONT(0.25) WITHIN GROUP (ORDER BY "{column}") as q25, | |
| PERCENTILE_CONT(0.50) WITHIN GROUP (ORDER BY "{column}") as q50, | |
| PERCENTILE_CONT(0.75) WITHIN GROUP (ORDER BY "{column}") as q75, | |
| MAX("{column}") as max_val | |
| FROM "{table_name}" | |
| WHERE "{column}" IS NOT NULL AND "{group_col}" = {grp!r} | |
| """).fetchone() | |
| group_names.append(str(grp)) | |
| if stats and stats[1] is not None: | |
| min_v = float(stats[0]) | |
| q25_v = float(stats[1]) | |
| q50_v = float(stats[2]) | |
| q75_v = float(stats[3]) | |
| max_v = float(stats[4]) | |
| # Compute whiskers (1.5 * IQR) | |
| iqr = q75_v - q25_v | |
| lower_whisker = max(min_v, q25_v - 1.5 * iqr) | |
| upper_whisker = min(max_v, q75_v + 1.5 * iqr) | |
| box_data.append([lower_whisker, q25_v, q50_v, q75_v, upper_whisker]) | |
| else: | |
| box_data.append([0, 0, 0, 0, 0]) | |
| x_data = group_names | |
| label = f"Distribution of {column} by {group_col}" | |
| else: | |
| # Single boxplot for the column | |
| stats = con.execute(f""" | |
| SELECT | |
| MIN("{column}") as min_val, | |
| PERCENTILE_CONT(0.25) WITHIN GROUP (ORDER BY "{column}") as q25, | |
| PERCENTILE_CONT(0.50) WITHIN GROUP (ORDER BY "{column}") as q50, | |
| PERCENTILE_CONT(0.75) WITHIN GROUP (ORDER BY "{column}") as q75, | |
| MAX("{column}") as max_val | |
| FROM "{table_name}" | |
| WHERE "{column}" IS NOT NULL | |
| """).fetchone() | |
| min_v = float(stats[0]) | |
| q25_v = float(stats[1]) | |
| q50_v = float(stats[2]) | |
| q75_v = float(stats[3]) | |
| max_v = float(stats[4]) | |
| iqr = q75_v - q25_v | |
| lower_whisker = max(min_v, q25_v - 1.5 * iqr) | |
| upper_whisker = min(max_v, q75_v + 1.5 * iqr) | |
| x_data = [column] | |
| box_data = [[lower_whisker, q25_v, q50_v, q75_v, upper_whisker]] | |
| label = f"Distribution of {column}" | |
| chart = base_chart() | |
| chart["title"] = title(label) | |
| chart["tooltip"] = {**tooltip_style(), "trigger": "item"} | |
| chart["xAxis"] = {**axis_style(group_col or column), "type": "category", "data": x_data} | |
| chart["yAxis"] = {**axis_style(column), "type": "value"} | |
| chart["series"] = [{ | |
| "type": "boxplot", | |
| "data": box_data, | |
| "itemStyle": {"color": PALETTE[0], "borderColor": PALETTE[4]}, | |
| }] | |
| return chart | |