繁体   English   中英

使用 mplcursors 访问“本地数据”

[英]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 ,这样每一行都有随机属性xytypejedisithcolorbluered ,具体取决于该行是jedi还是sith ,然后是散点图颜色的绝地武士,附加一个 cursor,然后用他们的颜色绘制西斯的散点图,并附加另一个jedi ,并显示一个图例框,告诉读者蓝色点对应sith地行,红色点对应西斯行。 但是悬停点时,注释说所有的点都是sith ,坐标不好看。

我想了解为什么代码不执行我希望它执行的操作。

澄清一下:我为每种类型( jedisith )调用.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()

带有“本地数据”的 mplcursors

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM