I have a heatmap done in seaborn and a contour plotted via matplotlib.pyplot.
Is it possible to overlay the two?
Seaborn uses matplotlib under the hood. You can combine seaborn plots as if they were directly created by matplotlib. To draw onto the same subplot, the same ax should be used. To align the centers of the heatmap cells with the contour lines, you need to add 0.5 to the x and the y coordinates.
Here is an example to get you started:
from matplotlib import pyplot as plt
import seaborn as sns
import numpy as np
from scipy.ndimage.filters import gaussian_filter
data = gaussian_filter(np.random.randn(20, 40), sigma=2)
fig, ax = plt.subplots(figsize=(15, 5))
sns.heatmap(data=data, cbar_kws={'pad': 0.02}, ax=ax)
ax.contour(np.arange(.5, data.shape[1]), np.arange(.5, data.shape[0]), data, colors='yellow')
plt.show()
Related
I want to plot seaborn boxplot with box from min to max, rather than from 2nd to 3rd quartile, can I control it in matplotlib or seaborn? I know I can control the whiskers - how about boxes?
Here is an approach that mimics seaborn's boxplot via a horiontal plot using an aggregated dataframe.
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
# set sns plot style
sns.set()
tips = sns.load_dataset('tips')
fig, (ax1, ax2) = plt.subplots(nrows=2)
sns.boxplot(x='total_bill', y='day', data=tips, ax=ax1)
day_min_max = tips[['day', 'total_bill']].groupby('day').agg(['min', 'max', 'median'])
day_min_max.columns = day_min_max.columns.droplevel(0) # remove the old column name, only leaving 'min' and 'max'
ax2.use_sticky_edges = False
sns.barplot(y=day_min_max.index, x=day_min_max['median'] - day_min_max['min'], left=day_min_max['min'], ec='k', ax=ax2)
sns.barplot(y=day_min_max.index, x=day_min_max['max'] - day_min_max['median'], left=day_min_max['median'], ec='k', ax=ax2)
plt.tight_layout()
plt.show()
Depicting the first and third quartiles is the defining characteristic of a boxplot, so I don't think that this option exists. However, if you want to use the minima and maxima, you are not going to plot any whiskers, and hence you can simply use a barplot instead:
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
data = np.random.rand(10, 3)
sns.barplot(x=np.arange(10), y=data.ptp(axis=1), bottom=data.min(axis=1))
plt.show()
Is it possible to take a histogram from seaborn and add a normal distribution?
Say I had something like this scatter plot and histogram from the documentation.
import seaborn as sns
penguins = sns.load_dataset("penguins")
sns.jointplot(data=penguins, x="bill_length_mm", y="bill_depth_mm");
plt.savefig('deletethis.png', bbox_inches='tight')
Can i superimpose a distribution on the sides like the image below?
import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import norm
x = np.random.normal(size=100000)
# Plot histogram in one-dimension
plt.hist(x,bins=80,density=True)
xvals = np.arange(-4,4,0.01)
plt.plot(xvals, norm.pdf(xvals),label='$N(0,1)$')
plt.legend();
The following gives a Kernel Density Estimate which displays the distribution (and if it is normal):
g = sns.JointGrid(data=penguins, x="bill_length_mm", y="bill_depth_mm")
g.plot_joint(sns.scatterplot, s=100, alpha=.5)
g.plot_marginals(sns.histplot, kde=True)
The following superimposes a normal distribution on the histograms in the axes.
import seaborn as sns
import numpy as np
import pandas as pd
from scipy.stats import norm
df1 = penguins.loc[:,["bill_length_mm", "bill_depth_mm"]]
axs = sns.jointplot("bill_length_mm", "bill_depth_mm", data=df1)
axs.ax_joint.scatter("bill_length_mm", "bill_depth_mm", data=df1, c='r', marker='x')
axs.ax_marg_x.cla()
axs.ax_marg_y.cla()
sns.distplot(df1.bill_length_mm, ax=axs.ax_marg_x, fit=norm)
sns.distplot(df1.bill_depth_mm, ax=axs.ax_marg_y, vertical=True, fit=norm)
I'm trying to plot a colorbar next to my density plot with marginal axes.
It does plot the colorbar, but unfortunately not on the side.
That's what a tried so far:
sns.jointplot(x,y, data=df3, kind="kde", color="skyblue", legend=True, cbar=True,
xlim=[-10,40], ylim=[900,1040])
It looks like this:
I also tried this:
from matplotlib import pyplot as plt
import seaborn as sns
import numpy as np
kdeplot = sns.jointplot(x=tumg, y=pumg, kind="kde")
plt.subplots_adjust(left=0.2, right=0.8, top=0.8, bottom=0.2)
cbar_ax = kdeplot.fig.add_axes([.85, .25, .05, .4])
plt.colorbar(cax=cbar_ax)
plt.show()
But with the second option I'm getting a runtime error:
No mappable was found to use for colorbar creation.
First define a mappable such as an image (with imshow) or a contour set (with contourf).
Does anyone have an idea how to solve the problem?
There only seems to be information for a colorbar when effectively creating the colorbar.
So, an idea is to combine both approaches: add a colorbar via kdeplot, and then move it to the desired location. This will leave the main joint plot with insufficient width, so its width also should be adapted:
from matplotlib import pyplot as plt
import seaborn as sns
import numpy as np
# create some dummy data: gaussian multivariate with 10 centers with each 1000 points
tumg = np.random.normal(np.tile(np.random.uniform(10, 20, 10), 1000), 2)
pumg = np.random.normal(np.tile(np.random.uniform(10, 20, 10), 1000), 2)
kdeplot = sns.jointplot(x=tumg, y=pumg, kind="kde", cbar=True)
plt.subplots_adjust(left=0.1, right=0.8, top=0.9, bottom=0.1)
# get the current positions of the joint ax and the ax for the marginal x
pos_joint_ax = kdeplot.ax_joint.get_position()
pos_marg_x_ax = kdeplot.ax_marg_x.get_position()
# reposition the joint ax so it has the same width as the marginal x ax
kdeplot.ax_joint.set_position([pos_joint_ax.x0, pos_joint_ax.y0, pos_marg_x_ax.width, pos_joint_ax.height])
# reposition the colorbar using new x positions and y positions of the joint ax
kdeplot.fig.axes[-1].set_position([.83, pos_joint_ax.y0, .07, pos_joint_ax.height])
plt.show()
I have a basic heatmap created using the seaborn library, and want to move the colorbar from the default, vertical and on the right, to a horizontal one above the heatmap. How can I do this?
Here's some sample data and an example of the default:
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
# Create data
df = pd.DataFrame(np.random.random((5,5)), columns=["a","b","c","d","e"])
# Default heatma
ax = sns.heatmap(df)
plt.show()
Looking at the documentation we find an argument cbar_kws. This allows to specify argument passed on to matplotlib's fig.colorbar method.
cbar_kws : dict of key, value mappings, optional.
Keyword arguments for fig.colorbar.
So we can use any of the possible arguments to fig.colorbar, providing a dictionary to cbar_kws.
In this case you need location="top" to place the colorbar on top. Because colorbar by default positions the colorbar using a gridspec, which then does not allow for the location to be set, we need to turn that gridspec off (use_gridspec=False).
sns.heatmap(df, cbar_kws = dict(use_gridspec=False,location="top"))
Complete example:
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
df = pd.DataFrame(np.random.random((5,5)), columns=["a","b","c","d","e"])
ax = sns.heatmap(df, cbar_kws = dict(use_gridspec=False,location="top"))
plt.show()
I would like to show example with subplots which allows to control size of plot to preserve square geometry of heatmap. This example is very short:
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
# Create data
df = pd.DataFrame(np.random.random((5,5)), columns=["a","b","c","d","e"])
# Define two rows for subplots
fig, (cax, ax) = plt.subplots(nrows=2, figsize=(5,5.025), gridspec_kw={"height_ratios":[0.025, 1]})
# Draw heatmap
sns.heatmap(df, ax=ax, cbar=False)
# colorbar
fig.colorbar(ax.get_children()[0], cax=cax, orientation="horizontal")
plt.show()
You have to use axes divider to put colorbar on top of a seaborn figure. Look for the comments.
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
import numpy as np
from mpl_toolkits.axes_grid1.axes_divider import make_axes_locatable
from mpl_toolkits.axes_grid1.colorbar import colorbar
# Create data
df = pd.DataFrame(np.random.random((5,5)), columns=["a","b","c","d","e"])
# Use axes divider to put cbar on top
# plot heatmap without colorbar
ax = sns.heatmap(df, cbar = False)
# split axes of heatmap to put colorbar
ax_divider = make_axes_locatable(ax)
# define size and padding of axes for colorbar
cax = ax_divider.append_axes('top', size = '5%', pad = '2%')
# make colorbar for heatmap.
# Heatmap returns an axes obj but you need to get a mappable obj (get_children)
colorbar(ax.get_children()[0], cax = cax, orientation = 'horizontal')
# locate colorbar ticks
cax.xaxis.set_ticks_position('top')
plt.show()
For more info read this official example of matplotlib: https://matplotlib.org/gallery/axes_grid1/demo_colorbar_with_axes_divider.html?highlight=demo%20colorbar%20axes%20divider
Heatmap argument like sns.heatmap(df, cbar_kws = {'orientation':'horizontal'}) is useless because it put colorbar on bottom position.
Im making a density plot with matplotlib and I would also like to get rug plot under it. good example to make density plot is here How to create a density plot in matplotlib?
but I couldn't find any good example for rug plot. in R it can be done easly by rug(data).
You can plot markers at each datapoint.
from scipy import stats
import numpy as np
import matplotlib.pyplot as plt
sample = np.hstack((np.random.randn(30), np.random.randn(20)+5))
density = stats.kde.gaussian_kde(sample)
fig, ax = plt.subplots(figsize=(8,4))
x = np.arange(-6,12,0.1)
ax.plot(x, density(x))
ax.plot(sample, [0.01]*len(sample), '|', color='k')
You can find an example here!
ax = fig.add_subplot(111)
ax.plot(x1, np.zeros(x1.shape), 'b+', ms=20) # rug plot
x_eval = np.linspace(-10, 10, num=200)
ax.plot(x_eval, kde1(x_eval), 'k-', label="Scott's Rule")
ax.plot(x_eval, kde1(x_eval), 'r-', label="Silverman's Rule")
Seems to be the core of it!
You can also use Seaborn.distplot, which wraps histogram, KDE and rugs altogether. Figures made by Seaborn are also prettier by default.
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
sample = np.hstack((np.random.randn(30), np.random.randn(20)+5))
fig, ax = plt.subplots(figsize=(8,4))
sns.distplot(sample, rug=True, hist=False, rug_kws={"color": "g"},
kde_kws={"color": "k", "lw": 3})
plt.show()
Here's the answer for people just looking for a rugplot to use on a matplotlib axis: you can use a seaborn function.
import seaborn as sns
sns.rugplot(xdata, height=0.025, axis=ax, color='k')
This looks much nicer than a pure-matplotlib kludge because the rug is aligned to (flush with) the x-axis.