MBV
MBV

Reputation: 630

Zoom +/- capable matplotlib window embedded in a PySimpleGUI window tab

I have the following code (based on Matplotlib plot zooming with scroll wheel). I have tried to embed it into a PySimpleGUI window tab, so far I have not been able to do so.

I managed to make it work with a Tkinter window, but my main GUI is mainly PySImpleGUI.

from matplotlib.pyplot import figure, show 
import numpy import PySimpleGUI as sg 
import matplotlib.pyplot as plt

class ZoomPan:
    def __init__(self):
        self.press = None
        self.cur_xlim = None
        self.cur_ylim = None
        self.x0 = None
        self.y0 = None
        self.x1 = None
        self.y1 = None
        self.xpress = None
        self.ypress = None

    def zoom_factory(self, ax, base_scale = 2.):
        def zoom(event):
            cur_xlim = ax.get_xlim()
            cur_ylim = ax.get_ylim()

            xdata = event.xdata # get event x location
            ydata = event.ydata # get event y location

            if event.button == 'up':
                # deal with zoom in
                scale_factor = 1 / base_scale
            elif event.button == 'down':
                # deal with zoom out
                scale_factor = base_scale
            else:
                # deal with something that should never happen
                scale_factor = 1
                print (event.button)

            new_width = (cur_xlim[1] - cur_xlim[0]) * scale_factor
            new_height = (cur_ylim[1] - cur_ylim[0]) * scale_factor

            relx = (cur_xlim[1] - xdata)/(cur_xlim[1] - cur_xlim[0])
            rely = (cur_ylim[1] - ydata)/(cur_ylim[1] - cur_ylim[0])

            ax.set_xlim([xdata - new_width * (1-relx), xdata + new_width * (relx)])
            ax.set_ylim([ydata - new_height * (1-rely), ydata + new_height * (rely)])
            ax.figure.canvas.draw()

        fig = ax.get_figure() # get the figure of interest
        fig.canvas.mpl_connect('scroll_event', zoom)

        return zoom

    def pan_factory(self, ax):
        def onPress(event):
            if event.inaxes != ax: return
            self.cur_xlim = ax.get_xlim()
            self.cur_ylim = ax.get_ylim()
            self.press = self.x0, self.y0, event.xdata, event.ydata
            self.x0, self.y0, self.xpress, self.ypress = self.press

        def onRelease(event):
            self.press = None
            ax.figure.canvas.draw()

        def onMotion(event):
            if self.press is None: return
            if event.inaxes != ax: return
            dx = event.xdata - self.xpress
            dy = event.ydata - self.ypress
            self.cur_xlim -= dx
            self.cur_ylim -= dy
            ax.set_xlim(self.cur_xlim)
            ax.set_ylim(self.cur_ylim)

            ax.figure.canvas.draw()

        fig = ax.get_figure() # get the figure of interest

        # attach the call back
        fig.canvas.mpl_connect('button_press_event',onPress)
        fig.canvas.mpl_connect('button_release_event',onRelease)
        fig.canvas.mpl_connect('motion_notify_event',onMotion)

        #return the function
        return onMotion

"FIGURE"
plt.figure(1) 
fig = plt.gcf()   
ax = fig.add_subplot(111) 
ax.clear()
ax.set_title('') 

"RANDOM PLOT"
x,y,s,c = numpy.random.rand(4,200) s *= 200   
ax.scatter(x,y,s,c, label='label')

"FIGURE CONSTANT"
ax.grid() 
ax.set_xlabel('COORDENADA ESTE', size=15) 
ax.set_ylabel('COORDENADA NORTE', size=15) 
plt.tight_layout(pad=0.05, h_pad=0.05, w_pad=0.05, rect=(0.05,-0.05,0.95,0.95)) 
ax.legend(loc=2, bbox_to_anchor=(-0.15, 1)) 
mng = plt.get_current_fig_manager() 
mng.window.showMaximized()

"PLOT"
zp = ZoomPan() 
figZoom = zp.zoom_factory(ax, base_scale = 1.1) 
figPan= zp.pan_factory(ax) 
show()

Upvotes: 2

Views: 1865

Answers (1)

MBV
MBV

Reputation: 630

You began your plot as you would normally do, then you have to create the actual fig for the pysimplegui window canvas as follows:

def draw_figure(canvas, figure, loc=(0, 0)):
    figure_canvas_agg = FigureCanvasTkAgg(figure, canvas)
    figure_canvas_agg.draw()
    figure_canvas_agg.get_tk_widget().pack(side='top', fill='both', expand=1)
    return figure_canvas_agg

such as:

fig_canvas_agg = draw_figure(window['canvas'].TKCanvas, fig)

with fig= plt.figure() and window['canvas']=sg.Canvas(key='canvas') on the window layout for PYSImpleGUI, and then you apply the ZoomPan class as follows:

zp = plot_func()
figZoom = zp.zoom_factory(ax1, base_scale=1.7)
figPan = zp.pan_factory(ax1)

Upvotes: 2

Related Questions