Skip to content
112 changes: 16 additions & 96 deletions plots/altair/bar/bar-basic/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,101 +7,21 @@
import pandas as pd


def create_plot(
data: pd.DataFrame,
category: str,
value: str,
*,
color: str = "steelblue",
alpha: float = 0.8,
title: str | None = None,
xlabel: str | None = None,
ylabel: str | None = None,
rotation: int = 0,
**kwargs,
) -> alt.Chart:
"""
Create a basic vertical bar chart.

A fundamental bar chart that visualizes categorical data with numeric values,
ideal for comparing quantities across discrete categories.

Args:
data: Input DataFrame containing the data to plot.
category: Column name for categorical x-axis values.
value: Column name for numeric y-axis values.
color: Bar fill color. Defaults to "steelblue".
alpha: Transparency level for bars (0-1). Defaults to 0.8.
title: Plot title. Defaults to None.
xlabel: X-axis label. Defaults to column name if None.
ylabel: Y-axis label. Defaults to column name if None.
rotation: Rotation angle for x-axis labels. Defaults to 0.
**kwargs: Additional parameters passed to chart properties.

Returns:
Altair Chart object.

Raises:
ValueError: If data is empty.
KeyError: If required columns are not found in data.

Example:
>>> data = pd.DataFrame({
... 'category': ['A', 'B', 'C'],
... 'value': [10, 20, 15]
... })
>>> chart = create_plot(data, 'category', 'value', title='Example')
"""
# Input validation
if data.empty:
raise ValueError("Data cannot be empty")

for col in [category, value]:
if col not in data.columns:
available = ", ".join(data.columns)
raise KeyError(f"Column '{col}' not found. Available: {available}")

# Determine axis labels
x_label = xlabel if xlabel is not None else category
y_label = ylabel if ylabel is not None else value

# Build x-axis configuration
x_axis = alt.Axis(title=x_label, labelAngle=-rotation if rotation != 0 else 0)

# Build y-axis configuration with subtle grid
y_axis = alt.Axis(title=y_label, grid=True, gridOpacity=0.3)

# Create the bar chart
chart = (
alt.Chart(data)
.mark_bar(color=color, opacity=alpha)
.encode(
x=alt.X(f"{category}:N", axis=x_axis, sort=None),
y=alt.Y(f"{value}:Q", axis=y_axis, scale=alt.Scale(domain=[0, data[value].max() * 1.1])),
tooltip=[alt.Tooltip(f"{category}:N", title=x_label), alt.Tooltip(f"{value}:Q", title=y_label)],
)
.properties(width=800, height=450)
)

# Add title if provided
if title is not None:
chart = chart.properties(title=title)

# Configure chart appearance
chart = chart.configure_axis(labelFontSize=12, titleFontSize=14).configure_title(fontSize=16, anchor="middle")

return chart


