Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to plot axes with arrows in matplotlib

I want to achieve the following three things:

  • add arrows on x and y axes
  • show only the values that are used
  • add labels for coordinates

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:

enter image description here

And plot that I want to realize enter image description here

like image 328
Valerie Avatar asked Jan 30 '26 17:01

Valerie


1 Answers

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

enter image description here

like image 174
Cameron Riddell Avatar answered Feb 01 '26 07:02

Cameron Riddell