How to hide lines (onclick) in Seaborn scatterplot? - python

I have a Scatterplot made with seaborn similar to this:
tips = sns.load_dataset("tips")
g = sns.scatterplot(x="total_bill", y="tip", hue="time", data=tips)
plt.show()
Resulting Plot
I want to be able to do legend picking like in this matplotlib example:
https://matplotlib.org/stable/gallery/event_handling/legend_picking.html
How do I get the individual lines to change the visibility on?
I've tried to get them via the get_children method, but haven't had any success.

Related

Seaborn ecdf plot, adjust spacing in legend items

In a Seaborn scatter plot, I can adjust the spacing in the legend entries like so:
tips = sns.load_dataset('tips')
g = sns.scatterplot(data=tips, x="total_bill", y="tip", hue="time")
plt.legend(labelspacing=20)
How can I do this with a CDF plot? Running g = sns.ecdfplot(data=tips, x="total_bill", hue="time") gives a plot with the legend. I have tried the following without any luck.
plt.legend(labelspacing=20)
Finishes plot but removes the legend
Throws error No handles with labels found to put in legend.
g.get_legend().legend(labelspacing=20)
Doesn't plot
Throws AttributeError: 'Legend' object has no attribute 'legend'
The latest seaborn 0.11.2 has a new function move_legend() which apart from moving the legend also allows changing other legend properties (note that axes-level functions such as sns.scatterplot and sns.ecdfplot return an ax):
import seaborn as sns
tips = sns.load_dataset('tips')
ax = sns.ecdfplot(data=tips, x="total_bill", hue="time")
sns.move_legend(ax, labelspacing=5, loc='best')

Overriding Seaborn legend

I made a line plot using seaborn's relplot and I wanted to customize my legend labels. For some reason when I do this, It creates another legend with out deleting the old one. How do I get rid of the initial legend (The legend with title "Sex")? Also how do I add a legend title to my new legend?
Here is the code I used to generate my plot:
plt.figure(figsize=(12,10))
sns.relplot(x='Year',y = 'cancer/100k pop' , data = dataset_sex,hue="Sex", kind="line",ci=None)
title_string = "Trend of Cancer incidencies by Sex "
plt.xlabel('Years')
plt.title(title_string)
plt.legend(['Men','Women'])
regplot is a figure-level function, and returns a FacetGrid. You can remove its legend via g.legend.remove().
import matplotlib.pyplot as plt
import seaborn as sns
tips = sns.load_dataset("tips")
g = sns.relplot(data=tips, x="total_bill", y="tip", hue="day")
g.legend.remove()
plt.legend(['Jeudi', 'Vendredi', 'Samedi', 'Dimanche'])
plt.show()
This code has been tested with seaborn 0.11. Possibly you'll need to upgrade. To add a title to the legend: plt.legend([...], title='New title').
Note that plt.legend(...) will create the legend inside the last (or only) subplot. If you prefer the figure-level legend next to the plot, to change the legend labels, you can call g.add_legend(labels=[...], title='new title') after having removed the old legend.
PS: Adding legend=False to sns.relplot() will not create the legend entries. So, you'll need to recreate both the legend markers and their labels, while you lost the information of which colors were used.

How to subplot seaborn catplot (kind='count') on-top of catplot (kind='violin') with sharex=True