if __name__ == "__main__":
# Sample data for testing
sample_data = pd.DataFrame(
{"category": ["Product A", "Product B", "Product C", "Product D", "Product E"], "value": [45, 78, 52, 91, 63]}
# Data
data = pd.DataFrame(
{"category": ["Product A", "Product B", "Product C", "Product D", "Product E"], "value": [45, 78, 52, 91, 63]}
)

# Create chart
chart = (
alt.Chart(data)
.mark_bar(color="#306998")
.encode(
x=alt.X("category:N", title="Category", axis=alt.Axis(labelFontSize=16, titleFontSize=20)),
y=alt.Y("value:Q", title="Value", axis=alt.Axis(labelFontSize=16, titleFontSize=20)),
)
.properties(width=1600, height=900, title=alt.Title(text="Basic Bar Chart", fontSize=20))
)

# Create plot
fig = create_plot(sample_data, "category", "value", title="Sales by Product")

# Save
fig.save("plot.png", scale_factor=2.0)
print("Plot saved to plot.png")
# Save as PNG (1600 × 900 with scale_factor=3 = 4800 × 2700)
chart.save("plot.png", scale_factor=3.0)
174 changes: 33 additions & 141 deletions plots/bokeh/vbar/bar-basic/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,150 +3,42 @@
Library: bokeh
"""

from typing import TYPE_CHECKING

import pandas as pd
from bokeh.io import export_png
from bokeh.models import ColumnDataSource
from bokeh.plotting import figure


if TYPE_CHECKING:
from bokeh.plotting import figure as Figure


def create_plot(
data: pd.DataFrame,
category: str,
value: str,
figsize: tuple[int, int] = (1600, 900),
color: str = "steelblue",
edgecolor: str = "black",
alpha: float = 0.8,
title: str | None = None,
xlabel: str | None = None,
ylabel: str | None = None,
rotation: int = 0,
**kwargs,
) -> "Figure":
"""
Create a basic vertical bar chart.

A fundamental bar chart that visualizes categorical data with numeric values,
ideal for comparing quantities across discrete categories.

Args:
data: Input DataFrame with categorical and numeric columns
category: Column name for category labels (x-axis)
value: Column name for numeric values (bar heights)
figsize: Figure size as (width, height) in pixels. Defaults to (1600, 900).
color: Bar fill color. Defaults to "steelblue".
edgecolor: Bar edge color. Defaults to "black".
alpha: Transparency level for bars (0-1). Defaults to 0.8.
title: Plot title. Defaults to None.
xlabel: X-axis label. Defaults to category column name.
ylabel: Y-axis label. Defaults to value column name.
rotation: Rotation angle for x-axis labels in degrees. Defaults to 0.
**kwargs: Additional parameters passed to figure.

Returns:
Bokeh figure object with the bar chart.

Raises:
ValueError: If data is empty.
KeyError: If required columns are not found in data.

Example:
>>> data = pd.DataFrame({
... 'category': ['A', 'B', 'C', 'D'],
... 'value': [10, 25, 15, 30]
... })
>>> fig = create_plot(data, 'category', 'value', title='Sample Bar Chart')
"""
# Input validation
if data.empty:
raise ValueError("Data cannot be empty")

for col in [category, value]:
if col not in data.columns:
available = ", ".join(data.columns.tolist())
raise KeyError(f"Column '{col}' not found. Available: {available}")

# Prepare data - drop NaN values
plot_data = data[[category, value]].dropna()

# Get categories as list for x_range
categories = plot_data[category].astype(str).tolist()

# Create ColumnDataSource
source = ColumnDataSource(data={"categories": categories, "values": plot_data[value].tolist()})

# Set labels
x_label = xlabel if xlabel is not None else category
y_label = ylabel if ylabel is not None else value

# Create figure with categorical x-axis
p = figure(
width=figsize[0],
height=figsize[1],
x_range=categories,
title=title,
x_axis_label=x_label,
y_axis_label=y_label,
**kwargs,
)

# Calculate bar width (0.8 of available space)
bar_width = 0.8

# Add bars
p.vbar(
x="categories",
top="values",
width=bar_width,
source=source,
fill_color=color,
fill_alpha=alpha,
line_color=edgecolor,
line_width=1,
)

# Ensure y-axis starts at zero
p.y_range.start = 0

# Style grid - subtle y-grid only
p.xgrid.grid_line_color = None
p.ygrid.grid_line_alpha = 0.3

# Apply x-axis label rotation if specified
if rotation != 0:
from math import pi

p.xaxis.major_label_orientation = rotation * pi / 180

# Style axis labels
p.xaxis.axis_label_text_font_size = "12pt"
p.yaxis.axis_label_text_font_size = "12pt"
p.xaxis.major_label_text_font_size = "10pt"
p.yaxis.major_label_text_font_size = "10pt"

# Style title if present
if title:
p.title.text_font_size = "14pt"
p.title.align = "center"

return p


if __name__ == "__main__":
# Sample data for testing
sample_data = pd.DataFrame(
{"category": ["Product A", "Product B", "Product C", "Product D", "Product E"], "value": [45, 78, 52, 91, 63]}
)

# Create plot
fig = create_plot(sample_data, "category", "value", title="Sales by Product", xlabel="Product", ylabel="Sales ($)")

# Save
export_png(fig, filename="plot.png")
print("Plot saved to plot.png")
# Data
data = pd.DataFrame(
{"category": ["Product A", "Product B", "Product C", "Product D", "Product E"], "value": [45, 78, 52, 91, 63]}
)

# Create ColumnDataSource
source = ColumnDataSource(data)

# Create figure with categorical x-axis
p = figure(
width=4800,
height=2700,
x_range=data["category"].tolist(),
title="Basic Bar Chart",
x_axis_label="Category",
y_axis_label="Value",
)

# Plot vertical bars
p.vbar(x="category", top="value", source=source, width=0.7, color="#306998", alpha=0.8)

# Styling
p.title.text_font_size = "20pt"
p.xaxis.axis_label_text_font_size = "20pt"
p.yaxis.axis_label_text_font_size = "20pt"
p.xaxis.major_label_text_font_size = "16pt"
p.yaxis.major_label_text_font_size = "16pt"
p.xgrid.grid_line_color = None
p.ygrid.grid_line_alpha = 0.3
p.y_range.start = 0

# Save
export_png(p, filename="plot.png")
Loading
Loading