Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 158 additions & 0 deletions plots/smith-chart-basic/implementations/plotnine.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
""" pyplots.ai
smith-chart-basic: Smith Chart for RF/Impedance
Library: plotnine 0.15.2 | Python 3.13.11
Quality: 90/100 | Created: 2026-01-15
"""

import numpy as np
import pandas as pd
from plotnine import (
aes,
annotate,
coord_fixed,
element_blank,
element_rect,
element_text,
geom_path,
geom_point,
geom_text,
ggplot,
labs,
scale_x_continuous,
scale_y_continuous,
theme,
)


# Reference impedance
Z0 = 50

# Generate Smith chart grid - constant resistance circles
# For resistance r, circle center at (r/(r+1), 0) with radius 1/(r+1)
r_values = [0, 0.2, 0.5, 1, 2, 5]
theta = np.linspace(0, 2 * np.pi, 200)

r_circle_data = []
for r in r_values:
cx = r / (r + 1)
radius = 1 / (r + 1)
x = cx + radius * np.cos(theta)
y = radius * np.sin(theta)
# Clip to unit circle
mask = x**2 + y**2 <= 1.001
r_circle_data.append(pd.DataFrame({"x": x[mask], "y": y[mask], "type": "r_circle", "value": f"r={r}"}))

r_circles_df = pd.concat(r_circle_data, ignore_index=True)

# Constant reactance arcs
# For reactance x, circle center at (1, 1/x) with radius 1/|x|
x_values = [0.2, 0.5, 1, 2, 5]
reactance_data = []

for xv in x_values:
# Positive reactance (upper half)
radius_x = 1 / abs(xv)
cy_pos = 1 / xv
t = np.linspace(0, 2 * np.pi, 500)
arc_x = 1 + radius_x * np.cos(t)
arc_y = cy_pos + radius_x * np.sin(t)
# Keep only points inside unit circle
mask = (arc_x**2 + arc_y**2 <= 1.001) & (arc_x >= -0.01)
if np.any(mask):
reactance_data.append(pd.DataFrame({"x": arc_x[mask], "y": arc_y[mask], "type": "x_arc", "value": f"x={xv}"}))

# Negative reactance (lower half)
cy_neg = -1 / xv
arc_y_neg = cy_neg + radius_x * np.sin(t)
mask_neg = (arc_x**2 + arc_y_neg**2 <= 1.001) & (arc_x >= -0.01)
if np.any(mask_neg):
reactance_data.append(
pd.DataFrame({"x": arc_x[mask_neg], "y": arc_y_neg[mask_neg], "type": "x_arc", "value": f"x=-{xv}"})
)

reactance_df = pd.concat(reactance_data, ignore_index=True)

# Outer boundary circle (|gamma| = 1)
boundary_theta = np.linspace(0, 2 * np.pi, 200)
boundary_df = pd.DataFrame(
{"x": np.cos(boundary_theta), "y": np.sin(boundary_theta), "type": "boundary", "value": "boundary"}
)

# Horizontal axis (real axis)
axis_df = pd.DataFrame({"x": [-1, 1], "y": [0, 0], "type": "axis", "value": "axis"})

# Example impedance data: antenna S11 measurement from 1-6 GHz
np.random.seed(42)
n_points = 50
freq_ghz = np.linspace(1, 6, n_points)

# Simulate antenna impedance variation with frequency
# Creates realistic spiral pattern on Smith chart
z_real = 50 + 30 * np.sin(2 * np.pi * freq_ghz / 2.5) + np.random.randn(n_points) * 3
z_imag = 20 * np.cos(2 * np.pi * freq_ghz / 3) + 15 * (freq_ghz - 3) + np.random.randn(n_points) * 2

# Normalize impedance
z_norm = (z_real + 1j * z_imag) / Z0

# Convert to reflection coefficient (gamma) for Smith chart coordinates
gamma = (z_norm - 1) / (z_norm + 1)
gamma_real = np.real(gamma)
gamma_imag = np.imag(gamma)

impedance_df = pd.DataFrame({"x": gamma_real, "y": gamma_imag, "freq": freq_ghz, "type": "impedance"})

