Skip to content

Commit b56bd13

Browse files
update(candlestick-basic): letsplot — comprehensive quality review
Comprehensive quality review of letsplot implementation for candlestick-basic.
1 parent f543569 commit b56bd13

2 files changed

Lines changed: 80 additions & 66 deletions

File tree

Lines changed: 75 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,21 @@
11
""" pyplots.ai
22
candlestick-basic: Basic Candlestick Chart
3-
Library: letsplot 4.8.2 | Python 3.13.11
4-
Quality: 92/100 | Created: 2025-12-23
3+
Library: letsplot 4.8.2 | Python 3.14.3
4+
Quality: /100 | Updated: 2026-02-24
55
"""
66

7-
import cairosvg
87
import numpy as np
98
import pandas as pd
10-
from lets_plot import (
11-
LetsPlot,
12-
aes,
13-
element_blank,
14-
element_text,
15-
geom_rect,
16-
geom_segment,
17-
ggplot,
18-
ggsize,
19-
labs,
20-
scale_x_continuous,
21-
theme,
22-
theme_minimal,
23-
)
24-
from lets_plot.export import ggsave
9+
from lets_plot import * # noqa: F403
2510

2611

27-
LetsPlot.setup_html()
12+
LetsPlot.setup_html() # noqa: F405
2813

2914
# Data - simulated 30 trading days of stock OHLC data
3015
np.random.seed(42)
3116
n_days = 30
3217

33-
dates = pd.date_range(start="2024-01-02", periods=n_days, freq="B") # Business days
18+
dates = pd.date_range(start="2024-01-02", periods=n_days, freq="B")
3419

3520
# Generate realistic OHLC data with random walk
3621
price = 100.0
@@ -52,60 +37,89 @@
5237

5338
df = pd.DataFrame({"date": dates, "open": opens, "high": highs, "low": lows, "close": closes})
5439

55-
# Calculate candlestick properties
40+
# Candlestick properties
5641
df["bullish"] = df["close"] >= df["open"]
57-
df["color"] = df["bullish"].map({True: "#22C55E", False: "#EF4444"}) # Green/Red
5842
df["body_low"] = df[["open", "close"]].min(axis=1)
5943
df["body_high"] = df[["open", "close"]].max(axis=1)
60-
df["x"] = range(len(df)) # Numeric x for positioning
44+
df["x"] = range(len(df))
6145
df["xmin"] = df["x"] - 0.35
6246
df["xmax"] = df["x"] + 0.35
47+
df["date_str"] = df["date"].dt.strftime("%b %d")
48+
49+
bull_color = "#2271B5" # Blue for bullish (up)
50+
bear_color = "#D55E00" # Orange for bearish (down) — colorblind-safe
51+
52+
bull_df = df[df["bullish"]].copy()
53+
bear_df = df[~df["bullish"]].copy()
54+
55+
# Tick label positions: every 5th trading day
56+
tick_pos = list(range(0, n_days, 5))
57+
tick_labels = [dates[i].strftime("%b %d") for i in tick_pos]
58+
59+
# Tooltip template for interactive HTML export
60+
tip_fmt = (
61+
layer_tooltips() # noqa: F405
62+
.line("@date_str")
63+
.line("Open|$@open")
64+
.line("High|$@high")
65+
.line("Low|$@low")
66+
.line("Close|$@close")
67+
)
6368

