Seaborn gives wrong values on x-axis ticks? - python

In the code below Matplotlib gives the correct range of 5.0 to 10.0, why is Seaborn different?
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
from matplotlib import ticker
sns.set()
fig, (ax1, ax2) = plt.subplots(2)
x = np.linspace(5, 10)
y = x ** 2
sns.barplot(x, y, ax=ax1)
ax1.xaxis.set_major_locator(ticker.MultipleLocator(5))
ax1.xaxis.set_major_formatter(ticker.FormatStrFormatter('%.2f'))
ax2.bar(x, y, width = 0.1)
ax2.xaxis.set_major_locator(ticker.MultipleLocator(5))
ax2.xaxis.set_major_formatter(ticker.FormatStrFormatter('%.2f'))
plt.show()

Seaborn's barplot is a categorical plot. This means it places the bars at successive integer positions (0,1,...N-1). Hence, if you have N bars, the axis will range from -0.5 to N-0.5.
There is no way to tell seaborn to place the bars at different positions; but you can of course fake the labels to let it appear as such. E.g. to label every 5th bar with the value from x:
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
from matplotlib import ticker
sns.set()
fig, ax = plt.subplots()
x = np.linspace(5, 10)
y = x ** 2
sns.barplot(x, y, ax=ax)
ax.xaxis.set_major_locator(ticker.FixedLocator(np.arange(0, len(x), 5)))
ax.xaxis.set_major_formatter(ticker.FixedFormatter(x[::5]))
ax.tick_params(axis="x", rotation=90)
plt.tight_layout()
plt.show()
Inversely, it is possible to plot categorical plots with matplotlib. To this end, one needs to plot strings.
ax.bar(x.astype(str), y)
ax.xaxis.set_major_locator(ticker.FixedLocator(np.arange(0, len(x), 5)))
ax.xaxis.set_major_formatter(ticker.FixedFormatter(x[::5]))
ax.tick_params(axis="x", rotation=90)
If you want a numerical bar plot, i.e. a plot where each bar is at the axis position of x, you would need to use matplotlib. This is the default case also shown in the question, where the bars range between 5 and 10. One should make sure to have the width of the bars smaller than the difference between successive x positions in this case.
ax.bar(x, y, width=np.diff(x).mean()*0.8)
ax.xaxis.set_major_locator(ticker.MultipleLocator(1))
ax.xaxis.set_major_formatter(ticker.FormatStrFormatter('%.2f'))
ax.tick_params(axis="x", rotation=90)

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 Adjusting Markers

As you can see here, the X axis labels here are quite unreadable. This will happen regardless of how I adjust the figure size. I'm trying to figure out how to adjust the labeling so that it only shows certain points. The X axis are all numerical between -1 to 1, and I think it would be nice and more viewer friendly to have labels at -1, -.5, 0, .5 and 1.
Is there a way to do this? Thank you!
Here's my code
sns.set(rc={'figure.figsize':(20,8)})
ax = sns.countplot(musi['Positivity'])
ax.set_xticklabels(ax.get_xticklabels(), rotation=40, ha='right')
plt.tight_layout()
plt.show()
Basically seaborn is wrapper on matplotlib. You can use matplotlib ticker function to do a Job. Refer the below example.
Let's Plots tick every 1 spacing.
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import seaborn as sns
sns.set_theme(style="whitegrid")
x = [0,5,9,10,15]
y = [0,1,2,3,4]
tick_spacing = 1
fig, ax = plt.subplots(1,1)
sns.lineplot(x, y)
ax.xaxis.set_major_locator(ticker.MultipleLocator(tick_spacing))
plt.show()
Now Let's plot ticks every 5 ticks.
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import seaborn as sns
sns.set_theme(style="whitegrid")
x = [0,5,9,10,15]
y = [0,1,2,3,4]
tick_spacing = 5
fig, ax = plt.subplots(1,1)
sns.lineplot(x, y)
ax.xaxis.set_major_locator(ticker.MultipleLocator(tick_spacing))
plt.show()
P.S.: This solution give you explicit control of the tick spacing via the number given to ticker.MultipleLocater(), allows automatic limit determination, and is easy to read later.

How to label quartiles in matplotlib boxplots?

