|
3 | 3 | Library: bokeh |
4 | 4 | """ |
5 | 5 |
|
6 | | -from typing import TYPE_CHECKING |
7 | | - |
8 | 6 | import pandas as pd |
9 | 7 | from bokeh.io import export_png |
10 | 8 | from bokeh.models import ColumnDataSource |
11 | 9 | from bokeh.plotting import figure |
12 | 10 |
|
13 | 11 |
|
14 | | -if TYPE_CHECKING: |
15 | | - from bokeh.plotting import figure as Figure |
16 | | - |
17 | | - |
18 | | -def create_plot( |
19 | | - data: pd.DataFrame, |
20 | | - category: str, |
21 | | - value: str, |
22 | | - figsize: tuple[int, int] = (1600, 900), |
23 | | - color: str = "steelblue", |
24 | | - edgecolor: str = "black", |
25 | | - alpha: float = 0.8, |
26 | | - title: str | None = None, |
27 | | - xlabel: str | None = None, |
28 | | - ylabel: str | None = None, |
29 | | - rotation: int = 0, |
30 | | - **kwargs, |
31 | | -) -> "Figure": |
32 | | - """ |
33 | | - Create a basic vertical bar chart. |
34 | | -
|
35 | | - A fundamental bar chart that visualizes categorical data with numeric values, |
36 | | - ideal for comparing quantities across discrete categories. |
37 | | -
|
38 | | - Args: |
39 | | - data: Input DataFrame with categorical and numeric columns |
40 | | - category: Column name for category labels (x-axis) |
41 | | - value: Column name for numeric values (bar heights) |
42 | | - figsize: Figure size as (width, height) in pixels. Defaults to (1600, 900). |
43 | | - color: Bar fill color. Defaults to "steelblue". |
44 | | - edgecolor: Bar edge color. Defaults to "black". |
45 | | - alpha: Transparency level for bars (0-1). Defaults to 0.8. |
46 | | - title: Plot title. Defaults to None. |
47 | | - xlabel: X-axis label. Defaults to category column name. |
48 | | - ylabel: Y-axis label. Defaults to value column name. |
49 | | - rotation: Rotation angle for x-axis labels in degrees. Defaults to 0. |
50 | | - **kwargs: Additional parameters passed to figure. |
51 | | -
|
52 | | - Returns: |
53 | | - Bokeh figure object with the bar chart. |
54 | | -
|
55 | | - Raises: |
56 | | - ValueError: If data is empty. |
57 | | - KeyError: If required columns are not found in data. |
58 | | -
|
59 | | - Example: |
60 | | - >>> data = pd.DataFrame({ |
61 | | - ... 'category': ['A', 'B', 'C', 'D'], |
62 | | - ... 'value': [10, 25, 15, 30] |
63 | | - ... }) |
64 | | - >>> fig = create_plot(data, 'category', 'value', title='Sample Bar Chart') |
65 | | - """ |
66 | | - # Input validation |
67 | | - if data.empty: |
68 | | - raise ValueError("Data cannot be empty") |
69 | | - |
70 | | - for col in [category, value]: |
71 | | - if col not in data.columns: |
72 | | - available = ", ".join(data.columns.tolist()) |
73 | | - raise KeyError(f"Column '{col}' not found. Available: {available}") |
74 | | - |
75 | | - # Prepare data - drop NaN values |
76 | | - plot_data = data[[category, value]].dropna() |
77 | | - |
78 | | - # Get categories as list for x_range |
79 | | - categories = plot_data[category].astype(str).tolist() |
80 | | - |
81 | | - # Create ColumnDataSource |
82 | | - source = ColumnDataSource(data={"categories": categories, "values": plot_data[value].tolist()}) |
83 | | - |
84 | | - # Set labels |
85 | | - x_label = xlabel if xlabel is not None else category |
86 | | - y_label = ylabel if ylabel is not None else value |
87 | | - |
88 | | - # Create figure with categorical x-axis |
89 | | - p = figure( |
90 | | - width=figsize[0], |
91 | | - height=figsize[1], |
92 | | - x_range=categories, |
93 | | - title=title, |
94 | | - x_axis_label=x_label, |
95 | | - y_axis_label=y_label, |
96 | | - **kwargs, |
97 | | - ) |
98 | | - |
99 | | - # Calculate bar width (0.8 of available space) |
100 | | - bar_width = 0.8 |
101 | | - |
102 | | - # Add bars |
103 | | - p.vbar( |
104 | | - x="categories", |
105 | | - top="values", |
106 | | - width=bar_width, |
107 | | - source=source, |
108 | | - fill_color=color, |
109 | | - fill_alpha=alpha, |
110 | | - line_color=edgecolor, |
111 | | - line_width=1, |
112 | | - ) |
113 | | - |
114 | | - # Ensure y-axis starts at zero |
115 | | - p.y_range.start = 0 |
116 | | - |
117 | | - # Style grid - subtle y-grid only |
118 | | - p.xgrid.grid_line_color = None |
119 | | - p.ygrid.grid_line_alpha = 0.3 |
120 | | - |
121 | | - # Apply x-axis label rotation if specified |
122 | | - if rotation != 0: |
123 | | - from math import pi |
124 | | - |
125 | | - p.xaxis.major_label_orientation = rotation * pi / 180 |
126 | | - |
127 | | - # Style axis labels |
128 | | - p.xaxis.axis_label_text_font_size = "12pt" |
129 | | - p.yaxis.axis_label_text_font_size = "12pt" |
130 | | - p.xaxis.major_label_text_font_size = "10pt" |
131 | | - p.yaxis.major_label_text_font_size = "10pt" |
132 | | - |
133 | | - # Style title if present |
134 | | - if title: |
135 | | - p.title.text_font_size = "14pt" |
136 | | - p.title.align = "center" |
137 | | - |
138 | | - return p |
139 | | - |
140 | | - |
141 | | -if __name__ == "__main__": |
142 | | - # Sample data for testing |
143 | | - sample_data = pd.DataFrame( |
144 | | - {"category": ["Product A", "Product B", "Product C", "Product D", "Product E"], "value": [45, 78, 52, 91, 63]} |
145 | | - ) |
146 | | - |
147 | | - # Create plot |
148 | | - fig = create_plot(sample_data, "category", "value", title="Sales by Product", xlabel="Product", ylabel="Sales ($)") |
149 | | - |
150 | | - # Save |
151 | | - export_png(fig, filename="plot.png") |
152 | | - print("Plot saved to plot.png") |
| 12 | +# Data |
| 13 | +data = pd.DataFrame( |
| 14 | + {"category": ["Product A", "Product B", "Product C", "Product D", "Product E"], "value": [45, 78, 52, 91, 63]} |
| 15 | +) |
| 16 | + |
| 17 | +# Create ColumnDataSource |
| 18 | +source = ColumnDataSource(data) |
| 19 | + |
| 20 | +# Create figure with categorical x-axis |
| 21 | +p = figure( |
| 22 | + width=4800, |
| 23 | + height=2700, |
| 24 | + x_range=data["category"].tolist(), |
| 25 | + title="Basic Bar Chart", |
| 26 | + x_axis_label="Category", |
| 27 | + y_axis_label="Value", |
| 28 | +) |
| 29 | + |
| 30 | +# Plot vertical bars |
| 31 | +p.vbar(x="category", top="value", source=source, width=0.7, color="#306998", alpha=0.8) |
| 32 | + |
| 33 | +# Styling |
| 34 | +p.title.text_font_size = "20pt" |
| 35 | +p.xaxis.axis_label_text_font_size = "20pt" |
| 36 | +p.yaxis.axis_label_text_font_size = "20pt" |
| 37 | +p.xaxis.major_label_text_font_size = "16pt" |
| 38 | +p.yaxis.major_label_text_font_size = "16pt" |
| 39 | +p.xgrid.grid_line_color = None |
| 40 | +p.ygrid.grid_line_alpha = 0.3 |
| 41 | +p.y_range.start = 0 |
| 42 | + |
| 43 | +# Save |
| 44 | +export_png(p, filename="plot.png") |
0 commit comments