|
1 | | -""" pyplots.ai |
| 1 | +""" anyplot.ai |
2 | 2 | barcode-code128: Code 128 Barcode |
3 | | -Library: matplotlib 3.10.8 | Python 3.13.11 |
4 | | -Quality: 92/100 | Created: 2026-01-19 |
| 3 | +Library: matplotlib 3.10.9 | Python 3.13.13 |
| 4 | +Quality: 86/100 | Updated: 2026-05-21 |
5 | 5 | """ |
6 | 6 |
|
| 7 | +import os |
| 8 | +import sys |
| 9 | + |
| 10 | + |
| 11 | +sys.path = sys.path[1:] # prevent this file from shadowing the installed matplotlib package |
| 12 | + |
7 | 13 | import matplotlib.pyplot as plt |
8 | 14 | import numpy as np |
| 15 | +from matplotlib.colors import LinearSegmentedColormap |
9 | 16 |
|
10 | 17 |
|
11 | | -# Code 128 encoding tables |
12 | | -# Each character is encoded as 6 bar widths (alternating bars and spaces) |
13 | | -# Values represent the relative widths of each element (1-4 units) |
| 18 | +# Theme tokens |
| 19 | +THEME = os.getenv("ANYPLOT_THEME", "light") |
| 20 | +PAGE_BG = "#FAF8F1" if THEME == "light" else "#1A1A17" |
| 21 | +INK = "#1A1A17" if THEME == "light" else "#F0EFE8" |
| 22 | +INK_SOFT = "#4A4A44" if THEME == "light" else "#B8B7B0" |
| 23 | +INK_MUTED = "#6B6A63" if THEME == "light" else "#A8A79F" |
| 24 | + |
| 25 | +# Code 128B encoding: each character → 6 bar/space widths (alternating) |
14 | 26 | CODE128_B = { |
15 | 27 | " ": [2, 1, 2, 2, 2, 2], |
16 | 28 | "!": [2, 2, 2, 1, 2, 2], |
|
109 | 121 | "~": [1, 3, 1, 1, 4, 1], |
110 | 122 | } |
111 | 123 |
|
112 | | -# Character value mapping for Code 128B (used for checksum calculation) |
113 | 124 | CODE128_B_VALUES = { |
114 | 125 | char: i |
115 | 126 | for i, char in enumerate( |
116 | 127 | " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" |
117 | 128 | ) |
118 | 129 | } |
119 | 130 |
|
120 | | -# Start code B pattern |
121 | 131 | START_B = [2, 1, 1, 4, 1, 2] |
122 | 132 | START_B_VALUE = 104 |
123 | | - |
124 | | -# Stop pattern (includes final bar) |
125 | 133 | STOP = [2, 3, 3, 1, 1, 1, 2] |
126 | 134 |
|
127 | | -# Patterns for checksum characters (indices 0-102) |
| 135 | +# Checksum symbol patterns (indices 0–102 for modulo-103 calculation) |
128 | 136 | CHECKSUM_PATTERNS = [ |
129 | 137 | [2, 1, 2, 2, 2, 2], |
130 | 138 | [2, 2, 2, 1, 2, 2], |
|
234 | 242 | [2, 1, 1, 2, 3, 2], |
235 | 243 | ] |
236 | 244 |
|
237 | | -# Data to encode |
| 245 | +# Data |
238 | 246 | content = "SHIP-2024-ABC123" |
239 | 247 |
|
240 | | -# Build the barcode pattern |
241 | | -bars = [] |
242 | | -bars.extend(START_B) # Start Code B |
243 | | - |
244 | | -# Calculate checksum while encoding |
| 248 | +# Encode: start + data + checksum + stop |
| 249 | +bars = list(START_B) |
245 | 250 | checksum = START_B_VALUE |
246 | 251 | for i, char in enumerate(content): |
247 | | - if char in CODE128_B: |
248 | | - bars.extend(CODE128_B[char]) |
249 | | - checksum += CODE128_B_VALUES[char] * (i + 1) |
250 | | - else: |
251 | | - # Replace unsupported characters with space |
252 | | - bars.extend(CODE128_B[" "]) |
253 | | - checksum += CODE128_B_VALUES[" "] * (i + 1) |
254 | | - |
255 | | -# Add checksum character |
256 | | -checksum_value = checksum % 103 |
257 | | -bars.extend(CHECKSUM_PATTERNS[checksum_value]) |
| 252 | + pattern = CODE128_B.get(char, CODE128_B[" "]) |
| 253 | + bars.extend(pattern) |
| 254 | + checksum += CODE128_B_VALUES.get(char, 0) * (i + 1) |
258 | 255 |
|
259 | | -# Add stop pattern |
| 256 | +bars.extend(CHECKSUM_PATTERNS[checksum % 103]) |
260 | 257 | bars.extend(STOP) |
261 | 258 |
|
262 | | -# Convert bar widths to binary pattern (1=bar, 0=space) |
| 259 | +# Convert bar widths to binary (1=bar, 0=space) |
263 | 260 | binary_pattern = [] |
264 | 261 | is_bar = True |
265 | 262 | for width in bars: |
266 | 263 | binary_pattern.extend([1 if is_bar else 0] * width) |
267 | 264 | is_bar = not is_bar |
268 | 265 |
|
269 | | -# Create the barcode image |
270 | | -bar_width = 3 # Width of each module in pixels |
| 266 | +# Layout |
271 | 267 | barcode_height = 200 |
272 | | -quiet_zone = 30 # Quiet zone width in modules |
273 | | - |
274 | | -# Add quiet zones |
| 268 | +quiet_zone = 30 |
275 | 269 | full_pattern = [0] * quiet_zone + binary_pattern + [0] * quiet_zone |
276 | | - |
277 | | -# Create plot (16:9 aspect ratio) |
278 | | -fig, ax = plt.subplots(figsize=(16, 9)) |
279 | | - |
280 | | -# Create barcode array |
281 | 270 | barcode_width = len(full_pattern) |
282 | 271 | barcode_array = np.array([full_pattern] * barcode_height) |
283 | 272 |
|
284 | | -# Plot barcode |
285 | | -ax.imshow(barcode_array, cmap="binary", aspect="auto", interpolation="nearest") |
| 273 | +# Zone boundaries for structural annotations |
| 274 | +# Code 128 standard: every symbol (except STOP) = 11 modules; STOP = 13 modules |
| 275 | +_sw = 11 |
| 276 | +_stop_w = sum(STOP) # 13 |
| 277 | +_qz0_end = quiet_zone |
| 278 | +_start_end = _qz0_end + _sw |
| 279 | +_data_end = _start_end + len(content) * _sw |
| 280 | +_check_end = _data_end + _sw |
| 281 | +_stop_end = _check_end + _stop_w |
| 282 | + |
| 283 | +zones = [ |
| 284 | + (_qz0_end - quiet_zone, _qz0_end, "Quiet Zone"), |
| 285 | + (_qz0_end, _start_end, "Start"), |
| 286 | + (_start_end, _data_end, f"Data · Code B ({len(content)} chars)"), |
| 287 | + (_data_end, _check_end, "Check"), |
| 288 | + (_check_end, _stop_end, "Stop"), |
| 289 | + (_stop_end, barcode_width, "Quiet Zone"), |
| 290 | +] |
| 291 | + |
| 292 | +# Plot — landscape canvas: figsize=(8, 4.5) × dpi=400 → 3200×1800 px |
| 293 | +fig, ax = plt.subplots(figsize=(8, 4.5), dpi=400, facecolor=PAGE_BG) |
| 294 | +ax.set_facecolor(PAGE_BG) |
| 295 | + |
| 296 | +# Theme-adaptive colormap: 0 (space) → PAGE_BG, 1 (bar) → INK |
| 297 | +bar_cmap = LinearSegmentedColormap.from_list("barcode_cmap", [PAGE_BG, INK], N=2) |
| 298 | +ax.imshow(barcode_array, cmap=bar_cmap, aspect="auto", interpolation="nearest", vmin=0, vmax=1) |
286 | 299 |
|
287 | | -# Remove axes for clean barcode appearance |
288 | 300 | ax.set_xticks([]) |
289 | 301 | ax.set_yticks([]) |
290 | 302 |
|
291 | | -# Add human-readable text below barcode |
| 303 | +# Structural zone annotations above the barcode |
| 304 | +y_tick_top = 0 # tick mark at barcode top edge |
| 305 | +y_bracket = -9 # horizontal bracket line |
| 306 | +y_label = -20 # zone label center |
| 307 | + |
| 308 | +for x0, x1, label in zones: |
| 309 | + cx = (x0 + x1) / 2 |
| 310 | + ax.plot([x0, x1], [y_bracket, y_bracket], color=INK_MUTED, lw=0.6, solid_capstyle="butt") |
| 311 | + ax.plot([x0, x0], [y_tick_top, y_bracket], color=INK_MUTED, lw=0.6) |
| 312 | + ax.plot([x1, x1], [y_tick_top, y_bracket], color=INK_MUTED, lw=0.6) |
| 313 | + ax.text(cx, y_label, label, fontsize=6, ha="center", va="center", color=INK_MUTED, fontfamily="monospace") |
| 314 | + |
| 315 | +# Human-readable text below barcode |
292 | 316 | ax.text( |
293 | 317 | barcode_width / 2, |
294 | | - barcode_height + 30, |
| 318 | + barcode_height + 28, |
295 | 319 | content, |
296 | | - fontsize=32, |
| 320 | + fontsize=16, |
297 | 321 | ha="center", |
298 | 322 | va="top", |
299 | 323 | fontfamily="monospace", |
300 | 324 | fontweight="bold", |
| 325 | + color=INK, |
301 | 326 | ) |
302 | 327 |
|
303 | | -# Add title |
304 | | -ax.set_title("barcode-code128 · matplotlib · pyplots.ai", fontsize=24, pad=40) |
305 | | - |
306 | | -# Set limits to show the text |
307 | 328 | ax.set_xlim(-10, barcode_width + 10) |
308 | | -ax.set_ylim(barcode_height + 80, -40) |
| 329 | +ax.set_ylim(barcode_height + 75, -38) |
309 | 330 |
|
310 | | -# Add border around barcode area |
311 | 331 | for spine in ax.spines.values(): |
312 | 332 | spine.set_visible(False) |
313 | 333 |
|
314 | | -plt.tight_layout() |
315 | | -plt.savefig("plot.png", dpi=300, bbox_inches="tight", facecolor="white") |
| 334 | +# Style |
| 335 | +ax.set_title("barcode-code128 · python · matplotlib · anyplot.ai", fontsize=12, fontweight="medium", color=INK, pad=8) |
| 336 | +ax.tick_params(colors=INK_SOFT) |
| 337 | + |
| 338 | +fig.subplots_adjust(left=0.02, right=0.98, top=0.93, bottom=0.04) |
| 339 | + |
| 340 | +# Save |
| 341 | +plt.savefig(f"plot-{THEME}.png", dpi=400, facecolor=PAGE_BG) |
0 commit comments