Reputation: 37
I want to achieve the following three things:
My code on this moment:
x = [9, 8, 11, 11, 14, 13, 16, 14, 14]
y = [9, 16, 15, 11, 10, 11, 10, 8, 8]
fig = plt.figure(figsize=(7,7), dpi=300)
axes = fig.add_axes([0,1,1,1])
axes.set_xlim(0, 17)
axes.set_ylim(0, 17)
axes.invert_yaxis()
axes.scatter(x, y, color='green')
axes.vlines(x, 0, y, linestyle="dashed", color='green')
axes.hlines(y, 0, x, linestyle="dashed", color='green')
axes.spines.right.set_visible(False)
axes.spines.bottom.set_visible(False)
plt.show()
Visually:
And plot that I want to realize
Upvotes: 3
Views: 2226
Reputation: 157
Came across this when looking for a way to make arrows on axes, but I wanted to control the aspect ratio of the arrows, which you can do using the above answers, slightly modified.
You define (a) an Affine2D
scale transform (mpl.transforms.Affine2D().scale(sx,sy)
) and (b) use a MarkerStyle
using that transform (mpl.markers.MarkerStyle()
) . This transform is independent of the coordinate transform that uses axes coordinates (e.g. ax.get_xaxis_transform()
). Do this once for each axis. See this page for example.
Example with 2:1 length:width arrowheads:
# Arrows on axes
# We'll stretch out the triangular markers
stretchxax = mpl.transforms.Affine2D().scale(sx=2.,sy=1.)
stretchyax = mpl.transforms.Affine2D().scale(sx=1.,sy=2.)
ax.plot(1,0,'k',marker=mpl.markers.MarkerStyle('>',transform=stretchxax),transform=ax.get_yaxis_transform(),clip_on=False)
ax.plot(0,1,'k',marker=mpl.markers.MarkerStyle('^',transform=stretchyax),transform=ax.get_xaxis_transform(),clip_on=False)
Upvotes: 0
Reputation: 13447
You can draw arrows by overlaying triangle shaped points over the ends of your spines.
You'll need to leverage some transforms
, but you can also create your labels by manually adding text to your Axes
objects as well.
Labelling each coordinate can be done via axes.annotate, but you'll need to manually specify the location of each annotation to ensure they don't overlap with lines or other annotations.
import matplotlib.pyplot as plt
from matplotlib.ticker import FixedLocator
x = [9, 8, 11, 11, 14, 13, 16, 14, 14]
y = [9, 16, 15, 11, 10, 11, 10, 8, 8]
fig = plt.figure(figsize=(7,7), dpi=300)
axes = fig.add_axes([.05,.05,.9,.9])
# Plots the data
axes.scatter(x, y, color='green')
axes.vlines(x, 0, y, linestyle="dashed", color='green')
axes.hlines(y, 0, x, linestyle="dashed", color='green')
axes.set_xlim(0, 17)
axes.set_ylim(0, 17)
axes.set_xticks(x)
axes.set_yticks(y)
axes.invert_yaxis()
# Move ticks to top side of plot
axes.xaxis.set_tick_params(
length=0, bottom=False, labelbottom=False, top=True, labeltop=True
)
axes.xaxis.set_tick_params(length=0)
# Add arrows to the spines by drawing triangle shaped points over them
axes.plot(1, 1, '>k', transform=axes.transAxes, clip_on=False)
axes.plot(0, 0, 'vk', transform=axes.transAxes, clip_on=False)
axes.spines[['bottom', 'right']].set_visible(False)
# Add labels for 0, F_1 and F_2
from matplotlib.transforms import offset_copy
axes.text(
0, 1, s='0', fontstyle='italic', ha='right', va='bottom',
transform=offset_copy(axes.transAxes, x=-5, y=5, fig=fig, units='points'),
)
axes.text(
1, 1, s='$F_1$', fontstyle='italic', ha='right', va='bottom',
transform=offset_copy(axes.transAxes, x=0, y=5, fig=fig, units='points'),
)
axes.text(
0, 0, s='$F_2$', fontstyle='italic', ha='right',
transform=offset_copy(axes.transAxes, x=-5, y=0, fig=fig, units='points'),
)
# Add labels at each point. Leveraging the alignment of the text
# AND padded offset.
lc = ('top', 'center', 0, -5)
ll = ('top', 'right', -5, -5)
lr = ('top', 'left', 5, -5)
ur = ('bottom', 'left', 5, 5)
alignments = [lc, lc, lc, ll, lc, ll, lc, ur, lr]
for i, (xc, yc, (va, ha, padx, pady)) in enumerate(zip(x, y, alignments)):
axes.annotate(
xy=(xc, yc), xytext=(padx, pady),
text=f'$F(x_{i})$', ha=ha, va=va, textcoords='offset points')
plt.show()
Upvotes: 3
Reputation: 3967
Adding
axes.plot(1, 0, ">k", transform=axes.get_yaxis_transform(), clip_on=False)
axes.plot(0, 0, "vk", transform=axes.get_xaxis_transform(), clip_on=False)
Will do it for you. This is basically just a cheat plot of markers.
There are also
from mpl_toolkits.axisartist.axislines.AxesZero
which allow
for direction in ["xzero", "yzero"]:
# adds arrows at the ends of each axis
ax.axis[direction].set_axisline_style("-|>")
but they can't handle the reversed y axis in your case with default settings.
Upvotes: 1