Plot intersection between y-axis grid and kdeplot on seaborn - python

I have created the following plot using seaborn kdeplot and customizing the gridlines.
sns.set_style('whitegrid')
cdf_accuracy = sns.kdeplot(eval_df['accuracy'], cumulative=True)
cdf_accuracy.yaxis.set_major_locator(ticker.MultipleLocator(0.25))
cdf_accuracy.xaxis.set_major_locator(ticker.MultipleLocator(10))
However, I would like to show the gridlines on the x-axis just on the points were the y-axis gridlines intersect the plot. There is a way to do this?
Thanks for your answers

As long as your characteristic is monotonic, which should be given with a cumulative dataset, you could simply use interpolation on the y-values:
import numpy as np
y_intrsct = [.25, .5, .75]
x_intrsct = np.interp(y_intrsct, y_data, x_data)
which results in
array([67.69792378, 83.24194722, 92.24041857])
plotted with the following code:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot(x_data, y_data)
ax.set_yticks(np.linspace(0, 1, 5))
ax.grid(axis='y')
ax.vlines(x_intrsct, *ax.get_ylim())

Related

How to center x axis values on seaborn histogram?

I know that when discrete = True, x-axis values are aligned on the center. However, I don't understand why it brakes when it comes to creating histogram with certain bin number (e.g., when setting a bins value of 19):
sns.histplot(data=df_ckd, x="HEIGHT", hue="SEX", multiple="stack",bins=19)
plt.xticks(np.arange(32, 198, 12))
plt.show()
How can I put those x axis values in the center?
You can use xlim, example:
import matplotlib.pyplot as plt
import seaborn as sns
data = [5,8,12,18,19,19.9,20.1,21,24,28]
fig, ax = plt.subplots()
sns.histplot(data, ax=ax) # distplot is deprecate and replaced by histplot
ax.set_xlim(1,31)
ax.set_xticks(range(1,32))
plt.show()

Seaborn heatmaps in subplots - align x-axis

I am trying to plot a figure containing two subplots, a seaborn heatmap and simple matplotlib lines. However, when sharing the x-axis for both plots, they do not align as can be seen in this figure:
It would seem that the problem is similar to this post, but when displaying ax[0].get_xticks() and ax[1].get_xticks() I get the same positions, so I don't know what to change. And in my picture the the deviation seems to be more than a 0.5 shift.
What am I doing wrong?
The code I used to plot the figure is the following:
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
M_1=np.random.random((15,15))
M_2=np.random.random((15,15))
L_1=np.random.random(15)
L_2=np.random.random(15)
x=range(15)
cmap = sns.color_palette("hot", 100)
sns.set(style="white")
fig, ax = plt.subplots(2, 1, sharex='col', figsize=(10, 12))
ax[0].plot(x,L_1,'-', marker='o',color='tab:orange')
sns.heatmap(M_1, cmap=cmap, vmax=np.max(M_1), center=np.max(M_1)/2., square=False, ax=ax[1])
#Mr-T 's comment is spot on. The easiest would be to create the axes beforehand instead of letting heatmap() shrink your axes in order to make room for the colorbar.
There is the added complication that the labels for the heatmap are not actually placed at [0,1,...] but are in the middle of each cell at [0.5, 1.5, ...]. So if you want your upper plot to align with the labels at the bottom (and with the center of each cell), you may have to shift your plot by 0.5 units to the right:
M_1=np.random.random((15,15))
M_2=np.random.random((15,15))
L_1=np.random.random(15)
L_2=np.random.random(15)
x=np.arange(15)
cmap = sns.color_palette("hot", 100)
sns.set(style="white")
fig, ax = plt.subplots(2, 2, sharex='col', gridspec_kw={'width_ratios':[100,5]})
ax[0,1].remove() # remove unused upper right axes
ax[0,0].plot(x+0.5,L_1,'-', marker='o',color='tab:orange')
sns.heatmap(M_1, cmap=cmap, vmax=np.max(M_1), center=np.max(M_1)/2., square=False, ax=ax[1,0], cbar_ax=ax[1,1])

Seaborn align plots in subplots

I'm using Seaborn to plot 3 ghaphs. I would like to know how could I align vertically different plots.
This is my plot so far:
And this is my code:
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.ticker as plticker
import seaborn as sns
import numpy as np
flatui = ["#636EFA", "#EF553B", "#00CC96", "#AB63FA"]
fig, ax = plt.subplots(figsize=(17, 7))
plot=sns.lineplot(ax=ax,x="number of weeks", y="avg streams", hue="year", data=df, palette=flatui)
ax.yaxis.set_major_formatter(ticker.FuncFormatter(lambda x, pos: '{:,.2f}'.format(x/1000) + 'K'))
plot.set(title='Streams trend')
plot.xaxis.set_major_locator(ticker.MultipleLocator(2))
fig, ax =plt.subplots(1,2, figsize=(17,7))
plot = sns.barplot(x="Artist", y="Releases", data = result.head(10), ax=ax[0])
plot.set_xticklabels(
plot.get_xticklabels(),
rotation=90,
horizontalalignment='center',
fontweight='light',
fontsize='x-large'
)
plot=sns.barplot(x="Artist", y="Streams", data = result.head(10), ax=ax[1])
plot.set_xticklabels(
plot.get_xticklabels(),
rotation=90,
horizontalalignment='center',
fontweight='light',
fontsize='x-large'
)
Basically I create a figure where I plot the trend graph and then a figure with 2 subplots where I plot my 2 bar plots.
What I would like to do is to align the trend plot and the 2 barplots. As you might notice on the left, the trend plot and the first barplot are not aligned, I would like to make the two figures start from the same point (like at the ending of the trend plot and the second barplot, where the 2 graphs are aligned).
How could I do that?
Here is a solution using GridSpec
fig = plt.figure()
gs0 = matplotlib.gridspec.GridSpec(2,2, figure=fig)
ax1 = fig.add_subplot(gs0[0,:])
ax2 = fig.add_subplot(gs0[1,0])
ax3 = fig.add_subplot(gs0[1,1])
sns.lineplot(ax=ax1, ...)
sns.barplot(ax=ax2, ...)
sns.barplot(ax=ax3, ...)
If you have the newest version of matplotlib, you can also use the new semantic figure composition engine
axd = plt.figure(constrained_layout=True).subplot_mosaic(
"""
AA
BC
"""
)
sns.lineplot(ax=axd['A'], ...)
sns.barplot(ax=axd['B'], ...)
sns.barplot(ax=axd['C'], ...)

