matplotlib 多个地物的单击事件

6za6bjd0  于 2023-11-22  发布在  其他
关注(0)|答案(2)|浏览(171)

我想通过点击图中的值来提取图中的值,同时在此时添加标记/删除旧标记。我只对一个图执行此操作,但在我的实践案例中,我有多个图。
当我有多个图时,点击事件只对最近的图有效。点击其他图将打印出最后一个图的值/在最后一个图中添加标记。

import numpy as np
import matplotlib.pyplot as plt

%matplotlib qt

# Function to get the closest actual value
def find_nearest(array,value):
    idx = (np.abs(array-value)).argmin()
    return array[idx]

# Function to ectract the value from the graph by clicking
def onclick(event,x,y,fig):
    if event.inaxes is not None:
        ix = find_nearest(x,event.xdata )
        iy = y[np.where(x==ix)[0][0]]

        text = (f'x = {ix},   y = {iy}\n')

        ax1 = fig.get_axes()[0]
        # Update the plots
        if len(ax1.get_lines()) > 1: 
            delete = ax1.get_lines()[-1]
            delete.remove()
        ax1.plot([ix],[iy],marker="x",color="b")
        fig.canvas.draw_idle()
        print(text)

# test case
x = np.arange(0,10,1)
y1 = x
y2 = x**2
y3 = x**3

f1 = [x,y1]
f2 = [x,y2]
f3 = [x,y3]
functions = [f1,f2,f3]

for f in functions:
    fig, ax1 = plt.subplots(1)
    ax1.plot(f[0],f[1])
    #plt.show()
    cid = fig.canvas.mpl_connect('button_press_event', lambda event: onclick(event,f[0],f[1],fig))

字符串
如果有人知道热修复它,这将是高度赞赏。
我已经试过把fig,ax 1和cid放入字典中,并调整函数参数,但这并没有改变任何东西。
有趣的是,如果我在没有循环的情况下绘制和调用函数,但是单独地进行3次,至少函数的坐标部分的检索工作。只有添加/删除标记不工作。
我在这里发现了一个类似的问题,但我不太明白答案。

6l7fqoea

6l7fqoea1#

我试着写一个代码多个情节,但我不认为这是可能的。所以,我想出了一个主意-当你运行代码,所有的情节显示:
x1c 0d1x的数据
然后你可以点击其中一个。例如,如果你点击第二个图,它会像这样打开,



您可以点击这个图,它将显示标记并在终端中输出坐标。如果您想访问其他图,只需关闭此窗口。3个图将出现。然后您可以选择例如,第三个。然后如果您想终止代码,只需关闭原始窗口(具有所有3个子图的窗口)
下面是我的代码:

# Import modules
import numpy as np 
import matplotlib.pyplot as plt 
from matplotlib.animation import FuncAnimation
# ------------------------------------------------------------------------------------------------------------------------------------------- #

# Test data
x = np.arange(0.0, 10.0, 1.0)
y1 = x
y2 = x**2
y3 = x**3
# 
x_data = [x, x, x]
y_data = [y1, y2, y3]
#
colors = ["red", "blue", "green"]  # color to identify which data is viewed
# ------------------------------------------------------------------------------------------------------------------------------------------- #

