|
1 | | -""" pyplots.ai |
| 1 | +""" anyplot.ai |
2 | 2 | rug-basic: Basic Rug Plot |
3 | | -Library: pygal 3.1.0 | Python 3.13.11 |
4 | | -Quality: 85/100 | Created: 2025-12-23 |
| 3 | +Library: pygal 3.1.0 | Python 3.13.13 |
| 4 | +Quality: 81/100 | Updated: 2026-04-30 |
5 | 5 | """ |
6 | 6 |
|
| 7 | +import os |
| 8 | +import sys |
| 9 | + |
7 | 10 | import numpy as np |
8 | | -import pygal |
9 | | -from pygal.style import Style |
10 | 11 |
|
11 | 12 |
|
12 | | -# Data - Response times (in milliseconds) showing realistic clustering patterns |
| 13 | +# Pop script directory so local pygal.py doesn't shadow the installed package |
| 14 | +_script_dir = sys.path.pop(0) |
| 15 | +import pygal # noqa: E402 |
| 16 | +from pygal.style import Style # noqa: E402 |
| 17 | + |
| 18 | + |
| 19 | +sys.path.insert(0, _script_dir) |
| 20 | + |
| 21 | +# Theme tokens |
| 22 | +THEME = os.getenv("ANYPLOT_THEME", "light") |
| 23 | +PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17" |
| 24 | +INK = "#1A1A17" if THEME == "light" else "#F0EFE8" |
| 25 | +INK_MUTED = "#6B6A63" if THEME == "light" else "#A8A79F" |
| 26 | +BRAND = "#009E73" # Okabe-Ito position 1 |
| 27 | + |
| 28 | +# Data - API response times (ms) with realistic multi-modal distribution |
13 | 29 | np.random.seed(42) |
14 | 30 | values = np.concatenate( |
15 | 31 | [ |
16 | | - np.random.normal(150, 20, 60), # Main cluster of typical responses |
17 | | - np.random.normal(250, 30, 25), # Slower responses |
18 | | - np.random.normal(400, 15, 10), # Occasional outliers |
19 | | - np.random.uniform(50, 100, 5), # Very fast responses |
| 32 | + np.random.normal(150, 20, 60), # Typical fast responses |
| 33 | + np.random.normal(250, 30, 25), # Medium responses |
| 34 | + np.random.normal(400, 15, 10), # Slow outlier cluster |
| 35 | + np.random.uniform(50, 100, 5), # Very fast cache hits |
20 | 36 | ] |
21 | 37 | ) |
22 | | -values = np.clip(values, 30, 500) # Realistic bounds |
23 | | -values = np.sort(values) # Sort for better visual ordering |
| 38 | +values = np.clip(values, 30, 500) |
| 39 | +values = np.sort(values) |
24 | 40 |
|
25 | | -# Custom style - keep text readable, minimize distracting elements |
| 41 | +# Style - single color so all rug ticks share brand green |
26 | 42 | custom_style = Style( |
27 | | - background="white", |
28 | | - plot_background="white", |
29 | | - foreground="#333333", |
30 | | - foreground_strong="#333333", |
31 | | - foreground_subtle="#666666", |
32 | | - colors=("#306998",), # Python Blue |
33 | | - title_font_size=72, |
34 | | - label_font_size=48, |
35 | | - major_label_font_size=42, |
36 | | - legend_font_size=42, |
37 | | - value_font_size=36, |
38 | | - opacity=0.85, |
39 | | - opacity_hover=1.0, |
40 | | - tooltip_font_size=36, |
| 43 | + background=PAGE_BG, |
| 44 | + plot_background=PAGE_BG, |
| 45 | + foreground=INK, |
| 46 | + foreground_strong=INK, |
| 47 | + foreground_subtle=INK_MUTED, |
| 48 | + colors=(BRAND,), # All ticks cycle through brand green only |
| 49 | + title_font_size=28, |
| 50 | + label_font_size=22, |
| 51 | + major_label_font_size=18, |
| 52 | + legend_font_size=16, |
| 53 | + value_font_size=14, |
| 54 | + stroke_width=8, |
| 55 | + opacity=0.7, |
41 | 56 | ) |
42 | 57 |
|
43 | | -# Create XY chart for rug plot visualization |
| 58 | +# Plot - XY chart used as rug plot |
44 | 59 | chart = pygal.XY( |
45 | 60 | width=4800, |
46 | 61 | height=2700, |
47 | 62 | style=custom_style, |
48 | | - title="rug-basic · pygal · pyplots.ai", |
| 63 | + title="rug-basic · pygal · anyplot.ai", |
49 | 64 | x_title="Response Time (ms)", |
50 | 65 | y_title=None, |
51 | 66 | show_legend=False, |
52 | 67 | show_dots=False, |
53 | 68 | stroke=True, |
54 | | - stroke_style={"width": 10}, |
55 | 69 | show_x_guides=False, |
56 | 70 | show_y_guides=False, |
57 | 71 | show_y_labels=False, |
58 | 72 | print_values=False, |
59 | 73 | explicit_size=True, |
60 | | - margin=80, |
61 | | - margin_top=180, |
62 | | - margin_bottom=280, |
63 | | - margin_left=80, |
64 | | - margin_right=80, |
65 | | - tooltip_border_radius=10, |
66 | | - xrange=(30, 450), |
67 | | - range=(0, 1), |
| 74 | + margin=100, |
| 75 | + margin_top=220, |
| 76 | + margin_bottom=300, |
| 77 | + xrange=(30, 520), |
| 78 | + range=(0, 0.2), |
68 | 79 | ) |
69 | 80 |
|
70 | | -# Rug ticks - uniform height filling 90% of vertical canvas |
71 | | -tick_bottom = 0.05 |
72 | | -tick_top = 0.95 |
| 81 | +# Rug ticks - short vertical marks along the x-axis |
| 82 | +tick_bottom = 0.0 |
| 83 | +tick_top = 0.15 |
73 | 84 |
|
74 | | -# Add rug ticks with interactive tooltips showing exact values |
75 | 85 | for val in values: |
76 | | - x = float(val) |
77 | | - chart.add(f"{val:.1f} ms", [(x, tick_bottom), (x, tick_top)], stroke_style={"width": 10}, show_dots=False) |
| 86 | + chart.add( |
| 87 | + f"{val:.1f} ms", [(float(val), tick_bottom), (float(val), tick_top)], stroke_style={"width": 8}, show_dots=False |
| 88 | + ) |
78 | 89 |
|
79 | | -# Save outputs - HTML preserves pygal's SVG interactivity with hover tooltips |
80 | | -chart.render_to_png("plot.png") |
81 | | -chart.render_to_file("plot.html") |
| 90 | +# Save |
| 91 | +chart.render_to_png(f"plot-{THEME}.png") |
| 92 | +with open(f"plot-{THEME}.html", "wb") as f: |
| 93 | + f.write(chart.render()) |
0 commit comments