|
1 | 1 | """ pyplots.ai |
2 | 2 | candlestick-basic: Basic Candlestick Chart |
3 | | -Library: plotnine 0.15.2 | Python 3.13.11 |
4 | | -Quality: 91/100 | Created: 2025-12-23 |
| 3 | +Library: plotnine 0.15.3 | Python 3.14.3 |
| 4 | +Quality: /100 | Updated: 2026-02-24 |
5 | 5 | """ |
6 | 6 |
|
7 | 7 | import numpy as np |
8 | 8 | import pandas as pd |
9 | 9 | from plotnine import ( |
10 | 10 | aes, |
| 11 | + coord_cartesian, |
| 12 | + element_blank, |
11 | 13 | element_line, |
12 | 14 | element_text, |
13 | 15 | geom_rect, |
14 | 16 | geom_segment, |
15 | 17 | ggplot, |
16 | 18 | labs, |
| 19 | + scale_color_manual, |
17 | 20 | scale_fill_manual, |
| 21 | + scale_x_continuous, |
| 22 | + scale_y_continuous, |
18 | 23 | theme, |
19 | 24 | theme_minimal, |
20 | 25 | ) |
|
32 | 37 |
|
33 | 38 | for _ in range(n_days): |
34 | 39 | open_price = price |
35 | | - # Daily movement: random direction and magnitude |
36 | 40 | change = np.random.randn() * 3 |
37 | 41 | close_price = open_price + change |
38 | | - # High and low extend beyond open/close |
39 | 42 | high_price = max(open_price, close_price) + abs(np.random.randn() * 1.5) |
40 | 43 | low_price = min(open_price, close_price) - abs(np.random.randn() * 1.5) |
41 | 44 |
|
|
44 | 47 | lows.append(low_price) |
45 | 48 | closes.append(close_price) |
46 | 49 |
|
47 | | - # Next day opens near previous close |
48 | 50 | price = close_price + np.random.randn() * 0.5 |
49 | 51 |
|
50 | 52 | df = pd.DataFrame({"date": dates, "open": opens, "high": highs, "low": lows, "close": closes}) |
51 | 53 |
|
52 | | -# Add columns for plotting |
53 | | -df["date_num"] = np.arange(len(df)) |
| 54 | +# Derived columns for plotting |
| 55 | +df["day"] = np.arange(len(df)) |
54 | 56 | df["direction"] = np.where(df["close"] >= df["open"], "up", "down") |
55 | 57 | df["body_top"] = df[["open", "close"]].max(axis=1) |
56 | 58 | df["body_bottom"] = df[["open", "close"]].min(axis=1) |
57 | 59 |
|
58 | | -# Plot - build candlestick with segments (wicks) and rectangles (bodies) |
| 60 | +# Date labels for x-axis (show every 5th trading day) |
| 61 | +tick_indices = list(range(0, n_days, 5)) |
| 62 | +tick_labels = [dates[i].strftime("%b %d") for i in tick_indices] |
| 63 | + |
| 64 | +# Palette: blue for bullish, amber for bearish (colorblind-safe) |
| 65 | +palette = {"up": "#2196F3", "down": "#FF6F00"} |
| 66 | +edge_palette = {"up": "#1565C0", "down": "#E65100"} |
| 67 | + |
| 68 | +# Plot - candlestick with segments (wicks) and rectangles (bodies) |
59 | 69 | plot = ( |
60 | 70 | ggplot(df) |
61 | 71 | # Wicks (high-low lines) |
62 | | - + geom_segment(aes(x="date_num", xend="date_num", y="low", yend="high"), color="#333333", size=1) |
63 | | - # Candle bodies (rectangles) |
| 72 | + + geom_segment(aes(x="day", xend="day", y="low", yend="high"), color="#555555", size=0.7) |
| 73 | + # Candle bodies with subtle edge for definition |
64 | 74 | + geom_rect( |
65 | | - aes(xmin="date_num - 0.4", xmax="date_num + 0.4", ymin="body_bottom", ymax="body_top", fill="direction") |
| 75 | + aes( |
| 76 | + xmin="day - 0.35", |
| 77 | + xmax="day + 0.35", |
| 78 | + ymin="body_bottom", |
| 79 | + ymax="body_top", |
| 80 | + fill="direction", |
| 81 | + color="direction", |
| 82 | + ), |
| 83 | + size=0.3, |
66 | 84 | ) |
67 | | - # Colors: green for up, red for down |
68 | | - + scale_fill_manual(values={"up": "#22ab94", "down": "#f23645"}, guide=None) |
69 | | - + labs(x="Trading Day", y="Price ($)", title="candlestick-basic \u00b7 plotnine \u00b7 pyplots.ai") |
| 85 | + + scale_fill_manual(values=palette, guide=None) |
| 86 | + + scale_color_manual(values=edge_palette, guide=None) |
| 87 | + # Date labels on x-axis |
| 88 | + + scale_x_continuous(breaks=tick_indices, labels=tick_labels, expand=(0.02, 0.5)) |
| 89 | + + scale_y_continuous(labels=lambda vals: [f"${v:,.0f}" for v in vals]) |
| 90 | + + coord_cartesian(ylim=(df["low"].min() - 1.5, df["high"].max() + 1.5)) |
| 91 | + + labs(x="", y="Price ($)", title="candlestick-basic · plotnine · pyplots.ai") |
70 | 92 | + theme_minimal() |
71 | 93 | + theme( |
72 | 94 | figure_size=(16, 9), |
73 | 95 | text=element_text(size=14), |
74 | 96 | axis_title=element_text(size=20), |
75 | 97 | axis_text=element_text(size=16), |
76 | 98 | plot_title=element_text(size=24), |
77 | | - panel_grid_major=element_line(color="#cccccc", size=0.5, alpha=0.3), |
78 | | - panel_grid_minor=element_line(color="#eeeeee", size=0.3, alpha=0.2), |
| 99 | + panel_grid_major_x=element_blank(), |
| 100 | + panel_grid_minor_x=element_blank(), |
| 101 | + panel_grid_major_y=element_line(color="#d0d0d0", size=0.4, alpha=0.4), |
| 102 | + panel_grid_minor_y=element_blank(), |
79 | 103 | ) |
80 | 104 | ) |
81 | 105 |
|
|
0 commit comments