while True:

     # Define the figure and axes of each subplot
     # Documentation https://matplotlib.org/stable/gallery/subplots_axes_and_figures/subplots_demo.html
     fig, axs = plt.subplots(1, len(x_data), figsize=(16,16))

     # Axis added when viewing one subplot
     ax_added = None

     # Plot the data in each plot
     for i in range(len(x_data)):
          axs[i].plot(x_data[i], y_data[i], color=colors[i])
     # ------------------------------------------------------------------------------------------------------------------------------------------- #

     # Variable that stores which subplot is selected
     ax_selected_index = None
     ax_selected_index_copy = None

     # Boolean that keeps track if only one plot is displayed
     selected = False

     # Function to retrieve which subplot has been clicked
     def onClick1(event):
          global axs, ax_selected_index, ax_selected_index_copy

          # Iterate through each plot
          for i in range(len(axs)):

               # Check which plot has been clicked
               # Answer from https://stackoverflow.com/questions/25047846/determine-button-clicked-subplot
               if (event.inaxes == axs[i]):
                    
                    ax_selected_index = i
                    ax_selected_index_copy = i

                    return
     # ----- #

     # Define the coordinates of the mouse when clicked
     mouse_pos_click = [None, None]

     # Function to get mouse coordinates
     def onClick2(event):
          global mouse_pos_click

          # Saves x and y coordinates of mouse
          mouse_pos_click = [event.xdata, event.ydata]
     # ----- #

     def on_close(event):
          global selected

          # Close on first window
          if not selected:
               exit()
     # ----- #

     def animate(i):
          global axs, ax_selected_index, selected, mouse_pos_click, ax_selected_index_copy, ax_added

          # Exit if the user close the first window
          fig.canvas.mpl_connect('close_event', on_close)

          # Retrieve the clicked mouse coordinates
          # If mouse is click --> run onClick1 event
          plt.connect('button_press_event', onClick1)

          # Check whether user has clicked a subplot
          if ax_selected_index != None:
               
               for ax in axs:
                    # Hide X and Y axes label marks
                    ax.xaxis.set_tick_params(labelbottom=False)
                    ax.yaxis.set_tick_params(labelleft=False)

                    # Hide X and Y axes tick marks
                    ax.set_xticks([])
                    ax.set_yticks([])

               # Add another plot "on top" of axs
               ax_added = fig.add_subplot()
               # Plot the required graph
               ax_added.plot(x_data[ax_selected_index], y_data[ax_selected_index], color=colors[ax_selected_index]) 

               # Reset the selected index 
               ax_selected_index = None

               # Update the boolean
               selected = True

          if selected:

               # Retrieve the coordinates of the mouse
               plt.connect('button_press_event', onClick2)

               # Check if user has clicked
               if mouse_pos_click[0] != None:

                    # Find the closest actual value
                    indx = (np.abs(x_data[ax_selected_index_copy]-mouse_pos_click[0])).argmin()

                    # Clear the plot
                    ax_added.clear()
                    # Plot the line
                    ax_added.plot(x_data[ax_selected_index_copy], y_data[ax_selected_index_copy], color=colors[ax_selected_index_copy])
                    # Scatter the point
                    ax_added.scatter(x_data[ax_selected_index_copy][indx], y_data[ax_selected_index_copy][indx], color="black", s=50)

                    # Reset the mouse position
                    mouse_pos_click = [None, None]
                    
                    # Output the coordinates
                    print(f"Figure : {ax_selected_index_copy}")
                    print(f"x = {x_data[ax_selected_index_copy][indx]}, y = {y_data[ax_selected_index_copy][indx]}")
                    print("\n")
          

     animation = FuncAnimation(fig, animate, interval=50)

     # Display the plot
     plt.show()
     # ------------------------------------------------------------------------------------------------------------------------------------------- #

字符串
我希望这对你有帮助!

gc0ot86w

gc0ot86w2#

我能够弄清楚它。某种程度上,问题在于循环.我不知道确切的原因,但当我把数字放入字典,然后单独执行点击事件时,它工作了。但是,当我试图通过循环来做这件事时,它不工作。如果有人知道这种奇怪行为的原因,我很乐意得到解释。
然而,我最终解决这个问题的方法是添加一个函数,它执行click事件。通过这样做,我可以再次使用循环。

def access_click_event(figure,x,y):
    figure.canvas.mpl_connect('button_press_event', lambda event: onclick(event,x,y,figure))

figures = {}
for n,f in enumerate(functions):
    fig, ax1 = plt.subplots(1)
    figures[n] = fig
    ax1.plot(f[0],f[1])
    access_click_event(figures[n],f[0],f[1])

字符串

相关问题