Search code examples
pythonmatplotlibtkinterz-order

Matplotlib: twinx plot hidden behind main axis background


I'm struggling to show a twinx axis plot along with a main axis plot. Here is what I am doing:

  1. I create the main axis and the twinx axis.
  2. I set the zorder of the main axis to a higher value than that of the twin axis, because I want the event handler to pick the events for the main axis (i.e, track the Y axis in the toolbar)
  3. Then, I plot both figures and the patch located at the twin axis is hidden behind the main axis' background. (I know this because I am able to see the twinx axis plot if I uncomment a.patch.set_visible(False) line)

However, I would like to keep both the ability to track Y axis of the main track and also the background since they have different scales. Here you have a minimal example:


import matplotlib
matplotlib.use('TkAgg')
import numpy as np
from numpy import arange, sin, pi
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure

import sys
if sys.version_info[0] < 3:
    import Tkinter as Tk
else:
    import tkinter as Tk


root = Tk.Tk()
root.wm_title("Embedding in TK")


f = Figure(figsize=(5, 4), dpi=100)
a = f.add_subplot(111)
a.grid(True)
a.set_facecolor('grey')
aTwin = a.twinx()
aTwin.grid(False)



# PROBLEM HERE # Whenever I uncomment this, "aTwin" axis remains hidden.
# Set "a" axis zorder to higher value so that event handler tracks y axis from "a" and not from "aTwin"
a.set_zorder(aTwin.get_zorder() + 1)

#a.patch.set_visible(False) # Uncomment to show volume, but I lose the background from the main axis. I cannot use twinx axis' background/grid since they are different scales

x = np.arange(0.0, 2, 0.01)
y1 = abs(np.sin(2*np.pi*x))
y2 = 10.2*np.sin(4*np.pi*x)

aTwin.set_ylim(0, 3*max(y1))

a.plot(x, y2)
aTwin.fill_between(x, 0, y1, alpha = 0.4)
a.set_ylabel('between y1 and 0')


# a tk.DrawingArea
canvas = FigureCanvasTkAgg(f, master=root)
canvas.show()
canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)

toolbar = NavigationToolbar2TkAgg(canvas, root)
toolbar.update()

canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1)

def _quit():
    root.quit()
    root.destroy()

button = Tk.Button(master=root, text='Quit', command=_quit)
button.pack(side=Tk.BOTTOM)

Tk.mainloop()

Thanks in advance for the time you take in reading this question. :)


Solution

  • It seems you want to turn grid of the first axes on, set its patch invisible, set the twin axes' patch visible instead and colorize this one in grey. Then moving the original axes in front is no problem.

    import numpy as np
    import matplotlib.pyplot as plt
    
    f = plt.figure(figsize=(5, 4), dpi=100)
    ax = f.add_subplot(111)
    axTwin = ax.twinx()
    
    # Turn grid of a on.
    ax.grid(True)
    axTwin.grid(False)
    
    # Set ax's patch invisible
    ax.patch.set_visible(False)
    # Set axtwin's patch visible and colorize it in grey
    axTwin.patch.set_visible(True)
    axTwin.patch.set_facecolor('grey')
    
    # move ax in front
    ax.set_zorder(axTwin.get_zorder() + 1)
    
    x = np.arange(0.0, 2, 0.01)
    y1 = abs(np.sin(2*np.pi*x))
    y2 = 10.2*np.sin(4*np.pi*x)
    
    axTwin.set_ylim(0, 3*max(y1))
    
    ax.plot(x, y2)
    axTwin.fill_between(x, 0, y1, alpha = 0.4)
    ax.set_ylabel('between y1 and 0')
    
    plt.show()
    

    enter image description here