Reputation: 89
I have been searching for hours how to add space between a bar chart and a table using matplotlib.pyplot but I haven't found a solution on how to display the layout properly. Currently the top of the table collides with the bar chart x axis header and the bottom of the table is out of the figure. I have tried making the figure bigger with figsize
, I have tried using bbox
, subplots_adjust
, plt.tight_layout()
but none works. Any help is appreciated.
def plot_bar(df, *args):
df = pd.DataFrame([{'OPEN': 4, 'CLOSED': 139, 'DATE': '2019-01-01'}, {'OPEN': 0, 'CLOSED': 139, 'DATE': '2019-02-01'}, {'OPEN': 1, 'CLOSED': 124, 'DATE': '2019-03-01'}, {'OPEN': 4, 'CLOSED': 127, 'DATE': '2019-04-01'}, {'OPEN': 1, 'CLOSED': 84, 'DATE': '2019-05-01'}, {'OPEN': 6, 'CLOSED': 113, 'DATE': '2019-06-01'}, {'OPEN': 0, 'CLOSED': 123, 'DATE': '2019-07-01'}, {'OPEN': 2, 'CLOSED': 109, 'DATE': '2019-08-01'}, {'OPEN': 0, 'CLOSED': 107, 'DATE': '2019-09-01'}, {'OPEN': 7, 'CLOSED': 119, 'DATE': '2019-10-01'}, {'OPEN': 2, 'CLOSED': 82, 'DATE': '2019-11-01'}, {'OPEN': 4, 'CLOSED': 83, 'DATE': '2019-12-01'}, {'OPEN': 12, 'CLOSED': 112, 'DATE': '2020-01-01'}, {'OPEN': 10, 'CLOSED': 89, 'DATE': '2020-02-01'}, {'OPEN': 31, 'CLOSED': 64, 'DATE': '2020-03-01'}])
df["DATE"] = pd.to_datetime(df["DATE"])
df['DATE'] = df['DATE'].apply(lambda x: [x.month, x.year])
df['DATE'] = df['DATE'].apply(lambda x: f'{calendar.month_abbr[x[0]]}-{x[1]}')
ax = df.plot.bar(x=args[0]['x'], y=args[0]['y'], figsize=(15, 7))
for i, v in enumerate(df['OPEN']):
ax.text(i - .20, v + 1, str(v), color='blue', fontweight='bold')
for i, v in enumerate(df['CLOSED']):
ax.text(i - .20, v + 1, str(v), color='orange', fontweight='bold')
plt.title('Open vs Closed Tickets')
plt.xlabel('Time')
plt.ylabel('Tickets')
table_columns = df['DATE'].values.tolist()
open = df['OPEN'].values.tolist()
closed = df['CLOSED'].values.tolist()
table_data = [open, closed]
table_rows = df.columns.values.tolist()[0:2]
plt.table(cellText=table_data, rowLabels=table_rows, colLabels=table_columns, loc='bottom',
bbox=[0, -0.250, 1, 0.2])
plt.tight_layout()
plt.show()
return
Answering Diziet Asahi: I made those 2 changes but my table somehow is still cut in half man this is so frustrating.
Upvotes: 1
Views: 1122
Reputation: 40697
One possible issue is that you have to use plt.subplots_adjust(bottom=xxx)
after tight_layout()
(otherwise tight_layout will undo what you did with subplots_adjust). This will change the size of the plot and make more room for the table below. Increase the xxx
value to suit your need, the value is given in fraction of the figure, so bottom=0.2
would locate the bottom of the plot at 20% of the figure height.
The other issue is that you are using plt.table()
which was made to have the table "stick" to the axes. If you place the table below the axes, then it's basically supposed to replace the x-axis labels. But you have to chose between using loc=
(automatic placement) or bbox=
(manual placement). You cannot use both.
Here is the results of doing those two things:
import calendar
df = pd.DataFrame([{'OPEN': 4, 'CLOSED': 139, 'DATE': '2019-01-01'}, {'OPEN': 0, 'CLOSED': 139, 'DATE': '2019-02-01'}, {'OPEN': 1, 'CLOSED': 124, 'DATE': '2019-03-01'}, {'OPEN': 4, 'CLOSED': 127, 'DATE': '2019-04-01'}, {'OPEN': 1, 'CLOSED': 84, 'DATE': '2019-05-01'}, {'OPEN': 6, 'CLOSED': 113, 'DATE': '2019-06-01'}, {'OPEN': 0, 'CLOSED': 123, 'DATE': '2019-07-01'}, {'OPEN': 2, 'CLOSED': 109, 'DATE': '2019-08-01'}, {'OPEN': 0, 'CLOSED': 107, 'DATE': '2019-09-01'}, {'OPEN': 7, 'CLOSED': 119, 'DATE': '2019-10-01'}, {'OPEN': 2, 'CLOSED': 82, 'DATE': '2019-11-01'}, {'OPEN': 4, 'CLOSED': 83, 'DATE': '2019-12-01'}, {'OPEN': 12, 'CLOSED': 112, 'DATE': '2020-01-01'}, {'OPEN': 10, 'CLOSED': 89, 'DATE': '2020-02-01'}, {'OPEN': 31, 'CLOSED': 64, 'DATE': '2020-03-01'}])
df["DATE"] = pd.to_datetime(df["DATE"])
df['DATE'] = df['DATE'].apply(lambda x: [x.month, x.year])
df['DATE'] = df['DATE'].apply(lambda x: f'{calendar.month_abbr[x[0]]}-{x[1]}')
ax = df.plot.bar(x='DATE', y=['OPEN','CLOSED'], figsize=(15, 7))
for i, v in enumerate(df['OPEN']):
ax.text(i - .20, v + 1, str(v), color='blue', fontweight='bold')
for i, v in enumerate(df['CLOSED']):
ax.text(i - .20, v + 1, str(v), color='orange', fontweight='bold')
plt.title('Open vs Closed Tickets')
plt.ylabel('Tickets')
#remove all x-labels since the table will be used instead
plt.xlabel('')
plt.xticks([])
table_columns = df['DATE'].values.tolist()
open = df['OPEN'].values.tolist()
closed = df['CLOSED'].values.tolist()
table_data = [open, closed]
table_rows = df.columns.values.tolist()[0:2]
plt.table(cellText=table_data, rowLabels=table_rows, colLabels=table_columns, loc='bottom')
plt.tight_layout()
plt.subplots_adjust(bottom=0.1)
plt.show()
Upvotes: 1