我想通过单击图中的值来提取图形的值,同时还在此时添加标记/删除旧标记。我设法对单个数字执行此操作,但在我的实践案例中,我有多个数字。
当我有多个数字时,单击事件仅适用于最新的数字。单击其他图形将打印出最后一个图形的值/在最后一个图形中添加标记。
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、ax1和cid放入字典中并调整函数参数,但这并没有改变任何东西。
有趣的是,如果我在没有循环的情况下绘制和调用函数,但单独进行 3 次,至少可以检索函数的坐标部分。只有添加/删除标记不起作用...
我发现了一个类似的问题here,但是我不太明白答案。
我尝试为多个图编写代码,但我认为这是不可能的。所以,我想出了一个想法 - 当你运行代码时,所有的图都会显示出来:
然后您可以单击其中之一。例如,如果您单击第二个图,它将像这样打开,
您可以单击该图,它将显示标记并在终端中输出坐标。如果您想访问其他图,只需关闭此窗口即可。将出现 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()
# ------------------------------------------------------------------------------------------------------------------------------------------- #
希望这对您有帮助!
我能够弄清楚。不知何故,问题出在循环中......我不知道到底为什么,但是当我将数字放入字典中然后单独执行单击事件时,它起作用了。但是,当我尝试通过循环来完成它时,它就不起作用了。如果有人知道这种奇怪行为的原因,我会很高兴得到解释。
但是,我最终解决这个问题的方法是添加一个执行点击事件的函数。通过这样做,我可以再次使用循环。
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])