I have a list of values which I want to plot the distribution for. I'm using a box-plot but it would be nice to add some dotted lines going from the boxplot quartiles to the axis. Also I want just the quartile values displayed on the x ticks.
Here's a rough idea but with values at the end instead of names.
import numpy as np
import pandas as pd
import matplotlib.pylab as plt
vel_arr = np.random.rand(1000,1)
fig = plt.figure(1, figsize=(9, 6))
ax = fig.add_subplot(111)
# Create the boxplot
ax.boxplot(vel_arr,vert=False, manage_ticks=True)
ax.set_xlabel('value')
plt.yticks([1], ['category'])
plt.show()
np.quantile calculates the desired quantiles.
ax.vlines draws vertical lines, for example from the center of the boxplot to y=0. zorder=0 makes sure these lines go behind the boxplot.
ax.set_ylim(0.5, 1.5) resets the ylims. Default, the vlines force the ylims with some extra padding.
ax.set_xticks(quantiles) sets xticks at the position of every quantile.
import numpy as np
import matplotlib.pylab as plt
vel_arr = np.random.rand(50, 1)
fig = plt.figure(1, figsize=(9, 6))
ax = fig.add_subplot(111)
ax.boxplot(vel_arr, vert=False, manage_ticks=True)
ax.set_xlabel('value')
ax.set_yticks([1])
ax.set_yticklabels(['category'])
quantiles = np.quantile(vel_arr, np.array([0.00, 0.25, 0.50, 0.75, 1.00]))
ax.vlines(quantiles, [0] * quantiles.size, [1] * quantiles.size,
color='b', ls=':', lw=0.5, zorder=0)
ax.set_ylim(0.5, 1.5)
ax.set_xticks(quantiles)
plt.show()

Setting the interval of x-axis for seaborn plot

I have a set of subplots to plot. Here, how do we set the interval for x-axis in the subplot in second row, i.e ax4 to ax6. Currently all the values from 1 to 100 are printed as shown in the figure. I tried ax4.set_xticks(range(1,100,5)). But there, the range shown was 1 to 20. I was expecting a range from 1 to 100, with an interval of 5, i.e. 1,5,10...95,100
Currently the plot has x-axis as shown below. I have not added the code for first row.
yInit = initRes
yInit = yInit[(yInit['nodeSKT'] < 92) & (yInit['nodeSKT'] > 1)]
sns.set_context("paper", font_scale=2, rc={"lines.linewidth": 1.2})
fig, (ax4, ax5, ax6) = plt.subplots(nrows=1,ncols=3,figsize=(18,10))
plt.figure()
xval = 'nodeSKT'
sns.pointplot(x=xval, y='lemmaPrec', data=yInit,join=False,ax=ax4)
sns.pointplot(x=xval, y='wordPrec',color="#2ecc71",data=yInit, join=False,ax=ax4)
sns.pointplot(x=xval, y='lemmaReca', data=yInit,join=False,ax=ax5)
sns.pointplot(x=xval, y='wordReca',color="#2ecc71",data=yInit, join=False,ax=ax5)
sns.pointplot(x=xval, y='lemmaFsco', data=yInit,join=True,ax=ax6)
sns.pointplot(x=xval, y='wordFsco',color="#2ecc71",data=yInit, join=False,ax=ax6)
plt.savefig('lem_fscore.png')
Seaborn pointplot is a categorical plot. This means that the different categories are simply placed one by one along the x axis.
The idea would therefore be to change the locator as well as the formatter for the xticks.
import seaborn.apionly as sns
import matplotlib.pyplot as plt
import matplotlib.ticker as ticker
import numpy as np; np.random.seed(1)
x = np.random.randint(0,20,size=(100))
y = np.random.rand(100)
ax = sns.pointplot(x,y )
ax.xaxis.set_major_locator(ticker.MultipleLocator(5))
ax.xaxis.set_major_formatter(ticker.ScalarFormatter())
plt.show()

incorrect Colorbar for log values in scatter plot

I want to use a scatter plot to describe the relationship between X, Y and Z. Z is p-value so it is better to denote it as log values.
Following the instructions here, I can plot a logarithmic scatter plot, but the color bar seems wrong. The color bar is almost totally blue, but there should be some red! Below is the figure and my codes.
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
from matplotlib.colors import LogNorm
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
ax1.set_title("P-value")
Z1 = pos_spearmanr['pval']
X = pos_spearmanr['X']
Y = pos_spearmanr['Y']
im = ax1.scatter(X,
Y,
edgecolors=None,
c=Z1,
norm=LogNorm(),
cmap=plt.get_cmap('bwr'), alpha=0.2)
ax1.set_xlabel('X')
ax1.set_ylabel('Y')
ax1.set_xlim(0, 1)
ax1.set_ylim(0, 1)
cbar = fig.colorbar(im,ax=ax1)

Categories

Resources