-1

i am developing a GUI application for which there will be multiple dynamic subplots for which i would like to have a cursor integration for which is used "Matplotlib's MultiCursor widget" the code seems to be all good without any errors but the cursor alone is not being displayed on the screen The below is a small snippet function which iam currently using

import numpy as np
import PySimpleGUI as sg
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg,
                                               NavigationToolbar2Tk)
from matplotlib.widgets import Cursor
from matplotlib.widgets import MultiCursor
from matplotlib.gridspec import GridSpec
from matplotlib.figure import Figure

class Toolbar(NavigationToolbar2Tk):

    def __init__(self, *args, **kwargs):
        super(Toolbar, self).__init__(*args, **kwargs)

def repack(widget, option):
    pack_info = widget.pack_info()
    pack_info.update(option)
    widget.pack(**pack_info)

def draw_figure_w_toolbar(canvas, fig, canvas_toolbar):
    if canvas.children:
        for child in canvas.winfo_children():
            child.destroy()
    if canvas_toolbar.children:
        for child in canvas_toolbar.winfo_children():
            child.destroy()
    figure_canvas_agg = FigureCanvasTkAgg(fig, master=canvas)
    figure_canvas_agg.draw_idle()
    toolbar = Toolbar(figure_canvas_agg, canvas_toolbar)
    toolbar.update()
    figure_canvas_agg.get_tk_widget().pack(side='right', fill='both', expand=1)

layout=[
        [
            sg.Frame(
                'Controls',
                expand_x=True,
                layout=[[
                    sg.Canvas(key='controls_cv')
                ]])
        ],
            [
                sg.Canvas(
                    key='fig_cv',
                    size=(1024, 525),  #(W,H)
                    expand_x=True,
                    expand_y=True,
                    background_color='black')
            ],
        ]

window = sg.Window('Data Visualization Tool',
                   layout=layout,
                   location=(0, 0),
                  
                   resizable=True,
                   margins=(0, 0),
                   finalize=True)

fig = Figure()

def get_data_ax(x_data, y_data, y_label, marker_sym=None):
    ax = fig.add_subplot()
    lines = ax.step(
        x_data,
        y_data,
    
        marker=marker_sym,
        where='post')
    
    return ax, lines
cursor_handle_list = []
axes_handle_list = []
def on_move(event, flag=False, c_flag=False):
    global cursor_present_flag, cursor_handle_list, axes_handle_list
    if event.dblclick:     
        def change_cursor_position(handle_obj):
            for handles in handle_obj:
                handles.set_xdata(float(event.xdata))   
        if event.inaxes is not None:
            ax = event.inaxes
            if ax not in axes_handle_list:
                cursor_handle = ax.axvline(event.xdata, color ='red', lw = .75, alpha = 0.65, visible=True)
                cursor_handle_list.append(cursor_handle)
                axes_handle_list.append(ax)
            else:
                change_cursor_position(cursor_handle_list)
            
            draw_figure_w_toolbar(window['fig_cv'].TKCanvas, fig,
                                        window['controls_cv'].TKCanvas)
        window.refresh()

fig.canvas.mpl_connect("button_press_event", on_move)
t = np.arange(0.0, 2.0, 0.01)
s = 1 + np.sin(2 * np.pi * t) 
num_rows = 2
gs = GridSpec(num_rows, 1, hspace=0)
ax0, lines = get_data_ax(t, s, 'test')

ax0.set_subplotspec(gs[0])
fig.add_subplot(ax0)
ax, lines = get_data_ax(t, s, 'test')
ax.set_subplotspec(gs[1])
fig.add_subplot(ax)
ax.get_shared_x_axes().join(ax0, ax)

graph = FigureCanvasTkAgg(fig, master=window['fig_cv'].TKCanvas)
cursor_multi = MultiCursor(graph, [ax,], color='r', lw=2.0, vertOn=True)
graph.draw()  
draw_figure_w_toolbar(window['fig_cv'].TKCanvas, fig,
                                      window['controls_cv'].TKCanvas)
while True:
    event, values = window.read()
    if event in (sg.WIN_CLOSED, 'Exit'):
        break

I tried using axvline with matplotlib events but the results were not satisfactory i saw somewhere that defining the return value of MultiCursor as gloabl should fix the issue but that did not happen in my case next i tried simple putting plt.var_name as a variable for catching the returned object from MultiCursor but even this did not yeild me any result Note: The code with mpl_connect and on_move callback with axvline integration were just an workaround i was trying as MultiCursor was not working you can discard that part if not required

Sreenath R
  • 13
  • 6
  • 1
    You need to provide a [mre] and debugging details. Anyway create a ```Multicursor``` instance only once and give it the list of all axes objects. See [the official sample](https://matplotlib.org/stable/gallery/widgets/multicursor.html). – relent95 Feb 08 '23 at 02:04
  • @relent95 Iam sorry my bad i should have provided an reproducible code now i hope the issue is more clear and also i updated the code snippet with a miniature version of my requirement thanks further more you can refer to the below thread https://github.com/PySimpleGUI/PySimpleGUI/issues/2055#issuecomment-1423178870 – Sreenath R Feb 08 '23 at 20:21

1 Answers1

0

It's because you created the MultiCursor widget before you created the FigureCanvasTkAgg for the axes objects. So do like this.

draw_figure_w_toolbar(window['fig_cv'].TKCanvas, ...)
cursor_multi = MultiCursor(None, [ax,], ...)

Also note that the first argument of the MultiCursor() is recommended to be set to None because it is ignored. Also your code contain many problems, such as an unused object graph.

relent95
  • 3,703
  • 1
  • 14
  • 17
  • Yes, I did not use those objects, I just mentioned them in the code just to showcase all my debugging steps and alternate measures that I took. thank you @relent95 I did not know I made such a blunder mistake now it's all working as expected – Sreenath R Feb 09 '23 at 06:40