How to change title space in matplotlib/seaborn plot - Python? - python

I have created a plot using matplotlib and seaborn in python. The code is given below:
fig = plt.figure(figsize=(15, 8), facecolor='#e4e5e9', dpi=100,)
spec = fig.add_gridspec(ncols=6, nrows=2)
ax0 = fig.add_subplot(spec[0, :4])
sns.countplot(x='Min. Exp.',data=df, color='#657ffb', **{'edgecolor':'black'})
plt.ylabel("Job Count", fontsize=11)
plt.xlabel('Minimum Experience', fontsize=11)
plt.xlim(0,20)
plt.ylim(0,2400)
ax1 = fig.add_subplot(spec[1, :4])
sns.countplot(x='Max. Exp.',data=df, color='#bad2ef', **{'edgecolor':'black'})
plt.ylabel("Job Count", fontsize=11)
plt.xlabel('Maximum Experience', fontsize=11)
plt.ylim(0,2400)
# plt.xlim(0,20)
ax2 = fig.add_subplot(spec[:, 4])
sns.boxplot(y=df['Min. Exp.'], color='#657ffb')
plt.xlabel('Minimum Experience',labelpad=5, **{'fontsize':10})
plt.ylim(0,31)
plt.ylabel('')
ax3 = fig.add_subplot(spec[:, 5])
sns.boxplot(y=df['Max. Exp.'], color='#bad2ef')
plt.xlabel('Maximum Experience',labelpad=5, **{'fontsize':10})
plt.ylabel('')
plt.ylim(0,31)
for ax in [ax0,ax1,ax2,ax3]:
ax.patch.set_alpha(0.0)
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
fig.suptitle('Job Experience Demanded in Data Scientist Roles in India', fontsize=17, y=1)
plt.savefig('job_exp2.jpg')
plt.show()
And the output is:
job_exp2.jpg
But the title is too close to the top edge. (The y parameter in fig.suptitle() can only adjust space below the title). How can I adjust the title position slightly downwards or add some space above the title (so that it is not too close to the edge)?

use plt.savefig('job_exp2.jpg',bbox_inches='tight')
or try using plt.title('Title', x=0.5, y=0.9) or whatever fits in your figure.
can also try plt.title('Title', pad=value)

Related

Modifying subplots sizes

