Creating Magnifier Inset Effect with ggbunch()

The ggbunch() here combines two plots into a single figure with custom layout - a main scatter plot showing diamond price vs. carat weight colored by cut quality, and a zoomed-in inset that magnifies a specific region of interest.

In [1]:
import pandas as pd
from lets_plot import *
In [2]:
LetsPlot.setup_html()
In [3]:
df = pd.read_csv("https://raw.githubusercontent.com/JetBrains/lets-plot-docs/refs/heads/master/data/diamonds.csv")
print(df.shape)
df.head(3)
(53940, 10)
Out[3]:
carat cut color clarity depth table price x y z
0 0.23 Ideal E SI2 61.5 55.0 326 3.95 3.98 2.43
1 0.21 Premium E SI1 59.8 61.0 326 3.89 3.84 2.31
2 0.23 Good E VS1 56.9 65.0 327 4.05 4.07 2.31
In [4]:
# Convert the 'cut' column to categorical data type with specified order
cut_categories = ['Fair', 'Good', 'Very Good', 'Premium', 'Ideal']
df['cut'] = pd.Categorical(df['cut'], categories=cut_categories, ordered=True)
In [5]:
p_base = (ggplot(df, aes("carat", "price", color="cut")) 
 + geom_point() 
 + geom_smooth(deg=2, size=1, tooltips='none')
 + scale_color_viridis(direction = -1)
)
In [6]:
# The region of interest
carat_min = 2.1
carat_max = 2.7
price_min = 12650
price_max = 17100
In [7]:
# The main plot
p_main = (p_base
 + geom_rect(xmin=carat_min, 
             xmax=carat_max, 
             ymin=price_min, 
             ymax=price_max, 
             alpha=0.4, inherit_aes=False, fill='white')         
 + theme_grey() 
 + coord_cartesian(ylim = [0, 20000])
 + theme(legend_position=[0.58, 0.02], legend_justification=[0, 0])
)

p_main
Out[7]:
In [8]:
# The 'magnifier' plot
p_mag = (p_base
 + theme_minimal() 
 + coord_cartesian(xlim=[carat_min, carat_max], 
                   ylim=[price_min, price_max])
 + theme_void()
 + theme(legend_position='none', plot_inset=0)
)

p_mag
Out[8]:
In [9]:
(ggbunch(
    plots = [
        (p_main
          + geom_segment(x=carat_min, y=price_min, xend=4.30, yend=5800, inherit_aes=False, size=0.5)
          + geom_segment(x=carat_min, y=price_max, xend=4.30, yend=19100, inherit_aes=False, size=0.5)
        ), 
        p_mag + theme(plot_background=element_rect(size=2, fill='rgba(255, 255, 255, 0.7)'))
    ],
    regions = [
        (0, 0, 0.9, 1),
        (0.75, 0.05, 0.25, 0.6)
    ]
) 
 + ggsize(900, 600) 
 + ggtitle('Diamond Price vs. Carat Weight by Cut Quality') 
 + theme(plot_title=element_text(hjust=0.5, size=18))
) 
Out[9]: