Skip to content
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

"Classical" zero-axis plot with arrows and symmetric ticks seems to be impossible #17157

Closed
m-oliver opened this issue Apr 16, 2020 · 3 comments · Fixed by #17180
Closed

"Classical" zero-axis plot with arrows and symmetric ticks seems to be impossible #17157

m-oliver opened this issue Apr 16, 2020 · 3 comments · Fixed by #17180
Labels

Comments

@m-oliver
Copy link

Bug report

Bug summary

I am trying to use matplotlib to produce classical "Mathematics-style" plots in production quality, with a cross of coordinate axes through the origin, arrow tips on the axes, and symmetic ("inout") ticks (in fact, since the entire plot is symmetric, there is no in or out, so asymmetric tick placement looks out of place).

Following axisartist-demo-axisline-style from the Matplotlib gallery, I am able to get the arrows, but it fails on the symmetric ticks. Using an alternative incantation which a student of mine came up with (I don't know where from), the symmetric ticks work, but we don't seem to be able to get arrow heads on the axes.

Both examples also differ in other placement decisions (why???), none is optimal, but all other things look fixable with some effort.

I am not sure whether this is a documentation bug or a code bug, but what bugs me is the apparent impossibility to meet the two requirements, arrow heads and symmetric ticks, at once.

Code for reproduction

#! /usr/bin/env python3

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.axes_grid.axislines import SubplotZero

plt.rcParams.update({'xtick.direction': "inout",
                     'ytick.direction': "inout"})

xx = np.linspace(-np.pi, np.pi, 200)

# from https://matplotlib.org/gallery/axisartist/demo_axisline_style.html#sphx-glr-gallery-axisartist-demo-axisline-style-py
fig = plt.figure()
ax = SubplotZero(fig, 111)
fig.add_subplot(ax)

for direction in ["xzero", "yzero"]:
    # adds arrows at the ends of each axis
    ax.axis[direction].set_axisline_style("-|>")
     
    # adds X and Y-axis from the origin
    ax.axis[direction].set_visible(True)

for direction in ["left", "right", "bottom", "top"]:
    # hides borders
    ax.axis[direction].set_visible(False)

ax.plot(xx, np.sin(xx))
plt.title("Arrow heads work, symmetric ticks don't")
plt.show()

fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)

ax.spines['left'].set_position('zero')
ax.spines['bottom'].set_position('zero')
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')

ax.plot(xx, np.sin(xx))
plt.title("Symmetric ticks work, but how to get arrow heads?")
plt.show()

Actual outcome
test1
test2

Expected outcome

The first plot should just produce symmetric ticks, as requested in the rcParams. For the second one, it might be missing documentation, I just don't know how to proceed. The differences between the two versions are very strange, and not documented in any obvious place.

Matplotlib version

  • Operating system: Fedora 30
  • Matplotlib version: python3-matplotlib-3.0.3-2.fc30.x86_64
  • Matplotlib backend (print(matplotlib.get_backend())): Qt5Agg
  • Python version: 3.7.6
  • Jupyter version (if applicable): N/A
  • Other libraries: N/A

Default Fedora 30 install.

@jklymak
Copy link
Member

jklymak commented Apr 16, 2020

This would more appropriately be discussed at http://discourse.matplotlib.org or stackoverflow. SubplotZero doesn't look at the rcParams, and is not really part of core Matplotlib.

@jklymak jklymak added the Community support Users in need of help. label Apr 16, 2020
@ImportanceOfBeingErnest
Copy link
Member

Indeed, mpl_toolkits.axisartist.axislines axes do not support "inout" ticks. They either need to be "in" or "out" (the reason being that one is just a 180° rotated version of the other). A very dirty hack would be to change the tick path, like

ax.axis["yzero"].major_ticks._tickvert_path = matplotlib.path.Path([[-1, 0.], [1., 0.]])

(Obviously that uses internal private attributes and is hence not an option for being documented.)


The other example comes from https://matplotlib.org/3.2.1/gallery/ticks_and_spines/spine_placement_demo.html and is hence part of core core matplotlib. It uses normal axes and those do not support arrows at the tips.
As a consequence some other hacks have emerged. Though, I might suggest to just use a marker for the arrows. (I will add this to the stackoverflow thread as well.)

import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(-np.pi, np.pi, 100)
y = 2 * np.sin(x)

rc = {"xtick.direction" : "inout", "ytick.direction" : "inout",
      "xtick.major.size" : 5, "ytick.major.size" : 5,}
with plt.rc_context(rc):
    fig, ax = plt.subplots()
    ax.plot(x, y)
    
    ax.spines['left'].set_position('zero')
    ax.spines['right'].set_visible(False)
    ax.spines['bottom'].set_position('zero')
    ax.spines['top'].set_visible(False)
    ax.xaxis.set_ticks_position('bottom')
    ax.yaxis.set_ticks_position('left')
    
    # make arrows
    ax.plot((1), (0), ls="", marker=">", ms=10, color="k",
            transform=ax.get_yaxis_transform(), clip_on=False)
    ax.plot((0), (1), ls="", marker="^", ms=10, color="k",
            transform=ax.get_xaxis_transform(), clip_on=False)
    
    plt.show()

image

I guess adding this (or any similar solution) to the docs would be a win. Because many people actually want such direction arrows on axes.

@m-oliver
Copy link
Author

Thank you very much for the detailed reply. This solution works great for all practical purposes. Indeed, it might be nice to add it to the gallery or otherwise to the documentation.

Ideally, it would make sense to develop a style sheet for this purpose. The available styles are very nice, but all seem targeted toward presenting data, not toward technical sketches, where the plot is usually reduced to the bare-bone qualitative features.

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