A modern Python data visualization library with smart defaults
Project description
BottleViz
A modern Python data visualization library with smart defaults.
BottleViz addresses the gaps in Matplotlib, Seaborn, and Plotly by providing a simplified, intuitive API with beautiful defaults out of the box, excellent performance with large datasets, and seamless integration with pandas and polars.
✨ Now with 55+ plot types, including full Seaborn-style statistical visualizations! ✨
Key Features
1. Simplified API
One function handles most use cases:
import bottleviz as vz
vz.plot(df, x='column1', y='column2') # All in one line!
vs. Matplotlib:
fig, ax = plt.subplots()
ax.scatter(df['column1'], df['column2'])
ax.set_xlabel('column1')
ax.set_ylabel('column2')
2. Intelligent Plot Type Detection
BottleViz automatically chooses the right plot type based on your data:
- Basic: Scatter, line, histogram, bar, pie, area
- Distributions: Box, violin, boxen, KDE, rug, strip, swarm
- Relationships: Scatter, hexbin, jointplot, pairplot
- Time Series: Line, lagplot, autocorrelation
- Statistical Diagnostics: Q-Q plot, residual plot
- Multivariate: Heatmap, contour, parallel coordinates, andrews curves, radviz
- Advanced: Sankey, Sunburst, Treemap, Network, Candlestick
- 3D: 3D scatter, surface, wireframe, contour, quiver, voxels
- Geographic: Choropleth, Scatter Geo, Flow Maps, Tile Maps, Cartogram
vz.plot(df) # Auto-detects appropriate visualization!
3. Beautiful Defaults
Stunning visualizations with zero configuration:
- Modern color palettes (colorblind-friendly)
- Professional typography
- Optimized layout and sizing
- Publication-ready styles
- Dark mode support
vz.set_style('dark') # Multiple presets available
vz.plot(df) # Automatically looks great
4. AI-Powered Suggestions (Optional)
Get intelligent plot recommendations from AI models:
Cloud providers:
- OpenAI GPT-4o, GPT-4o-mini
- Anthropic Claude 3 (Haiku, Sonnet, Opus)
Local models:
- Ollama (run models locally: llama3.2, mistral, codellama, etc.)
# Use AI to suggest the best visualization
vz.suggest_plots(df, ai=True, api_key="your-api-key")
# Or with local Ollama (no API key needed)
vz.suggest_plots(df, ai=True, ai_provider='ollama', model='llama3.2:1b')
# Result includes AI's reasoning and exact code to generate the plot
4. Excellent Performance
Optimized for large datasets:
- Smart downsampling for >10k points
- Optional GPU acceleration
- Datashader backend for millions of points
- Lazy evaluation where applicable
vz.plot(large_df) # Handles 1M+ rows smoothly
5. Seamless Dataframe Integration
Works perfectly with pandas, polars, and more:
vz.plot(df, x='date', y='sales')
vz.plot(polars_df, x='col1', y='col2')
6. Unified Interface
One consistent API across all plot types:
vz.plot(df, x='col1', y='col2', kind='scatter') # Same interface
vz.plot(df, x='col1', y='col2', kind='line')
vz.plot(df, x='col1', y='col2', kind='bar')
vz.plot(df, kind='hist') # Even works without x/y
7. Advanced Visualizations
Explore complex data relationships with specialized chart types:
Sankey Diagrams - Flow between stages/categories
vz.plot(flow_data, kind='sankey', source='from', target='to', value='count')
Requires: networkx
Sunburst Charts - Hierarchical radial layouts
vz.plot(hierarchy_data, kind='sunburst', path=['region', 'city'], value='sales')
Optional: squarify for treemap variant
Treemaps - Hierarchical rectangular layouts
vz.plot(hierarchy_data, kind='treemap', path=['region', 'city'], value='sales')
Requires: squarify
Network Graphs - Visualize relationships and connections
vz.plot(edges, kind='network', source='node1', target='node2', layout='spring')
Requires: networkx
Candlestick Charts - Financial OHLC time series
vz.plot(stock_data, x='date', kind='candlestick', open='open', high='high', low='low', close='close')
3D Visualizations - Comprehensive 3D plotting suite
# Surface plot (points connected by planes)
fig, ax = vz.plot_3d_surface(X, Y, Z, title='Surface', cmap='viridis')
# Wireframe mesh
fig, ax = vz.plot_3d_wireframe(X, Y, Z, title='Wireframe')
# Triangular surface (for scattered data)
fig, ax = vz.plot_3d_trisurf(x, y, z, title='Triangular Surface')
# Contour lines and filled contours
fig, ax = vz.plot_3d_contour(X, Y, Z, levels=15)
fig, ax = vz.plot_3d_contourf(X, Y, Z, levels=20)
# Vector field (arrows)
fig, ax = vz.plot_3d_quiver(X, Y, Z, U, V, W, title='Vector Field')
# 3D stem plot
fig, ax = vz.plot_3d_stem(x, y, z, title='3D Stem')
# 3D bar chart
fig, ax = vz.plot_3d_bar(x, y, z, dx, dy, dz, title='3D Bars')
# 3D voxel/volume rendering
fig, ax = vz.plot_3d_voxels(voxel_array, title='3D Voxels')
# Advanced: Create custom 3D figure and add multiple elements
fig, ax = vz.figure3d(title='Custom 3D Plot')
ax.plot_surface(X, Y, Z, cmap='plasma')
ax.contour(X, Y, Z, levels=10)
vz.show()
All 3D functions support full matplotlib customization via **kwargs.
Installation
# Basic installation
pip install bottleviz
# With all optional backends
pip install bottleviz[all]
# Just pandas/numpy + matplotlib
pip install bottleviz
# For interactive plots (Plotly)
pip install bottleviz[plotly]
# For massive datasets (Datashader)
pip install bottleviz[datashader]
# For AI-powered suggestions
pip install bottleviz[ai] # Installs openai, anthropic, ollama packages
Quick Start
import bottleviz as vz
import pandas as pd
import numpy as np
# Create sample data
df = pd.DataFrame({
'x': np.random.randn(1000),
'y': np.random.randn(1000),
'category': np.random.choice(['A', 'B', 'C'], 1000),
'value': np.random.randint(0, 100, 1000)
})
# Simple plot - auto-detects scatter
vz.plot(df, x='x', y='y')
# Bar chart with categories
vz.plot(df, x='category', y='value', kind='bar')
# Histogram
vz.plot(df, kind='hist', x='value')
# Time series
dates = pd.date_range('2024-01-01', periods=100)
ts_df = pd.DataFrame({
'date': dates,
'price': np.random.randn(100).cumsum() + 100
})
vz.plot(ts_df, x='date', y='price') # Auto-detects line plot
# Change style
vz.set_style('dark')
vz.plot(df, x='x', y='y')
# Get suggestions
vz.suggest_plots(df)
# Quick dashboard
vz.visualize(df)
New Plot Types Gallery
Stacked & Grouped Bar Charts
# Stacked bar (shows composition)
vz.plot(df, x='category', y=['sales_2023', 'sales_2024'], kind='stacked_bar')
# Grouped bar (side-by-side comparison)
vz.plot(df, x='group', y=['A', 'B', 'C'], kind='grouped_bar')
2D Density & Bin Plots
# Hexbin for large scatter datasets
vz.plot(large_df, x='x', y='y', kind='hexbin', gridsize=50, cmap='viridis')
# Step plot for discrete/constant changes
vz.plot(df, x='time', y='value', kind='step', where='pre')
# Fill between for confidence intervals
vz.plot(df, x='time', y='value', y_lower='ci_lower', y_upper='ci_upper', kind='fill_between')
vz.plot(df, x='time', y='value', kind='fill_between') # fills to zero
2D Contour & Grid Plots
# 2D Contour lines
x = np.linspace(-3, 3, 50)
y = np.linspace(-3, 3, 50)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) * np.cos(Y)
grid_data = pd.DataFrame({'x': X.flatten(), 'y': Y.flatten(), 'z': Z.flatten()})
vz.plot(grid_data, x='x', y='y', z='z', kind='contour')
vz.plot(grid_data, x='x', y='y', z='z', kind='contour', filled=True) # filled contours
# Pcolormesh for flexible gridded data
vz.plot(grid_data, x='x', y='y', value='z', kind='pcolormesh', cmap='plasma')
Heatmaps with Annotations
Heatmaps support text annotations in each cell:
# Correlation matrix with values
corr = df.corr()
vz.plot(corr, kind='heatmap', cmap='RdYlBu', center=0,
annot=True, fmt='.2f', annot_fontsize=9)
Vector & Sparse Data
# 2D Quiver (vector field)
vz.plot(vector_df, x='x', y='y', u='u', v='v', kind='quiver')
# Streamplot (flow lines) -自动 handles both gridded and long-form data
vz.plot(stream_df, x='x', y='y', u='u', v='v', kind='streamplot',
color='speed', cmap='viridis', density=2)
# Spy plot for sparse matrices
sparse_matrix = np.random.choice([0, 1], size=(100, 100), p=[0.95, 0.05])
vz.plot(pd.DataFrame(sparse_matrix), kind='spy', markersize=2)
Contours on Scattered Data
For data that is not on a regular grid, use tricontour variants:
# Generate scattered points
n = 500
x = np.random.uniform(-3, 3, n)
y = np.random.uniform(-3, 3, n)
z = np.sin(x) * np.cos(y) + np.random.randn(n)*0.1
scattered = pd.DataFrame({'x': x, 'y': y, 'z': z})
# Tricontour (lines)
vz.plot(scattered, x='x', y='y', z='z', kind='tricontour', levels=15)
# Tricontourf (filled)
vz.plot(scattered, x='x', y='y', z='z', kind='tricontourf', levels=20)
Special Coordinate Systems
# Polar plots (radial)
theta = np.linspace(0, 2*np.pi, 100)
r = 1 + np.cos(2*theta)
polar_df = pd.DataFrame({'theta': theta, 'r': r})
vz.plot(polar_df, theta='theta', r='r', kind='polar')
vz.plot(polar_df, theta='theta', r='r', kind='polar', fill=True, alpha=0.5)
Tables & Event Timeline
# Table visualization
vz.plot(df, kind='table', max_rows=10, fontsize=9)
# Event plot for sequences (R&D, healthcare events)
event_data = pd.DataFrame({
'patient_id': [1, 2, 3],
'diagnosis': [1, 0, 1],
'treatment': [1, 1, 0],
'recovery': [0, 1, 1]
})
vz.plot(event_data, columns=['diagnosis', 'treatment', 'recovery'], kind='eventplot')
Financial & Project Charts
# Waterfall chart (profit walk, bridge charts)
waterfall_data = pd.DataFrame({
'category': ['Starting', 'Revenue', 'Cost', 'Investment', 'Return'],
'value': [100, 50, -30, -20, 40]
})
vz.plot(waterfall_data, x='category', y='value', kind='waterfall')
# Gantt chart (project timelines)
gantt_data = pd.DataFrame({
'task': ['Design', 'Development', 'Testing', 'Deployment'],
'start': ['2024-01-01', '2024-02-01', '2024-03-01', '2024-04-01'],
'end': ['2024-01-31', '2024-03-01', '2024-03-31', '2024-04-15']
})
vz.plot(gantt_data, task='task', start='start', end='end', kind='gantt')
# OHLC with volume (financial candlestick + volume)
ohlc_data = pd.DataFrame({
'date': pd.date_range('2024-01-01', periods=20, freq='D'),
'open': np.random.rand(20) * 100 + 100,
'high': np.random.rand(20) * 110 + 100,
'low': np.random.rand(20) * 90 + 100,
'close': np.random.rand(20) * 100 + 100,
'volume': np.random.randint(1000, 5000, 20)
})
ohlc_data['high'] = ohlc_data[['open','close','high']].max(axis=1)
ohlc_data['low'] = ohlc_data[['open','close','low']].min(axis=1)
vz.plot(ohlc_data, x='date', open='open', high='high', low='low',
close='close', volume='volume', kind='ohlc_volume')
Statistical & Exploratory Data Analysis (EDA) Plots
BottleViz includes a comprehensive suite of statistical and EDA plots for in-depth data exploration:
Pair Plot - Scatter matrix with histograms/KDE on diagonal
# Multi-variable scatter matrix
vz.plot(df, kind='pairplot', columns=['x1', 'x2', 'x3', 'x4'])
# With grouping (uses color for different classes)
vz.plot(df, kind='pairplot', columns=['x1', 'x2', 'x3'], hue='category')
Joint Plot - Scatter plot with marginal distributions (histogram or KDE)
# Basic joint plot
vz.plot(df, x='x', y='y', kind='jointplot')
# With KDE margins
vz.plot(df, x='x', y='y', kind='jointplot', marginal_kind='kde')
# With hexbin for the main plot
vz.plot(df, x='x', y='y', kind='jointplot', joint_kind='hexbin')
Boxen Plot - Letter-value box plots (enhanced box plot showing more distribution details)
vz.plot(df, x='category', y='value', kind='boxen')
vz.plot(df, x='category', y='value', kind='boxen', k_depth='profound') # More detail
Rug Plot - Marginal tick marks showing distribution along one axis
vz.plot(df, x='value', kind='rug', height=0.2)
vz.plot(df, x='value', kind='rug', color='blue', alpha=0.5)
Strip Plot - Categorical scatter plot with jitter to prevent overplotting
vz.plot(df, x='category', y='value', kind='strip', jitter=0.2)
vz.plot(df, x='category', y='value', kind='strip', hue='subcategory')
Swarm Plot - Non-overlapping categorical scatter (like strip but points don't overlap)
vz.plot(df, x='category', y='value', kind='swarm')
vz.plot(df, x='category', y='value', kind='swarm', size=3, alpha=0.7)
Q-Q Plot - Quantile-Quantile plot for normality testing
# Compare distribution to normal
vz.plot(df, x='residuals', kind='qqplot', dist='norm')
# Compare to other distributions
vz.plot(df, x='data', kind='qqplot', dist='uniform')
Residual Plot - Plot residuals vs fitted values for regression diagnostics
vz.plot(df, x='predictor', y='response', kind='residualplot', order=1)
vz.plot(df, x='x', y='y', kind='residualplot', lowess=True) # With LOWESS smooth
Autocorrelation Plot (ACF) - Shows correlation of time series with its lags
vz.plot(ts_df, x='value', kind='autocorrelation', lags=50)
vz.plot(ts_df, x='value', kind='autocorrelation', lags=30, alpha=0.05) # 95% CI
Lag Plot - Scatter plot of time series vs its lag (check for autocorrelation)
vz.plot(ts_df, x='value', kind='lagplot', lag=1) # Lag-1 plot
vz.plot(ts_df, x='value', kind='lagplot', lag=12) # Seasonal lag
Andrews Curves - Visualize multivariate data as continuous functions (for classification)
# Each sample becomes a curve; curves group by class
vz.plot(df, x='species', columns=['sepal_length', 'sepal_width', 'petal_length', 'petal_width'],
kind='andrews_curves')
Parallel Coordinates - Parallel axes showing multivariate observations
vz.plot(df, x='class', columns=['feat1', 'feat2', 'feat3', 'feat4'],
kind='parallel_coordinates', alpha=0.5)
RadViz - Radial coordinate system for multivariate visualization
vz.plot(df, x='species', columns=['x1', 'x2', 'x3', 'x4'],
kind='radviz', alpha=0.7)
Notes:
- Most statistical plots support optional
scipyfor enhanced features (KDE, distributions) - Pair plot and joint plot can be memory intensive for very large datasets (>10k rows)
- Consider using
sampleparameter for large data:vz.plot(df.sample(5000), kind='pairplot', ...)
Demo: See examples/demo_statistical_plots.py for complete examples of all these plot types.
Geographic & Map Visualizations
# Requires geopandas
import bottleviz as vz
# gdf must have a geometry column (GeoSeries or shapely geometries)
vz.plot(gdf, kind='choropleth', geometry='geometry', value='population',
title='Population by Region', cmap='viridis')
Scatter Geo - Scatter plot overlaid on geographic coordinates.
vz.plot(df, kind='scatter_geo', lat='latitude', lon='longitude',
value='temperature', title='Temperature by Location',
cmap='plasma', markersize=50, alpha=0.7)
Flow Maps - Show movement/flows between origins and destinations using lines.
vz.plot(df, kind='flow_map', origin_lat='olat', origin_lon='olon',
dest_lat='dlat', dest_lon='dlon', flow='volume',
title='Migration Flows Between Cities', color='#2196F3')
Tile Maps - Choropleth with a basemap tile layer (e.g., OpenStreetMap).
# Requires contextily
import geopandas as gpd
import contextily as ctx
gdf = gpd.GeoDataFrame(df, geometry='geometry').to_crs(epsg=3857)
vz.plot(gdf, kind='tile_map', value='density', title='Population Density',
tile_source=ctx.providers.OpenStreetMap.Mapnik)
Cartograms - Distort geographic areas proportionally to a data value.
vz.plot(gdf, kind='cartogram', value='population',
title='Population Cartogram', color='#4CAF50')
API Reference
Main Functions
vz.plot(data, x=None, y=None, kind=None, **kwargs)
Core plotting function with smart defaults.
Parameters:
data: DataFrame, Series, ndarray, list, or dictx: Column name for x-axis (optional)y: Column name(s) for y-axis (optional)kind: Plot type ('scatter', 'line', 'bar', 'stacked_bar', 'grouped_bar', 'hist', 'box', 'violin', 'heatmap', 'pcolormesh', 'pie', 'area', 'kde', '3d', 'stem', 'errorbar', 'sankey', 'sunburst', 'treemap', 'network', 'candlestick', 'hexbin', 'step', 'fill_between', 'contour', 'quiver', 'spy', 'polar', 'table', 'eventplot', 'waterfall', 'gantt', 'ohlc_volume', 'scatter_geo', 'cartogram', 'choropleth', 'flow_map', 'tile_map', 'pairplot', 'jointplot', 'boxen', 'rug', 'strip', 'swarm', 'qqplot', 'residualplot', 'autocorrelation', 'lagplot', 'andrews_curves', 'parallel_coordinates', 'radviz', 'streamplot', 'tricontour', 'tricontourf')**kwargs: Additional arguments (title, xlabel, ylabel, etc.)
Examples:
vz.plot(df, x='col1', y='col2') # Auto-detects scatter
vz.plot(df, x='col1', y='col2', kind='line') # Force line
vz.plot(df, kind='hist') # Histogram of all numeric columns
vz.plot(df, x='category', y='value', kind='bar') # Bar chart
# Statistical & EDA plots
vz.plot(df, kind='pairplot', columns=['x1', 'x2', 'x3'])
vz.plot(df, x='x', y='y', kind='jointplot')
vz.plot(df, x='category', y='value', kind='boxen')
vz.plot(df, x='value', kind='qqplot')
vz.plot(ts_df, x='value', kind='autocorrelation', lags=50)
# Advanced scientific plots
vz.plot(stream_df, x='x', y='y', u='u', v='v', kind='streamplot')
vz.plot(scattered_df, x='x', y='y', z='z', kind='tricontour', levels=15)
vz.quickplot(*args, **kwargs)
Ultra-simple one-liner plotting.
vz.quickplot([1,2,3,4,5]) # Line plot from list
vz.quickplot(x=[1,2,3], y=[4,5,6]) # Named lists
vz.quickplot(df) # Auto-visualize first two numeric columns
vz.subplots(n_rows=2, n_cols=2, sharex=False, sharey=False, figsize=(12,8), title=None, **kwargs)
Create a figure with multiple subplots. Returns (fig, axes).
fig, axes = vz.subplots(2, 3, sharex=True, figsize=(15, 8))
axes[0,0].plot(x, y)
axes[0,1].scatter(x, y2)
vz.show()
vz.inset(x, y, kind='line', title=None, xlabel=None, ylabel=None, figsize=None, inset_bounds=(0.6, 0.6, 0.35, 0.35), xlim=None, ylim=None, loc='upper right', borderpad=1, **kwargs)
Create a main plot with an inset axes for zoomed detail. Returns (fig, main_ax, inset_ax).
fig, main_ax, inset_ax = vz.inset(
x=time_series, y=data,
kind='line',
title='Time Series with Zoomed Inset',
xlim=(2, 4), ylim=(-0.5, 0.5) # Limits applied to inset
)
# main_ax already has the line plot; customize inset_ax as needed
vz.show()
vz.figure(figsize=None, **kwargs)
Create a simple figure with a single axes. Returns (fig, ax).
fig, ax = vz.figure(figsize=(10, 6))
ax.plot(x, y)
ax.set_xlabel('X')
ax.set_ylabel('Y')
vz.show()
vz.visualize(data, columns=None, plot_type='auto', max_plots=6, **kwargs)
Create a multi-panel dashboard for exploratory analysis.
vz.visualize(df) # Dashboard with all numeric columns
vz.visualize(df, columns=['x','y','z']) # Specific columns only
vz.visualize(df, plot_type='dist') # Distribution plots only
vz.suggest_plots(data, ai=False, ai_provider=None, api_key=None, **ai_kwargs)
Get recommendations for visualizations, optionally using AI.
recs = vz.suggest_plots(df)
print(recs)
# type x y rationale example_code
# 0 hist x None Distribution of 'x' - shows... vz.plot(df, x='x')
# 1 scatter x y Relationship between... vz.plot(df, x='x', y='y')
# With AI enhancement (OpenAI)
recs = vz.suggest_plots(df, ai=True, api_key="your-openai-key")
# With local Ollama model
recs = vz.suggest_plots(df, ai=True, ai_provider='ollama', model='llama3.2:1b')
vz.report(data, show_plots=False)
Generate a comprehensive report.
report = vz.report(df) # Text report
report = vz.report(df, show_plots=True) # Report + dashboard figure
vz.explore(data, mode='auto')
Smart exploratory data analysis.
vz.explore(df) # Auto-choose best visualizations
vz.explore(df, mode='distribution') # Distribution plots only
vz.explore(df, mode='relationship') # Correlation plots
vz.show_plotly(data, kind, **kwargs)
Create an interactive Plotly visualization and return as HTML string.
# Generate interactive HTML for a scatter plot
html = vz.show_plotly(df, x='x', y='y', kind='scatter')
# Save to file
with open('plot.html', 'w') as f:
f.write(html)
# Or display in Jupyter notebook
from IPython.display import HTML
HTML(html)
vz.save_plotly(data, filepath, kind, **kwargs)
Create an interactive Plotly visualization and save directly to HTML file.
# Save interactive plot to HTML file
vz.save_plotly(df, 'interactive_scatter.html', x='x', y='y', kind='scatter')
# With additional customization
vz.save_plotly(df, 'interactive_hist.html', x='value', kind='hist',
title='Interactive Histogram', nbins=50)
3D Plotting Functions
BottleViz provides specialized functions for true 3D visualizations that work with array data:
vz.plot_3d_surface(X, Y, Z, title=None, xlabel='X', ylabel='Y', zlabel='Z', **kwargs)
Create a 3D surface plot (mesh grid connected as a continuous surface).
import numpy as np
x = np.linspace(-5, 5, 50)
y = np.linspace(-5, 5, 50)
X, Y = np.meshgrid(x, y)
Z = np.sin(np.sqrt(X**2 + Y**2))
fig, ax = vz.plot_3d_surface(X, Y, Z, title='Surface Plot', cmap='viridis')
vz.show()
vz.plot_3d_wireframe(X, Y, Z, title=None, xlabel='X', ylabel='Y', zlabel='Z', **kwargs)
Create a 3D wireframe plot (shows grid structure with lines).
fig, ax = vz.plot_3d_wireframe(X, Y, Z, title='Wireframe', color='blue', linewidth=0.5)
vz.show()
vz.plot_3d_trisurf(x, y, z, title=None, xlabel='X', ylabel='Y', zlabel='Z', **kwargs)
Triangular surface plot for irregularly scattered data (automatic triangulation).
x_rand = np.random.uniform(-5, 5, 500)
y_rand = np.random.uniform(-5, 5, 500)
z_rand = np.sin(np.sqrt(x_rand**2 + y_rand**2))
fig, ax = vz.plot_3d_trisurf(x_rand, y_rand, z_rand, cmap='plasma')
vz.show()
vz.plot_3d_contour(X, Y, Z, title=None, xlabel='X', ylabel='Y', levels=15, **kwargs)
3D contour lines (projected onto 3D surface).
fig, ax = vz.plot_3d_contour(X, Y, Z, levels=20, cmap='coolwarm')
vz.show()
vz.plot_3d_contourf(X, Y, Z, title=None, xlabel='X', ylabel='Y', levels=15, **kwargs)
Filled 3D contour plot.
fig, ax = vz.plot_3d_contourf(X, Y, Z, levels=20, cmap='RdYlBu')
vz.show()
vz.plot_3d_quiver(X, Y, Z, U, V, W, title=None, xlabel='X', ylabel='Y', zlabel='Z', **kwargs)
3D quiver plot (vector field with arrows).
# Create grid
x = y = z = np.linspace(-2, 2, 10)
X, Y, Z = np.meshgrid(x, y, z)
U = -Y
V = X
W = np.zeros_like(Z)
fig, ax = vz.plot_3d_quiver(X, Y, Z, U, V, W, length=0.3, normalize=True)
vz.show()
vz.plot_3d_stem(x, y, z, title=None, xlabel='X', ylabel='Y', zlabel='Z', **kwargs)
3D stem plot (discrete points with stems to baseline).
x = np.linspace(0, 10, 20)
y = np.sin(x)
z = np.cos(x)
fig, ax = vz.plot_3d_stem(x, y, z, linefmt='b-', markerfmt='bo')
vz.show()
vz.plot_3d_bar(x, y, z, dx, dy, dz, title=None, **kwargs)
3D bar chart.
x = np.arange(5)
y = np.arange(5)
X, Y = np.meshgrid(x, y)
Z = np.random.rand(5, 5)
dx = dy = 0.8
dz = Z.flatten()
fig, ax = vz.plot_3d_bar(X.flatten(), Y.flatten(), np.zeros_like(Z.flatten()), dx, dy, dz)
vz.show()
vz.plot_3d_voxels(voxels, title=None, **kwargs)
3D voxel/volume rendering.
# Create a sphere
voxels = np.zeros((20, 20, 20), dtype=bool)
x = y = z = np.linspace(-10, 10, 20)
X, Y, Z = np.meshgrid(x, y, z)
voxels[X**2 + Y**2 + Z**2 <= 100] = True
fig, ax = vz.plot_3d_voxels(voxels, edgecolor='k', facecolors='cyan')
vz.show()
vz.figure3d(title=None, xlabel='X', ylabel='Y', zlabel='Z', figsize=(10, 8))
Create an empty 3D figure for custom plotting. Returns (fig, ax).
fig, ax = vz.figure3d(title='Custom 3D Plot')
# Now use matplotlib's 3D API directly
ax.plot_surface(X, Y, Z, cmap='viridis')
ax.scatter(x_points, y_points, z_points, c='red')
ax.contour(X, Y, Z, levels=10, colors='black')
vz.show()
All 3D functions return (fig, ax) tuple and support full matplotlib customization via **kwargs.
Style Management
vz.set_style(style)
Set global visual style.
vz.set_style('default') # Clean, modern default
vz.set_style('dark') # Dark theme
vz.set_style('minimal') # Minimal ink, maximum data
vz.set_style('publication')# Publication-ready
vz.set_style('seaborn') # Seaborn-compatible
vz.available_styles()
List available style presets.
print(vz.available_styles())
# ['default', 'dark', 'minimal', 'publication', 'seaborn']
vz.create_custom_style(name, **kwargs)
Create your own style.
vz.create_custom_style('my_style',
figure.figsize=(12, 8),
axes.titlesize=16,
axes.prop_cycle=plt.cycler('color', ['#FF0000', '#00FF00', '#0000FF'])
)
vz.set_style('my_style')
Plot Types Supported
Standard 2D Plots
| Plot Type | Use Case | Auto-detected When |
|---|---|---|
scatter |
Relationship between two numeric variables | Two numeric columns provided |
line |
Time series or sequential data | Datetime index or sorted x-axis |
bar |
Categorical comparisons | Categorical x with numeric y |
stacked_bar |
Part-to-whole comparisons across categories | Multiple y columns with stacked=True |
grouped_bar |
Side-by-side category comparisons | Multiple y columns with grouped layout |
hist |
Distribution of single variable | Single numeric column |
box |
Distribution with outliers | Box plot recommended |
violin |
Detailed distribution shape | Violin plot recommended |
kde |
Smooth density estimate | KDE recommended |
area |
Cumulative totals | Area plot specified |
heatmap |
Correlation matrix (with optional annotations) | Matrix data or 3+ numeric columns; supports annot=True, fmt, annot_fontsize |
pcolormesh |
Flexible colored grid cells (non-uniform grids) | Gridded x, y, z data |
contour |
2D contour lines (topographic maps) | Gridded x, y, z data |
hexbin |
2D density for large scatter (>50k points) | Large dataset auto-detected (>50k points) |
step |
Discrete changes, digital signals | Explicit kind='step' |
fill_between |
Confidence intervals, ranges | Requires y, optionally y_lower/y_upper |
quiver |
2D vector field (arrows) | Requires x, y, u, v components |
spy |
Sparse matrix visualization | DataFrame or 2D array |
polar |
Radial/angular coordinates (cyclic data) | Requires theta and r |
table |
Render data as table figure | Explicit kind='table' |
eventplot |
Multiple event sequences/timelines | Multiple sequence columns |
waterfall |
Cumulative effect (bridge chart) | Requires x (category) and y (value) |
gantt |
Project/task timelines | Requires task, start, and end/duration |
ohlc_volume |
Financial OHLC with volume bars | Requires open, high, low, close, volume |
pie |
Proportional breakdown | Single categorical column with ≤6 unique values |
stem |
Discrete data points with stems | Stem plot specified |
errorbar |
Data with error margins | Error values provided |
candlestick |
Financial OHLC data | Open, high, low, close columns |
streamplot |
Vector field flow lines | Requires x, y, u, v grid components; handles flattened long-form data automatically |
tricontour |
Contour lines on scattered (unstructured) data | Requires x, y, z columns; triangulates automatically |
tricontourf |
Filled contours on scattered data | Requires x, y, z columns; triangulates automatically |
Advanced Visualizations
| Plot Type | Use Case | Requirements |
|---|---|---|
sankey |
Flow between stages/categories | Multi-stage path or source-target pairs; requires networkx |
sunburst |
Hierarchical radial layout | Hierarchical path with value; optional squarify |
treemap |
Hierarchical rectangular layout | Hierarchical path with value; requires squarify |
network |
Graph relationships | Edge list (source, target); requires networkx |
Statistical & EDA Plots
| Plot Type | Use Case | Requirements |
|---|---|---|
pairplot |
Scatter matrix with histograms/KDE on diagonal | Multiple numeric columns; optional scipy |
jointplot |
Scatter plot with marginal distributions | Two numeric columns; optional scipy |
boxen |
Letter-value box plot (enhanced box) | Categorical x, numeric y |
rug |
Marginal tick marks showing distribution | Single numeric column |
strip |
Categorical scatter with jitter | Categorical x, numeric y |
swarm |
Non-overlapping categorical scatter | Categorical x, numeric y |
qqplot |
Q-Q plot vs theoretical distribution | Single numeric column; requires scipy |
residualplot |
Residuals vs fitted for regression | Two numeric columns (x predictor, y response) |
autocorrelation |
Autocorrelation function (ACF) | Single time series column |
lagplot |
Scatter of series vs its lag | Single time series column |
andrews_curves |
Multivariate visualization by class | Multiple numeric columns + grouping column |
parallel_coordinates |
Multivariate lines on parallel axes | Multiple numeric columns + grouping column |
radviz |
Radial visualization for multivariate data | Multiple numeric columns + grouping column; optional scipy |
All these plots are also available via vz.plot(df, kind='...') with appropriate parameters.
Example Usage:
import bottleviz as vz
import pandas as pd
# Pair plot (scatter matrix)
vz.plot(df, kind='pairplot', columns=['x1', 'x2', 'x3'])
# Joint plot with histogram margins
vz.plot(df, x='x', y='y', kind='jointplot')
# Boxen plot (letter-value boxes)
vz.plot(df, x='category', y='value', kind='boxen')
# QQ plot for normality check
vz.plot(df, x='residuals', kind='qqplot')
# Autocorrelation plot for time series
vz.plot(ts_df, x='value', kind='autocorrelation', lags=50)
# Andrews curves for multi-class data
vz.plot(iris, x='species', columns=['sepal_length', 'sepal_width', 'petal_length', 'petal_width'], kind='andrews')
3D Visualizations
| Plot Type | Use Case | Data Format |
|---|---|---|
plot_3d_surface |
Continuous surface (points connected as planes) | 2D meshgrid arrays (X, Y, Z) |
plot_3d_wireframe |
Wireframe mesh showing grid structure | 2D meshgrid arrays (X, Y, Z) |
plot_3d_trisurf |
Triangular surface for scattered data | 1D arrays (x, y, z) - triangulated automatically |
plot_3d_contour |
3D contour lines | 2D meshgrid arrays (X, Y, Z) |
plot_3d_contourf |
Filled 3D contours | 2D meshgrid arrays (X, Y, Z) |
plot_3d_quiver |
3D vector field (arrows) | Grid coordinates (X, Y, Z) and vector components (U, V, W) |
plot_3d_stem |
3D stem plots | 1D arrays (x, y, z) |
plot_3d_bar |
3D bar chart | Positions (x, y, z) and dimensions (dx, dy, dz) |
plot_3d_voxels |
3D volume/cube rendering | 3D boolean or scalar array |
figure3d |
Create empty 3D figure for custom plotting | Returns (fig, ax) for manual plotting |
All 3D functions provide full access to matplotlib's 3D API via **kwargs.
Geographic Plots
| Plot Type | Use Case | Requirements |
|---|---|---|
choropleth |
Color regions by data values | Geometry column; requires geopandas |
scatter_geo |
Points on map from lat/lon | lat and lon columns; requires geopandas, shapely |
flow_map |
Flow lines between locations | Origin/destination coordinates; requires geopandas, shapely |
tile_map |
Choropleth with basemap tiles | Geometry column; requires geopandas, contextily |
cartogram |
Area-scaled cartogram | Geometry column and value; requires geopandas |
Detailed Geographic Plot Examples
Choropleth Maps
import bottleviz as vz
import geopandas as gpd
from shapely.geometry import Polygon
# Create GeoDataFrame with polygon geometries
polygons = [Polygon([(0,0), (1,0), (1,1), (0,1)]),
Polygon([(1,0), (2,0), (2,1), (1,1)])]
gdf = gpd.GeoDataFrame({
'region': ['A', 'B'],
'population': [1000, 2000]
}, geometry=polygons, crs='EPSG:4326')
vz.plot(gdf, kind='choropleth', geometry='geometry', value='population',
title='Population by Region', cmap='viridis')
Scatter Geo
import bottleviz as vz
import pandas as pd
df = pd.DataFrame({
'latitude': [40.7128, 34.0522, 41.8781],
'longitude': [-74.0060, -118.2437, -87.6298],
'city': ['New York', 'Los Angeles', 'Chicago'],
'temperature': [22, 18, 15]
})
vz.plot(df, kind='scatter_geo', lat='latitude', lon='longitude',
value='temperature', title='Temperature by City',
cmap='plasma', markersize=100, alpha=0.7)
Flow Maps
import bottleviz as vz
flow_data = pd.DataFrame({
'origin_lat': [40.7128, 34.0522],
'origin_lon': [-74.0060, -118.2437],
'dest_lat': [40.7589, 34.0522],
'dest_lon': [-73.9851, -118.2437],
'volume': [1000, 500]
})
vz.plot(flow_data, kind='flow_map',
origin_lat='origin_lat', origin_lon='origin_lon',
dest_lat='dest_lat', dest_lon='dest_lon',
flow='volume', title='Migration Flows', color='#2196F3')
Tile Maps
import bottleviz as vz
import geopandas as gpd
import contextily as ctx
# Load or create GeoDataFrame
gdf = gpd.GeoDataFrame(...).to_crs(epsg=3857) # Reproject to Web Mercator
vz.plot(gdf, kind='tile_map', value='density',
tile_source=ctx.providers.OpenStreetMap.Mapnik)
Cartograms
import bottleviz as vz
import geopandas as gpd
from shapely.geometry import Polygon
polygons = [Polygon([(0,0), (1,0), (1,1), (0,1)]),
Polygon([(1,0), (2,0), (2,1), (1,1)])]
gdf = gpd.GeoDataFrame({
'region': ['A', 'B'],
'population': [1000, 4000] # B will appear 4x larger
}, geometry=polygons)
vz.plot(gdf, kind='cartogram', geometry='geometry', value='population',
title='Population Cartogram')
Solving Gaps in Existing Libraries
vs Matplotlib
- Simplicity: No more verbose
fig, ax = plt.subplots()boilerplate - Smarter defaults: Beautiful plots automatically
- Type inference: No need to specify plot type manually
vs Seaborn
- Performance: Better optimization for large datasets
- Consistency: One function for all plot types
- Flexibility: Works with numpy arrays directly
vs Plotly
- Lightweight: Pure Python core, no JavaScript needed
- Static quality: Publication-ready out of the box
- Easier deployment: No browser dependencies
Advanced Features
Large Dataset Optimization
# Automatic downsampling for >10k points
vz.plot(huge_df) # Smooth even with 1M rows
Smart Color Palettes
# Automatically colorblind-friendly
vz.plot(df, x='cat', y='val', kind='bar') # Beautiful colors
# Custom palette
vz.plot(df, x='cat', y='val', kind='bar', palette='pastel')
Automatic Subplot Layout
# Automatically arranges subplots
vz.visualize(df, max_plots=6) # Smart 2x3 layout
Pandas/Polars Integration
# Works with many data structures
vz.plot(df) # pandas DataFrame
vz.plot(pl.DataFrame(...)) # polars DataFrame
vz.plot(np_array) # NumPy array
vz.plot([1,2,3,4,5]) # Python list
vz.plot({'x': [...], 'y': [...]}) # Dictionary
Limitations and Future Work
Current limitations:
- Only matplotlib backend implemented (Plotly backend planned)
- Some advanced charts (Sankey, Sunburst, Treemap, Network) require optional dependencies (networkx, squarify)
- 3D visualizations use matplotlib's mplot3d (limited interactivity compared to Plotly)
- Polar plots use matplotlib's polar projection (basic features only)
- Pcolormesh and contour require gridded data format
Planned features:
- Plotly interactive backend with enhanced 3D
- Bokeh backend
- GPU acceleration with CuPy
- Animation support for time series
- Export to HTML with interactivity
- Graphviz layout for network graphs
- Faceted/trellised subplot grids
Requirements
- Python >= 3.8
- NumPy >= 1.18.0
- Pandas >= 1.0.0
- Matplotlib >= 3.0.0
Optional:
- plotly >= 5.0.0 (for interactive plots)
- datashader >= 0.13.0 (for massive datasets)
- networkx (for network graphs and Sankey diagrams)
- squarify (for treemaps)
- polars (alternative to pandas)
- geopandas >= 0.10.0, shapely >= 1.8.0, contextily >= 1.0.0 (for geographic visualizations)
Install all geographic dependencies: pip install bottleviz[geo]
Interactive HTML Plots (Plotly Backend)
BottleViz includes an optional Plotly backend for creating interactive, web-based visualizations:
import bottleviz as vz
import pandas as pd
df = pd.DataFrame({'x': [1,2,3], 'y': [4,5,6]})
# Create interactive HTML
html = vz.show_plotly(df, x='x', y='y', kind='scatter', title='My Plot')
# Save to file
vz.save_plotly(df, 'interactive.html', x='x', y='y', kind='scatter')
# Or display in Jupyter
from IPython.display import HTML
HTML(html)
Features:
- Interactive zoom, pan, hover tooltips
- 3D rotation (for 3D plots)
- Clickable legends
- Animation support
- Works in any modern web browser
Requirements: pip install plotly
Demo: See examples/demo_plotly_interactive.py
Contributing
We welcome contributions! Please see our contributing guide in the repository.
License
MIT License - see LICENSE file for details.
Examples Gallery
More examples available in the examples/ directory:
- Basic Plots: Line, scatter, bar, histogram (
demo.py,example.py) - Statistical: Box, violin, KDE
- Compositional: Pie, area, stacked charts, grouped bar
- Multivariate: Heatmap, pair plots, 3D, contour, pcolormesh
- Time Series: Date handling, rolling windows, candlestick
- Large Data: Downsampling, datashader, hexbin
- Styling: Themes, custom palettes, publication tips
- Advanced: Sankey, Sunburst, Treemap, Network, Candlestick
- New Plot Types (v0.2.0):
stacked_bar&grouped_bar- Categorical comparisonshexbin- 2D density for large datasetsstep- Discrete step plotsfill_between- Confidence intervalscontour- 2D contour linespcolormesh- Flexible grid coloringquiver- 2D vector fieldsspy- Sparse matrix visualizationpolar- Radial/angular plotstable- Data as table figureeventplot- Event sequences/timelineswaterfall- Waterfall/bridge charts (cumulative effects)gantt- Gantt charts for project managementohlc_volume- OHLC candlestick with volume barsstreamplot- Vector field flow linestricontour&tricontourf- Contours on scattered (unstructured) data
- Layout & Composition Utilities:
subplots()- Create multi-subplot figures with shared axesinset()- Create plots with zoomed inset axesfigure()- Simple figure creation shortcut
- Statistical & EDA Plots:
demo_statistical_plots.py- Comprehensive demo of 13+ statistical plots (pairplot, jointplot, boxen, rug, strip, swarm, qqplot, residualplot, autocorrelation, lagplot, andrews_curves, parallel_coordinates, radviz)
- Interactive HTML Plots:
demo_plotly_interactive.py- Create interactive Plotly visualizations withshow_plotly()andsave_plotly()functions
- 3D Visualizations:
all_3d_plots.py- Comprehensive demo of all 10+ 3D plot types (surface, wireframe, trisurf, contour, quiver, stem, bar3d, voxels)array_slices_3d.py- Advanced 3D array slices with intersecting planesdemo_show_close.py- Cone surface plot with show/close functions
- Complete Plot Type Gallery:
demo_all_plot_types.py- NEW! Comprehensive demonstration of ALL 40+ plot types (matplotlib PNG + plotly HTML outputs)
Run examples:
python -m bottleviz.examples
Citation
If you use BottleViz in your research, please cite:
@software{bottleviz2024,
author = {{Pavan Paari}},
title = {{BottleViz: A Modern Python Visualization Library}},
year = {2026},
url = {https://github.com/DHS-IT-Solutions/BottleViz.git}
}
Project details
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 bottleviz-0.2.1.tar.gz.
File metadata
- Download URL: bottleviz-0.2.1.tar.gz
- Upload date:
- Size: 441.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dfa9d7a911684af4a6ea9877a2166802b02560d33a5e6ef404df89508adba885
|
|
| MD5 |
c1ce0d72d4de3f5620ac3a699a866603
|
|
| BLAKE2b-256 |
b7d4203e419990ee3d126b0754e4bfa5158b163b56493faa53eb93a19f5c0971
|
File details
Details for the file bottleviz-0.2.1-py3-none-any.whl.
File metadata
- Download URL: bottleviz-0.2.1-py3-none-any.whl
- Upload date:
- Size: 84.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ca46c7cb1288887d08786496e83be814419c1eb095b5be76f8552a7c47e9c801
|
|
| MD5 |
b076b3f56a574d81dfc7768ba3afefcc
|
|
| BLAKE2b-256 |
1c63039c9af74440dcafe1e09b5baa0a32e9b64222deac0c8add89fd9180aeb7
|