A Python library to generate beautiful, clean charts in premium visual styles
Project description
Clean Charts
clean-charts is a lightweight, premium Python library designed to generate beautiful, publication-quality data visualizations inspired by modern editorial styles like The Economist.
Featuring right-aligned axes, custom date boundaries, distinct line colors, smooth spline curves, automatic overlap-avoiding label placement, and dynamic scaling for varying canvas resolutions, clean-charts makes it effortless to create presentation-ready visualizations — both saved to disk and displayed inline in Jupyter notebooks.
Key Features
- Premium Aesthetics: Light cream-gray backgrounds, minimal gridlines, elegant typography, and consistent padding.
- Jupyter Inline Display: When
output_path=None, charts render directly in Jupyter notebooks viaIPython.display. - Time-Series Line Charts (
plot_time_series):- Right-aligned Y-axes.
- Automatically identifies date/time columns and handles multiple value series.
- Smooth PCHIP spline curves through data points (requires
scipy). - Optional data-point markers with configurable style.
- Generates custom color gradients or uses a refined default palette.
- Intelligently spaces dates and years on the X-axis to prevent label overlap.
- Smart inline label placement at line endpoints (
name,value,both, ornone).
- Horizontal Bar Charts (
plot_barh_chart):- Left-aligned categories, top-aligned numeric ticks with custom suffixes.
- Values labeled inside/outside the end of each bar.
- Grouped Horizontal Bar Charts (
plot_grouped_barh_chart):- Multi-series bars per category in stacked vertical lanes.
- Gradient color palette across series, compact legend row above the chart.
- Optional bar labels (
value,name,both,none).
- Responsive Scaling: All text, line-weights, and paddings scale proportionally based on target width and height.
Installation
pip install clean-charts
Quick Start
1. Grouped Horizontal Bar Chart
Display multiple numeric series side-by-side for each category, with an automatic color gradient and legend.
import pandas as pd
from clean_charts import plot_grouped_barh_chart
df = pd.DataFrame({
'Fruit': ['Apples', 'Bananas', 'Cherries', 'Dates', 'Elderberries', 'Figs', 'Grapes'],
'2024': [380, 410, 150, 420, 85, 280, 490],
'2025': [510, 180, 830, 450, 190, 240, 560],
'2026': [415, 450, 590, 310, 60, 310, 400]
})
plot_grouped_barh_chart(
data = df,
title="Regional Supermarket Inventory and Fruit Category Performance Analysis",
subtitle="Comparative overview of total stock volume across key produce items to optimize supply chain distribution",
bar_padding=0,
group_padding=0.3,
value_suffix = ' Kg'
)
Output Example:
2. Horizontal Bar Chart
Draw a single-series horizontal bar chart with category labels and value annotations. If no data is provided, a built-in survey dataset is used.
import pandas as pd
from clean_charts import plot_barh_chart
df = pd.DataFrame({
'Category': ['Apples', 'Bananas', 'Cherries', 'Dates', 'Elderberries', 'Figs', 'Grapes', 'Honeydew'],
'Sales': [400, 350, 300, 450, 120, 210, 520, 180],
})
plot_barh_chart(
data=df,
title="Regional Supermarket Inventory and Fruit Category Performance Analysis",
subtitle="Comparative overview of total stock volume across key produce items to optimize supply chain distribution",
value_suffix=' Kg',
)
Output Example:
3. Time-Series Line Chart
Call plot_time_series to generate a time-series line chart from a DataFrame. If no data argument is provided, the function uses a built-in sample dataset of monthly automobile sales by type from 2020 to 2025.
import pandas as pd
from clean_charts import plot_time_series
df = pd.DataFrame({
'Dates': pd.date_range("2026-01-01", periods=12, freq="MS"),
'Apples': [500, 596, 590, 523, 582, 515, 501, 551, 494, 467, 548, 490],
'Bananas': [350, 339, 349, 382, 328, 359, 403, 390, 459, 390, 373, 437],
'Elderberries': [160, 118, 118, 124, 179, 126, 117, 115, 157, 114, 120, 127],
})
plot_time_series(
data=df,
aspect_ratio='1:1',
title="Regional Supermarket Inventory and Fruit Category Performance Analysis",
subtitle="Comparative overview of total stock volume across key produce items to optimize supply chain distribution",
label_frequency="month",
line_labels='name',
value_suffix=' Kg',
)
Output Example:
Customizing Data & Advanced Usage
Custom Time-Series Data
Supply your own pandas.DataFrame containing a date/time column and one or more value columns. The library automatically parses the datetime column and maps all other numeric columns as lines.
import pandas as pd
from clean_charts import plot_time_series
data = pd.DataFrame({
"Day": pd.date_range("2026-05-01", periods=10, freq="D"),
"Active Users": [120, 150, 190, 240, 220, 250, 270, 310, 340, 320],
"Signups": [15, 22, 35, 40, 28, 30, 32, 45, 52, 48],
})
plot_time_series(
data=data,
output_path="daily_stats.png",
title="Daily Server Growth",
subtitle="Active users and registrations in May 2026",
label_frequency="day", # "year" | "quarter" | "month" | "week" | "day" | "hour" | "minute" | "second"
start_color="#006400", # Dark green gradient start
end_color="#ffd700", # Gold gradient end
smooth=True, # Smooth PCHIP spline curves (default True)
markers=True, # Show circle markers on data points
line_labels="both", # Show "Series: value" inline labels
value_suffix="%", # Append "%" to Y-axis ticks and inline labels
)
Custom Horizontal Bar Chart Data
Pass a pandas.DataFrame where the first column contains string labels and the second column contains numeric values.
import pandas as pd
from clean_charts import plot_barh_chart
df = pd.DataFrame({
"Category": ["Apples", "Bananas", "Cherries", "Dates", "Elderberries", "Figs", "Grapes", "Honeydew"],
"Sales (tons)":[400, 350, 300, 450, 120, 210, 520, 180],
})
plot_barh_chart(
data=df,
output_path="fruit_sales.png",
title="Fruit Performance Analysis",
subtitle="Total sales volume by item",
value_suffix=" t",
color="#1f77b4",
)
Custom Grouped Bar Chart Data
Pass a DataFrame whose first column contains category labels and each subsequent column represents one series.
import pandas as pd
from clean_charts import plot_grouped_barh_chart
df = pd.DataFrame({
"Country": ["Germany", "France", "Italy", "Spain", "Poland"],
"BEV": [18, 14, 8, 5, 3],
"PHEV": [9, 7, 5, 4, 2],
"Hybrid": [22, 19, 12, 9, 6],
})
plot_grouped_barh_chart(
data=df,
output_path="ev_by_country.png",
title="EV Adoption by Country",
subtitle="Share of new car sales by powertrain, %",
value_suffix="%",
bar_labels="value", # "none" | "value" | "name" | "both"
start_color="#005f73",
end_color="#94d2bd",
)
API Reference
plot_time_series
| Parameter | Type | Default | Description |
|---|---|---|---|
data |
pd.DataFrame |
None |
DataFrame with a datetime column and value series. If None, uses built-in default data. |
output_path |
str |
None |
File path to save the image. If None, displays inline in Jupyter. |
width |
int |
1000 |
Target image width in pixels. |
height |
int |
562 |
Target image height in pixels. |
aspect_ratio |
str |
None |
Predefined ratio: "square"/"1:1", "landscape"/"2:1", "vertical"/"1:2". Overrides width/height. |
title |
str |
None |
Bold title text, left-aligned. Auto-wraps to 2 lines. |
subtitle |
str |
None |
Subtitle below the title. Auto-wraps to 2 lines. |
start_color |
str |
None |
Hex color for the first series in a gradient. |
end_color |
str |
None |
Hex color for the last series in a gradient. |
label_frequency |
str |
"year" |
X-axis tick frequency: "year", "quarter", "month", "week", "day", "hour", "minute", "second". |
markers |
bool or str |
None |
Data-point markers. False/None = none, True = circles, or any matplotlib marker string (e.g. "s", "D"). |
line_labels |
str |
"name" |
Inline endpoint labels: "name", "value", "both", or "none". |
value_suffix |
str |
"" |
String appended to Y-axis ticks and inline value labels (e.g. "%"). |
smooth |
bool |
True |
Draw smooth PCHIP spline curves. Falls back to straight lines if scipy is not installed. |
scale_text |
bool |
False |
Scale fonts and line weights proportionally to image size. |
plot_barh_chart
| Parameter | Type | Default | Description |
|---|---|---|---|
data |
pd.DataFrame |
None |
DataFrame: column 0 = category strings, column 1 = numeric values. If None, uses built-in survey data. |
output_path |
str |
None |
File path to save the image. If None, displays inline in Jupyter. |
width |
int |
600 |
Target image width in pixels. |
height |
int |
None |
Target image height in pixels. Auto-sized by number of categories if None. |
aspect_ratio |
str |
None |
Predefined ratio: "square"/"1:1", "landscape"/"2:1", "vertical"/"1:2". |
title |
str |
None |
Bold title text. |
subtitle |
str |
None |
Subtitle below the title. |
color |
str |
"#000000" |
Hex color for the bars. |
bar_padding |
float |
0.35 |
Fraction of bar slot left as gap between bars (0.0–1.0). |
value_suffix |
str |
"" |
String appended to value labels and axis ticks (e.g. "%"). |
scale_text |
bool |
True |
Scale fonts proportionally to image size. |
plot_grouped_barh_chart
| Parameter | Type | Default | Description |
|---|---|---|---|
data |
pd.DataFrame |
None |
DataFrame: column 0 = category labels, remaining columns = numeric series. If None, uses built-in example data. |
output_path |
str |
None |
File path to save the image. If None, displays inline in Jupyter. |
width |
int |
600 |
Target image width in pixels. |
height |
int |
None |
Target image height in pixels. Auto-sized when None. |
aspect_ratio |
str |
None |
Predefined ratio: "square"/"1:1", "landscape"/"2:1", "vertical"/"1:2". |
title |
str |
None |
Bold title text. Auto-wraps to 2 lines. |
subtitle |
str |
None |
Subtitle below the title. Auto-wraps to 3 lines. |
start_color |
str |
"#000000" |
Hex color for the first series in the gradient. |
end_color |
str |
"#2323FF" |
Hex color for the last series in the gradient. |
bar_padding |
float |
0 |
Fraction of a single bar slot left as whitespace (0–1). |
group_padding |
float |
0.45 |
Fraction of the group height used as spacing between groups (0–1). |
value_suffix |
str |
"" |
String appended to axis tick labels (e.g. "%"). |
bar_labels |
str |
"none" |
Labels drawn on each bar: "none", "value", "name", or "both". |
scale_text |
bool |
True |
Scale fonts proportionally to image size. |
Global Customization
Import and modify the global configuration variables to apply a consistent theme across all charts:
import clean_charts.config as config
from clean_charts import plot_time_series
# Override styling tokens before plotting
config.BACKGROUND_COLOR = "#ffffff" # Pure white background
config.GRID_COLOR = "#eaeaea" # Light gridlines
config.AXIS_COLOR = "#333333" # Dark charcoal axes
plot_time_series(
title="Custom White Theme",
output_path="white_theme_chart.png"
)
Available Config Variables (clean_charts.config)
| Variable | Default | Description |
|---|---|---|
BACKGROUND_COLOR |
"#f4f3f0" |
Chart background (cream-gray). |
GRID_COLOR |
"#dcdbd7" |
Horizontal/vertical gridline color. |
AXIS_COLOR |
"#000000" |
Axis spine and tick color. |
TITLE_COLOR |
"#111111" |
Title text color. |
SUBTITLE_COLOR |
"#444444" |
Subtitle text color. |
LINE_COLOR |
"#000000" |
Default line/bar color. |
DEFAULT_COLOR |
"#000000" |
Fallback single-bar color. |
DEFAULT_START_COLOR |
"#000000" |
Gradient start for grouped bars. |
DEFAULT_END_COLOR |
"#2323FF" |
Gradient end for grouped bars. |
DEFAULT_COLORS_LIST |
['#000000', '#2323FF', ...] |
Default multi-line color palette. |
Examples & Development
Generate Sample Charts
Run the provided script to generate a set of sample charts showcasing aspect ratios, gradient themes, custom label frequencies, and more:
python generate_sample.py
This produces:
sales_chart_2_1.png— Landscape 2:1 time-seriessales_chart_1_1.png— Square 1:1 time-seriessales_chart_1_2.png— Vertical 1:2 time-seriessales_chart_gradient.png— Gradient color demonstrationsales_chart_daily.png— Day-level label frequencysales_chart_long_title.png— Long title wrapping demo
Running Tests
python -m unittest tests/test_plot.py
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file clean_charts-0.4.0.tar.gz.
File metadata
- Download URL: clean_charts-0.4.0.tar.gz
- Upload date:
- Size: 26.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1c96b10b072e800c77becad24ec2420975852a6150f693c3b1186c44d038185f
|
|
| MD5 |
077da102e4de939ebd5c6c2f0f09ff48
|
|
| BLAKE2b-256 |
ce8cc0321ffb67a9e617f9a98f07e044115bf88996320176692ca3d021dc4d60
|
File details
Details for the file clean_charts-0.4.0-py3-none-any.whl.
File metadata
- Download URL: clean_charts-0.4.0-py3-none-any.whl
- Upload date:
- Size: 23.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
86f9cf87a2202eced6ac5faec5f10b7ac5ea74ace7f2fa7175ebd9c1d6358044
|
|
| MD5 |
2919957bc8f0ce20cdf65f5549e99fda
|
|
| BLAKE2b-256 |
5236d94ad921c12c128babd0b314a92b08c2cfa60b9f4e51bdd3c403f725ec27
|