2017-08-25 115 views
1

我创建了一个布局看起来很像这个互动式图表:如何使用唯一ID标记散点图中的特定点?

Sample layout

每个点都有一个唯一的ID,通常是一组的一部分。每个组都有自己的颜色,所以我使用多个散点图来创建整个布局。点击单点时需要进行以下操作:

  1. 单击鼠标,检索所选点的ID。
  2. 将ID插入黑匣子函数,该函数返回附近的* ID列表。
  3. 突出显示返回列表中ID的点。

    *某些ID可能来自不同的群组/地块。

我如何:

  1. 关联的每个点有一个ID,并点击点时返回ID?
  2. 当我知道他们的ID时,突出显示布局中的其他点?
  3. 重新定位各个点,同时保持它们各自的组,即用属于不同组/点的点交换位置。

我在切换到matplotlib之前使用了pyqtgraph,所以我首先想到创建一个ID和它们的点对象的字典。在对pick_event进行实验之后,我认为matplotlib中不存在点对象的概念。从我迄今为止所了解到的情况来看,每个点都由一个索引表示,只有它的PathCollection可以返回关于其本身的信息,例如,坐标。我还了解到,特定点的颜色修改是通过其PathCollection来完成的,而在pyqtgraph中,我可以通过点对象来完成,例如, point.setBrush('#000000')

+0

有matplotlib的onclick事件:https://matplotlib.org/users/event_handling.html – Moritz

回答

1

我仍然坚信使用单散点图将是更好的选择。这个问题中没有任何东西会与此相矛盾。

您可以将所有数据合并到一个DataFrame中,并将其列为group, id, x, y, color。在下面它说“创造一些数据集”的代码部分不建立这样一个数据帧

group id x y  color 
0  1 AEBB 0 0 palegreen 
1  3 DCEB 1 0  plum 
2  0 EBCC 2 0 sandybrown 
3  0 BEBE 3 0 sandybrown 
4  3 BEBB 4 0  plum 

注意,每个组都有自己的颜色。然后可以使用color列中的颜色从中创建散点图。

this previous question中注册挑选事件,并且一旦点击了一个不是黑色的点,就获得与所选点对应的DataFrame中的id。从id中,通过“黑匣子函数”生成其他id,并且对于通过这种方式获得的每个id,确定数据帧中的点的相应索引。因为我们有单散点,所以这个索引直接是分散点(PathCollection)中点的索引,我们可以将它绘成黑色。

import numpy as np; np.random.seed(1) 
import pandas as pd 
import matplotlib.pyplot as plt 
import matplotlib.colors 

### create some dataset 
x,y = np.meshgrid(np.arange(20), np.arange(20)) 
group = np.random.randint(0,4,size=20*20) 
l = np.array(np.meshgrid(list("ABCDE"),list("ABCDE"), 
        list("ABCDE"),list("ABCDE"))).T.reshape(-1,4) 
ide = np.random.choice(list(map("".join, l)), size=20*20, replace=False) 
df = pd.DataFrame({"id" : ide, "group" : group , 
        "x" : x.flatten(), "y" : y.flatten() }) 
colors = ["sandybrown", "palegreen", "paleturquoise", "plum"] 
df["color"] = df["group"] 
df["color"].update(df["color"].map(dict(zip(range(4), colors)))) 
print df.head() 

### plot a single scatter plot from the table above 
fig, ax = plt.subplots() 
scatter = ax.scatter(df.x,df.y, facecolors=df.color, s=64, picker=4) 


def getOtherIDsfromID(ID): 
    """ blackbox function: create a list of other IDs from one ID """ 
    l = [np.random.permutation(list(ID)) for i in range(5)] 
    return list(set(map("".join, l))) 


def select_point(event): 
    if event.mouseevent.button == 1: 
     facecolor = scatter._facecolors[event.ind,:] 
     if (facecolor == np.array([[0, 0, 0, 1]])).all(): 
      c = df.color.values[event.ind][0] 
      c = matplotlib.colors.to_rgba(c) 
      scatter._facecolors[event.ind,:] = c 
     else: 
      ID = df.id.values[event.ind][0] 
      oIDs = getOtherIDsfromID(ID) 
      # for each ID obtained, make the respective point black. 
      rows = df.loc[df.id.isin([ID] + oIDs)] 
      for i, row in rows.iterrows(): 
       scatter._facecolors[i,:] = (0, 0, 0, 1) 
      tx = "You selected id {}.\n".format(ID) 
      tx += "Points with other ids {} will be affected as well" 
      tx = tx.format(oIDs) 
      print tx 

     fig.canvas.draw_idle() 

fig.canvas.mpl_connect('pick_event', select_point) 

plt.show() 

在下面的图像,与ID DAEE点已经被点击,并且其它点与IDS [“EDEA”,“DEEA”,“EDAE”,“DEAE”]已经由黑盒选择功能。并非所有这些ID都存在,因此其他两个带有现有ID的点也会着色。

enter image description here

+0

感谢您的例子。我没有意识到DataFrames的功能,因为我之前从未使用熊猫。 – FatHippo

+0

如何在更改DataFrame中的某些xy值之后更新散点图? – FatHippo