|
| 1 | +""" pyplots.ai |
| 2 | +subplot-grid-custom: Custom Subplot Grid Layout |
| 3 | +Library: bokeh 3.8.1 | Python 3.13.11 |
| 4 | +Quality: 91/100 | Created: 2025-12-30 |
| 5 | +""" |
| 6 | + |
| 7 | +import numpy as np |
| 8 | +from bokeh.io import export_png |
| 9 | +from bokeh.layouts import column, row |
| 10 | +from bokeh.models import ColumnDataSource, Title |
| 11 | +from bokeh.plotting import figure |
| 12 | + |
| 13 | + |
| 14 | +# Data |
| 15 | +np.random.seed(42) |
| 16 | + |
| 17 | +# Main time series data (simulating daily stock prices) |
| 18 | +n_days = 100 |
| 19 | +dates = np.arange(n_days) |
| 20 | +prices = 100 + np.cumsum(np.random.randn(n_days) * 2) |
| 21 | +volumes = np.random.uniform(1, 5, n_days) * 1e6 |
| 22 | +returns = np.diff(prices) / prices[:-1] * 100 |
| 23 | + |
| 24 | +# Additional data for supporting plots |
| 25 | +categories = ["Product A", "Product B", "Product C", "Product D"] |
| 26 | +sales = [45, 72, 38, 65] |
| 27 | + |
| 28 | +scatter_x = np.random.randn(80) |
| 29 | +scatter_y = scatter_x * 0.8 + np.random.randn(80) * 0.5 |
| 30 | + |
| 31 | +# Column data sources |
| 32 | +price_source = ColumnDataSource(data={"x": dates, "y": prices}) |
| 33 | +bar_source = ColumnDataSource(data={"x": categories, "y": sales}) |
| 34 | +scatter_source = ColumnDataSource(data={"x": scatter_x, "y": scatter_y}) |
| 35 | + |
| 36 | +# Color palette |
| 37 | +python_blue = "#306998" |
| 38 | +python_yellow = "#FFD43B" |
| 39 | +accent_green = "#2E8B57" |
| 40 | +accent_red = "#CD5C5C" |
| 41 | + |
| 42 | +# Plot 1: Main time series (large - spans conceptually 2 columns) |
| 43 | +p1 = figure( |
| 44 | + width=3000, |
| 45 | + height=1400, |
| 46 | + title="Price Trend Over Time", |
| 47 | + x_axis_label="Day", |
| 48 | + y_axis_label="Price ($)", |
| 49 | + toolbar_location=None, |
| 50 | +) |
| 51 | +p1.line("x", "y", source=price_source, line_width=4, color=python_blue, alpha=0.9) |
| 52 | +p1.scatter("x", "y", source=price_source, size=12, color=python_blue, alpha=0.6) |
| 53 | +p1.title.text_font_size = "32pt" |
| 54 | +p1.xaxis.axis_label_text_font_size = "24pt" |
| 55 | +p1.yaxis.axis_label_text_font_size = "24pt" |
| 56 | +p1.xaxis.major_label_text_font_size = "20pt" |
| 57 | +p1.yaxis.major_label_text_font_size = "20pt" |
| 58 | +p1.grid.grid_line_alpha = 0.3 |
| 59 | +p1.outline_line_color = "#cccccc" |
| 60 | +p1.outline_line_width = 2 |
| 61 | + |
| 62 | +# Add main title above p1 |
| 63 | +main_title = Title(text="subplot-grid-custom · bokeh · pyplots.ai", text_font_size="36pt", align="center") |
| 64 | +p1.add_layout(main_title, "above") |
| 65 | + |
| 66 | +# Plot 2: Volume bar chart (right side panel) |
| 67 | +p2 = figure( |
| 68 | + width=1600, |
| 69 | + height=1400, |
| 70 | + title="Daily Trading Volume", |
| 71 | + x_axis_label="Day", |
| 72 | + y_axis_label="Volume (millions)", |
| 73 | + toolbar_location=None, |
| 74 | +) |
| 75 | +p2.vbar(x=dates, top=volumes / 1e6, width=0.7, color=python_yellow, alpha=0.85) |
| 76 | +p2.title.text_font_size = "32pt" |
| 77 | +p2.xaxis.axis_label_text_font_size = "24pt" |
| 78 | +p2.yaxis.axis_label_text_font_size = "24pt" |
| 79 | +p2.xaxis.major_label_text_font_size = "20pt" |
| 80 | +p2.yaxis.major_label_text_font_size = "20pt" |
| 81 | +p2.grid.grid_line_alpha = 0.3 |
| 82 | +p2.outline_line_color = "#cccccc" |
| 83 | +p2.outline_line_width = 2 |
| 84 | + |
| 85 | +# Plot 3: Returns histogram (bottom left) |
| 86 | +hist, edges = np.histogram(returns, bins=20) |
| 87 | +hist_source = ColumnDataSource(data={"top": hist, "left": edges[:-1], "right": edges[1:]}) |
| 88 | +p3 = figure( |
| 89 | + width=1500, |
| 90 | + height=1100, |
| 91 | + title="Returns Distribution", |
| 92 | + x_axis_label="Daily Return (%)", |
| 93 | + y_axis_label="Frequency", |
| 94 | + toolbar_location=None, |
| 95 | +) |
| 96 | +p3.quad( |
| 97 | + top="top", |
| 98 | + bottom=0, |
| 99 | + left="left", |
| 100 | + right="right", |
| 101 | + source=hist_source, |
| 102 | + fill_color=accent_green, |
| 103 | + line_color="white", |
| 104 | + line_width=2, |
| 105 | + alpha=0.85, |
| 106 | +) |
| 107 | +p3.title.text_font_size = "28pt" |
| 108 | +p3.xaxis.axis_label_text_font_size = "22pt" |
| 109 | +p3.yaxis.axis_label_text_font_size = "22pt" |
| 110 | +p3.xaxis.major_label_text_font_size = "18pt" |
| 111 | +p3.yaxis.major_label_text_font_size = "18pt" |
| 112 | +p3.grid.grid_line_alpha = 0.3 |
| 113 | +p3.outline_line_color = "#cccccc" |
| 114 | +p3.outline_line_width = 2 |
| 115 | + |
| 116 | +# Plot 4: Categorical bar chart (bottom center) |
| 117 | +p4 = figure( |
| 118 | + width=1500, |
| 119 | + height=1100, |
| 120 | + x_range=categories, |
| 121 | + title="Sales by Product Category", |
| 122 | + x_axis_label="Product", |
| 123 | + y_axis_label="Units Sold", |
| 124 | + toolbar_location=None, |
| 125 | +) |
| 126 | +p4.vbar(x="x", top="y", source=bar_source, width=0.6, color=python_blue, alpha=0.85) |
| 127 | +p4.title.text_font_size = "28pt" |
| 128 | +p4.xaxis.axis_label_text_font_size = "22pt" |
| 129 | +p4.yaxis.axis_label_text_font_size = "22pt" |
| 130 | +p4.xaxis.major_label_text_font_size = "18pt" |
| 131 | +p4.yaxis.major_label_text_font_size = "18pt" |
| 132 | +p4.xaxis.major_label_orientation = 0.3 |
| 133 | +p4.grid.grid_line_alpha = 0.3 |
| 134 | +p4.outline_line_color = "#cccccc" |
| 135 | +p4.outline_line_width = 2 |
| 136 | + |
| 137 | +# Plot 5: Scatter plot with correlation (bottom right) |
| 138 | +p5 = figure( |
| 139 | + width=1600, |
| 140 | + height=1100, |
| 141 | + title="Variable Correlation Analysis", |
| 142 | + x_axis_label="X Variable", |
| 143 | + y_axis_label="Y Variable", |
| 144 | + toolbar_location=None, |
| 145 | +) |
| 146 | +p5.scatter("x", "y", source=scatter_source, size=18, color=accent_red, alpha=0.7) |
| 147 | +p5.title.text_font_size = "28pt" |
| 148 | +p5.xaxis.axis_label_text_font_size = "22pt" |
| 149 | +p5.yaxis.axis_label_text_font_size = "22pt" |
| 150 | +p5.xaxis.major_label_text_font_size = "18pt" |
| 151 | +p5.yaxis.major_label_text_font_size = "18pt" |
| 152 | +p5.grid.grid_line_alpha = 0.3 |
| 153 | +p5.outline_line_color = "#cccccc" |
| 154 | +p5.outline_line_width = 2 |
| 155 | + |
| 156 | +# Custom grid layout demonstrating non-uniform cell sizes |
| 157 | +# Row 1: Main time series (3000px) + Volume sidebar (1600px) = 4600px |
| 158 | +# Row 2: Histogram (1500px) + Bar chart (1500px) + Scatter (1600px) = 4600px |
| 159 | +# This creates a dashboard with varied cell sizes (colspan/rowspan concept) |
| 160 | + |
| 161 | +top_row = row(p1, p2) |
| 162 | +bottom_row = row(p3, p4, p5) |
| 163 | +final_layout = column(top_row, bottom_row) |
| 164 | + |
| 165 | +# Save |
| 166 | +export_png(final_layout, filename="plot.png") |
0 commit comments