6469
# Plot
6570
plot = (
66-
ggplot()
67-
# Wicks (high-low lines)
68-
+ geom_segment(aes(x="x", xend="x", y="low", yend="high"), data=df, color="#666666", size=1)
69-
# Bullish candle bodies (green)
70-
+ geom_rect(
71-
aes(xmin="xmin", xmax="xmax", ymin="body_low", ymax="body_high"),
72-
data=df[df["bullish"]],
73-
fill="#22C55E",
74-
color="#22C55E",
71+
ggplot() # noqa: F405
72+
# Wicks (high-low lines) colored per direction
73+
+ geom_segment( # noqa: F405
74+
aes(x="x", xend="x", y="low", yend="high"), # noqa: F405
75+
data=bull_df,
76+
color=bull_color,
77+
size=0.9,
78+
tooltips=tip_fmt,
79+
)
80+
+ geom_segment( # noqa: F405
81+
aes(x="x", xend="x", y="low", yend="high"), # noqa: F405
82+
data=bear_df,
83+
color=bear_color,
84+
size=0.9,
85+
tooltips=tip_fmt,
86+
)
87+
# Bullish candle bodies (blue)
88+
+ geom_rect( # noqa: F405
89+
aes(xmin="xmin", xmax="xmax", ymin="body_low", ymax="body_high"), # noqa: F405
90+
data=bull_df,
91+
fill=bull_color,
92+
color=bull_color,
7593
size=0.5,
94+
tooltips=tip_fmt,
7695
)
77-
# Bearish candle bodies (red)
78-
+ geom_rect(
79-
aes(xmin="xmin", xmax="xmax", ymin="body_low", ymax="body_high"),
80-
data=df[~df["bullish"]],
81-
fill="#EF4444",
82-
color="#EF4444",
96+
# Bearish candle bodies (orange)
97+
+ geom_rect( # noqa: F405
98+
aes(xmin="xmin", xmax="xmax", ymin="body_low", ymax="body_high"), # noqa: F405
99+
data=bear_df,
100+
fill=bear_color,
101+
color=bear_color,
83102
size=0.5,
103+
tooltips=tip_fmt,
84104
)
85-
# Labels and theme
86-
+ scale_x_continuous(
87-
breaks=list(range(0, n_days, 5)), labels=[df["date"].iloc[i].strftime("%b %d") for i in range(0, n_days, 5)]
105+
+ scale_x_continuous(breaks=tick_pos, labels=tick_labels, expand=[0.02, 0]) # noqa: F405
106+
+ labs( # noqa: F405
107+
x="Trading Day (Jan\u2013Feb 2024)", y="Price ($)", title="candlestick-basic \u00b7 letsplot \u00b7 pyplots.ai"
88108
)
89-
+ labs(x="Date", y="Price ($)", title="candlestick-basic · letsplot · pyplots.ai")
90-
+ theme_minimal()
91-
+ theme(
92-
axis_title=element_text(size=20),
93-
axis_text=element_text(size=16),
94-
plot_title=element_text(size=24),
95-
panel_grid_major_x=element_blank(),
96-
panel_grid_minor=element_blank(),
109+
+ theme_minimal() # noqa: F405
110+
+ theme( # noqa: F405
111+
axis_title=element_text(size=20, color="#333333"), # noqa: F405
112+
axis_text=element_text(size=16, color="#555555"), # noqa: F405
113+
plot_title=element_text(size=24, color="#222222"), # noqa: F405
114+
panel_grid_major_x=element_line(color="#ececec", size=0.3), # noqa: F405
115+
panel_grid_major_y=element_line(color="#e0e0e0", size=0.4), # noqa: F405
116+
panel_grid_minor=element_blank(), # noqa: F405
117+
axis_ticks=element_blank(), # noqa: F405
118+
plot_background=element_rect(fill="white", color="white"), # noqa: F405
97119
)
98-
+ ggsize(1600, 900)
120+
+ ggsize(1600, 900) # noqa: F405
99121
)
100122

101-
# Save HTML for interactive version
102-
ggsave(plot, "plot.html", path=".")
103-
104-
# Save SVG first, then convert to PNG
105-
ggsave(plot, "plot.svg", path=".", w=1600, h=900, unit="px")
106-
107-
# Convert SVG to PNG using cairosvg
108-
with open("plot.svg", "r") as f:
109-
svg_content = f.read()
110-
111-
cairosvg.svg2png(bytestring=svg_content.encode("utf-8"), write_to="plot.png", output_width=4800, output_height=2700)
123+
# Save
124+
ggsave(plot, "plot.png", path=".", scale=3) # noqa: F405
125+
ggsave(plot, "plot.html", path=".") # noqa: F405

plots/candlestick-basic/metadata/letsplot.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
library: letsplot
22
specification_id: candlestick-basic
33
created: '2025-12-23T10:01:30Z'
4-
updated: '2025-12-23T10:07:36Z'
5-
generated_by: claude-opus-4-5-20251101
4+
updated: '2026-02-24T20:50:21+00:00'
5+
generated_by: claude-opus-4-6
66
workflow_run: 20457535627
77
issue: 0
8-
python_version: 3.13.11
9-
library_version: 4.8.2
8+
python_version: "3.14.3"
9+
library_version: "4.8.2"
1010
preview_url: https://storage.googleapis.com/pyplots-images/plots/candlestick-basic/letsplot/plot.png
1111
preview_thumb: https://storage.googleapis.com/pyplots-images/plots/candlestick-basic/letsplot/plot_thumb.png
1212
preview_html: https://storage.googleapis.com/pyplots-images/plots/candlestick-basic/letsplot/plot.html
13-
quality_score: 92
13+
quality_score: null
1414
impl_tags:
1515
dependencies:
1616
- cairosvg

0 commit comments

Comments
 (0)