double tick labels (bottom and top, but with different labels)

Hello,

I'd like to know if it's possible to get a sort of double tick labeling
(e.g. bottom and top), but with different labels. One way to think of my
use case is that there are two different units for the x data (or more
precisely in my case, I've two different x quantities which are bound by
a linear relationship).

The result I'd like is the right part of the attached image (it's a
Gimp-edited mockup composition of the two actual plots on the left).

I've tried to play with the double labeling of a single axe. Indeed, the
following two calls put the double labeling

    ax1.xaxis.set_ticks_position('both')
    ax1.xaxis.set_tick_params(labeltop=True)

However, when I want to alter only the top labels using

    for tick, l in zip(ax1.xaxis.get_major_ticks(), l2):
    ??? tick.set_label2(l)

I get no visible change on the plot. (full script attached). Did I need
to call some update ?

Did I miss something with the proper way to call Tick.set_label2?

Looking at the source code of ax1.xaxis.set_ticklabels, there is
something I don't get. First it sets a FixedFormatter(ticklabels), and
then it sets label1 and/or label2 for each Tick object. So in the end,
where is the text coming from?

Also, to complement the second series of tick labels, I'd like a second
axis label as well. However, I only know
ax.xaxis.set_label_position('top') to move xlabel to the top, not to get
a 2nd one...

As an alternative approach, I see twinx. I didn't try it yet, because I
feel like my objective is not of the objective of twinx (e.g. I'm
plotting only a single dataset, not two). However, I suspect it's
possible to 'bend" twinx to get what I want. What do you think.

Thank you in advance for your ideas.

Best,

Pierre

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/matplotlib-users/attachments/20180425/4ff5cfd7/attachment-0001.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: double_labels_mockup.png
Type: image/png
Size: 69026 bytes
Desc: not available
URL: <http://mail.python.org/pipermail/matplotlib-users/attachments/20180425/4ff5cfd7/attachment-0001.png>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: DoubleTicksTest.py
Type: text/x-python
Size: 1211 bytes
Desc: not available
URL: <http://mail.python.org/pipermail/matplotlib-users/attachments/20180425/4ff5cfd7/attachment-0001.py>

Hi Pierre,

I am not sure that label2 can be used for what you want to do. See for
example: What is the use of Tick.set_label2 and can we make it useful? · Issue #8181 · matplotlib/matplotlib · GitHub . If it
can, I would be eager to know too :)! But I have currently little hopes
that there is an easy *dedicated* method available right now, as Jody K.
recently opened an issue on the GitHub tracker, about a very similar
problem: ENH: secondary axis for a x or y scale. · Issue #10976 · matplotlib/matplotlib · GitHub

At least, as a workaround, a twinned axis allows to get things
reasonably working without too much hassle (I think). Here is an example
that uses uses `FuncFormatter` and seems to be OK, even when
interactively playing with it.

import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter, MultipleLocator

fig, ax = plt.subplots(num="example_pierre", clear=True)

# A dummy plot
xx, yy = [10, 20, 30], [1, 4, 9]
ax.plot(xx, yy)
ax.set_ylabel("An y-label")
ax.set_xlabel("Quantity $x$")
ax.xaxis.set_major_locator(MultipleLocator(10))

# Secondary labelling with twiny
k = 5
ax1 = ax.twiny()
ax1.plot(xx, yy, ls="", color="none")  # dummy trace
ax1.xaxis.set_major_locator(ax.xaxis.get_major_locator())
ax1.xaxis.set_major_formatter(FuncFormatter(lambda x, pos: f"{k*x:g}"))
ax1.set_xlabel(f"{k} times quantity $x$")

fig.show()
fig.savefig(fig.get_label() + ".pdf")

Hopefully this helps a bit.

Best
Adrien

PS: If there are better solution to share the ticker and the view
limits, I am interesting to know about it :).

Le 25/04/2018 ? 05:34, Pierre Haessig a ?crit?:

Hello,

I'd like to know if it's possible to get a sort of double tick labeling
(e.g. bottom and top), but with different labels. One way to think of my
use case is that there are two different units for the x data (or more
precisely in my case, I've two different x quantities which are bound by
a linear relationship).

The result I'd like is the right part of the attached image (it's a
Gimp-edited mockup composition of the two actual plots on the left).

