Matplotlib fill in missing Tic labels
I have a list of Pandas dataframes (example):
df1 = pd.DataFrame({'Number':[-9,-8,0,1,2,3], 'A':[3,6,4,1,7,19], 'B':[2,4,4,0,7,1]})
df1.set_index('Number',inplace=True)
df2 = pd.DataFrame({'Number':[0,5,6,7,8,9], 'A':[8,7,3,5,2,15], 'B':[1,7,1,1,1,3]})
df2.set_index('Number',inplace=True)
df_list = [df1, df2] #In reality there are more than two in the list
and I would try to plot them using Matplotlib:
nrow = 2
ncol = 2
fig, axs = plt.subplots(nrow,ncol)
for i in range(nrow*ncol):
#Convert 1D to 2D
row = i / ncol
col = i % ncol
if i >= len(df_list):
axs[row,col].axis('off')
else:
df_list[i]['A'].plot(kind='bar',
ax=axs[row,col],
ylim=(0,20),
xlim=(-10,10),
figsize=(20,15),
color=('green'),
legend=False,
)
df_list[i]['B'].plot(kind='bar',
ax=axs[row,col],
ylim=(0,20),
xlim=(-10,10),
figsize=(20,15),
color=('yellow'),
legend=False,
)
The resulting plots look like this: Everything looks fine except for the xtic labels, which I believe will be spaced according to its value (i.e. "-9" should not be in the middle of the plot or "0" should not be near with "5", etc.). In fact, since my x-range is roughly (-10,10), I want the entire full range to be displayed along the x-axis, and for the color stripes accordingly by their "number". One possible solution I came across was to fill in the missing values ββfrom (-10,10) using Pandas, but I guess there is a better / more obvious way to handle this. I just couldn't figure out this solution.
Update:
Thanks to Ajean's (and JD Long's) answers below, I am now using this Matplotlib code:
df_list = [df1, df2]
nrow = 2
ncol = 2
fig, axs = plt.subplots(nrow,ncol,figsize=(20,15))
for i in range(nrow*ncol):
#Convert 1D to 2D
row = i / ncol
col = i % ncol
if i >= len(df_list):
axs[row,col].axis('off')
else:
axs[row,col].bar(np.array(df_list[i].index)-0.5, df_list[i]['A'], width=1, color='green')
axs[row,col].bar(np.array(df_list[i].index)-0.5, df_list[i]['B'], width=1, color='yellow')
axs[row,col].set_xlim([-10,10])
axs[row,col].set_ylim([0,20])
axs[row,col].xaxis.set_ticks(np.arange(-10, 11, 1))
which produces this (desired) result:
Note: The width of each bar is set to 1.0, and they are shifted by -0.5 to center each baht over the tic marks.
source to share
It looks like Pandas has not yet provided the functionality of its histogram wrapper to explicitly place bar positions. A value of 0.14.0 "What's New" means "the coordinates of the lineplots are now at integer values ββ(0.0, 1.0, 2.0 ...)" and nothing changed until 0.15.1 as far as I can tell.
So I would skip the Pandas interface (which you most definitely use) for this and use Matplotlib directly.
nrow = 1
ncol = 2
fig, axs = plt.subplots(nrow,ncol)
for i in range(nrow*ncol):
if i >= len(df_list):
axs[i].axis('off')
else:
# You could theoretically turn this into a loop over your columns
# with appropriate widths and offsets
axs[i].bar(df_list[i].index-0.4, df_list[i]['A'], width=0.4, color='green')
axs[i].bar(df_list[i].index, df_list[i]['B'], width=0.4, color='yellow')
The above code is modified with your specific DataFrame list, which creates the graph below (I've excluded the additional axes for simplicity).
NOTE . The operation df_list[i].index-0.4
under Pandas 0.14.0 throws an error, which is a bug that was fixed in 0.15.1. You can work around this by converting the index to a regular numpy array first, or by simply updating pandas.
source to share
You have asked a very good question. Thanks for having a reproducible example that makes it easier to help him.
The problem is that Pandas chart code accepts categorical data on the x axis. Obviously, you don't have categorical data. However, there is no way to tell Matplotlib that through the Pandas interface (which I know).
The most obvious solution to me is the one you present for adding values. I would do it, perhaps via a connection. I would join an existing fileframe with an index that had all the values ββI wanted on the x-axis and join the option how='outer'
.
source to share