The violin plots I am making with Matplotlib have one of the plot intersecting with ytick label. See the picture below:
The code I am using as follow:
alp = 1
fig, axes = plt.subplots(nrows=10, ncols=1, figsize=(8, 6), dpi=100)#, sharex=True)
for i,t in enumerate(top_features):
# print(i)
alp = alp - 0.08
parts = axes[i].violinplot(data[i], vert=False, widths=0.9,
showmeans=True, showextrema=True, showmedians=False,
bw_method='scott')#, points=200)
for pc in parts['bodies']:
pc.set_facecolor('#D43F3A')
pc.set_edgecolor('black')
pc.set_alpha(alp)
axes[i].set_ylabel('{:.3f}'.format(top_features[i]), rotation=0)
# axes[i].axis('off')
axes[i].set_xlim(-0.0010, 0.0030)
axes[i].spines['top'].set_visible(False)
axes[i].spines['right'].set_visible(False)
axes[i].spines['bottom'].set_visible(False)
axes[i].spines['left'].set_visible(False)
for i, ax in enumerate(axes):
if i !=9:
ax.set_xticks([])
ax.set_yticks([])
fig.tight_layout()
fig.subplots_adjust(left=0.01,right= 1.1, hspace=0.14, wspace=0.3)
ax.set_yticklabels(top_features)
How can move the figure to the right with the shared X-axis ticks and all the other violinplots?
That moment when you find an answer to your own question! -_-
axes[i].set_ylabel('{:.3f}'.format(top_features[i]), rotation=0, labelpad=30)
Adjusting the labelpad value solves!
Thanks all!
Related
I try to understand how different coordinate systems work in matplotlib. My understanding is that if I add some texts using data coordinates, then I can achieve the same effect if I first transform the data coordinates to the display coordinates and then add the text using these display coordinates. In the following snippet, I expect the 'x' in green are right on top of the 'x' in red. But they are not. What do I miss here? Thank you!
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.set_xlim(0, 10)
ax.set_ylim(-1, 1)
ax.grid()
ax.text(4,0,'x', horizontalalignment='center', verticalalignment='center', color='r')
_x2, _y2 = ax.transData.transform((4.0, 0))
ax.text(_x2,_y2,'x', horizontalalignment='center', verticalalignment='center', transform=None, color='g')
Result:
Once again, we have examined the FIGURE, DATA, and AXIS criteria. We have modified them for clarity from the data range in question. The same is obtained with the figure criterion, divided by the graph size in inches and dpi value. The position of the origin of the axis is also obtained with the figure reference, and when drawn, it overlaps with the origin of the graph. The origin of the graph is shown in black.
import matplotlib.pyplot as plt
fig_x, fig_y = plt.rcParams['figure.figsize']
dpi = plt.rcParams['figure.dpi']
print(fig_x, fig_y, dpi)
fig, ax = plt.subplots()
ax.set_xlim(-1, 1)
ax.set_ylim(-1, 1)
ax.grid()
g = ax.text(0,0,'o', horizontalalignment='center', verticalalignment='center', color='r')
print('get_position', g.get_position())
_x2, _y2 = ax.transData.transform((0.0, 0))
print('ax.transData', _x2, _y2)
_x3, _y3 = ax.transAxes.transform((0.0, 0))
print('ax.transAxes', _x3, _y3)
# From Figure position to ax.transData
ax.text(_x2/fig_x/dpi,_y2/fig_y/dpi,'x', horizontalalignment='center', verticalalignment='center', color='g', transform=fig.transFigure)
# From Figure position to ax.transAxes
ax.text(_x3/fig_x/dpi,_y3/fig_y/dpi,'x', horizontalalignment='center', verticalalignment='center', color='b', transform=fig.transFigure)
# Figure x0, y0
ax.text(0,0,'x', horizontalalignment='center', verticalalignment='center', color='k', transform=fig.transFigure)
plt.show()
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]))
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')
The following code is for generating the 3 subplots. And on all the 3 subplots scale is mentioned. I want to stack them in such a way that x-axis and y-axis scale appear once like this. Can I get this plot with plt.subplot() or fig.add_axes is compulsory for this? I actually want to do this with subplots because in fig.add_subplot I havve to specify the width and height of each plot that I don't want.
`fig,axes = plt.figure(nrow=3, ncolmn=1)
ax1 = fig.add_subplot(311)
ax2 = fig.add_subplot(312)
ax3 = fig.add_subplot(313)
ind1 =[1,2,3]
ind2 = [4,5,6]
for i in range(len(3)):
data1=np.load(..)
data2=np.load(..)
axes[i].plot(data1, data2)`
Here is one solution using subplots_adjust where you put the space between two plots to 0 using hspace. Also, use sharex=True to have a shared x-axis
fig, axes = plt.subplots(nrows=3, ncols=1,sharex=True)
x = np.linspace(0, 2*np.pi, 100)
y = np.sin(x)
for i, ax in enumerate(axes.ravel()): # or axes.flatten() or axes.flat
ax.plot(x, y, label='File %d' %i)
ax.legend()
fig.text(0.5, 0.01, 'X-label', ha='center')
fig.text(0.01, 0.5, 'Y-label', va='center', rotation='vertical')
plt.tight_layout() # To get a better spacing between the subplots
plt.subplots_adjust(hspace=.0)
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.