Matplotlib/Seaborn: how to plot a rugplot on the top edge of x-axis?

Suppose I draw a plot using the code below. How to plot the rug part on the top edge of x-axis?
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
sns.distplot(np.random.normal(0, 0.1, 100), rug=True, hist=False)
plt.show()
The seaborn.rugplot creates a LineCollection with the length of the lines being defined in axes coordinates. Those are always the same, such that the plot does not change if you invert the axes.
You can create your own LineCollection from the data though. The advantage compared to using bars is that the linewidth is in points and therefore no lines will be lost independend of the data range.
import numpy as np; np.random.seed(42)
import matplotlib.pyplot as plt
import seaborn as sns
def upper_rugplot(data, height=.05, ax=None, **kwargs):
from matplotlib.collections import LineCollection
ax = ax or plt.gca()
kwargs.setdefault("linewidth", 1)
segs = np.stack((np.c_[data, data],
np.c_[np.ones_like(data), np.ones_like(data)-height]),
axis=-1)
lc = LineCollection(segs, transform=ax.get_xaxis_transform(), **kwargs)
ax.add_collection(lc)
fig, ax = plt.subplots()
data = np.random.normal(0, 0.1, 100)
sns.distplot(data, rug=False, hist=False, ax=ax)
upper_rugplot(data, ax=ax)
plt.show()
Rugs are just thin lines at the data points. Yo can think of them as thin bars. That being said, you can have a following work around: Plot distplot without rugs and then create a twin x-axis and plot a bar chart with thin bars. Following is a working answer:
import numpy as np; np.random.seed(21)
import matplotlib.pyplot as plt
import seaborn as sns
fig, ax = plt.subplots()
data = np.random.normal(0, 0.1, 100)
sns.distplot(data, rug=False, hist=False, ax=ax)
ax1 = ax.twinx()
ax1.bar(data, height=ax.get_ylim()[1]/10, width=0.001)
ax1.set_ylim(ax.get_ylim())
ax1.invert_yaxis()
ax1.set_yticks([])
plt.show()

Use Seaborn to plot 1D time series as a line with marginal histogram along y-axis

I'm trying to recreate the broad features of the following figure:
(from E.M. Ozbudak, M. Thattai, I. Kurtser, A.D. Grossman, and A. van Oudenaarden, Nat Genet 31, 69 (2002))
seaborn.jointplot does most of what I need, but it seemingly can't use a line plot, and there's no obvious way to hide the histogram along the x-axis. Is there a way to get jointplot to do what I need? Barring that, is there some other reasonably simple way to create this kind of plot using Seaborn?
Here is a way to create roughly the same plot as shown in the question. You can share the axes between the two subplots and make the width-ratio asymmetric.
import matplotlib.pyplot as plt
import numpy as np; np.random.seed(42)
x = np.linspace(0,8, 300)
y = np.tanh(x)+np.random.randn(len(x))*0.08
fig, (ax, axhist) = plt.subplots(ncols=2, sharey=True,
gridspec_kw={"width_ratios" : [3,1], "wspace" : 0})
ax.plot(x,y, color="k")
ax.plot(x,np.tanh(x), color="k")
axhist.hist(y, bins=32, ec="k", fc="none", orientation="horizontal")
axhist.tick_params(axis="y", left=False)
plt.show()
It turns out that you can produce a modified jointplot with the needed characteristics by working directly with the underlying JointGrid object:
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
x = np.linspace(0,8, 300)
y = (1 - np.exp(-x*5))*.5
ynoise= y + np.random.randn(len(x))*0.08
grid = sns.JointGrid(x, ynoise, ratio=3)
grid.plot_joint(plt.plot)
grid.ax_joint.plot(x, y, c='C0')
plt.sca(grid.ax_marg_y)
sns.distplot(grid.y, kde=False, vertical=True)
# override a bunch of the default JointGrid style options
grid.fig.set_size_inches(10,6)
grid.ax_marg_x.remove()
grid.ax_joint.spines['top'].set_visible(True)
Output:
You can use ax_marg_x.patches to affect the outcome.
Here, I use it to turn the x-axis plot white so that it cannot be seen (although the margin for it remains):
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
sns.set(style="white", color_codes=True)
x, y = np.random.multivariate_normal([2, 3], [[0.3, 0], [0, 0.5]], 1000).T
g = sns.jointplot(x=x, y=y, kind="hex", stat_func=None, marginal_kws={'color': 'green'})
plt.setp(g.ax_marg_x.patches, color="w", )
plt.show()
Output:

Categories

Resources