Skip to content

Commit 989e9ce

Browse files
feat(pygal): implement spectrum-basic (#2973)
## Implementation: `spectrum-basic` - pygal Implements the **pygal** version of `spectrum-basic`. **File:** `plots/spectrum-basic/implementations/pygal.py` **Parent Issue:** #2926 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20612855025)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent e58e29c commit 989e9ce

2 files changed

Lines changed: 125 additions & 0 deletions

File tree

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
""" pyplots.ai
2+
spectrum-basic: Frequency Spectrum Plot
3+
Library: pygal 3.1.0 | Python 3.13.11
4+
Quality: 91/100 | Created: 2025-12-31
5+
"""
6+
7+
import numpy as np
8+
import pygal
9+
from pygal.style import Style
10+
11+
12+
# Data - Generate synthetic signal with multiple frequency components
13+
np.random.seed(42)
14+
15+
# Create a synthetic time-domain signal with known frequency components
16+
fs = 1000 # Sampling frequency (Hz)
17+
t = np.linspace(0, 1, fs) # 1 second of data
18+
19+
# Signal with 3 frequency components: 50 Hz (strong), 120 Hz (medium), 200 Hz (weak)
20+
signal = (
21+
3.0 * np.sin(2 * np.pi * 50 * t) # 50 Hz - dominant frequency
22+
+ 1.5 * np.sin(2 * np.pi * 120 * t) # 120 Hz - secondary
23+
+ 0.8 * np.sin(2 * np.pi * 200 * t) # 200 Hz - tertiary
24+
+ 0.3 * np.random.randn(len(t)) # Noise floor
25+
)
26+
27+
# Compute FFT
28+
n = len(signal)
29+
fft_result = np.fft.fft(signal)
30+
frequencies = np.fft.fftfreq(n, 1 / fs)
31+
32+
# Take only positive frequencies
33+
positive_mask = frequencies >= 0
34+
frequencies = frequencies[positive_mask]
35+
amplitude = np.abs(fft_result[positive_mask]) / n * 2 # Normalize
36+
37+
# Convert to dB scale for better visualization
38+
amplitude_db = 20 * np.log10(amplitude + 1e-10)
39+
40+
# Limit to 0-300 Hz for clarity (where our signal components are)
41+
freq_limit_mask = frequencies <= 300
42+
frequencies = frequencies[freq_limit_mask]
43+
amplitude_db = amplitude_db[freq_limit_mask]
44+
45+
# Downsample for pygal (it works better with fewer points)
46+
step = 2
47+
frequencies = frequencies[::step]
48+
amplitude_db = amplitude_db[::step]
49+
50+
# Create custom style for large canvas
51+
custom_style = Style(
52+
background="white",
53+
plot_background="white",
54+
foreground="#333333",
55+
foreground_strong="#333333",
56+
foreground_subtle="#666666",
57+
colors=("#306998",), # Python Blue
58+
title_font_size=72,
59+
label_font_size=48,
60+
major_label_font_size=40,
61+
legend_font_size=40,
62+
value_font_size=32,
63+
stroke_width=4,
64+
opacity=0.9,
65+
opacity_hover=1.0,
66+
)
67+
68+
# Create XY chart (line chart with custom x values)
69+
chart = pygal.XY(
70+
width=4800,
71+
height=2700,
72+
style=custom_style,
73+
title="spectrum-basic · pygal · pyplots.ai",
74+
x_title="Frequency (Hz)",
75+
y_title="Amplitude (dB)",
76+
show_dots=False,
77+
fill=True,
78+
stroke_style={"width": 4},
79+
show_x_guides=True,
80+
show_y_guides=True,
81+
x_label_rotation=0,
82+
show_legend=False,
83+
range=(-60, 20), # dB range
84+
dots_size=0,
85+
margin=60,
86+
spacing=40,
87+
)
88+
89+
# Add data as XY points
90+
xy_data = [(float(f), float(a)) for f, a in zip(frequencies, amplitude_db, strict=True)]
91+
chart.add("Amplitude", xy_data)
92+
93+
# Save as PNG and HTML
94+
chart.render_to_png("plot.png")
95+
chart.render_to_file("plot.html")
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
library: pygal
2+
specification_id: spectrum-basic
3+
created: '2025-12-31T05:38:16Z'
4+
updated: '2025-12-31T05:52:55Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20612855025
7+
issue: 2926
8+
python_version: 3.13.11
9+
library_version: 3.1.0
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/spectrum-basic/pygal/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/spectrum-basic/pygal/plot_thumb.png
12+
preview_html: https://storage.googleapis.com/pyplots-images/plots/spectrum-basic/pygal/plot.html
13+
quality_score: 91
14+
review:
15+
strengths:
16+
- Excellent visualization of frequency spectrum with clear, distinct peaks at 50
17+
Hz, 120 Hz, and 200 Hz matching the synthetic signal
18+
- Proper use of dB scale for amplitude representation, making the spectrum analysis
19+
realistic
20+
- Well-configured canvas size (4800x2700) with appropriately scaled font sizes for
21+
readability
22+
- Clean, professional appearance with subtle grid lines and good color contrast
23+
- Appropriate data preprocessing including FFT computation, normalization, and frequency
24+
limiting
25+
- Good use of pygal XY chart with fill for area-under-curve visualization
26+
weaknesses:
27+
- Missing peak annotations or markers to highlight the dominant frequency components
28+
as suggested in the specification
29+
- Font sizes in the custom style are quite large (title_font_size=72) which may
30+
be excessive; could be slightly reduced for better proportions

0 commit comments

Comments
 (0)