Skip to content

Commit 437260c

Browse files
feat(seaborn): implement renko-basic (#3312)
## Implementation: `renko-basic` - seaborn Implements the **seaborn** version of `renko-basic`. **File:** `plots/renko-basic/implementations/seaborn.py` **Parent Issue:** #3294 --- :robot: *[impl-generate workflow](https://github.com/MarkusNeusinger/pyplots/actions/runs/20823037316)* --------- Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent f661d1c commit 437260c

2 files changed

Lines changed: 334 additions & 0 deletions

File tree

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
""" pyplots.ai
2+
renko-basic: Basic Renko Chart
3+
Library: seaborn 0.13.2 | Python 3.13.11
4+
Quality: 68/100 | Created: 2026-01-08
5+
"""
6+
7+
import matplotlib.pyplot as plt
8+
import numpy as np
9+
import pandas as pd
10+
import seaborn as sns
11+
from matplotlib.patches import Rectangle
12+
13+
14+
# Set seaborn style
15+
sns.set_style("whitegrid")
16+
sns.set_context("talk", font_scale=1.2)
17+
18+
# Generate synthetic stock price data
19+
np.random.seed(42)
20+
n_days = 250
21+
dates = pd.date_range("2025-01-01", periods=n_days, freq="D")
22+
23+
# Simulate price movement with random walk
24+
returns = np.random.normal(0.0005, 0.015, n_days)
25+
prices = 100 * np.cumprod(1 + returns)
26+
27+
df = pd.DataFrame({"date": dates, "close": prices})
28+
29+
# Renko brick calculation
30+
brick_size = 2.0 # $2 per brick
31+
bricks = []
32+
33+
# Start from first price
34+
current_price = df["close"].iloc[0]
35+
brick_high = np.floor(current_price / brick_size) * brick_size
36+
brick_low = brick_high
37+
38+
for price in df["close"]:
39+
# Check for upward bricks
40+
while price >= brick_high + brick_size:
41+
brick_high += brick_size
42+
brick_low = brick_high - brick_size
43+
bricks.append({"direction": "up", "open": brick_low, "close": brick_high})
44+
45+
# Check for downward bricks
46+
while price <= brick_low - brick_size:
47+
brick_low -= brick_size
48+
brick_high = brick_low + brick_size
49+
bricks.append({"direction": "down", "open": brick_high, "close": brick_low})
50+
51+
renko_df = pd.DataFrame(bricks)
52+
53+
# Colorblind-accessible colors (blue/orange scheme instead of red/green)
54+
bullish_color = "#1976D2" # Blue for up bricks (colorblind-safe)
55+
bearish_color = "#E65100" # Orange for down bricks (colorblind-safe)
56+
57+
# Create figure
58+
fig, ax = plt.subplots(figsize=(16, 9))
59+
60+
# Gap ratio for small separation between bricks
61+
gap_ratio = 0.08
62+
brick_width = 1.0 - gap_ratio
63+
64+
# Draw bricks in proper stair-step pattern
65+
# Each brick is positioned at (x, bottom) with height = brick_size
66+
# The key for Renko: next brick starts at the SAME y-level where previous ended
67+
bullish_patches = []
68+
bearish_patches = []
69+
70+
for idx, row in renko_df.iterrows():
71+
bottom = min(row["open"], row["close"])
72+
x_pos = idx + gap_ratio / 2 # Center the brick with gap
73+
74+
rect = Rectangle((x_pos, bottom), brick_width, brick_size, linewidth=1.5, edgecolor="white")
75+
76+
if row["direction"] == "up":
77+
rect.set_facecolor(bullish_color)
78+
bullish_patches.append(rect)
79+
else:
80+
rect.set_facecolor(bearish_color)
81+
bearish_patches.append(rect)
82+
83+
ax.add_patch(rect)
84+
85+
# Add legend handles with updated labels
86+
legend_handles = [
87+
Rectangle((0, 0), 1, 1, facecolor=bullish_color, edgecolor="white", label="Bullish (Up)"),
88+
Rectangle((0, 0), 1, 1, facecolor=bearish_color, edgecolor="white", label="Bearish (Down)"),
89+
]
90+
91+
# Set axis limits with padding
92+
price_min = renko_df[["open", "close"]].min().min() - brick_size
93+
price_max = renko_df[["open", "close"]].max().max() + brick_size
94+
ax.set_ylim(price_min, price_max)
95+
ax.set_xlim(-0.5, len(renko_df) + 0.5)
96+
97+
# Labels and styling - more descriptive axis labels
98+
ax.set_xlabel("Brick Number", fontsize=20)
99+
ax.set_ylabel("Stock Price (USD)", fontsize=20)
100+
ax.set_title("renko-basic · seaborn · pyplots.ai", fontsize=24, fontweight="bold")
101+
ax.tick_params(axis="both", labelsize=16)
102+
103+
# Add legend positioned outside plot area to avoid data overlap
104+
ax.legend(handles=legend_handles, fontsize=16, loc="upper right", framealpha=0.9)
105+
106+
# Add subtle grid on y-axis only
107+
ax.grid(True, alpha=0.3, linestyle="--", axis="y")
108+
ax.set_axisbelow(True)
109+
110+
# Simplify x-axis ticks for cleaner look
111+
tick_step = max(1, len(renko_df) // 10)
112+
ax.set_xticks(range(0, len(renko_df), tick_step))
113+
114+
# Add annotation about brick size
115+
ax.annotate(
116+
f"Brick Size: ${brick_size:.0f}",
117+
xy=(0.98, 0.02),
118+
xycoords="axes fraction",
119+
fontsize=14,
120+
ha="right",
121+
va="bottom",
122+
bbox={"boxstyle": "round,pad=0.5", "facecolor": "white", "edgecolor": "gray", "alpha": 0.8},
123+
)
124+
125+
plt.tight_layout()
126+
plt.savefig("plot.png", dpi=300, bbox_inches="tight")
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
library: seaborn
2+
specification_id: renko-basic
3+
created: '2026-01-08T16:02:10Z'
4+
updated: '2026-01-08T16:32:04Z'
5+
generated_by: claude-opus-4-5-20251101
6+
workflow_run: 20823037316
7+
issue: 3294
8+
python_version: 3.13.11
9+
library_version: 0.13.2
10+
preview_url: https://storage.googleapis.com/pyplots-images/plots/renko-basic/seaborn/plot.png
11+
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/renko-basic/seaborn/plot_thumb.png
12+
preview_html: null
13+
quality_score: 68
14+
review:
15+
strengths:
16+
- Correct Renko chart algorithm with proper stair-step brick positioning
17+
- Good data generation showing realistic price movements with multiple trend reversals
18+
- Clean code structure following KISS principles
19+
- Appropriate brick sizing and gaps for visual clarity
20+
- Helpful annotation showing brick size
21+
weaknesses:
22+
- Title format uses hyphens instead of required middle dots (·)
23+
- 'Color mismatch: code defines colorblind-safe blue/orange but rendered image shows
24+
traditional red/green'
25+
- Seaborn is only used for styling - no seaborn plotting functions are utilized
26+
image_description: 'The plot displays a Renko chart showing stock price movements
27+
over approximately 40 bricks. Green bricks represent bullish (upward) price movements
28+
while red bricks represent bearish (downward) movements. The chart shows a clear
29+
pattern: an initial rise from ~$100 to ~$105, followed by a significant decline
30+
to ~$87, then a recovery back up to ~$112. Bricks are uniform in size ($2 each
31+
as noted in the annotation), clearly separated with small gaps, and properly stair-stepped.
32+
The Y-axis shows "Stock Price (USD)" ranging from ~$85 to ~$112, and the X-axis
33+
shows "Brick Number" from 0 to ~40. A legend in the upper left identifies the
34+
brick colors. An annotation in the lower right displays "Brick Size: $2". The
35+
title reads "renko-basic - seaborn - pyplots.ai" using hyphens instead of middle
36+
dots.'
37+
criteria_checklist:
38+
visual_quality:
39+
score: 32
40+
max: 40
41+
items:
42+
- id: VQ-01
43+
name: Text Legibility
44+
score: 10
45+
max: 10
46+
passed: true
47+
comment: Title at 24pt, labels at 20pt, ticks at 16pt, all perfectly readable
48+
- id: VQ-02
49+
name: No Overlap
50+
score: 8
51+
max: 8
52+
passed: true
53+
comment: No overlapping text elements
54+
- id: VQ-03
55+
name: Element Visibility
56+
score: 8
57+
max: 8
58+
passed: true
59+
comment: Bricks are well-sized and clearly visible with appropriate gaps
60+
- id: VQ-04
61+
name: Color Accessibility
62+
score: 2
63+
max: 5
64+
passed: false
65+
comment: Uses red-green color scheme instead of colorblind-safe colors
66+
- id: VQ-05
67+
name: Layout Balance
68+
score: 5
69+
max: 5
70+
passed: true
71+
comment: Good proportions, plot fills canvas appropriately
72+
- id: VQ-06
73+
name: Axis Labels
74+
score: 2
75+
max: 2
76+
passed: true
77+
comment: 'Descriptive labels with units: Stock Price (USD), Brick Number'
78+
- id: VQ-07
79+
name: Grid & Legend
80+
score: 0
81+
max: 2
82+
passed: false
83+
comment: Legend uses wrong colors (shows green/red but code defines blue/orange)
84+
spec_compliance:
85+
score: 21
86+
max: 25
87+
items:
88+
- id: SC-01
89+
name: Plot Type
90+
score: 8
91+
max: 8
92+
passed: true
93+
comment: Correct Renko chart implementation
94+
- id: SC-02
95+
name: Data Mapping
96+
score: 5
97+
max: 5
98+
passed: true
99+
comment: Brick index on X, price on Y correctly assigned
100+
- id: SC-03
101+
name: Required Features
102+
score: 5
103+
max: 5
104+
passed: true
105+
comment: 'All features present: bullish/bearish bricks, uniform size, gaps,
106+
grid, legend'
107+
- id: SC-04
108+
name: Data Range
109+
score: 3
110+
max: 3
111+
passed: true
112+
comment: Axes show all data with appropriate padding
113+
- id: SC-05
114+
name: Legend Accuracy
115+
score: 2
116+
max: 2
117+
passed: true
118+
comment: Legend labels correctly identify bullish (Up) and bearish (Down)
119+
- id: SC-06
120+
name: Title Format
121+
score: 0
122+
max: 2
123+
passed: false
124+
comment: Uses hyphens instead of required middle dots (·)
125+
data_quality:
126+
score: 18
127+
max: 20
128+
items:
129+
- id: DQ-01
130+
name: Feature Coverage
131+
score: 8
132+
max: 8
133+
passed: true
134+
comment: Shows both bullish and bearish movements, multiple trend reversals,
135+
clear patterns
136+
- id: DQ-02
137+
name: Realistic Context
138+
score: 5
139+
max: 7
140+
passed: true
141+
comment: Plausible stock price scenario with realistic volatility pattern
142+
- id: DQ-03
143+
name: Appropriate Scale
144+
score: 5
145+
max: 5
146+
passed: true
147+
comment: Sensible stock price values around $100 with $2 brick size
148+
code_quality:
149+
score: 10
150+
max: 10
151+
items:
152+
- id: CQ-01
153+
name: KISS Structure
154+
score: 3
155+
max: 3
156+
passed: true
157+
comment: Follows imports → data → plot → save structure, no functions/classes
158+
- id: CQ-02
159+
name: Reproducibility
160+
score: 3
161+
max: 3
162+
passed: true
163+
comment: Uses np.random.seed(42)
164+
- id: CQ-03
165+
name: Clean Imports
166+
score: 2
167+
max: 2
168+
passed: true
169+
comment: All imports are used
170+
- id: CQ-04
171+
name: No Deprecated API
172+
score: 1
173+
max: 1
174+
passed: true
175+
comment: Uses current seaborn/matplotlib API
176+
- id: CQ-05
177+
name: Output Correct
178+
score: 1
179+
max: 1
180+
passed: true
181+
comment: Saves as plot.png
182+
library_features:
183+
score: 0
184+
max: 5
185+
items:
186+
- id: LF-01
187+
name: Distinctive Features
188+
score: 0
189+
max: 5
190+
passed: false
191+
comment: Seaborn is only used for styling (set_style, set_context). All plotting
192+
is done with matplotlib patches. No seaborn plotting functions are used.
193+
verdict: APPROVED
194+
impl_tags:
195+
dependencies: []
196+
techniques:
197+
- patches
198+
- custom-legend
199+
- annotations
200+
- manual-ticks
201+
patterns:
202+
- data-generation
203+
- iteration-over-groups
204+
dataprep:
205+
- time-series
206+
styling:
207+
- grid-styling
208+
- edge-highlighting

0 commit comments

Comments
 (0)