Trying mathplotlib for the first time. I want to create two separate graphs. I'm able to get both graphs to show, however, the second graph has extra space underneath the x-axis and makes the x-axis scale labels/axis label show way below. If I comment out the first graph, the extra space disappears.
I've attempted using plt.tight_layout() and that made the rest of the graph tight (labels were laying over-each other), but did not help w/ my extra space at the bottom. see the right graph with the red marking
Note: I changed the configuration on the right graph to show the extra space, so that's why it'll look different than the ranges I included in the code.
#left graph
fig_Sub = plt.figure(1)
fig_Sub.suptitle('Subreddits', fontsize=14, fontweight='bold')
ax1 = fig_Sub.add_subplot(111)
fig_Sub.subplots_adjust(top=0.85)
ax1.set_title('axes title')
ax1.set_xlabel('Word')
y_rotate=ax1.set_ylabel('Instances')
y_rotate.set_rotation(0)
ax1.axis([0, 1000, 0, 1000])
plt.rc('xtick', color='k', labelsize='medium', direction='out')
plt.rc('xtick.major', size=10, pad=100) #size of tick, interval
plt.rc('xtick.minor', size=10, pad=100)
#right graph
fig_user = plt.figure(2)
fig_user.suptitle('Users', fontsize=14, fontweight='bold')
ax2 = fig_user.add_subplot(111)
fig_user.subplots_adjust(top=0.85)
ax2.set_title('axes title')
ax2.set_xlabel('Word')
y2_rotate=ax2.set_ylabel('Instances')
y2_rotate.set_rotation(0)
ax2.axis([0, 1000, 0, 1000])
plt.rc('xtick', color='k', labelsize='medium', direction='out')
plt.rc('xtick.major', size=0, pad=0)
plt.rc('xtick.minor', size=0, pad=0)
plt.show()
Per #ImportanceOfBeingErnest, get rid of pad in plt.rc().
Related
I want to make a plot with a grid of thumbnails on the left and a line plot on the right. Here is a minimal example
import numpy as np
from matplotlib import pyplot as plt
### This can change at runtime
n_grid = 4
### Grid of thumbnails
fig = plt.figure(figsize=(20,10.2))
for i in range(n_grid):
for j in range(n_grid):
ax = plt.subplot2grid(shape=(n_grid, 2*n_grid), loc=(i,j))
plt.imshow(np.random.random((16,16)))
ax.set_axis_off()
### Line plot
ax = plt.subplot2grid(shape=(n_grid, 2*n_grid), loc=(0,n_grid), rowspan=n_grid-1, colspan=n_grid)
plt.plot(np.cumsum(np.random.random(100)), label='Random Sum')
plt.xlim([0, 100])
plt.ylim(0,50)
plt.xlabel('Number', fontsize=12)
plt.ylabel('Sum', fontsize=12)
plt.figtext(0.5, 0.01, f'Unique identifier', ha='center', va='baseline')
#plt.tight_layout()
plt.subplots_adjust(left=0.01, bottom=0.03, right=0.99, top=0.99, wspace = 0.06, hspace=0.06)
plt.savefig('plot_1.png', dpi=96)
The problem is that the yticklabels and ylabel stick over the center into the area of the thumbnails. The lineplot on the right is too wide.
One common solution found on the internet is using automatic resizing with tight_layout(), so I change the last three lines to
plt.tight_layout()
#plt.subplots_adjust(left=0.01, bottom=0.03, right=0.99, top=0.99, wspace = 0.06, hspace=0.06)
plt.savefig('plot_2.png', dpi=96)
This does not rescale the lineplot, but instead makes the wspace and hspace attributes so big I get way too much whitespace between the thumbnails.
I am looking for a solution to either
Set wspace and hspace of only the right subplot, not all of them together, or
resize the lineplot to fit into the designated area, without the labels sticking out
It would seem that this is an easy problem, but despite searching for about 2 hours and digging around in the object properties with iPython I found nothing suitable. All solutions seem to change the size and padding of the subplots, not fitting a plot into the area defined with subplot2grid. The only other solution I can think of is a hack that calculates a modified aspect from the value ranges to make the lineplot always a given percentage thinner.
You can play around with subfigures. For example, if you do:
import numpy as np
from matplotlib import pyplot as plt
### This can change at runtime
n_grid = 4
### Grid of thumbnails
fig = plt.figure(figsize=(20,10.2))
# add 2 subfigures
subfigs = fig.subfigures(1, 2, wspace=0)
# add thumbnail grid into left subfig
gsLeft = subfigs[0].add_gridspec(n_grid, n_grid)
axLeft = []
for i in range(n_grid):
for j in range(n_grid):
axLeft.append(subfigs[0].add_subplot(gsLeft[i, j]))
axLeft[-1].imshow(np.random.random((16,16)))
axLeft[-1].set_axis_off()
### Line plot
gsRight = subfigs[1].add_gridspec(3, 1)
axRight = subfigs[1].add_subplot(gsRight[:2, 0])
axRight.plot(np.cumsum(np.random.random(100)), label='Random Sum')
axRight.set_xlim([0, 100])
axRight.set_ylim(0,50)
axRight.set_xlabel('Number', fontsize=12)
axRight.set_ylabel('Sum', fontsize=12)
# adjust subfigures here (play around with these to get the desired effect)
subfigs[0].subplots_adjust(wspace=0.03, hspace=0.03, bottom=0.05, top=0.95, left=0.05, right=0.95)
subfigs[1].subplots_adjust(left=0.01)
# add title (here I've had to add it to the left figure, so it's not centred,
# in my test adding it to the figure itself meant it was not visible, although
# the example in the Matplotlib docs suggests it should work!)
# fig.suptitle(f'Unique identifier', x=0.5, y=0.025, ha='center', va='baseline')
subfigs[0].suptitle(f'Unique identifier', x=0.5, y=0.025, ha='center', va='baseline')
fig.savefig("plot_1.png", dpi=150)
This gives:
but you can play around with the values to adjust it as you like.
I have problems with the arrangement of the legend and the font size. As you can see on the picture, the legend is in the diagram and not next to it (it should be on the right). I would also like to change the font size of the heading and the axes. Unfortunately, I can only do this if they are not placed next to each other. Does anyone have an idea how this could work? Is the error perhaps due to the way I made the subplot?
Many thanks already!
#Create Boxplots for beliefed ranks
f, axes = plt.subplots(1, 2)
figure_Grank = sns.boxplot(x='Treatment',y='Believed Rank within own Gender',data=df_fig, hue="sex", palette='vlag_r', ax=axes[0]).set(title="Beliefed Rank within own Gender")
plt.legend(title="Sex", bbox_to_anchor=(0.75, 1), loc=2, borderaxespad=0., fancybox=True)
figure_rank = sns.boxplot(x='Treatment',y='Believed Rank',data=df_fig[df_fig["Period"]==4], hue="sex", palette='vlag_r', ax=axes[1]).set(title="Beliefed Rank whithin own Group")
plt.legend(title="Sex", bbox_to_anchor=(1.01, 1), loc=2, borderaxespad=0., fancybox=True)
plt.subplots_adjust(left=0,
bottom=0.2,
right=2,
top=1.2,
wspace=0.2, #this is the horizontal space between the diagrams
hspace=4) #this is the vertical space between the diagrams #0.8
If i run this code in python:
titles = ctf01[0,1:]
fig = plt.figure(figsize=(11.69,8.27), dpi=100)
for num in range(len(titles)):
ax = fig.add_subplot(3,4,num+1)
ax.plot(ctf03[1:,num+1], ctf0102[:,num], 'ro')
ax.set_title(titles[num])
plt.tight_layout()
fig.text(0.5, 0.04, 'CTF12', ha='center')
fig.text(0.04, 0.5, 'CTF3', va='center', rotation='vertical')
fig.savefig("example.pdf")
i get this in the pdf file:
I would like to fix the problem with the "figure title" shown in the red circles.
If i set the 0.04 value as an negative value the title runs out of paper.
I also would like to save some space with moving the title of the subplots (green circles) into the diagram. Any idea how i can realize this?
Thanks for help.
try to add before fig.savefig("example.pdf") following line.
plt.tight_layout()
you have it in your script but it should come after text
It looks like you're trying to set the x and y labels for the whole figure, which isn't possible as these can only be set on an Axes object. Fortunately we can work around it by creating an 'invisible' subplot that fills the whole area and set the labels on this.
After plotting your subplots you would create the invisible one with:
label_ax = fig.add_subplot(111, frameon=False)
The frameon argument prevents it from drawing the box that is added by the default style. Then you tell it not to draw tick marks and make the tick labels invisible (we can't just remove them as it will mess up the spacing).
label_ax.tick_params(bottom=False, left=False, labelcolor="none")
Finally, set your labels:
label_ax.set_xlabel("CTF12")
label_ax.set_ylabel("CTF3")
You can adjust the vertical positioning of the plot titles by providing a pad argument to the set_title function. Giving a negative value will push the title into the plot, you'll need trial and error to find the value that works.
Putting it all together (with made-up data):
fig = plt.figure(figsize=(11.69, 8.27), dpi=100)
for i in range(10):
ax = fig.add_subplot(3, 4, i + 1)
ax.plot([1, 2, 3, 4, 5], "ro")
ax.set_title("Plot {}".format(i), pad=-15)
label_ax = fig.add_subplot(111, frameon=False)
label_ax.tick_params(bottom=False, left=False, labelcolor="none")
label_ax.grid(False) # In case the current style displays a grid.
label_ax.set_xlabel("CTF12")
label_ax.set_ylabel("CTF3")
fig.tight_layout()
fig.savefig("example.pdf")
Which gives:
I have the following plot:
dfA.plot.bar(stacked=True, color=[colorDict.get(x, '#333333') for x in
dfA.columns],figsize=(10,8))
plt.legend(loc='upper right', bbox_to_anchor=(1.4, 1))
Which displays this:
I want to remove all of the borders of the chart and legend i.e. the box around the chart (leaving the axis numbers like 2015 and 6000 etc)
All of the examples I find refer to spines and 'ax', however I have not built my chart using fig = plt.figure() etc.
Anyone know how to do it?
You can remove the border of the legend by using the argument frameon=False in the call to plt.legend().
If you only have one figure and axes active, then you can use plt.gca() to get the current axes. Alternatively df.plot.bar returns an axes object (which I would suggest using because plt.gca() might get confusing when working with multiple figures). Therefore you can set the visibility of the spines to False:
ax = dfA.plot.bar(stacked=True, color=[colorDict.get(x, '#333333') for x in
dfA.columns],figsize=(10,8))
plt.legend(loc='upper right', bbox_to_anchor=(1.4, 1), frameon=False)
for spine in ax.spines:
ax.spines[spine].set_visible(False)
# Color of the spines can also be set to none, suggested in the comments by ScoutEU
# ax.spines[spine].set_color("None")
Looking to add in vertical space between plotted graphs to allow a X-Axis label to show:
Each graph needs to have space to show the day, currently the last 2 graphs are the only one's that show simply because the graphs are overlapping it.
Also curious if I could actually remove the notch labels for the X-Axis for the graphs above the one's marked Thursday/Friday, i.e. the bottom X-axis is the only one that shows. Same for the Y-Axis, but only the graphs on the left having the scale shown.
*Unfortunately I can't post an image to show this since I don't have enough rep.
Code snippet:
import mathlib.pyplot as pyplot
fig = pyplot.figure()
ax1 = fig.add_subplot(4,2,1)
ax1.set_yscale('log')
ax2 = fig.add_subplot(4,2,2, sharex=ax1, sharey=ax1)
ax3 = fig.add_subplot(4,2,3, sharex=ax2, sharey=ax2)
ax4 = fig.add_subplot(4,2,4, sharex=ax3, sharey=ax3)
ax5 = fig.add_subplot(4,2,5, sharex=ax4, sharey=ax4)
ax6 = fig.add_subplot(4,2,6, sharex=ax5, sharey=ax5)
ax7 = fig.add_subplot(4,2,7, sharex=ax6, sharey=ax6)
ax1.plot(no_dict["Saturday"],'k.-',label='Saturday')
ax1.set_xlabel('Saturday')
ax1.axis([0,24,0,10000])
pyplot.suptitle('Title')
pyplot.xlabel('Hour in 24 Hour Format')
ax2.plot(no_dict["Sunday"],'b.-',label='Sunday')
ax2.set_xlabel('Sunday')
...
Use subplots_adjust. In your case this looks good:
fig.subplots_adjust(hspace=.5)
to remove the tick labels do this:
ax1.set_xticklabels([])
Similar for the yticklabels. However, you cannot share the x-axis with the plots that do have tick labels.
To change the spacing around a certain subplot, instead of all of them, you can adjust the position of the axes of that subplot using:
bbox=plt.gca().get_position()
offset=-.03
plt.gca().set_position([bbox.x0, bbox.y0 + offset, bbox.x1-bbox.x0, bbox.y1 - bbox.y0])
If offset < 0, the subplot is moved down. If offset > 0, the subplot is moved up.
Note that the subplot will disappear if offset is so big that the new position of the subplot overlaps with another subplot.