[英]Accessing"local data" with mplcursors
我无法理解mplcursors
游标的工作原理。 让我举个例子。
import pandas as pd
import matplotlib.pyplot as plt
import mplcursors
%matplotlib qt5
def random_data(rows_count):
data = []
for i in range(rows_count):
row = {}
row["x"] = np.random.uniform()
row["y"] = np.random.uniform()
if (i%2 == 0):
row["type"] = "sith"
row["color"] = "red"
else:
row["type"] = "jedi"
row["color"] = "blue"
data.append(row)
return pd.DataFrame(data)
data_df = random_data(30)
fig, ax = plt.subplots(figsize=(8,8))
ax = plt.gca()
types = ["jedi","sith"]
for scat_type in types:
local_data_df = data_df.loc[data_df["type"] == scat_type]
scat = ax.scatter(local_data_df["x"],
local_data_df["y"],
c=local_data_df["color"],
label=scat_type)
cursor = mplcursors.cursor(scat, hover=mplcursors.HoverMode.Transient)
@cursor.connect("add")
def on_add(sel):
annotation = (local_data_df.iloc[sel.index]["type"]+
"\n"+str(local_data_df.iloc[sel.index]["x"])+
"\n"+str(local_data_df.iloc[sel.index]["y"]))
sel.annotation.set(text=annotation)
ax.legend()
plt.title("a battle of Force users")
plt.xlabel("x")
plt.ylabel("y")
plt.xlim(-1, 2)
plt.ylim(-1, 2)
ax.set_aspect('equal', adjustable='box')
plt.show()
这段代码应该生成一个 DataFrame ,这样每一行都有随机属性x
、 y
, type
是jedi
或sith
, color
是blue
或red
,具体取决于该行是jedi
还是sith
,然后是散点图颜色的绝地武士,附加一个 cursor,然后用他们的颜色绘制西斯的散点图,并附加另一个jedi
,并显示一个图例框,告诉读者蓝色点对应sith
地行,红色点对应西斯行。 但是悬停点时,注释说所有的点都是sith
,坐标不好看。
我想了解为什么代码不执行我希望它执行的操作。
澄清一下:我为每种类型( jedi
或sith
)调用.scatter()
,然后尝试将 cursor 附加到每个图,因为我尝试在整个data_df
上调用scatter
,但是.legend()
没有显示我想要的。
我希望你给我的答案足以让我能够编写显示jedi
地和sith
点的代码,显示正确的注释和正确的图例框。
发生了很多奇怪的事情。
混淆之一是,在for
循环中使用变量local_data_df
会创建一个仅对循环的一个循环有效的变量。 相反,它只是一个全局变量,每个周期都会被覆盖。 同样,在for
循环中定义 function on_add
不会使其成为本地。 on_add
也将是全局的,并被for
循环的每个循环覆盖。
另一个混淆是连接的 function 可以访问来自另一个 function 或循环的局部变量。 相反,一旦 function 或循环结束,这些局部变量就无法访问。
此外,并不是说sel.index
不会成为 dataframe 的索引,而是进入散点 plot 的点。您可以重置“本地 df”的索引,使其类似于sel.index
的排序方式。
要模拟您的局部变量,您可以向scat
object 添加额外数据。例如scat.my_data = local_df
会将该变量添加到包含散点元素的全局PathCollection
(包含所有信息 matplotlib 的 PathCollection 需要表示散点) . 尽管变量scat
被覆盖了,但对PathCollection
的每次调用都有一个ax.scatter
。 (您也可以通过ax.collections
访问这些)。
这是您的代码的重写,试图尽可能接近原始代码:
import pandas as pd
import matplotlib.pyplot as plt
import mplcursors
def random_data(rows_count):
df = pd.DataFrame({'x': np.random.uniform(0, 1, rows_count),
'y': np.random.uniform(0, 1, rows_count),
'type': np.random.choice(['sith', 'jedi'], rows_count)})
df['color'] = df['type'].replace({'sith': 'red', 'jedi': 'blue'})
return df
def on_add(sel):
local_data_df = sel.artist.my_data
annotation = (local_data_df.iloc[sel.index]["type"] +
"\n" + str(local_data_df.iloc[sel.index]["x"]) +
"\n" + str(local_data_df.iloc[sel.index]["y"]))
sel.annotation.set(text=annotation)
data_df = random_data(30)
fig, ax = plt.subplots(figsize=(8, 8))
types = ["jedi", "sith"]
for scat_type in types:
local_data_df = data_df.loc[data_df["type"] == scat_type].reset_index() # resetting the index is necessary
scat = ax.scatter(local_data_df["x"],
local_data_df["y"],
c=local_data_df["color"],
label=scat_type)
scat.my_data = local_data_df # store the data into the scat object
cursor = mplcursors.cursor(scat, hover=mplcursors.HoverMode.Transient)
cursor.connect("add", on_add)
ax.legend()
ax.set_title("a battle of Force users")
ax.set_xlabel("x")
ax.set_ylabel("y")
ax.set_xlim(-1, 2)
ax.set_ylim(-1, 2)
ax.set_aspect('equal', adjustable='box')
plt.show()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.