Skip to content

Commit f199080

Browse files
github-actions[bot]claudeMarkusNeusinger
authored
feat(matplotlib): implement barcode-code128 (#7572)
## Implementation: `barcode-code128` - python/matplotlib Implements the **python/matplotlib** version of `barcode-code128`. **File:** `plots/barcode-code128/implementations/python/matplotlib.py` **Parent Issue:** #3809 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/anyplot/actions/runs/26198178163)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Markus Neusinger <2921697+MarkusNeusinger@users.noreply.github.com>
1 parent 250488e commit f199080

2 files changed

Lines changed: 232 additions & 161 deletions

File tree

plots/barcode-code128/implementations/python/matplotlib.py

Lines changed: 80 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,28 @@
1-
""" pyplots.ai
1+
""" anyplot.ai
22
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
55
"""
66

7+
import os
8+
import sys
9+
10+
11+
sys.path = sys.path[1:] # prevent this file from shadowing the installed matplotlib package
12+
713
import matplotlib.pyplot as plt
814
import numpy as np
15+
from matplotlib.colors import LinearSegmentedColormap
916

1017

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)
1426
CODE128_B = {
1527
" ": [2, 1, 2, 2, 2, 2],
1628
"!": [2, 2, 2, 1, 2, 2],
@@ -109,22 +121,18 @@
109121
"~": [1, 3, 1, 1, 4, 1],
110122
}
111123

112-
# Character value mapping for Code 128B (used for checksum calculation)
113124
CODE128_B_VALUES = {
114125
char: i
115126
for i, char in enumerate(
116127
" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
117128
)
118129
}
119130

120-
# Start code B pattern
121131
START_B = [2, 1, 1, 4, 1, 2]
122132
START_B_VALUE = 104
123-
124-
# Stop pattern (includes final bar)
125133
STOP = [2, 3, 3, 1, 1, 1, 2]
126134

127-
# Patterns for checksum characters (indices 0-102)
135+
# Checksum symbol patterns (indices 0102 for modulo-103 calculation)
128136
CHECKSUM_PATTERNS = [
129137
[2, 1, 2, 2, 2, 2],
130138
[2, 2, 2, 1, 2, 2],
@@ -234,82 +242,100 @@
234242
[2, 1, 1, 2, 3, 2],
235243
]
236244

237-
# Data to encode
245+
# Data
238246
content = "SHIP-2024-ABC123"
239247

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)
245250
checksum = START_B_VALUE
246251
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)
258255

259-
# Add stop pattern
256+
bars.extend(CHECKSUM_PATTERNS[checksum % 103])
260257
bars.extend(STOP)
261258

262-
# Convert bar widths to binary pattern (1=bar, 0=space)
259+
# Convert bar widths to binary (1=bar, 0=space)
263260
binary_pattern = []
264261
is_bar = True
265262
for width in bars:
266263
binary_pattern.extend([1 if is_bar else 0] * width)
267264
is_bar = not is_bar
268265

269-
# Create the barcode image
270-
bar_width = 3 # Width of each module in pixels
266+
# Layout
271267
barcode_height = 200
272-
quiet_zone = 30 # Quiet zone width in modules
273-
274-
# Add quiet zones
268+
quiet_zone = 30
275269
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
281270
barcode_width = len(full_pattern)
282271
barcode_array = np.array([full_pattern] * barcode_height)
283272

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)
286299

287-
# Remove axes for clean barcode appearance
288300
ax.set_xticks([])
289301
ax.set_yticks([])
290302

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
292316
ax.text(
293317
barcode_width / 2,
294-
barcode_height + 30,
318+
barcode_height + 28,
295319
content,
296-
fontsize=32,
320+
fontsize=16,
297321
ha="center",
298322
va="top",
299323
fontfamily="monospace",
300324
fontweight="bold",
325+
color=INK,
301326
)
302327

303-
# Add title
304-
ax.set_title("barcode-code128 · matplotlib · pyplots.ai", fontsize=24, pad=40)
305-
306-
# Set limits to show the text
307328
ax.set_xlim(-10, barcode_width + 10)
308-
ax.set_ylim(barcode_height + 80, -40)
329+
ax.set_ylim(barcode_height + 75, -38)
309330

310-
# Add border around barcode area
311331
for spine in ax.spines.values():
312332
spine.set_visible(False)
313333

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

Comments
 (0)