Skip to content

Commit 7b2f5bd

Browse files
feat(letsplot): implement facet-grid (#6521)
## Implementation: `facet-grid` - python/letsplot Implements the **python/letsplot** version of `facet-grid`. **File:** `plots/facet-grid/implementations/python/letsplot.py` **Parent Issue:** #2696 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/anyplot/actions/runs/25776658361)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Markus Neusinger <2921697+MarkusNeusinger@users.noreply.github.com>
1 parent a4c5118 commit 7b2f5bd

2 files changed

Lines changed: 210 additions & 154 deletions

File tree

Lines changed: 56 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
1-
""" pyplots.ai
1+
""" anyplot.ai
22
facet-grid: Faceted Grid Plot
3-
Library: letsplot 4.8.2 | Python 3.13.11
4-
Quality: 91/100 | Created: 2025-12-30
3+
Library: letsplot 4.9.0 | Python 3.13.13
4+
Quality: 95/100 | Updated: 2026-05-13
55
"""
66

7+
import os
8+
79
import numpy as np
810
import pandas as pd
911
from lets_plot import (
1012
LetsPlot,
1113
aes,
14+
element_blank,
15+
element_line,
16+
element_rect,
1217
element_text,
1318
facet_grid,
1419
geom_point,
@@ -25,50 +30,76 @@
2530

2631
LetsPlot.setup_html()
2732

28-
# Data - create dataset with two categorical faceting variables
33+
# Theme tokens (see prompts/default-style-guide.md "Background" + "Theme-adaptive Chrome")
34+
THEME = os.getenv("ANYPLOT_THEME", "light")
35+
PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17"
36+
ELEVATED_BG = "#FFFDF6" if THEME == "light" else "#242420"
37+
INK = "#1A1A17" if THEME == "light" else "#F0EFE8"
38+
INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0"
39+
RULE = "rgba(26,26,23,0.10)" if THEME == "light" else "rgba(240,239,232,0.10)"
40+
41+
# Okabe-Ito palette (categorical)
42+
OKABE_ITO = ["#009E73", "#D55E00", "#0072B2"]
43+
44+
# Data - sales analysis by category and region
2945
np.random.seed(42)
3046

31-
# Product categories and regions for a sales analysis scenario
3247
categories = ["Electronics", "Clothing", "Home"]
3348
regions = ["North", "South", "East", "West"]
3449

35-
data = []
50+
# Generate all combinations of categories and regions
51+
category_list = []
52+
region_list = []
53+
price_list = []
54+
units_list = []
55+
3656
for cat in categories:
3757
for region in regions:
3858
n_points = 25
39-
# Base relationship varies by category and region
4059
base_price = {"Electronics": 200, "Clothing": 50, "Home": 100}[cat]
4160
region_factor = {"North": 1.2, "South": 0.9, "East": 1.0, "West": 1.1}[region]
4261

4362
price = np.random.uniform(base_price * 0.5, base_price * 1.5, n_points)
44-
# Sales units inversely related to price with some noise
4563
units = (base_price * 100 / price) * region_factor + np.random.randn(n_points) * 10
64+
units = np.maximum(units, 0)
65+
66+
category_list.extend([cat] * n_points)
67+
region_list.extend([region] * n_points)
68+
price_list.extend(price)
69+
units_list.extend(units)
4670

47-
for p, u in zip(price, units, strict=True):
48-
data.append({"Category": cat, "Region": region, "Price": p, "Units Sold": max(0, u)})
71+
df = pd.DataFrame({"Category": category_list, "Region": region_list, "Price": price_list, "Units Sold": units_list})
4972

50-
df = pd.DataFrame(data)
73+
# Theme-adaptive styling
74+
anyplot_theme = theme(
75+
plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG),
76+
panel_background=element_rect(fill=PAGE_BG, color=PAGE_BG),
77+
panel_grid_major=element_line(color=RULE, size=0.3),
78+
panel_grid_minor=element_blank(),
79+
axis_title=element_text(color=INK, size=20),
80+
axis_text=element_text(color=INK_SOFT, size=16),
81+
axis_line=element_line(color=INK_SOFT, size=0.5),
82+
plot_title=element_text(color=INK, size=24),
83+
legend_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),
84+
legend_text=element_text(color=INK_SOFT, size=16),
85+
legend_title=element_text(color=INK, size=18),
86+
strip_text=element_text(color=INK, size=16),
87+
strip_background=element_rect(fill=ELEVATED_BG, color=INK_SOFT),
88+
)
5189

52-
# Plot - faceted grid with scatter and smooth trend
90+
# Plot
5391
plot = (
5492
ggplot(df, aes(x="Price", y="Units Sold", color="Category"))
5593
+ geom_point(size=3, alpha=0.7)
5694
+ geom_smooth(method="lm", se=False, size=1.5)
5795
+ facet_grid(x="Region", y="Category")
58-
+ scale_color_manual(values=["#306998", "#FFD43B", "#DC2626"])
59-
+ labs(title="facet-grid \u00b7 letsplot \u00b7 pyplots.ai", x="Unit Price ($)", y="Units Sold")
96+
+ scale_color_manual(values=OKABE_ITO)
97+
+ labs(title="facet-grid · letsplot · anyplot.ai", x="Unit Price ($)", y="Units Sold")
6098
+ theme_minimal()
61-
+ theme(
62-
plot_title=element_text(size=24),
63-
axis_title=element_text(size=20),
64-
axis_text=element_text(size=14),
65-
legend_text=element_text(size=16),
66-
legend_title=element_text(size=18),
67-
strip_text=element_text(size=16),
68-
)
99+
+ anyplot_theme
69100
+ ggsize(1600, 900)
70101
)
71102

72-
# Save PNG and HTML
73-
ggsave(plot, "plot.png", path=".", scale=3)
74-
ggsave(plot, "plot.html", path=".")
103+
# Save PNG and HTML with theme-suffixed names
104+
ggsave(plot, f"plot-{THEME}.png", path=".", scale=3)
105+
ggsave(plot, f"plot-{THEME}.html", path=".")

0 commit comments

Comments
 (0)