Reputation: 133
My goal is to create a hierarchical x-axis with the dates. To do this, I am following the steps of this answer. I have the day on the first x-axis:
import pandas as pd
import numpy as np
from matplotlib import pyplot as plt
import matplotlib.ticker as ticker
date = ['2021-01-29', '2021-01-30', '2021-01-31',
'2021-02-01', '2021-02-02', '2021-01-03', '2021-01-04']
day = ['29', '30', '31', '01', '02', '03', '04']
data = [5, 4, 3, 9, 7, 8, 2]
fig = plt.figure(num="TEST")
ax1 = fig.add_subplot(1, 1, 1)
ax1.plot(date, data)
ax1.set_xticks(date)
ax1.set_xticklabels(day)
ax1.margins(x=0)
plt.show()
And with the following code block, I generate the month on the second x-axis:
ax2 = ax1.twiny()
ax2.spines['bottom'].set_position(('axes', -0.08))
ax2.tick_params('both', direction='in', which='major')
ax2.xaxis.set_ticks_position('bottom')
ax2.xaxis.set_label_position('bottom')
ax2.set_xticks([0, 2.5, 6])
ax2.xaxis.set_major_formatter(ticker.NullFormatter())
ax2.xaxis.set_minor_locator(ticker.FixedLocator([1, 4]))
ax2.xaxis.set_minor_formatter(ticker.FixedFormatter(['JAN', 'FEB']))
This works perfectly on a line plot:
However, when I change the chart type to bar ax1.bar(date, data)
, the beginning and end ticks of both axis don't match :
Is there a way for both axis to start and end at the same point? Either extending the first axis all the way (regardless overlapping) or adjusting the second axis to match the first axis.
Upvotes: 0
Views: 6084
Reputation: 80279
To get both x-axis nicely aligned, it is important that they have the same datalimits (ax2.set_xlim(ax1.get_xlim())
). Then, ax2.set_xticks([0, 2.5, 6])
will have the ticks at the center of the first and last bar, and inbetween the third and fourth.
You can use ax2.spines['bottom'].set_bounds([0, 6])
to stop the x-axis at those positions.
If you also want to hide the tick marks of ax1
, the standard way is to set their length to zero: ax1.tick_params(axis='x', length=0)
.
If desired, you can also hide the top and right spines. You'll need to do that for both axes.
from matplotlib import pyplot as plt
import matplotlib.ticker as ticker
date = ['2021-01-29', '2021-01-30', '2021-01-31',
'2021-02-01', '2021-02-02', '2021-01-03', '2021-01-04']
day = ['29', '30', '31', '01', '02', '03', '04']
data = [5, 4, 3, 9, 7, 8, 2]
fig, ax1 = plt.subplots(num="TEST")
ax1.bar(date, data)
ax1.set_xticks(np.arange(len(date)))
ax1.set_xticklabels(day)
ax1.margins(x=0)
ax1.tick_params(axis='x', length=0) # hide tick marks
ax2 = ax1.twiny()
ax2.spines['bottom'].set_position(('axes', -0.08))
ax2.tick_params(axis='x', direction='in', which='major')
ax2.xaxis.set_ticks_position('bottom')
ax2.xaxis.set_label_position('bottom')
ax2.set_xlim(ax1.get_xlim()) # same datalimits
ax2.set_xticks([0, 2.5, 6])
ax2.spines['bottom'].set_bounds([0, 6])
ax2.xaxis.set_major_formatter(ticker.NullFormatter())
ax2.xaxis.set_minor_locator(ticker.FixedLocator([1, 4]))
ax2.xaxis.set_minor_formatter(ticker.FixedFormatter(['JAN', 'FEB']))
for ax in (ax1, ax2):
for spine in ['top', 'right']:
ax.spines[spine].set_visible(False)
plt.tight_layout()
plt.show()
Instead of shorten, set_bounds()
can also extend a bit. For example:
ax2.set_xticks([-0.5, 2.5, 6.5])
ax2.spines['bottom'].set_bounds([-0.5, 6.5])
Upvotes: 2