A Python library for creating bump chart visualizations showing how rankings change over time.
pip install pybumpchartFor seaborn color palette support:
pip install pybumpchart[seaborn]import pandas as pd
import pybumpchart as bc
# Create sample data
df = pd.DataFrame({
'year': [2020, 2020, 2020, 2021, 2021, 2021, 2022, 2022, 2022],
'team': ['A', 'B', 'C', 'A', 'B', 'C', 'A', 'B', 'C'],
'rank': [1, 2, 3, 3, 1, 2, 2, 3, 1]
})
# Create a bump chart
ax = bc.bumpchart(df, time_col='year', entity_col='team', rank_col='rank')
ax.figure.savefig('bumpchart.png')- Automatic rank calculation: Provide values and let pybumpchart calculate ranks
- Multiple tie-breaking methods: average, min, max, first, dense
- Customizable appearance: colors, line widths, markers, labels
- Entity highlighting: Emphasize specific entities while dimming others
- Label collision avoidance: Automatic adjustment of overlapping labels
- Matplotlib integration: Returns standard Axes objects for further customization
The main function for creating bump charts.
bc.bumpchart(
df, # DataFrame with your data
time_col, # Column name for time values (x-axis)
entity_col, # Column name for entity identifiers
rank_col=None, # Column with pre-calculated ranks
value_col=None, # Column with values to rank by
ascending=True, # Lower values = better rank (when using value_col)
tie_method='average', # How to handle ties: 'average', 'min', 'max', 'first', 'dense'
ax=None, # Existing matplotlib Axes to draw on
figsize=(10, 6), # Figure size if creating new figure
palette=None, # Color palette: colormap name, list, or None for default
highlight=None, # List of entities to highlight
highlight_color=None, # Custom color for highlighted entities
show_labels=True, # True, False, 'left', 'right', or 'both'
label_padding=0.3, # Distance between line and label
min_label_distance=0.5, # Minimum vertical space between labels
label_fontsize=10, # Font size for labels
linewidth=2.5, # Line thickness
markersize=10.0, # Marker size
marker='o', # Marker style
show_grid=True, # Show horizontal grid lines
show_points=True, # Show markers at each time point
)Returns: matplotlib.axes.Axes - The axes containing the bump chart.
import pandas as pd
import pybumpchart as bc
df = pd.DataFrame({
'year': [2020, 2020, 2020, 2021, 2021, 2021],
'team': ['Warriors', 'Lakers', 'Celtics', 'Warriors', 'Lakers', 'Celtics'],
'rank': [1, 2, 3, 2, 1, 3]
})
ax = bc.bumpchart(df, time_col='year', entity_col='team', rank_col='rank')df = pd.DataFrame({
'quarter': ['Q1', 'Q1', 'Q1', 'Q2', 'Q2', 'Q2'],
'product': ['Widget', 'Gadget', 'Gizmo', 'Widget', 'Gadget', 'Gizmo'],
'sales': [1000, 800, 900, 850, 950, 920]
})
# Higher sales = better rank (rank 1)
ax = bc.bumpchart(
df,
time_col='quarter',
entity_col='product',
value_col='sales',
ascending=False # Higher values get lower (better) ranks
)ax = bc.bumpchart(
df,
time_col='year',
entity_col='team',
rank_col='rank',
highlight=['Warriors'],
palette='tab10'
)ax = bc.bumpchart(
df,
time_col='year',
entity_col='team',
rank_col='rank',
palette=['#e41a1c', '#377eb8', '#4daf4a'], # Custom colors
linewidth=4,
markersize=12,
show_labels='right', # Labels only on the right
figsize=(12, 8)
)
# Further customize with matplotlib
ax.set_title('Team Rankings Over Time', fontsize=14)
ax.set_xlabel('Year')
ax.set_ylabel('Rank')import matplotlib.pyplot as plt
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 6))
bc.bumpchart(df1, time_col='year', entity_col='team', rank_col='rank', ax=ax1)
ax1.set_title('Sports Rankings')
bc.bumpchart(df2, time_col='quarter', entity_col='product', value_col='sales', ax=ax2)
ax2.set_title('Product Sales Rankings')
plt.tight_layout()
plt.savefig('comparison.png')Your DataFrame should have:
- Time column: Values representing time periods (years, quarters, dates, etc.)
- Entity column: Identifiers for the items being ranked (team names, product names, etc.)
- Rank or value column: Either pre-calculated ranks OR values to rank by
Each entity should appear once per time period.
- Python >= 3.9
- matplotlib >= 3.5
- pandas >= 1.4
- numpy >= 1.21
- seaborn >= 0.12 (optional, for extended palette support)
Contributions are welcome! Please feel free to submit a Pull Request.
MIT License - see LICENSE for details.