Matplotlib subplots size bigger than figure size - matplotlib

I discovered Matplotlib and I have a rendering problem. The 5 subplot I create step on each other, the xaxis labels and titles are behind the other plot.
Here is a part of the code I use :
fig, axs = plt.subplots(5,figsize=(8,25))
axs[0].plot(array_system_index, array_system_value, label="System", color="red", linewidth=1)
axs[0].set(xlabel="time", ylabel="Latency (µs)", yscale="log", title="System")
axs[0].axis([0, len(array_system_value), 1, 10000])
axs[1].plot(array_core0_index, array_core0_value, label="core 0", color="green", linewidth=1)
axs[1].set(xlabel="Time", ylabel="Latency (µs)", yscale="log", title="Core1")
axs[1].axis([0, len(array_core0_value), 1, 10000])
...
fig.tight_layout()
plt.show()
# fig.set_size_inches((15, 8), forward=False) # Break the png file
fig.savefig("my_graph.png", dpi=500)
Here is the result :
Graph
Do you know how can I increase the size of the figure itself ?
I tried to it after the subplot but it doesn't work and break the saved .png.

Related

Add xticks within margins

I am trying create two plots that should have the same width when displayed in a row-wise fashion. I have noticed that adding xticks followed by tight_layout makes the plot (pcolormesh) decrease in width from increasing the x-margins. I would like to move the ticks in such a way that the x-margins are eliminated and both pcolormesh have the same width.
I have the following example:
import numpy as np, matplotlib.pyplot as plt
def plot(ticks=True):
fig, ax = plt.subplots(figsize=(6,1))
np.random.seed(42)
a = np.random.randn(1,6)
ax.pcolormesh(a)
plt.gca().invert_yaxis()
ax.xaxis.tick_top()
ax.set(yticklabels=[])
ax.tick_params(left=False, length=5)
if ticks:
ax.set_xticks([0, 3, 6])
else:
plt.axis('off')
plt.tight_layout()
plt.savefig(f'plot-{ticks}.png', dpi=300, bbox_inches='tight', pad_inches=0.0)
I get the following plots when running with and without the ticks:
The x-margins are not the same, which is more noticeable when increasing the font-size. How do I move the 3 label to right and the 6 label to the left to make both images have the same x-margins (0 margin)?
EDIT
Using the suggestion from Align specific x labels differently to each other? we have
import numpy as np, matplotlib.pyplot as plt
plt.rcParams.update({'font.size': 17})
fig, ax = plt.subplots(figsize=(6,1))
np.random.seed(42)
a = np.random.randn(1,6)
ax.pcolormesh(a)
plt.gca().invert_yaxis()
ax.xaxis.tick_top()
ax.set(yticklabels=[])
ax.tick_params(left=False, length=5)
# get list of x tick objects
xtick_objects = ax.xaxis.get_major_ticks()
xtick_objects[0].label1.set_horizontalalignment('left') # left align first tick
xtick_objects[-1].label1.set_horizontalalignment('right') # right align last tick
ax.set_xticks([0, 3, 6])
plt.tight_layout()
# plt.savefig(f'plot.png', dpi=300, bbox_inches='tight', pad_inches=0.0
plt.show()
which does not seem to change the alignment.

No Plotting all values of X in xaxis and why there is the background grey?

I would like to get a plot with less data on xaxis. I have this very simple script. I put a 'range' for xaxis. Furthemore I would like that my background was white with contours black and not grey (see figure). How can I do?
import matplotlib.pyplot as plt
plt.figure()
# Increase the plot size and font size.
plt.rcParams["figure.figsize"] = (60,30)
plt.xticks(fontsize=40)
plt.yticks(fontsize=40)
plt.grid(True, color='gray', linestyle='dashed', linewidth=0.5, axis='y')
# Plot the learning curve.
plt.plot(df_stats['Training Loss'], color='b', marker='.', linestyle='solid', mec='b', markersize=24, markerfacecolor='white', label="Training", linewidth=7)
plt.plot(df_stats['Valid. Loss'], color='g', marker='.', linestyle='solid', mec='b', markersize=24, markerfacecolor='white',label="Validation", linewidth=7)
# Label the plot.
plt.title("Training & Validation Loss",fontsize=60)
plt.xlabel("Epoch", fontsize=52)
plt.ylabel("Loss", fontsize=52)
plt.legend(fontsize=50)
plt.xticks(list(range(1, 72)))
plt.show()
To set the X-axis ticks to a lower frequency, you will need to change the xticks to a lower frequency. One way to do this using numpy.arange().
Regarding the background color, the default is white. But, if for reason it is not, you can set it to white using the plot and axis facecolor() to white explicitly.
The code below is the updated version with these changes. Note that I used some dummy data to demonstrate the same.
Code
df_stats= pd.DataFrame(columns=['Training Loss', 'Valid. Loss'])
df_stats['Training Loss'] = list(range(1,72))
df_stats['Valid. Loss'] = df_stats['Training Loss'] * 2.1
import matplotlib.pyplot as plt
plt.figure()
# Background color of outer area
plt.figure(facecolor='white')
# Background color of the plot area
ax = plt.axes()
ax.set_facecolor("white")
# Increase the plot size and font size.
plt.rcParams["figure.figsize"] = (60,30)
plt.xticks(fontsize=40)
plt.yticks(fontsize=40)
plt.grid(True, color='gray', linestyle='dashed', linewidth=0.5, axis='y')
# Plot the learning curve.
plt.plot(df_stats['Training Loss'], color='b', marker='.', linestyle='solid', mec='b', markersize=24, markerfacecolor='white', label="Training", linewidth=7)
plt.plot(df_stats['Valid. Loss'], color='g', marker='.', linestyle='solid', mec='b', markersize=24, markerfacecolor='white',label="Validation", linewidth=7)
# Label the plot.
plt.title("Training & Validation Loss",fontsize=60)
plt.xlabel("Epoch", fontsize=52)
plt.ylabel("Loss", fontsize=52)
plt.legend(fontsize=50)
plt.xticks(list(np.arange(1, 72, 9)))
plt.show()
Output plot

