Skip to content

[ENH]: Scale Invariant Arrow Styling #24272

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
suuuehgi opened this issue Oct 25, 2022 · 6 comments
Closed

[ENH]: Scale Invariant Arrow Styling #24272

suuuehgi opened this issue Oct 25, 2022 · 6 comments

Comments

@suuuehgi
Copy link

suuuehgi commented Oct 25, 2022

Problem

When using pyplot.arrow, the coordinates x, y, dx, dy are within the same coordinate system than the styling kwargs, resulting in different appearances, when used on multiple plots with different scales.

import matplotlib.pyplot as plt

fig, axs = plt.subplots(nrows=3, layout='constrained')

for ii, ax in enumerate(axs.flat):

    ax.set_xlim( [ ii/5, 1 - ii/5 ] )
    ax.set_ylim( [ .5 - (ii+1)/50, .5 + (ii+1)/50 ] )

    ax.arrow( 1 - ii/5, .5, 2 * ii/5 - 1, 0, length_includes_head=True, linewidth=0, width=.01 )

arrows

transform=ax.transAxes transforms both, placement and appearance, resulting in homogeneous appearance and hard to handle placement.

arrows2

Proposed solution

Having coordinates x, y, dx, dy in data coordinates and styling kwargs in axes coordinates.

(And length_includes_head=True as default cough)

@jklymak
Copy link
Member

jklymak commented Oct 25, 2022

I'm going to close this, as there are quite a few issues saying the same thing. We should boost it to the call this week, but I think the plan is to deprecate arrow: #20387

@jklymak jklymak closed this as not planned Won't fix, can't repro, duplicate, stale Oct 25, 2022
@suuuehgi
Copy link
Author

suuuehgi commented Oct 25, 2022

I'm going to close this, as there are quite a few issues saying the same thing.

Sorry, I haven't found them.

We should boost it to the call this week [...]

All right, thank you!

In the meantime, is there anything other than a manual / cumbersome transformation like ax.transAxes.inverted().transform(ax.transData.transform((x,y)))?


Edit: I mean

fig, axs = plt.subplots(nrows=3, layout='constrained')

# Coord. Data -> Axes
ta = lambda x, y, ax: ax.transAxes.inverted().transform(ax.transData.transform((x, y)))

for ii, ax in enumerate(axs.flat):
    
    ax.set_xlim( [ ii/5, 1 - ii/5 ] )
    ax.set_ylim( [ .5 - (ii+1)/50, .5 + (ii+1)/50 ] )
    
    dx, dy = ta( 1, 1, ax ) - ta( 0, 0, ax )
    ax.arrow( *ta( 1 - ii/5, .5, ax=ax ), dx * ( 2 * ii/5 - 1 ), 0, length_includes_head=True, linewidth=0, width=.05, head_length=.05, transform=ax.transAxes )

arrows2

@tacaswell
Copy link
Member

ax.annotate is probably the best option https://matplotlib.org/stable/tutorials/text/annotations.html#sphx-glr-tutorials-text-annotations-py when used with an empty string.

@suuuehgi
Copy link
Author

ax.annotate is probably the best option https://matplotlib.org/stable/tutorials/text/annotations.html#sphx-glr-tutorials-text-annotations-py when used with an empty string.

Nice! 🥳 I store it in my box of secret mpl knowledge next to the get_xticks-thing. 😋

import matplotlib.pyplot as plt

fig, axs = plt.subplots(nrows=3, layout='constrained')

for ii, ax in enumerate(axs.flat):

    ax.set_xlim( [ ii/5, 1 - ii/5 ] )
    ax.set_ylim( [ .5 - (ii + 1) / 50, .5 + (ii + 1) / 50 ] )

    ax.annotate( "", xytext=(1 - ii/5, .5), xy=(ii/5, .5), arrowprops={ 'width':2, 'linewidth':0 } )

arrow

@tacaswell
Copy link
Member

I store it in my box of secret mpl knowledge..

Where else can we put this to make it less secret!

@timhoffm
Copy link
Member

Should we put a note admonition in the arrow docstring? I mean it’s documented in the notes section, but that can be overlooked easily.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants