Christopher James
Christopher James

Reputation: 332

How do I get the x and y labels to appear when displaying more then one histogram using pandas hist() function with the by argument?

I am trying to create a series of graphs that share x and y labels. I can get the graphs to each have a label (explained well here!), but this is not what I am looking for.

I want one label that covers the y axis of both graphs, and same for the x axis.

I've been looking at the matplotlib and pandas documentation and I was unable to find anything that addresses this issues when the using by argument.

import matplotlib.pyplot as plt
import pandas as pd

df = pd.DataFrame({'A': [1, 2, 1, 2, 3, 4, 3, 4],
                   'B': [1, 7, 2, 4, 1, 4, 8, 3],
                   'C': [1, 4, 8, 3, 1, 7, 3, 4],
                   'D': [1, 2, 6, 5, 8, 3, 1, 7]},
                  index=[0, 1, 2, 3, 5, 6, 7, 8])

histo = df.hist(by=df['A'], sharey=True, sharex=True)
plt.ylabel('ylabel') # I assume the label is created on the 4th graph and then deleted?
plt.xlabel('xlabel') # Creates a label on the 4th graph.
plt.tight_layout()
plt.show()

The ouput looks like this. Histograms

Is there any way that I can create a Y Label that goes across the entire left side of the image (not each graph individually) and the same for the X Label.

As you can see, the x label only appears on the last graph created, and there is no y label.

Help?

Upvotes: 1

Views: 76

Answers (2)

terrycojones
terrycojones

Reputation: 317

I fixed the issue with the variable number of sub-plots using something like this:

cols = 3
n = len(set(df['A']))
rows = int(n / cols) + (0 if n % cols == 0 else 1)

fig, axes = plt.subplots(rows, cols)

extra = rows * cols - n

if extra:
    newaxes = []
    count = 0
    for row in range(rows):
        for col in range(cols):
            if count < n:
                newaxes.append(axes[row][col])
            else:
                axes[row][col].axis('off')
            count += 1
else:
    newaxes = axes

hist = df.hist(by=df['A'], ax=newaxes)

Upvotes: 0

Sheldore
Sheldore

Reputation: 39052

This is one way to do it indirectly using the x- and y-labels as texts. I am not aware of a direct way using plt.xlabel or plt.ylabel. When passing an axis object to df.hist, the sharex and sharey arguments have to be passed in plt.subplots(). Here you can manually control/specify the position where you want to put the labels. For example, if you think the x-label is too close to the ticks, you can use 0.5, -0.02, 'X-label' to shift it slightly below.

import matplotlib.pyplot as plt
import pandas as pd

f, ax  = plt.subplots(2, 2, figsize=(8, 6), sharex=True, sharey=True)

df = pd.DataFrame({'A': [1, 2, 1, 2, 3, 4, 3, 4],
                   'B': [1, 7, 2, 4, 1, 4, 8, 3],
                   'C': [1, 4, 8, 3, 1, 7, 3, 4],
                   'D': [1, 2, 6, 5, 8, 3, 1, 7]},
                  index=[0, 1, 2, 3, 5, 6, 7, 8])

histo = df.hist(by=df['A'], ax=ax)
f.text(0, 0.5, 'Y-label', ha='center', va='center', fontsize=20, rotation='vertical')
f.text(0.5, 0, 'X-label', ha='center', va='center', fontsize=20)

plt.tight_layout()

enter image description here

Upvotes: 2

Related Questions