How to access and remove all unwanted objects in a matplotlib figure manually?

I am trying to understand the underlying concepts of matplotlib, especially Axes and Figure. Therefore I am trying to plot two scatters and then remove any superfluous space (the red one below) by accessing different APIs & objects in the hierarchy.
Yet I fail to understand where the remaining red space is coming from. This is the code:
# Random data
df = pd.DataFrame(np.random.randint(0,100,size=(100, 2)), columns=list('AB'))
# Create a single Axes and preconfigure the figure with red facecolor.
# Then plot a scatter
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(10,5), facecolor='r')
ax1 = df.plot(kind='scatter', x='A', y='B', ax=axes[0])
ax2 = df.plot(kind='scatter', x='B', y='A', ax=axes[1])
# Remove except the scatter
for a in [ax1, ax2]:
a.set_xlabel(''), a.set_ylabel('') # Remove x and y labels
for loc in ['left', 'right', 'bottom', 'top']:
a.spines[loc].set_visible(False) # Remove spines
a.set_xticks([], []), a.set_yticks([], []) # Remove ticks
a.set_xmargin(0), a.set_ymargin(0) # No margin beyond outer values
# On figure-level we can make it more tight
fig.tight_layout()
It produces the following figure:
I saw that there is something like..
a.set_axis_off()
.. but this doesn't seem to be the right solution. Somewhere there seems to be some kind of padding that remains. It doesn't look like it's from some X/Y axis as it's the same for all four edges in both subplots.
Any help appreciated.
Solution
Two things are needed:
First we need to initialize the Figure with frameon=False:
fig, axes = plt.subplots(
// ...
frameon=False)
The space between the subplots can be removed using the subplot layout:
plt.subplots_adjust(wspace=.0, hspace=.0)
For the finest level of layout control, you can position your axes manually instead of relying on matplotlib to do it for you. There are a couple of ways of doing this.
One option is Axes.set_position
# Random data
df = pd.DataFrame(np.random.randint(0,100,size=(100, 2)), columns=list('AB'))
# Create a pair of Axes and preconfigure the figure with red facecolor.
# Then plot a scatter
fig, axes = plt.subplots(1, 2, figsize=(10, 5), facecolor='r')
df.plot(kind='scatter', x='A', y='B', ax=axes[0]).set_position([0, 0, 0.5, 1])
df.plot(kind='scatter', x='B', y='A', ax=axes[1]).set_position([0, 0.5, 0.5, 1])
You could also use the old-fashioned Figure.add_axes method:
# Random data
df = pd.DataFrame(np.random.randint(0,100,size=(100, 2)), columns=list('AB'))
# Create a pair of Axes and preconfigure the figure with red facecolor.
# Then plot a scatter
fig = plt.figure(figsize=(10, 5), facecolor='r')
df.plot(kind='scatter', x='A', y='B', ax=fig.add_axes([0, 0, 0.5, 1]))
df.plot(kind='scatter', x='B', y='A', ax=fig.add_axes([0, 0.5, 0.5, 1]))

how to remove the white space of invisiable axes in matplotlib during active plot?