I've tried to play with the double labeling of a single axe. Indeed, the
following two calls put the double labeling

    ax1.xaxis.set_ticks_position('both')
    ax1.xaxis.set_tick_params(labeltop=True)

However, when I want to alter only the top labels using

    for tick, l in zip(ax1.xaxis.get_major_ticks(), l2):
    ??? tick.set_label2(l)

I get no visible change on the plot. (full script attached). Did I need
to call some update ?

Did I miss something with the proper way to call Tick.set_label2?

Looking at the source code of ax1.xaxis.set_ticklabels, there is
something I don't get. First it sets a FixedFormatter(ticklabels), and
then it sets label1 and/or label2 for each Tick object. So in the end,
where is the text coming from?

Also, to complement the second series of tick labels, I'd like a second
axis label as well. However, I only know
ax.xaxis.set_label_position('top') to move xlabel to the top, not to get
a 2nd one...

As an alternative approach, I see twinx. I didn't try it yet, because I
feel like my objective is not of the objective of twinx (e.g. I'm
plotting only a single dataset, not two). However, I suspect it's
possible to 'bend" twinx to get what I want. What do you think.

Thank you in advance for your ideas.

Best,

Pierre

_______________________________________________
Matplotlib-users mailing list
Matplotlib-users at python.org
Matplotlib-users Info Page

-------------- next part --------------
A non-text attachment was scrubbed...
Name: example_pierre.pdf
Type: application/pdf
Size: 13461 bytes
Desc: not available
URL: <http://mail.python.org/pipermail/matplotlib-users/attachments/20180425/1963774e/attachment-0001.pdf&gt;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: example_pierre.py
Type: text/x-python
Size: 679 bytes
Desc: not available
URL: <http://mail.python.org/pipermail/matplotlib-users/attachments/20180425/1963774e/attachment-0001.py&gt;

Yes, this is the goal and will be implimented for 3.0 if the approach is accepted. See also ENH: Allow axes to have child axes. · Issue #11005 · matplotlib/matplotlib · GitHub Comments very welcome. But for now Adrien?s workaround is the best we have.

Cheers, Jody

···

On 25 Apr 2018, at 08:52, vincent.adrien at gmail.com wrote:

Hi Pierre,

I am not sure that label2 can be used for what you want to do. See for
example: What is the use of Tick.set_label2 and can we make it useful? · Issue #8181 · matplotlib/matplotlib · GitHub . If it
can, I would be eager to know too :)! But I have currently little hopes
that there is an easy *dedicated* method available right now, as Jody K.
recently opened an issue on the GitHub tracker, about a very similar
problem: ENH: secondary axis for a x or y scale. · Issue #10976 · matplotlib/matplotlib · GitHub

At least, as a workaround, a twinned axis allows to get things
reasonably working without too much hassle (I think). Here is an example
that uses uses `FuncFormatter` and seems to be OK, even when
interactively playing with it.

import matplotlib.pyplot as plt
from matplotlib.ticker import FuncFormatter, MultipleLocator

fig, ax = plt.subplots(num="example_pierre", clear=True)

# A dummy plot
xx, yy = [10, 20, 30], [1, 4, 9]
ax.plot(xx, yy)
ax.set_ylabel("An y-label")
ax.set_xlabel("Quantity $x$")
ax.xaxis.set_major_locator(MultipleLocator(10))

# Secondary labelling with twiny
k = 5
ax1 = ax.twiny()
ax1.plot(xx, yy, ls="", color="none")  # dummy trace
ax1.xaxis.set_major_locator(ax.xaxis.get_major_locator())
ax1.xaxis.set_major_formatter(FuncFormatter(lambda x, pos: f"{k*x:g}"))
ax1.set_xlabel(f"{k} times quantity $x$")

fig.show()
fig.savefig(fig.get_label() + ".pdf")

Hopefully this helps a bit.

Best
Adrien

PS: If there are better solution to share the ticker and the view
limits, I am interesting to know about it :).

Le 25/04/2018 ? 05:34, Pierre Haessig a ?crit :

Hello,

I'd like to know if it's possible to get a sort of double tick labeling
(e.g. bottom and top), but with different labels. One way to think of my
use case is that there are two different units for the x data (or more
precisely in my case, I've two different x quantities which are bound by
a linear relationship).

The result I'd like is the right part of the attached image (it's a
Gimp-edited mockup composition of the two actual plots on the left).