I have been trying to find some answers, but most of them don't include a table, or they solve the problem generally and I get in trouble trying to find a workaround with the table I created as I managed to put the table through an empty axis. But now decreasing the right-axis size (as the table gets accommodated to the axis size) and increasing the left two-axis size is becoming a daunting task.
I have this code:
fig = plt.figure(figsize=(18,5))
ax1 = fig.add_subplot(221)
ax2 = fig.add_subplot(223)
ax3 = fig.add_subplot(122)
ax3.axis('off')
data = pd.DataFrame({'metrics': ['MSLE train', 'msle_test', 'asdsad'],
'values': [0.43, 0.52, 0.54]})
ax3.table(cellText=data.values, colLabels=data.columns, loc='center')
fig.suptitle(f'Train MSLE: {msle_train}, Test MSLE: {msle_test}')
ax1 = y_data.plot(label='Original data', ax=ax1, c='blue')
ax1 = y_pred_train.plot(ax=ax1, c='orange')
ax1 = y_pred_test.plot(ax=ax1, c='orange', linestyle='--')
ax1.legend()
ax2 = error_train.plot(label='Train error', ax=ax2)
ax2 = error_test.plot(label='Test error', ax=ax2, linestyle='--')
ax2.legend()
plt.show()
That returns this plot:
I'm looking to increase the horizontal size of the two left plots, something near the red mark:
Any suggestions?
You can use gridspec.
It even works with a vertical centered right hand side and a table:
import matplotlib.pyplot as plt
from matplotlib import gridspec
import pandas as pd
data = pd.DataFrame({'metrics': ['MSLE train', 'msle_test', 'asdsad'],
'values': [0.43, 0.52, 0.54]})
fig = plt.figure(figsize=(18,5))
gs = gridspec.GridSpec(4, 2, width_ratios=[3,1])
ax1 = fig.add_subplot(gs[0:2,:-1])
ax1.set_title('ax1')
ax2 = fig.add_subplot(gs[2:4,:-1])
ax2.set_title('ax2')
ax3 = fig.add_subplot(gs[1:3,1])
ax3.set_axis_off()
ax3.table(cellText=data.values, colLabels=data.columns, loc='center')
fig.tight_layout()
plt.show()
Notes:
Horizontal alignment is set with the ratio of width_ratios=[3,1]
fig.tight_layout() is helpfull to automatically align the spacing between the plots.
Vertical centering is achieved with a little workaround by having initially a larger vertical grid than required (no. of vertical plots) and distributing the plots and table accordingly (see e.g. gs[2:4).
The titles were just added for visual orientation.
ax3.set_axis_off() is required to suppress the plot frame at the table position - without it you'll get:

Trying to plot 2 charts side-by-side, but one of them always comes out empty

I have two plots that I generated from my data:
Here the second plot shows the distribution of results from the first one.
What I want is to plot them side-by-side so you could see both the data and the distribution on the same plot. And I want plots to share y-axis as well.
I tried to do the following:
fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(40, 15), sharey=True)
ax1 = sns.lineplot(plotting_df.index, plotting_df.error, color=('#e65400'), lw=2, label='random forest residual error')
ax1 = sns.lineplot(plotting_df.index, plotting_df.val, color=('#9b9b9b'), lw=1, label='current model residual error')
ax1 = sns.lineplot(plotting_df.index, 0, color=('#2293e3'), lw=1)
ax1.xaxis.set_visible(False)
ax1.set_ylabel('Residual Fe bias', fontsize=16)
ax1.set_title('Models residual error comparison', fontsize=20, fontweight='bold')
sns.despine(ax=ax1, top=True, bottom=True, right=True)
ax2 = sns.distplot(results_df.error, hist=True, color=('#e65400'), bins=81,
label='Random forest model', vertical=True)
ax2 = sns.distplot(plotting_df.val, hist=True, color=('#9b9b9b'),
bins=81, label='Rolling averages model', vertical=True)
ax2.set_title('Error distribution comparison between models', fontsize=20, fontweight='bold')
sns.despine(ax=ax2, top=True, right=True)
fig.savefig("blabla.png", format='png')
But when I do run it I get strange results - the first chart is in the second column, whereas I wanted it on the left and the second chart is completely blank. Not sure what I did wrong here.
Both lineplot and distplot accept a matplotlib axes object as an argument, which tells it which axes to plot onto. If no axes is passed into it, then the plot is placed onto the current axes.
You create a figure and 2 axes using :
fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(40, 15), sharey=True)
Therefore, ax2 will be the current axes. So your distplot is being plotted on top of your lineplot, both in ax2.
You need to pass the axes into the seaborn plotting functions.
sns.lineplot(..., ax=ax1)
sns.distplot(..., ax=ax2)

Matplotlib/Seaborn: ValueError when annotating 2nd subplot (annotating 1st subplot was successful)