So far I have tried the following code:
# Import to handle plotting
import seaborn as sns
# Import pyplot, figures inline, set style, plot pairplot
import matplotlib.pyplot as plt
# Make the figure space
fig = plt.figure(figsize=(2,4))
gs = fig.add_gridspec(2, 4)
ax1 = fig.add_subplot(gs[0, :])
ax2 = fig.add_subplot(gs[1, :])
# Load the example car crash dataset
tips = sns.load_dataset("tips")
# Plot the frequency counts grouped by time
sns.catplot(x='sex', hue='smoker',
kind='count',
col='time',
data=tips,
ax=ax1)
# View the data
sns.catplot(x='sex', y='total_bill', hue='smoker',
kind='violin',
col='time',
split='True',
cut=0,
bw=0.25,
scale='area',
scale_hue=False,
inner='quartile',
data=tips,
ax=ax2)
plt.close(2)
plt.close(3)
plt.show()
This seems to stack the categorial plots, of each kind respectively, on top of eachother.
What I want are the resulting plots of the following code in a single figure with the countplot in row one and the violin plot in row two.
# Import to handle plotting
import seaborn as sns
# Import pyplot, figures inline, set style, plot pairplot
import matplotlib.pyplot as plt
# Load the example car crash dataset
tips = sns.load_dataset("tips")
# Plot the frequency counts grouped by time
sns.catplot(x='sex', hue='smoker',
kind='count',
col='time',
data=tips)
# View the data
sns.catplot(x='sex', y='total_bill', hue='smoker',
kind='violin',
col='time',
split='True',
cut=0,
bw=0.25,
scale='area',
scale_hue=False,
inner='quartile',
data=tips)
The actual categorical countplot that I would like to span row one of a figure that also contains a categorical violin plot (Ref. Image 3):
The actual categorical violin plot that I would like to span row two of a figure that also contains a categorical countplot (Ref. Image 2):
I tried the following code which forced the plots to be in the same figure. The downside is that the children of the figure/axes did not transfer, i.e. axis-labels, legend, and grid lines. I feel pretty close with this hack but need another push or source for inspiration. Also, I'm no longer able to close the old/unwanted figures.
# Import to handle plotting
import seaborn as sns
# Import pyplot, figures inline, set style, plot pairplot
import matplotlib.pyplot as plt
# Set some style
sns.set_style("whitegrid")
# Load the example car crash dataset
tips = sns.load_dataset("tips")
# Plot the frequency counts grouped by time
a = sns.catplot(x='sex', hue='smoker',
kind='count',
col='time',
data=tips)
numSubs_A = len(a.col_names)
for i in range(numSubs_A):
for p in a.facet_axis(0,i).patches:
a.facet_axis(0,i).annotate(str(p.get_height()), (p.get_x()+0.15, p.get_height()+0.1))
# View the data
b = sns.catplot(x='sex', y='total_bill', hue='smoker',
kind='violin',
col='time',
split='True',
cut=0,
bw=0.25,
scale='area',
scale_hue=False,
inner='quartile',
data=tips)
numSubs_B = len(b.col_names)
# Subplots migration
f = plt.figure()
for i in range(numSubs_A):
f._axstack.add(f._make_key(a.facet_axis(0,i)), a.facet_axis(0,i))
for i in range(numSubs_B):
f._axstack.add(f._make_key(b.facet_axis(0,i)), b.facet_axis(0,i))
# Subplots size adjustment
f.axes[0].set_position([0,1,1,1])
f.axes[1].set_position([1,1,1,1])
f.axes[2].set_position([0,0,1,1])
f.axes[3].set_position([1,0,1,1])
It is in general not possible to combine the output of several seaborn figure-level functions into a single figure. See (this question, also this issue). I once wrote a hack to externally combine such figures, but it has several drawbacks. Feel free to use it if it works for you.
But in general, consider creating the plot you desired manually. In this case it could look like this:
import seaborn as sns
import matplotlib.pyplot as plt
sns.set()
fig, axes = plt.subplots(2,2, figsize=(8,6), sharey="row", sharex="col")
tips = sns.load_dataset("tips")
order = tips["sex"].unique()
hue_order = tips["smoker"].unique()
for i, (n, grp) in enumerate(tips.groupby("time")):
sns.countplot(x="sex", hue="smoker", data=grp,
order=order, hue_order=hue_order, ax=axes[0,i])
sns.violinplot(x='sex', y='total_bill', hue='smoker', data=grp,
order=order, hue_order=hue_order,
split='True', cut=0, bw=0.25,
scale='area', scale_hue=False, inner='quartile',
ax=axes[1,i])
axes[0,i].set_title(f"time = {n}")
axes[0,0].get_legend().remove()
axes[1,0].get_legend().remove()
axes[1,1].get_legend().remove()
plt.show()
seaborn.catplot does not accept an "ax" argument, hence the problem with your first code.
It appears that some hacking is needed to accomplish the x-sharing you aim for:
How to plot multiple Seaborn Jointplot in Subplot
As such, you could save the time and effort, and just manually stack the two figures from your second code.

Plotting multiple scattter plots in the same graph instead of Facet Grids

Currently I have a few plots using Facet Grids in seaborn. I have the following code:
g = sns.FacetGrid(masterdata1,col = "courseName")
g=g.map(plt.scatter, "SubjectwisePercentage", "SemesterPercentage")
The above code plots subjectwisepercentage vs semesterpercentage, for different courses across a semester. How can I plot the different scatter plots in a single plot, instead of multiple plots across the facet grid? In the single plot, the plotted points for each course should be a different color.
There are links online that specify how to plot different datasets in a single plot. However I need to use the same dataset. Therefore I need to specify col="courseName", or something equivalent, to plot course wise data in a single plot. I am not sure of how to accomplish this. Thank you in advance for your help.
You can try using seaborn's scatter plot features. It allows to define, x, y, hue and style, and even size. Which gives up to a 5D view of your data. Sometimes, people like to make hue and style based on the same variables for better-looking graphs.
Sample code (not pretty much mine, since the seaborn documentation pretty much explains everything).
import seaborn as sns
import matplotlib.pyplot as plt
sns.set(style="ticks", color_codes=True)
tips = sns.load_dataset("tips")
# g = sns.FacetGrid(tips, col="sex", hue="time", palette="Set1",
# hue_order=["Dinner", "Lunch"])
# g= (g.map(plt.scatter, "total_bill", "tip")).add_legend()
# sns.scatterplot(data=tips, x="total_bill", y="tip", hue='time', style='sex')
sns.scatterplot(data=tips, x="total_bill", y="tip", hue='time', style='sex', size='size')
plt.show()
The matplotlib scatter plot can also be helpful. Since you can plot several data on the same plot with different markers/colors/sizes.
See this example.

Python Seaborn Facetgrid change xlabels

I just can't figure out how to change the xlabels in a Seaborn Facetgrid. It offers a method for changing the x labels with set_xlabels() but unfortunately not individually for each subplot.
I have two subplots which share the y-axis but have a different x-axes and i want to label them with different texts.
Can anybody give me a hint. Thank you in advance.
You can access the individual axes of the FacetGrid using the axes property, and then use set_xlabel() on each of them. For example:
import seaborn as sns
import matplotlib.pyplot as plt
sns.set(style="ticks", color_codes=True)
tips = sns.load_dataset("tips")
g = sns.FacetGrid(tips, col="time", hue="smoker")
g = g.map(plt.scatter, "total_bill", "tip", edgecolor="w")
g.axes[0,0].set_xlabel('axes label 1')
g.axes[0,1].set_xlabel('axes label 2')
plt.show()
Note in this example, g.axes has a shape of (1,2) (one row, two columns).
for all axis to set them once use this
g.set_axis_labels("Total bill ($)")

Categories