Plot Overlay with ggdeck()#
The ggdeck() function enables multivariate comparison by synchronized overlaying of independent plots. This allows you to combine separate plot objects—each with its own coordinate system and geometries—into a unified view.
import numpy as np
import pandas as pd
from lets_plot import *
LetsPlot.setup_html()
1. Delhi Mean Temperature Chart#
climate_data = pd.read_csv("https://raw.githubusercontent.com/JetBrains/lets-plot-docs/refs/heads/master/data/delhi_climate.csv")
climate_data['date'] = pd.to_datetime(climate_data['date'])
climate_data.head(3)
| date | meantemp | humidity | wind_speed | meanpressure | |
|---|---|---|---|---|---|
| 0 | 2013-01-01 | 10.000000 | 84.5 | 0.000000 | 1015.666667 |
| 1 | 2013-01-02 | 7.400000 | 92.0 | 2.980000 | 1017.800000 |
| 2 | 2013-01-03 | 7.166667 | 87.0 | 4.633333 | 1018.666667 |
temperature_plot = (
ggplot(climate_data)
+ geom_line(aes('date', 'meantemp', color='meantemp'))
+ scale_color_gradient2(low='#0571b0', mid='#f7f7f7', high='#ca0020', midpoint=30)
+ labs(y='Mean Temperature [°C]')
+ theme(axis_text_y=element_text(color='#0571b0'), axis_title_y=element_text(color='#0571b0'))
)
temperature_plot
2. Fictional ‘Daily Ice Cream Cost’ Data#
def calculate_daily_cost(t):
base_cost = 1.5
surge = 0
if t > 30:
# Sharp surge above 30 degrees
surge = 0.15 * ((t - 30) ** 2)
return base_cost + surge
# Synthesize daily cost data and aggregate by month
cost_data = (
climate_data.assign(daily_cost=climate_data['meantemp'].apply(calculate_daily_cost))
.resample('MS', on='date')
.agg(
avg_daily_cost=('daily_cost', 'mean'),
min_daily_cost=('daily_cost', 'min'),
max_daily_cost=('daily_cost', 'max'),
)
.reset_index()
)
cost_data.head(3)
| date | avg_daily_cost | min_daily_cost | max_daily_cost | |
|---|---|---|---|---|
| 0 | 2013-01-01 | 1.5 | 1.5 | 1.5 |
| 1 | 2013-02-01 | 1.5 | 1.5 | 1.5 |
| 2 | 2013-03-01 | 1.5 | 1.5 | 1.5 |
3. ‘Daily Cost’ Plot with Y-Axis on the Right#
cost_plot = (
ggplot(cost_data)
+ geom_bar(aes('date', 'avg_daily_cost'), stat='identity',
fill='#F39C12', alpha=0.4)
+ geom_pointrange(aes('date', 'avg_daily_cost', ymin='min_daily_cost', ymax='max_daily_cost'),
color='#A04000', fatten=3, size=0.8)
+ labs(y='Daily Ice Cream Cost per Kid [$]')
+ theme(axis_text_y=element_text(color='#A04000'), axis_title_y=element_text(color='#A04000'))
+ scale_y_continuous(position='right')
)
cost_plot
4. Composing the ‘Temperature’ and ‘Daily Cost’ Plots into a Deck#
ggdeck([
temperature_plot + theme(legend_position='none'),
cost_plot,
]) + \
theme(
plot_title=element_text(hjust=0.5, size=21),
) + \
ggtitle('Delhi Mean Temperature & Ice Cream Cost') +\
ggsize(800, 400)
5. Managing Tooltips in Composites#
Since ggdeck() overlays independent plots, multiple tooltips may trigger simultaneously. This can lead to visual clutter and overlapping labels, especially on the axes.
To maintain clarity:
Silence background layers: Disable tooltips on secondary geometries to reduce hover noise.
Remove redundant axis labels: Suppress axis tooltips on overlaid plots to avoid duplication.
Use anchored tooltips: Consolidate information into a fixed position.
# Configure tooltips on the 'Daily Cost' plot
cost_plot2 = (
ggplot(cost_data)
+ geom_bar(aes('date', 'avg_daily_cost'), stat='identity',
fill='#F39C12', alpha=0.4,
tooltips='none') # <-- Disable all tooltips on bars
+ geom_pointrange(aes('date', 'avg_daily_cost', ymin='min_daily_cost', ymax='max_daily_cost'),
color='#A04000', fatten=3, size=0.8,
tooltips=layer_tooltips() # <-- Consolidate 'sideways' tooltips in a single panel
.title('@date')
.line('Avg | ^y')
.line('Min | ^ymin')
.line('Max | ^ymax')
.format('^Y', '${.2f}')
.format('@date', '%b')
.anchor('top_right') # <-- Anchor to the top-right corner
)
+ theme(axis_tooltip_x='blank') # <-- Suppress redundant X-axis tooltips
+ labs(y='Daily Ice Cream Cost per Kid [$]')
+ theme(axis_text_y=element_text(color='#A04000'), axis_title_y=element_text(color='#A04000'))
+ scale_y_continuous(position='right')
)
cost_plot2 + ggsize(800, 400)
6. Assembling the Updated ‘Daily Cost’ Plot into a Final Deck#
ggdeck([
temperature_plot + theme(legend_position='none'),
cost_plot2,
]) + \
theme(
plot_title=element_text(hjust=0.5, size=21),
) + \
ggtitle('Delhi Mean Temperature & Ice Cream Cost') +\
ggsize(800, 400)