I created this figure with two subplots and wanted to annotate both subplots separately (see figure and code below)
# Declare fig ax
fig, ax = plt.subplots(2,1,figsize=[12,10], sharey=True)
# Line plot for ax[0]
sns.lineplot(x=['2020-01-01', '2020-01-31'], y=[32.7477, 49.6184], ax=ax[0], marker='o', markersize=10)
# Add title for ax[0]
ax[0].set(title='Figure 1', xlabel=None, ylabel="Index")
ax[0].tick_params(axis = 'x', rotation = 45)
# Annotation for ax[0]
ax[0].text(0, 55, 52.53)
ax[0].text(0.4, 45, "Some annotation here", horizontalalignment='center', size='medium', color='black')
ax[0].text(1, 52, 49.62, horizontalalignment='center', size='medium', color='black')
# Line plot for ax[1]
sns.lineplot(x="date", y="ari", data=df_ari_jan, ax=ax[1], marker='o', markersize=10)
# Add title for ax[1]
ax[1].set(title='Figure 2', xlabel=None, ylabel="Index")
ax[1].set_xticks(df_ari_jan["date"].values)
ax[1].tick_params(axis = 'x', rotation = 45)
# Annotation for ax[1]
ax[1].text(-1, 0, 52.53)
fig.tight_layout()
Annotating the first subplot was fine, but I kept getting this ValueError: Image size of 15006958x630 pixels is too large. It must be less than 2^16 in each direction. when trying to annotate the 2nd one.
fig.tight_layout() wouldn't work either UserWarning: Tight layout not applied. The left and right margins cannot be made large enough to accommodate all axes decorations.
Any idea as to why?

How to collapse the space above a pie chart and below the axis title in Matplotlib?

For some reason, I'm getting a huge space between a pair of pie charts and their titles. I'm not sure what's controlling this spacing.
I would like to collapse this space. At the least, can we center the pie inside the space?
Here is some sample code similar to what I am actually doing:
import matplotlib.pyplot as plt
x = ['a', 'b', 'c']
y = [1.1, 3.5, 2.2]
y1_sizes = y
y2_sizes = y
fig, axarr = plt.subplots(1, 2)
ax1 = axarr[0]
ax2 = axarr[1]
ax1.pie(y1_sizes, shadow=True, startangle=90, autopct='%1.1f%%')
ax1.axis('equal')
ax1.set_title('Old Stuff')
ax2.pie(y2_sizes, shadow=True, startangle=90, autopct='%1.1f%%')
ax2.axis('equal')
ax2.set_title('New Stuff')
lgd1 = ax1.legend(x, loc='lower center')
lgd2 = ax2.legend(x, loc='lower center')
fig.suptitle('My Chart Title', fontweight='bold')
This is the result
I am answering your question in the comments: "Is there a way to move down the axis titles?". You can achieve this by specifying the vertical location for respective titles in fractional coordinates using the parameter y.
ax1.set_title('Old Stuff', y=0.8)
ax2.set_title('New Stuff', y=0.8)
fig.suptitle('My Chart Title', fontweight='bold', y=0.85)

How to add more stocks to a graph with twin axis's?

I have this code below to plt trends of stocks, and have 2 axis's one axis on the left and the other on right of the chart for 2 stocks with different scales. I can't figure out how I can add more stocks to the graph. I just have 2 stocks, but I like to add more.
How can I modify my code to add more stocks to the second axis?
fig, ax1 = plt.subplots()
fig = plt.figure(figsize=(6,4))
t = newdf['date']
s1 = newdf['IBM']
ax1.plot(t, s1, 'b-')
ax1.set_xlabel('Dates', fontsize=14)
ax1.set_xticklabels(t, rotation=45)
ax1.legend(loc=0)
ax1.grid()
# Make the y-axis label, ticks and tick labels match the line color.
ax1.set_ylabel('Price', color='b')
ax1.tick_params('y', colors='b')
ax2 = ax1.twinx()
s2 = newdf['AAPL']
ax2.plot(t, s2, 'r-')
ax2.set_ylabel('Price', color='r')
ax2.tick_params('date', colors='r', rotation=90)
ax2.legend(loc=2)
fig.tight_layout()
plt.show()
[
add more stocks just above fig.tight_layout() like this.
For nth stock add ax(n),s(n) and add stock name chose color from below link.
ax3 = ax1.twinx()
s3 = newdf[stock name]
ax3.plot(t, s3, 'r-')
ax3.set_ylabel('Price', color=your color)
ax3.tick_params('date', colors=your color, rotation=90)
ax3.legend(loc=3)
Color
RGB

Categories

Resources