Skip to content

Commit 8cb29fe

Browse files
github-actions[bot]claude[bot]MarkusNeusinger
authored
feat: add bar-basic implementation (9 libraries) (#487)
## Summary Adds `bar-basic` plot implementation. ### Libraries - **Merged:** 9 - **Not Feasible:** 0 ### Links - **Spec:** `specs/bar-basic.md` - **Parent Issue:** #202 (closes on merge) --- :robot: *Auto-generated by pyplots CI* --------- Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com> Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Markus Neusinger <2921697+MarkusNeusinger@users.noreply.github.com>
1 parent 32a7470 commit 8cb29fe

File tree

9 files changed

+293
-928
lines changed

9 files changed

+293
-928
lines changed

plots/altair/bar/bar-basic/default.py

Lines changed: 16 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -7,101 +7,21 @@
77
import pandas as pd
88

99

10-
def create_plot(
11-
data: pd.DataFrame,
12-
category: str,
13-
value: str,
14-
*,
15-
color: str = "steelblue",
16-
alpha: float = 0.8,
17-
title: str | None = None,
18-
xlabel: str | None = None,
19-
ylabel: str | None = None,
20-
rotation: int = 0,
21-
**kwargs,
22-
) -> alt.Chart:
23-
"""
24-
Create a basic vertical bar chart.
25-
26-
A fundamental bar chart that visualizes categorical data with numeric values,
27-
ideal for comparing quantities across discrete categories.
28-
29-
Args:
30-
data: Input DataFrame containing the data to plot.
31-
category: Column name for categorical x-axis values.
32-
value: Column name for numeric y-axis values.
33-
color: Bar fill color. Defaults to "steelblue".
34-
alpha: Transparency level for bars (0-1). Defaults to 0.8.
35-
title: Plot title. Defaults to None.
36-
xlabel: X-axis label. Defaults to column name if None.
37-
ylabel: Y-axis label. Defaults to column name if None.
38-
rotation: Rotation angle for x-axis labels. Defaults to 0.
39-
**kwargs: Additional parameters passed to chart properties.
40-
41-
Returns:
42-
Altair Chart object.
43-
44-
Raises:
45-
ValueError: If data is empty.
46-
KeyError: If required columns are not found in data.
47-
48-
Example:
49-
>>> data = pd.DataFrame({
50-
... 'category': ['A', 'B', 'C'],
51-
... 'value': [10, 20, 15]
52-
... })
53-
>>> chart = create_plot(data, 'category', 'value', title='Example')
54-
"""
55-
# Input validation
56-
if data.empty:
57-
raise ValueError("Data cannot be empty")
58-
59-
for col in [category, value]:
60-
if col not in data.columns:
61-
available = ", ".join(data.columns)
62-
raise KeyError(f"Column '{col}' not found. Available: {available}")
63-
64-
# Determine axis labels
65-
x_label = xlabel if xlabel is not None else category
66-
y_label = ylabel if ylabel is not None else value
67-
68-
# Build x-axis configuration
69-
x_axis = alt.Axis(title=x_label, labelAngle=-rotation if rotation != 0 else 0)
70-
71-
# Build y-axis configuration with subtle grid
72-
y_axis = alt.Axis(title=y_label, grid=True, gridOpacity=0.3)
73-
74-
# Create the bar chart
75-
chart = (
76-
alt.Chart(data)
77-
.mark_bar(color=color, opacity=alpha)
78-
.encode(
79-
x=alt.X(f"{category}:N", axis=x_axis, sort=None),
80-
y=alt.Y(f"{value}:Q", axis=y_axis, scale=alt.Scale(domain=[0, data[value].max() * 1.1])),
81-
tooltip=[alt.Tooltip(f"{category}:N", title=x_label), alt.Tooltip(f"{value}:Q", title=y_label)],
82-
)
83-
.properties(width=800, height=450)
84-
)
85-
86-
# Add title if provided
87-
if title is not None:
88-
chart = chart.properties(title=title)
89-
90-
# Configure chart appearance
91-
chart = chart.configure_axis(labelFontSize=12, titleFontSize=14).configure_title(fontSize=16, anchor="middle")
92-
93-
return chart
94-
95-
96-
if __name__ == "__main__":
97-
# Sample data for testing
98-
sample_data = pd.DataFrame(
99-
{"category": ["Product A", "Product B", "Product C", "Product D", "Product E"], "value": [45, 78, 52, 91, 63]}
10+
# Data
11+
data = pd.DataFrame(
12+
{"category": ["Product A", "Product B", "Product C", "Product D", "Product E"], "value": [45, 78, 52, 91, 63]}
13+
)
14+
15+
# Create chart
16+
chart = (
17+
alt.Chart(data)
18+
.mark_bar(color="#306998")
19+
.encode(
20+
x=alt.X("category:N", title="Category", axis=alt.Axis(labelFontSize=16, titleFontSize=20)),
21+
y=alt.Y("value:Q", title="Value", axis=alt.Axis(labelFontSize=16, titleFontSize=20)),
10022
)
23+
.properties(width=1600, height=900, title=alt.Title(text="Basic Bar Chart", fontSize=20))
24+
)
10125

102-
# Create plot
103-
fig = create_plot(sample_data, "category", "value", title="Sales by Product")
104-
105-
# Save
106-
fig.save("plot.png", scale_factor=2.0)
107-
print("Plot saved to plot.png")
26+
# Save as PNG (1600 × 900 with scale_factor=3 = 4800 × 2700)
27+
chart.save("plot.png", scale_factor=3.0)

plots/bokeh/vbar/bar-basic/default.py

Lines changed: 33 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -3,150 +3,42 @@
33
Library: bokeh
44
"""
55

6-
from typing import TYPE_CHECKING
7-
86
import pandas as pd
97
from bokeh.io import export_png
108
from bokeh.models import ColumnDataSource
119
from bokeh.plotting import figure
1210

1311

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

Comments
 (0)