2

Whenever I plot something in matplotlib, moving the mouse over the plot shows at the bottom the x and y position of the cursor. This is very convenient when exploring data.

Now, If I set the ticklabels to something else, the x position of the cursor at the bottom of the plot is empty, while the gui keeps track of the y position. Is there a way to keep getting the x position?

This is a simple example of this happening:

import numpy as np
fig, ax = plt.subplots()
x=np.linspace(0,np.pi)
y=np.sin(x)
ax.plot(x,y)
ax.set_xticks([0,np.pi/2,np.pi])
ax.set_xticklabels(['0','pi/2','pi'])
plt.show()
1
  • Interesting. As a side note, if you use ['0',r'$\pi/2$',r'$\pi$'] you can get the labels rendered as TeX. Commented Sep 26, 2012 at 16:47

2 Answers 2

3

No, there is no easy way to do this.

When you set the labels with a list of strings you set the xaxis.major_formatter to be FixedFormatter (doc) which has some peculiar behavior to make it work (it always returns '', unless you give it a third argument which given when it labels the x-axis, but not otherwise). The marking of where the cursor is is generated using the major_formatter and when you call a FixedFormatter it returns '', which is what is displayed.

If you really want this, you have to write your own call back, see Color values in imshow for matplotlib? for a starting point. (or subclass axes and re-implement format_coord (around line 2903 in axes.py in current matplotlib master branch)

Sign up to request clarification or add additional context in comments.

Comments

0

Well, x is not exactly always empty: it will display the label itself if you hover over an exact value corresponding to an assigned label, excluding the extremities. So in your case, hovering on the exact central vertical axis of the figure will yield pi/2:

plot with mouse exactly over the central vertical axis

Not very helpful, I know.

As indicated by tacaswell's answer, you could re-implement ax.format_coord(). It does not actually require you to subclass axes, it can be much simpler than that

In your case, you can simply override ax.fmt_xdata():

import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
x=np.linspace(0,np.pi)
y=np.sin(x)
ax.plot(x,y)
ax.set_xticks([0,np.pi/2,np.pi])
ax.set_xticklabels(['0','pi/2','pi'])
ax.fmt_xdata = lambda x: f"{x:.3f}"  # <-- the magic happens here
plt.show()

plot with mouse in arbitrary position, X shows properly

You can even go really fancy and format x in terms of pi:

import fractions
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
x=np.linspace(0, np.pi)
y=np.sin(x)
ax.plot(x,y)
ax.set_xticks([0,np.pi/2,np.pi])
ax.set_xticklabels(['0','pi/2','pi'])
def fmt_xdata(val):
    num, div = fractions.Fraction(val/np.pi).limit_denominator(100).as_integer_ratio()
    num_str = f"{str(num)[:-1] if abs(num) == 1 else num}\u03C0"  # 1pi => pi, -1pi => -pi
    div_str = "" if div == 1 else f"/{div}"  # pi/1 => pi
    return f" {val:.3f} = {val/np.pi:.3f}\u03C0 \u2248 {num_str if num else '0'}{div_str} "
ax.fmt_xdata = fmt_xdata
plt.show()

fancy representation of x when 2pi/3

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.