|
1 | | -""" pyplots.ai |
| 1 | +""" anyplot.ai |
2 | 2 | sudoku-basic: Basic Sudoku Grid |
3 | | -Library: plotnine 0.15.2 | Python 3.13.11 |
4 | | -Quality: 92/100 | Created: 2025-12-23 |
| 3 | +Library: plotnine 0.15.3 | Python 3.14.4 |
| 4 | +Quality: 89/100 | Updated: 2026-04-24 |
5 | 5 | """ |
6 | 6 |
|
| 7 | +import os |
| 8 | + |
7 | 9 | import pandas as pd |
8 | 10 | from plotnine import ( |
9 | 11 | aes, |
10 | 12 | coord_fixed, |
11 | | - element_blank, |
| 13 | + element_rect, |
12 | 14 | element_text, |
13 | 15 | geom_segment, |
14 | 16 | geom_text, |
|
20 | 22 | ) |
21 | 23 |
|
22 | 24 |
|
| 25 | +# Theme tokens |
| 26 | +THEME = os.getenv("ANYPLOT_THEME", "light") |
| 27 | +PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17" |
| 28 | +INK = "#1A1A17" if THEME == "light" else "#F0EFE8" |
| 29 | +INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0" |
| 30 | +INK_MUTED = "#6B6A63" if THEME == "light" else "#A8A79F" |
| 31 | + |
23 | 32 | # Data - A valid partially filled Sudoku puzzle |
24 | 33 | grid = [ |
25 | 34 | [5, 3, 0, 0, 7, 0, 0, 0, 0], |
|
33 | 42 | [0, 0, 0, 0, 8, 0, 0, 7, 9], |
34 | 43 | ] |
35 | 44 |
|
36 | | -# Convert grid to DataFrame for plotnine |
| 45 | +# Build cell number DataFrame |
37 | 46 | cells = [] |
38 | 47 | for row in range(9): |
39 | 48 | for col in range(9): |
40 | 49 | value = grid[row][col] |
41 | | - cells.append( |
42 | | - { |
43 | | - "x": col + 0.5, |
44 | | - "y": 8.5 - row, # Flip y to have row 0 at top |
45 | | - "value": str(value) if value != 0 else "", |
46 | | - } |
47 | | - ) |
| 50 | + cells.append({"x": col + 0.5, "y": 8.5 - row, "value": str(value) if value != 0 else ""}) |
48 | 51 | df_cells = pd.DataFrame(cells) |
49 | 52 |
|
50 | | -# Create thin grid lines (all cell boundaries) |
| 53 | +# Thin grid lines (internal cell boundaries, skipping the 3x3 box positions) |
51 | 54 | thin_lines = [] |
52 | | -for i in range(10): |
53 | | - # Skip positions where thick lines will be drawn |
| 55 | +for i in range(1, 9): |
54 | 56 | if i % 3 != 0: |
55 | | - # Vertical lines |
56 | 57 | thin_lines.append({"x": i, "xend": i, "y": 0, "yend": 9}) |
57 | | - # Horizontal lines |
58 | 58 | thin_lines.append({"x": 0, "xend": 9, "y": i, "yend": i}) |
59 | 59 | df_thin = pd.DataFrame(thin_lines) |
60 | 60 |
|
61 | | -# Create thick grid lines (3x3 box boundaries) |
| 61 | +# Thick grid lines (3x3 box boundaries and outer border) |
62 | 62 | thick_lines = [] |
63 | 63 | for i in [0, 3, 6, 9]: |
64 | | - # Vertical lines |
65 | 64 | thick_lines.append({"x": i, "xend": i, "y": 0, "yend": 9}) |
66 | | - # Horizontal lines |
67 | 65 | thick_lines.append({"x": 0, "xend": 9, "y": i, "yend": i}) |
68 | 66 | df_thick = pd.DataFrame(thick_lines) |
69 | 67 |
|
70 | | -# Create tile data for cell backgrounds |
71 | | -df_tiles = pd.DataFrame([{"x": col + 0.5, "y": row + 0.5, "fill": "white"} for row in range(9) for col in range(9)]) |
| 68 | +# Cell background tiles (ensures panel fill matches theme uniformly across cells) |
| 69 | +df_tiles = pd.DataFrame([{"x": col + 0.5, "y": row + 0.5} for row in range(9) for col in range(9)]) |
72 | 70 |
|
73 | | -# Build the plot |
| 71 | +# Plot |
74 | 72 | plot = ( |
75 | 73 | ggplot() |
76 | | - # Cell backgrounds |
77 | | - + geom_tile(data=df_tiles, mapping=aes(x="x", y="y"), fill="white", color="none", width=1, height=1) |
78 | | - # Thin grid lines |
79 | | - + geom_segment(data=df_thin, mapping=aes(x="x", y="y", xend="xend", yend="yend"), color="#888888", size=0.5) |
80 | | - # Thick grid lines for 3x3 boxes |
81 | | - + geom_segment(data=df_thick, mapping=aes(x="x", y="y", xend="xend", yend="yend"), color="black", size=2) |
82 | | - # Numbers in cells |
83 | | - + geom_text(data=df_cells, mapping=aes(x="x", y="y", label="value"), size=28, color="black", fontweight="bold") |
84 | | - # Title |
85 | | - + labs(title="sudoku-basic · plotnine · pyplots.ai") |
86 | | - # Fixed aspect ratio |
87 | | - + coord_fixed(ratio=1, xlim=(0, 9), ylim=(0, 9)) |
88 | | - # Clean theme |
| 74 | + + geom_tile(data=df_tiles, mapping=aes(x="x", y="y"), fill=PAGE_BG, color="none", width=1, height=1) |
| 75 | + + geom_segment( |
| 76 | + data=df_thin, mapping=aes(x="x", y="y", xend="xend", yend="yend"), color=INK_MUTED, size=0.6, alpha=0.55 |
| 77 | + ) |
| 78 | + + geom_segment(data=df_thick, mapping=aes(x="x", y="y", xend="xend", yend="yend"), color=INK, size=2.4) |
| 79 | + + geom_text(data=df_cells, mapping=aes(x="x", y="y", label="value"), size=30, color=INK, fontweight="bold") |
| 80 | + + labs(title="sudoku-basic · plotnine · anyplot.ai") |
| 81 | + + coord_fixed(ratio=1, xlim=(-0.05, 9.05), ylim=(-0.05, 9.05)) |
89 | 82 | + theme_void() |
90 | 83 | + theme( |
91 | | - figure_size=(12, 12), |
92 | | - plot_title=element_text(size=24, ha="center", weight="bold", margin={"b": 20}), |
93 | | - plot_background=element_blank(), |
94 | | - panel_background=element_blank(), |
| 84 | + figure_size=(14, 14), |
| 85 | + plot_background=element_rect(fill=PAGE_BG, color=PAGE_BG), |
| 86 | + panel_background=element_rect(fill=PAGE_BG, color=PAGE_BG), |
| 87 | + plot_title=element_text(size=26, ha="center", weight="bold", color=INK, margin={"b": 24}), |
| 88 | + plot_margin=0.04, |
95 | 89 | ) |
96 | 90 | ) |
97 | 91 |
|
98 | 92 | # Save |
99 | | -plot.save("plot.png", dpi=300, width=12, height=12, verbose=False) |
| 93 | +plot.save(f"plot-{THEME}.png", dpi=300, width=14, height=14, verbose=False) |
0 commit comments