0

I have one, two, or three plots in a canvas of Tkinter. Let's assume I don't have any Mouse. There only is a keyboard. I want a cursor on these plots that moves at the same horizontal axis on all graphs in the canvas and of course when the Tk window shows up the yellow cursors (mplcursors) on all graphs be at the first point of graphs without any mouse movement and clicks(if you run the following code there are two cursors yellow and green, yellow appears by clicking on the line). The yellow cursors must move together (the same x-axes point) by right/left arrow keys on the keyboard.

from matplotlib.widgets import MultiCursor
import matplotlib.pyplot as plt
import numpy as np
from tkinter import *
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
import mplcursors

root = Tk()

fig = Figure(figsize=(8,6))

fig, (ax1, ax2) = plt.subplots(nrows=2, sharex=True)

x = np.linspace(-np.pi, np.pi, 256, endpoint=True)
y = np.sin(x)
z = np.cos(x)

ax1.plot(x, y, label="sin function")
ax1.legend(loc="upper right")
ax2.plot(x, z, label="cos function")
canvas = FigureCanvasTkAgg(fig,root)

c1 = mplcursors.cursor(ax1, multiple=False,hover=False,highlight=False,bindings={"toggle_visible": "h", "toggle_enabled": "e","left": "left","right": "right"})
c2 = mplcursors.cursor(ax2, multiple=False,hover=False,highlight=False,bindings={"toggle_visible": "h", "toggle_enabled": "e","left": "left","right": "right"})

multi = MultiCursor(fig.canvas, (ax1, ax2), color='g', lw=0.5, horizOn=True, vertOn=True)

ax2.legend(loc="upper left")

canvas.draw()
#pack canavs
canvas.get_tk_widget().pack(side = BOTTOM, fill=BOTH, expand=True)
#create Navigation Toolbar

toolbar = NavigationToolbar2Tk(canvas, root) #add to canvas
canvas._tkcanvas.pack(side = TOP, fill=BOTH, expand=True)

root.mainloop()

Do you have any suggestions? Can I also make the Multi-Cursor (green lines) to move with mplcursors on plots and stick to them too?

I have tried multi-threading from this link, used mouse controlling from this link and getting pixels of first plot points by this question but I couldn't handle the first display event and it needed the mouse to be clicked on both plots separately to show the cursors.

My plots are more complicated, they are signals and I have multiple pages in my application.

Nedi
  • 1
  • 2

1 Answers1

0

The following code does what I wanted But couldn't solve to keep the green Multi-Cursor on the yellow ones! (Exploring yet)

the following code uses MouseEvent and _process_event which clicks on the plot by default, when calling it you should declare when this process happens?, on which plot, in which points!

from matplotlib.widgets import MultiCursor
import matplotlib.pyplot as plt
import numpy as np
from tkinter import *
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk
import mplcursors
import subprocess
from matplotlib.backend_bases import KeyEvent, MouseEvent
import copy

def _process_event(name, ax, coords, *args):
    ax.viewLim  # unstale viewLim.
    if name == "__mouse_click__":
        # So that the dragging callbacks don't go crazy.
        _process_event("button_press_event", ax, coords, *args)
        _process_event("button_release_event", ax, coords, *args)
        return
    display_coords = ax.transData.transform(coords)
    if name in ["button_press_event", "button_release_event",
                "motion_notify_event", "scroll_event"]:
        event = MouseEvent(name, ax.figure.canvas, *display_coords, *args)
    elif name in ["key_press_event", "key_release_event"]:
        event = KeyEvent(name, ax.figure.canvas, *args, *display_coords)
    else:
        raise ValueError(f"Unknown event name {name!r}")
    ax.figure.canvas.callbacks.process(name, event)

root = Tk()

fig = Figure(figsize=(8,6))

fig, (ax1, ax2) = plt.subplots(nrows=2, sharex=True)

x = np.linspace(-np.pi, np.pi, 256, endpoint=True)
y = np.sin(x)
z = np.cos(x)

ax1.plot(x, y, label="sin function")
ax1.legend(loc="upper right")
ax2.plot(x, z, label="cos function")
canvas = FigureCanvasTkAgg(fig,root)

c1 = mplcursors.cursor(ax1, multiple=False,hover=False,highlight=False,bindings={"toggle_visible": "h", "toggle_enabled": "e","left": "left","right": "right"})
c2 = mplcursors.cursor(ax2, multiple=False,hover=False,highlight=False,bindings={"toggle_visible": "h", "toggle_enabled": "e","left": "left","right": "right"})

multi = MultiCursor(fig.canvas, (ax1, ax2), color='g', lw=0.5, horizOn=True, vertOn=True)

ax2.legend(loc="upper left")
_process_event("__mouse_click__", ax1, (x[0], y[0]), 1)
sel, = c1.selections
c1.add_selection(copy.copy(sel))

_process_event("__mouse_click__", ax2, (x[0], z[0]), 1)
sel2, = c2.selections
c2.add_selection(copy.copy(sel2))
canvas.draw()
#pack canavs
canvas.get_tk_widget().pack(side = BOTTOM, fill=BOTH, expand=True)
#create Navigation Toolbar

toolbar = NavigationToolbar2Tk(canvas, root) #add to canvas
canvas._tkcanvas.pack(side = TOP, fill=BOTH, expand=True)
root.mainloop()
Nedi
  • 1
  • 2
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-ask). – Community Sep 11 '21 at 15:29