TinaTz
TinaTz

Reputation: 311

How to format bar chart values to two decimal places, only for the values present in the data?

I am trying to plot a horizontal barchart using searborn. But I'd like the y-axis to display two decimal points of my data, but only for the values that are present in the data, for example 0.96, 0.93, ... .

Here is what I have:

df=pd.read_excel('file.xlsx', sheet_name='all')
print(df['digits'])

1.   0.96270
1    0.93870
2    0.93610
3    0.69610
4    0.61250
5    0.61280
6    0.52965
7    0.50520

sns.histplot(y=df['digits'])
plt.xlabel("frequency", fontsize=15)
plt.ylabel("results",fontsize=15)

Here is the output

enter image description here

Upvotes: 0

Views: 5726

Answers (3)

JohanC
JohanC

Reputation: 80319

To create a histogram where the value rounded to 2 decimals defines the bin, you can create bin edges halfway between these values. E.g. bin edges at 0.195 and 0.205 would define the bin around 0.20. You can use `np.arange(-0.005, 1.01, 0.01)' to create an array with these bin edges.

In order to only set tick labels at the used positions, you can use ax.set_yticks(). You can round all the y-values and use the unique values for the y ticks.

If you don't want rounding, but truncation, you could use bins=np.arange(0, 1.01, 0.01) and ax.set_yticks(np.unique(np.round(y-0.005, 2))).

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import MaxNLocator
import seaborn as sns

y = np.array([0.96270, 0.93870, 0.93610, 0.69610, 0.61250, 0.61280, 0.52965, 0.50520])

ax = sns.histplot(y=y, bins=np.arange(-0.005, 1.01, 0.01), color='crimson')
ax.set_yticks(np.unique(np.round(y, 2)))
ax.xaxis.set_major_locator(MaxNLocator(integer=True))
ax.tick_params(axis='y', labelsize=6)
ax.set_xlabel("frequency", fontsize=15)
ax.set_ylabel("results", fontsize=15)
plt.show()

Note that even with a small fontsize the tick labels can overlap.

histplot with only tick labels at nonzero positions

Another approach, is to use a countplot on the rounded (or truncated) values. Then the bars get evenly spaced, without taking empty spots into account:

y = np.array([0.96270, 0.93870, 0.93610, 0.69610, 0.61250, 0.61280, 0.52965, 0.50520])
y_rounded = [f'{yi:.2f}' for yi in sorted(y)]
# y_truncated = [f'{yi - .005:.2f}' for yi in sorted(y)]
ax = sns.countplot(y=y_rounded, color='dodgerblue')

ax.xaxis.set_major_locator(MaxNLocator(integer=True))

countplot for values rounded to 2 decimals

Upvotes: 2

Muhan Li
Muhan Li

Reputation: 56

You might want to use this:

import matplotlib.ticker as tkr

y = [0.96270, 0.93870, 0.93610, 0.69610, 0.61250, 0.61280, 0.52965, 0.50520]
g = sns.histplot(y=y)
plt.xlabel("frequency", fontsize=15)
plt.ylabel("results",fontsize=15)

g.axes.yaxis.set_major_formatter(tkr.FuncFormatter(lambda y, p: f'{y:.2f}'))

set_major_formatter

or this:

import matplotlib.ticker as tkr

y = [0.96270, 0.93870, 0.93610, 0.69610, 0.61250, 0.61280, 0.52965, 0.50520]
g = sns.histplot(y=y, binwidth=0.01)
plt.xlabel("frequency", fontsize=15)
plt.ylabel("results",fontsize=15)

g.axes.yaxis.set_major_formatter(tkr.FuncFormatter(lambda y, p: f'{y:.2f}'))

binwidth=0.01:

binwidth=0.01

Upvotes: 0

mwaskom
mwaskom

Reputation: 49002

This is handled by matplotlib:

ax = sns.histplot(y=np.random.randn(20))
ax.xaxis.set_major_formatter("{x:.2f}")
ax.set_xlabel("frequency", fontsize=15)
ax.set_ylabel("results",fontsize=15)

enter image description here

Upvotes: 0

Related Questions