How to remove padding/border in a matplotlib subplot - matplotlib

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])

Related

How to make the plot's shape round?

I have created a plot, which is working just fine.
But I really want to change its shape to a circle.
This is my current plotting code:
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(5,5), dpi=300)
ax = fig.add_axes([0,0,1,1])
ax.plot(30, 80, marker="o", markersize=20, markeredgecolor="#ed6033", markerfacecolor="#ed6033")
ax.spines['left'].set_position('center')
ax.spines['bottom'].set_position('center')
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.yaxis.set_ticks_position('left')
ax.set_facecolor('#8cc9e2')
ax.margins(0.1)
plt.setp(ax.get_xticklabels()[4], visible=False)
plt.xlim(10, 90)
plt.ylim(10, 90)
plt.grid(color='white')
plt.show()
and this is the output I get:
eventually, this is my desired output:
You can clip the path of artists including the background patch using the path of another artist.
Add this snippet before the plt.show() call:
clip_path = plt.Circle(
(0.5, 0.5), 0.5, transform=ax.transAxes, # circle coordinates defined in axes fractions
fill=None, linewidth=0 # makes circle invisible
)
ax.add_patch(clip_path)
ax.patch.set_clip_path(clip_path)

Matplotlib subplots size bigger than figure size

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.

Pyplot: Circle class: What are the units of the axis arg?

What units does Pyplot use for the radius size of Circle class objects? Playing around with it, it seems that a radius of .6 is already almost off the screen... small example below
import matplotlib as plt
plt.use('TkAgg')
import matplotlib.pyplot as plt
circle = plt.Circle((0.5, 0.5), 0.6, color='white')
fig, ax = plt.subplots()
plt.subplot
plt.axis('off')
ax.add_artist(circle)
fig.set_facecolor("black")
Absolute units are used for the radius. The reason why 0.6 goes out of the axis is that by default, if you just plot a blank figure, its extent is from 0 to 1. For example
fig, ax = plt.subplots()
ax.set_aspect('equal')
results in
Now if you center your circle at (0.5, 0.5) and use radius of 0.6, it will go outside the axis and you will see a truncated patch as you see in your question.
Things become clear when you remove plt.axis('off') and use radius=0.5
circle = plt.Circle((0.5, 0.5), 0.5, color='blue')
fig, ax = plt.subplots(figsize=(3,3))
# plt.axis('off') <--- commented out
ax.add_artist(circle)
fig.set_facecolor("gray")
ax.set_aspect('equal')
plt.plot([0.5], [0.5], 'ro')

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')

Manipulation on vertical space in matplotlib subplots

I want to reduce the verticalspacing between subplot. Surfing along the web I just have found how to reduce the horizontal spacing, something like
import matplotlib.pyplot as plt
fig, axes = plt.subplots(nrows=4, ncols=4)
fig.tight_layout() # Or equivalently, "plt.tight_layout()"
fig.subplots_adjust(hspace=0.5)
plt.show()
The hspace thing is the one that manipulates such behaviour, but apparently there's no vspace.
EDIT:
This does not reduce the space between the y-axis, that is what I want to manipulate.
As you said in your question hspace reduces the vertical spacing between subplots. The equivalent for horizontal spacing between subplots is wspace. Below is an example:
x = np.linspace(0, 2 * np.pi, 400)
y = np.sin(x ** 2)
fig, ((ax1,ax2),(ax3,ax4)) = plt.subplots(nrows=2, ncols=2)
fig.tight_layout()
ax1.plot(x, y)
ax2.scatter(x, y)
ax3.scatter(x, y)
ax4.scatter(x, y)
fig.subplots_adjust(wspace=0.2)
plt.show()
Using a value for 1 for wspace gives
Using 0.2 as the value of wspace gives
An alternative approach is to pass the gridspec_kw argument a dict with keys wspace / hspace:
Example
fig, axes = plt.subplots(nrows=2, ncols=2, gridspec_kw={'hspace': 0.2, 'wspace': 0.9})
plt.tight_layout()
for ax, color in zip(axes.ravel(), list('rgbk')):
ax.scatter(np.arange(100), np.random.randn(100), color=color)
If I understood your question correctly, you want to reduce the vertical spacing, which is not what I have seen in all of the answers above.
If I am correct, you should reduce the hspace from 0.5 to 0.2, for instance. That's because hspace does not stand for horizontal spacing, it stands for height spacing, which is what you need.