I'm trying to plot two data sets that differ by some orders of magnitude. After some research (it was literally one google search away) I found out about the twinx() function.
However, I've run into some trouble when using it. I'm producing publication-grade figures with this tool, and there is something that is bugging me.
System: matplotlib v1.3.1, python v2.7.4 on Ubuntu
Consider the following code:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.ticker import MaxNLocator
from matplotlib.ticker import AutoMinorLocator
time = np.arange(0, 365, 1)
y1 = np.random.rand(len(time)) * np.exp(-0.03 * time)
y2 = 0.001 * np.random.rand(len(time)) * np.exp(-0.02 * time)
for i in range(30):
y2[-i] = 0
fig = plt.figure(figsize=(8,6), dpi=300)
fig.subplots_adjust(hspace=0.0, right=0.9, top=0.94, left=0.12, bottom=0.07)
ax1 = fig.add_subplot(111)
ax2 = ax1.twinx()
for tl in ax1.get_yticklabels():
tl.set_color('r')
for tl in ax2.get_yticklabels():
tl.set_color('b')
for ax in [ax1, ax2]:
ax.yaxis.set_major_locator(MaxNLocator(
nbins=5,
steps=[1,2,3,4,5,10],
integer=False,
symmetric=False,
prune=None))
ax.yaxis.set_minor_locator(AutoMinorLocator(4))
ax2.plot(time, y1, 'b-')
ax1.plot(time, y2, 'r-')
ax1.set_ylabel(r"y value", labelpad=15)
ax1.set_xlabel(r"x value")
ax1.set_xlim(0,365)
ax1.set_xticks(range(0,370,30))
ax1.xaxis.set_minor_locator(AutoMinorLocator(3))
fig.savefig("Errorplot.png", dpi=60)
Now, when looking at this low resolution output, I see nothing weird:

However, when zooming in on a high-resolution (say, dpi=300) version, I see the following:

It is obvious that the lines in the second axes are drawn over the spine of the first.
How do I alleviate this problem? Is there a way to redraw the spines of an axes instance?
plot() callszorder kwarg to -1, -10. Even when the ax2 zorder was smaller than the ax1, I had this behaviour.ax2.spines['bottom'].set_zorder(10)It does not seem this post gets many views but I found it helpful and would like to add another way to change the zorder on the off chance it will help someone else. This post more closely matched what I wanted to do but the important thing is changing the zorder, which @Ffisegydd's outlined. Another way to do this is using the following:
fig, ax1 = plt.subplots()
ax2 = ax1.twinx()
ax1.set_zorder(ax2.get_zorder()+1) # put ax1 in front of ax2
ax1.patch.set_visible(False) # hide the 'canvas'
ax1.plot(data1[:,0], data1[:,0]) # plot whatever data you want
ax2.plot(data2[:,0], data2[:,0]) # plot commands can precede the set_zorder command
I realize this does not directly solve the asked question but hopefully it can help someone who, like me, finds this post searching for a solution to a closely related issue.
You can use the zorder kwarg in matplotlib to change the order that objects are drawn, see an example code here
Below I have added two examples (I have cut out the majority of your code to save space). In one example I set the zorder to a larger value, meaning that it will be drawn last (and hence on top). In the other example I set zorder to -1 meaning that it will be drawn first (and hence below).
ax2.plot(time, y1, 'b-', zorder=5)
ax1.plot(time, y2, 'r-', zorder=5)

ax2.plot(time, y1, 'b-', zorder=-1)
ax1.plot(time, y2, 'r-', zorder=-1)

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With