I need to align the bars in my plots to be centered between the x axis tick lines in matplotlib. I have tried using the option align='edge'
which will move the bar towards the edge of the tick, but wont align it between ticks, I'm also not willing to widen the bars so that there is no white space between bars.
I have data with the form:
import matplotlib.pyplot as plt
import numpy as np
data = np.asarray([['7 Jan.', 60000],
['14 Jan.', 37000],
['21 Jan.', 32000]])
And I want to make a bar plot with it:
x = data[:, 0]
y = data[:, 1].astype(np.int)
plt.bar(x, y, width=0.7, color='#A90000')
plt.show()
Which yields:
Also, there's this tutorial which seems to approach the problem, but I haven't been able to my code. Any help is appreciated.
You're plotting categorical data. That is some strings like ["Apple", "Banana", "Cherry"]
. Now if you want to have bars in between categories, it's not really clear what unit that would be. What's half way between "Apple"
and "Banana"
? Maybe "Aubergine"
? But one cannot know.
So it's probably best to give up the categorical plot. Now you can of course map categories to numbers. So first category corresponds to 0
, second to 1
etc. Then it's easy to place the bars half way in between, at 0.5, 1.5, ...
.
import matplotlib.pyplot as plt
import numpy as np
data = np.asarray([['7 Jan.', 60000],
['14 Jan.', 37000],
['21 Jan.', 32000]])
cats = data[:, 0]
x = np.arange(len(cats)) + 0.5
y = data[:, 1].astype(np.int)
plt.bar(x, y, width=0.7, color='#A90000')
plt.xticks(x-0.5, cats)
plt.show()
Somehow the plot looks like it's missing the last label though, which is simply not present in your list. You could of course add it manually, if you want.
An alternative is to work with actual dates. Since your categories actually correspond to dates that should be possible.
from datetime import datetime
import matplotlib.pyplot as plt
import numpy as np
data = np.asarray([['7 Jan.', 60000],
['14 Jan.', 37000],
['21 Jan.', 32000]])
# convert categories to dates
xt = [datetime.strptime(d, "%d %b.") for d in data[:, 0]]
# assume all dates are equally spaced
dt = (xt[1] - xt[0])/2
# get bar positions by adding half the interval to each date
x = [tp + dt for tp in xt]
y = data[:, 1].astype(np.int)
plt.bar(x, y, width=(0.7*2*dt).days, color='#A90000')
plt.xticks(xt, data[:, 0])
plt.show()
The resulting plot is visually exactly the same as above, however, the xaxis is now in units of datetime. This allows to use tickers and formatters instead of manually placing the ticks and labels.
import numpy as np
from datetime import datetime
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
data = np.asarray([['7 Jan.', 60000],
['14 Jan.', 37000],
['21 Jan.', 32000]])
# convert categories to dates
xt = [datetime.strptime(d, "%d %b.") for d in data[:, 0]]
# assume all dates are equally spaced
dt = (xt[1] - xt[0])/2
# get bar positions by adding half the interval to each date
x = [tp + dt for tp in xt]
y = data[:, 1].astype(np.int)
plt.bar(x, y, width=(0.7*2*dt).days, color='#A90000')
plt.gca().xaxis.set_major_locator(mdates.WeekdayLocator(mdates.SU, interval=1))
plt.gca().xaxis.set_major_formatter(mdates.DateFormatter("%d %b %Y"))
plt.show()
Now the labels correspond to actual dates which can be formatted in a desired way. You'll notice that the dates here are from 1900 such that we needed to show the labels on every sunday (As the 7th of january 1900 was a sunday). You may want to add the real year to your data, such that this plot becomes correct.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With