I want to completely remove white space around my axes during active plot (not save_fig as others asked).
Here we cannot use bbox_inches='tight'. I can use tight_layout(pad=0).
When axis is on, it works fine, it shows all the ticks and x-y labels.
However, in some cases, I set the axis off. What I expected is to see the contents expand to fill up the empty space where the axes are. However, this does not work. It still keep the padding as there are still x-y labels and axes.
How can I remove the white space of invisible axes objects?
edit:
I am aware that I can use ax.set_yticks([]) and ax.set_xticks([]) to turn those off. But this is clumsy, I have to remember the the ticks before I clear them. And if I remove-then-add those ticks. The ticks cannot automatically update any more.
I wonder is there any more straightforward way to do this?
We can still see there is a small border spacing even after removing all ticks. If someone can come up a way to remove that too. It will be fantastic.
I would also like to keep the title if there is one. Thus the hard-coded ax.set_position([0,0,1,x]) is not very good for this usage. Surely we can still try to get the top spacing when there is a title, but if someone can provide a more direct/simple way to handle this, it will be preferred.
Example code:
def demo_tight_layout(w=10, h=6, axisoff=False, removeticks=False):
fig,ax = plt.subplots()
fig.set_facecolor((0.8, 0.8, 0.8))
rect = patches.Rectangle((-w/2, -h/2), w, h, color='#00ffff', alpha=0.5)
ax.add_patch(rect)
ax.plot([-w/2,w/2], [-h/2,h/2])
ax.plot([-w/2,w/2], [h/2,-h/2])
ax.set_ylabel("ylabel")
ax.margins(0)
_texts = []
if axisoff:
ax.set_axis_off()
_texts.append("axisoff")
if removeticks:
ax.set_xticks([])
ax.set_yticks([])
ax.set_ylabel("")
_texts.append("removeticks")
fig.text(0.5, 0.6, " ".join(_texts))
fig.tight_layout(pad=0)
plt.show()
return fig, ax, text
You may adjust the subplot parameters depending on whether you turned the axis off or not.
import matplotlib.pyplot as plt
from matplotlib import patches
def demo_tight_layout(w=10, h=6, axisoff=False):
fig,ax = plt.subplots()
fig.set_facecolor((0.8, 0.8, 0.8))
rect = patches.Rectangle((-w/2, -h/2), w, h, color='#00ffff', alpha=0.5)
ax.add_patch(rect)
ax.plot([-w/2,w/2], [-h/2,h/2])
ax.plot([-w/2,w/2], [h/2,-h/2])
ax.set_ylabel("ylabel")
ax.margins(0)
_texts = []
fig.tight_layout()
if axisoff:
ax.set_axis_off()
_texts.append("axisoff")
params = dict(bottom=0, left=0, right=1)
if ax.get_title() == "":
params.update(top=1)
fig.subplots_adjust(**params)
fig.text(0.5, 0.6, " ".join(_texts))
plt.show()
Now demo_tight_layout(axisoff=True) produces
and demo_tight_layout(axisoff=False) produces
You need to set the axes position to fill the figure. If you create your figure and plot with
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.gca()
ax.plot(some_x_data, some_y_data)
you need to add the following line to fill the figure with the axes:
ax.set_position([0, 0, 1, 1], which='both')
This sets the axes location relative to the figure size in the following way:
[left, bottom, width, height]
So to completely fill the figure use [0, 0, 1, 1] as shown above.
So taking your code, it should look like this (using fill_figure bool to check):
def demo_tight_layout(w=10, h=6, axisoff=False, removeticks=False, fill_figure=False):
fig,ax = plt.subplots()
fig.set_facecolor((0.8, 0.8, 0.8))
rect = patches.Rectangle((-w/2, -h/2), w, h, color='#00ffff', alpha=0.5)
ax.add_patch(rect)
ax.plot([-w/2,w/2], [-h/2,h/2])
ax.plot([-w/2,w/2], [h/2,-h/2])
ax.set_ylabel("ylabel")
ax.margins(0)
_texts = []
if axisoff:
ax.set_axis_off()
_texts.append("axisoff")
if removeticks:
ax.set_xticks([])
ax.set_yticks([])
ax.set_ylabel("")
_texts.append("removeticks")
fig.text(0.5, 0.6, " ".join(_texts))
fig.tight_layout(pad=0)
if fill_figure:
ax.set_position([0, 0, 1, 1], which='both')
plt.show()
return fig, ax, text
ax.set_position needs to be after fig.tight_layout.
If a figure title is needed, there is no direct way to do it. This unluckily can't be avoided. You need to adapt the height parameters manually so that the title fits in the figure, for example with:
ax.set_position([0, 0, 1, .9], which='both')

How to remove padding/border in a matplotlib subplot

The second subplot is just the first image with an overlay ploted. In the second plot there appears to have white padding/boarder. How do I remove this padding/whitespace?
For completness, here is the fragment of code that performs the plotting:
fig, ax = plt.subplots(1, 2)
fig.set_size_inches(16, 6, forward=True)
plt.subplots_adjust(0.05, 0.05, 0.95, 0.95, 0.05, 0.05)
ax[0].set_title("Region Labels")
ax[0].imshow(image_labels)
ax[1].set_title("Region Connectivity Graph")
ax[1].imshow(image_labels)
for edge in edges:
ax[1].plot([centers[edge[0]][0],centers[edge[1]][0]],
[centers[edge[0]][1],centers[edge[1]][1]])
for a in ax:
a.set_xticks(())
a.set_yticks(())
plt.show()
By default, Matplotlib adds some margin to plotted data. I cant test it because it dont have your image_labels and centers, but this should normally work:
ax[1].autoscale_view('tight')
An alternative would be to manually set the xlim and ylim of the axes:
ax[1].set_xlim(0,image_labels.shape[1])
ax[1].set_ylim(0,image_labels.shape[0])