I've tried to play with the double labeling of a single axe. Indeed, the
following two calls put the double labeling

   ax1.xaxis.set_ticks_position('both')
   ax1.xaxis.set_tick_params(labeltop=True)

However, when I want to alter only the top labels using

   for tick, l in zip(ax1.xaxis.get_major_ticks(), l2):
       tick.set_label2(l)

I get no visible change on the plot. (full script attached). Did I need
to call some update ?

Did I miss something with the proper way to call Tick.set_label2?

Looking at the source code of ax1.xaxis.set_ticklabels, there is
something I don't get. First it sets a FixedFormatter(ticklabels), and
then it sets label1 and/or label2 for each Tick object. So in the end,
where is the text coming from?

Also, to complement the second series of tick labels, I'd like a second
axis label as well. However, I only know
ax.xaxis.set_label_position('top') to move xlabel to the top, not to get
a 2nd one...

As an alternative approach, I see twinx. I didn't try it yet, because I
feel like my objective is not of the objective of twinx (e.g. I'm
plotting only a single dataset, not two). However, I suspect it's
possible to 'bend" twinx to get what I want. What do you think.

Thank you in advance for your ideas.

Best,

Pierre

_______________________________________________
Matplotlib-users mailing list
Matplotlib-users at python.org
Matplotlib-users Info Page

<example_pierre.pdf><example_pierre.py>_______________________________________________
Matplotlib-users mailing list
Matplotlib-users at python.org
Matplotlib-users Info Page

--
Jody Klymak

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/matplotlib-users/attachments/20180425/68188a55/attachment.html&gt;

Thanks for all your feedback. Interesting to see that there are indeed
issues and PR on this topic.

Looking at issue https://github.com/matplotlib/matplotlib/issues/10976,
it's makes no relation to the label2
https://github.com/matplotlib/matplotlib/issues/8181. Seems more like a
"smart twinx", because the ENH propose that the ticks are not
necessarily at the same position.

In my case, since I can use the same xtick positions, I think in the end
I can get away with just using one FuncFormatter which shows the two
numbers. Using Adrien's suggestion, I need to try something like
FuncFormatter(lambda x, pos: f"{x} -- {a*x+b}")).

Best,

Pierre

Hi Pierre,

Related to your last idea, maybe you'll find useful the following formatter:

FuncFormatter(lambda x, pos: f"{x:g}\n{a*x + b:g}")

as one can multiline strings as tick labels, to get something as shown
in the attached PDF (the whole script is provided as well). I guess that
one can even do fancier stuff by leveraging the [string formatting
Python
language](string — Common string operations — Python 3.12.0 documentation).

If you find a better way to achieve what you want, please note that
there would be at least one person glad to read about ;).

Best,
Adrien

Thanks for all your feedback. Interesting to see that there are indeed
issues and PR on this topic.

Looking at issue ENH: secondary axis for a x or y scale. · Issue #10976 · matplotlib/matplotlib · GitHub,
it's makes no relation to the label2
What is the use of Tick.set_label2 and can we make it useful? · Issue #8181 · matplotlib/matplotlib · GitHub. Seems more like a
"smart twinx", because the ENH propose that the ticks are not
necessarily at the same position.

In my case, since I can use the same xtick positions, I think in the end
I can get away with just using one FuncFormatter which shows the two
numbers. Using Adrien's suggestion, I need to try something like
FuncFormatter(lambda x, pos: f"{x} -- {a*x+b}")).

Best,

Pierre

_______________________________________________
Matplotlib-users mailing list
Matplotlib-users at python.org
Matplotlib-users Info Page

-------------- next part --------------
A non-text attachment was scrubbed...
Name: example_bis_pierre.py
Type: text/x-python
Size: 548 bytes
Desc: not available
URL: <http://mail.python.org/pipermail/matplotlib-users/attachments/20180426/dcdb2d4e/attachment-0001.py&gt;
-------------- next part --------------
A non-text attachment was scrubbed...
Name: example_bis_pierre.pdf
Type: application/pdf
Size: 151419 bytes
Desc: not available
URL: <http://mail.python.org/pipermail/matplotlib-users/attachments/20180426/dcdb2d4e/attachment-0001.pdf&gt;

···

On 04/26/2018 08:03 AM, Pierre Haessig wrote: