Search code examples
pythonmatplotlibseabornlegendscatter-plot

How to add edge line to markers on the legend using matplotlib/seabornn


I have a bubble chart with the legend showing two categories differentiated by color and size, the markers on the scatter have black edge color and I like the markers shown in the legend to have it too, anyone know how can I do it?

I'm using seaborn scatterplot to generate the graph

Summary = pd.read_csv("Summary.csv")

####################################################################################
# Plot the scatterplot
####################################################################################

f, (ax1, ax2) = plt.subplots(ncols=2, nrows=1, sharey=True, figsize=(8.27,5.8))
#----------------------------------------------------------------------------------------
# add a big axes, hide frame, common axis labels
#----------------------------------------------------------------------------------------
f.add_subplot(111, frameon=False)
# hide tick and tick label of the big axes
plt.tick_params(labelcolor='none', top=False, bottom=False, left=False, right=False)
plt.grid(False)
plt.xlabel('T$_{s}$ - T$_{sat}$ [$^{\circ}$C]', fontsize=14)
plt.ylabel('Heat Flux [W$\cdot$cm$^{-2}$]', fontsize=14)
#----------------------------------------------------------------------------------------

# Change the minimum and maximum point size
ax=sns.scatterplot(x='T_surf - T_sat [C]', y='Heat Flux [W/cm2]', data=Summary, # Choose the x and y values and the dataframe 
                     size='Mass flux [kg$\cdot$m$^{-2}$$\cdot$s$^{-1}$]', # Size of markers
                     hue='Enhanced Surface', # Color by surface type
                     #color='Greys',
                     alpha=1.0,
                     #style='Enhanced Surface', # Marker by surface type
                     sizes=(20, 700), # minimum and maximum marker size
                     palette = 'Blues',
                     #markers=["X","d", "*","s"], # Change the markers' style
                     markers='o',
                     edgecolor= "Black", # Change the edge color of the markers
                     linewidth=0.5, # Change the edge linewidth of the markers
                     legend=False,
                     ax=ax1
                    )

ax=sns.scatterplot(x='T_surf - T_sat [C]', y='Heat Flux [W/cm2]', data=Summary, # Choose the x and y values and the dataframe 
                     size='Mass flux [kg$\cdot$m$^{-2}$$\cdot$s$^{-1}$]', # Size of markers by population
                     hue='Enhanced Surface', # Color by surface type
                     #cmap='Greys',
                     alpha=1.0,
                     #style='Enhanced Surface', # Marker by surface type
                     sizes=(20, 700), # minimum and maximum marker size
                     palette = 'Blues',
                     #markers=["X","d", "*","s"], # Change the markers' style
                     markers='o',
                     edgecolor= "Black", # Change the edge color of the markers
                     linewidth=0.5, # Change the edge linewidth of the markers
                     legend='auto',
                     ax=ax2
                    )


ax1.set_xlim(-60, 120)
ax2.set_xlim(790, 810)

# labels = ax1.get_legend_handles_labels()
####################################################################################
# Use the matplotlib library to edit the plot
####################################################################################

#Legend
lgd = ax2.legend(loc="upper right", frameon = 0.5, framealpha=0.8, # Create a legend and define its location, frame and frame alpha
                  edgecolor='white', facecolor='white', ncol=2, # Edgecolor, facecolor and the number of columns
                  title='', fontsize=10, # the title and the font size
                  handlelength=1, handleheight=2, columnspacing = 1.0, labelspacing=1.5,
                  markerscale=1.0, markerfirst = False)



BubbleChart


Solution

  • You can create your plot as you would with seaborn and then tweak the legend style directly.

    Each ha handle is a matplotlib.collections.PathCollection, I've set the edge colour to red here so you can see the difference.

    import seaborn as sns
    
    tips = sns.load_dataset("tips")
    
    fig, ax = plt.subplots(figsize=(4,4))
    sns.scatterplot(data=tips, x="total_bill", y="tip", style="day", ax=ax)
    
    # Get the legend handles
    handles, labels = ax.get_legend_handles_labels()
    
    # Iterate through the handles and call `set_edgecolor` on each
    for ha in handles:
        ha.set_edgecolor("red")
    
    # Use `ax.legend` to set the modified handles and labels
    lgd = ax.legend(
        handles, 
        labels,
        loc="upper left", 
        ncol=2,
    )
    

    Which produces:

    Scatterplot with modified legend style

    Or, as mwaskom suggested, modify the artists in place to avoid redrawing the legend:

    tips = sns.load_dataset("tips")
    
    fig, ax = plt.subplots(figsize=(4,4))
    sns.scatterplot(data=tips, x="total_bill", y="tip", style="day", ax=ax)
    
    # Place the legend
    lgd = ax.legend(
        loc="upper left", 
        ncol=2,
    )
    # Modify the point edge colour
    for ha in ax.legend_.legendHandles:
        ha.set_edgecolor("red")
    

    which produces the same plot.