3

I'm working on a function that would make it easy for me to add parasite axes wherever I want on a plot, but I have encountered a weird situation. Take a look at the following code:

import matplotlib.pyplot as plt

plt.plot()
plt.gca().set_position([1/3, 1/3, 1/3, 1/3])
plt.gca().twinx()

plt.show()

The above code produces the following figure: enter image description here

As you can see, the twinx plot is generated using the old positions of the host plot. I would have expected the twinx plot to be generated on the new positions of the host plot.

How can I draw a twinx plot on the new positions of the host plot? (I know drawing the twinx plot beforehand "solves" this but it's not a practical solution)

Thanks for your help!

Amine Kchouk
  • 162
  • 1
  • 11
  • Maybe I'm misunderstanding your question. What you mean by new position ? A new position within the old plot? or outside the plot ? If it is the first one, changing the first two elements in [1/3, 1/3, 1/3, 1/3] should work, I guess. When you do `print(plt.gca().get_position())` before and after altering the position, it does change. – AshlinJP Jul 01 '20 at 02:02
  • 2
    @AshlinJP The "new position" is the [1/3,1/3,1/3,1/3], aka the small rectangle in the middle. I changed the position of the host plot first, and I would have expected the twinx plot to use the "new position" of the host plot. The figure shows that twinx doesn't care of the position of the host plot, it just uses the "old position", aka the big rectangle. – Amine Kchouk Jul 01 '20 at 02:26
  • I see. This is interesting. This might be worth looking at https://github.com/matplotlib/matplotlib/issues/7376#issuecomment-257898748 – AshlinJP Jul 01 '20 at 02:49
  • 1
    @tacaswell. Is this something that should be filed as a bug? – Mad Physicist Jul 01 '20 at 02:51
  • 1
    @AshlinJP. I filed that issue many moons ago, but I don't think it's directly related to this problem. My issue was just with formatters and locators. I think this is something different entirely. – Mad Physicist Jul 01 '20 at 02:59
  • @MadPhysicist True. For some reason, I thought position was similar to locator. Glad that you arrived here quickly! – AshlinJP Jul 01 '20 at 03:12
  • 1
    For what it's worth, I have just filed a bug report on this particular issue. https://github.com/matplotlib/matplotlib/issues/21409 – BBeast Oct 21 '21 at 02:08

2 Answers2

2

I figured out a way to go around the problem by trial and error. However, it should be noted that I have no idea how twinx works and I am very beginner in terms of matplotlib, so I would definitely not be able to understand any of what is happening.

What I did to solve this is I used plt.gcf().subplots_adjust() before creating the twinx. However, doing this effectively trashes the new positions, so I saved them beforehand to be able to reapply them after creating the twinx. The code becomes:

import matplotlib.pyplot as plt

plt.plot()
plt.gca().set_position([1/3, 1/3, 1/3, 1/3])
pos = plt.gca().get_position()     #added line
plt.gcf().subplots_adjust()        #added line
plt.gca().twinx()
plt.gca().set_position(pos)        #added line

plt.show()

I'm still open to reading some better answers than mine, however, so feel free to give your propositions!

NOTE: The code above seems pretty dumb (I'm setting the position just to reset it and then reapply it later), but in my actual application, the first set_position would have been executed by an earlier function call, and a later function call needs to add the twinx, so this does have a use case.

Amine Kchouk
  • 162
  • 1
  • 11
0

You can set the position of the axes after calling twinx, using the position data from the initial setting prior to twinx.

There are several ways to do it.

import matplotlib.pyplot as plt

# Create original plot
plt.plot()
ax = plt.gca()
ax.set_position([1/3,1/3,1/3,1/3])
# Make twin axes.
ax2 = ax.twinx()
ax2.set_position(ax.get_position())

plt.show()

Alternatively, you can do ax.set_position(ax.get_position()). But a key point is recording the original Axes to a variable because gca points to the new Axes (which have the wrong position) once you call twinx.

If you don't want to store the Axes in a variable, you can store the axes position in a variable.

import matplotlib.pyplot as plt

# Create original plot
plt.plot()
plt.gca().set_position([1/3, 1/3, 1/3, 1/3])
# Make twin axes
pos = plt.gca().get_position()
plt.gca().twinx()
plt.gca().set_position(pos)

plt.show()

It is not necessary to throw out the positions set previously.

BBeast
  • 101
  • 2