# Select frequency labels at key points
label_indices = [0, 12, 24, 36, 49]
labels_df = impedance_df.iloc[label_indices].copy()
labels_df["label"] = [f"{f:.1f} GHz" for f in labels_df["freq"]]
labels_df["y_offset"] = labels_df["y"] + 0.08

# Combine grid data
grid_df = pd.concat([r_circles_df, reactance_df, boundary_df, axis_df], ignore_index=True)

# Create plot
plot = (
ggplot()
# Grid lines
+ geom_path(
aes(x="x", y="y", group="value"),
data=grid_df[grid_df["type"] == "r_circle"],
color="#CCCCCC",
size=0.5,
alpha=0.8,
)
+ geom_path(
aes(x="x", y="y", group="value"), data=grid_df[grid_df["type"] == "x_arc"], color="#CCCCCC", size=0.5, alpha=0.8
)
# Boundary circle
+ geom_path(aes(x="x", y="y"), data=boundary_df, color="#333333", size=1)
# Real axis
+ geom_path(aes(x="x", y="y"), data=axis_df, color="#333333", size=0.5)
# Impedance locus curve
+ geom_path(aes(x="x", y="y"), data=impedance_df, color="#306998", size=1.5)
# Data points
+ geom_point(aes(x="x", y="y"), data=impedance_df, color="#306998", size=2, alpha=0.7)
# Frequency labels
+ geom_text(aes(x="x", y="y_offset", label="label"), data=labels_df, color="#FFD43B", size=12, fontweight="bold")
# Center point marker (Z = Z0)
+ annotate("point", x=0, y=0, color="#E74C3C", size=4)
+ annotate("text", x=0.12, y=-0.08, label="Z=Z₀", color="#E74C3C", size=11)
# Styling
+ coord_fixed(ratio=1, xlim=(-1.3, 1.3), ylim=(-1.3, 1.3))
+ scale_x_continuous(breaks=[])
+ scale_y_continuous(breaks=[])
+ labs(title="smith-chart-basic · plotnine · pyplots.ai", x="", y="")
+ theme(
figure_size=(12, 12),
plot_title=element_text(size=24, ha="center", weight="bold"),
panel_background=element_rect(fill="white"),
panel_grid_major=element_blank(),
panel_grid_minor=element_blank(),
axis_text=element_blank(),
axis_ticks=element_blank(),
plot_background=element_rect(fill="white"),
)
)

# Save
plot.save("plot.png", dpi=300)
218 changes: 218 additions & 0 deletions plots/smith-chart-basic/metadata/plotnine.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
library: plotnine
specification_id: smith-chart-basic
created: '2026-01-15T21:51:40Z'
updated: '2026-01-15T21:54:21Z'
generated_by: claude-opus-4-5-20251101
workflow_run: 21047489075
issue: 3792
python_version: 3.13.11
library_version: 0.15.2
preview_url: https://storage.googleapis.com/pyplots-images/plots/smith-chart-basic/plotnine/plot.png
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/smith-chart-basic/plotnine/plot_thumb.png
preview_html: null
quality_score: 90
review:
strengths:
- Excellent implementation of Smith chart using plotnine grammar of graphics approach
- Mathematically correct calculation of constant resistance circles and reactance
arcs
- Proper conversion from complex impedance to reflection coefficient coordinates
- Clean layered composition with grid, boundary, axis, data locus, and annotations
- Realistic RF engineering data scenario with antenna S11 measurements
- Good use of coord_fixed for maintaining circular aspect ratio
weaknesses:
- Frequency labels in yellow may have lower contrast against white background than
ideal
- Grid line labels (r=0, r=0.2, x=0.5, etc.) not shown - would enhance educational
value
- Data point markers could be slightly larger for better visibility at full resolution
image_description: The plot displays a Smith chart with the correct circular layout.
The outer boundary is a black circle representing |gamma|=1 (total reflection).
Inside, light gray constant resistance circles are drawn (centered along the horizontal
axis) and constant reactance arcs curve from the right edge. A horizontal real
axis line passes through the center. The impedance locus is drawn as a connected
blue (#306998) path with small markers showing an antenna S11 measurement sweep
from 1-6 GHz. Five frequency labels (1.0 GHz, 2.2 GHz, 3.4 GHz, 4.7 GHz, 6.0 GHz)
appear in yellow/gold text positioned above their corresponding data points. A
red dot marks the center point (Z=Z₀) with a red label. The chart uses a clean
white background with no axis labels or tick marks (appropriate for a Smith chart).
The title "smith-chart-basic · plotnine · pyplots.ai" appears centered at the
top in bold black text.
criteria_checklist:
visual_quality:
score: 36
max: 40
items:
- id: VQ-01
name: Text Legibility
score: 9
max: 10
passed: true
comment: Title is large and bold, frequency labels are readable though could
be slightly larger
- id: VQ-02
name: No Overlap
score: 8
max: 8
passed: true
comment: No overlapping text elements
- id: VQ-03
name: Element Visibility
score: 7
max: 8
passed: true
comment: Grid lines visible with appropriate alpha, data points could be slightly
larger
- id: VQ-04
name: Color Accessibility
score: 5
max: 5
passed: true
comment: Blue/yellow/red color scheme is colorblind-safe with good contrast
- id: VQ-05
name: Layout Balance
score: 5
max: 5
passed: true
comment: Chart is well-centered with balanced margins, uses square 1:1 aspect
ratio appropriately
- id: VQ-06
name: Axis Labels
score: 0
max: 2
passed: true
comment: N/A for Smith chart (no conventional axes), but spec-appropriate
- id: VQ-07
name: Grid & Legend
score: 2
max: 2
passed: true
comment: Grid lines are subtle with appropriate alpha, no legend needed
spec_compliance:
score: 24
max: 25
items:
- id: SC-01
name: Plot Type
score: 8
max: 8
passed: true
comment: Correct Smith chart with resistance circles and reactance arcs
- id: SC-02
name: Data Mapping
score: 5
max: 5
passed: true
comment: Complex impedance correctly converted to reflection coefficient (gamma)
coordinates
- id: SC-03
name: Required Features
score: 5
max: 5
passed: true
comment: 'All required features present: grid, normalized impedance, connected
locus curve, frequency labels, center marker'
- id: SC-04
name: Data Range
score: 3
max: 3
passed: true
comment: All data visible within unit circle boundary
- id: SC-05
name: Legend Accuracy
score: 1
max: 2
passed: true
comment: No legend needed, but labels could better explain the grid values
- id: SC-06
name: Title Format
score: 2
max: 2
passed: true
comment: 'Correct format: smith-chart-basic · plotnine · pyplots.ai'
data_quality:
score: 18
max: 20
items:
- id: DQ-01
name: Feature Coverage
score: 7
max: 8
passed: true
comment: Shows impedance variation with frequency creating realistic spiral
pattern, visits different regions of Smith chart
- id: DQ-02
name: Realistic Context
score: 7
max: 7
passed: true
comment: Antenna S11 measurement from 1-6 GHz is a realistic RF engineering
scenario
- id: DQ-03
name: Appropriate Scale
score: 4
max: 5
passed: true
comment: Impedance values around 50 ohms reference are realistic, frequency
range is typical for antenna design
code_quality:
score: 9
max: 10
items:
- id: CQ-01
name: KISS Structure
score: 3
max: 3
passed: true
comment: 'Flat structure: imports, data generation, plot construction, save'
- id: CQ-02
name: Reproducibility
score: 3
max: 3
passed: true
comment: Uses np.random.seed(42)
- id: CQ-03
name: Clean Imports
score: 2
max: 2
passed: true
comment: All imports are used
- id: CQ-04
name: No Deprecated API
score: 1
max: 1
passed: true
comment: Uses current plotnine API
- id: CQ-05
name: Output Correct
score: 0
max: 1
passed: false
comment: 'Minor: could use higher dpi for 4800x2700 target'
library_features:
score: 3
max: 5
items:
- id: LF-01
name: Distinctive Features
score: 3
max: 5
passed: true
comment: Uses plotnine grammar of graphics with layered geom_path and geom_point,
coord_fixed for aspect ratio, proper theming
verdict: APPROVED
impl_tags:
dependencies: []
techniques:
- annotations
- layer-composition
- patches
patterns:
- data-generation
- iteration-over-groups
- matrix-construction
dataprep:
- normalization
styling:
- minimal-chrome
- alpha-blending