每次运行后matplotlib标记类型的顺序不一致吗?

时间:2018-12-11 07:52:51

标签: python pandas matplotlib

在不更改任何代码的情况下,绘制的图形将有所不同。在第一轮中以新鲜的扑打纠正,在下一轮中无序。 (也许它可以循环回到正确的顺序)

具体来说: 环境:通过自制程序安装的MacOS Mojave 10.14.2,python3.7.1。
为此,请执行以下操作:在同一scatter上为两或三组数据绘制axes,每个数据集具有不同的markertype和不同的colors。绘制自定义图例,显示每个markertype代表哪些数据集。

很抱歉,我现在没有足够的时间来准备可测试的代码,但这似乎是问题所在:

markerTypes = cycle(['o', 's', '^', 'd', 'p', 'P', '*'])
strainLegends = []
strains = list(set([idx.split('_')[0] for idx in pca2Plot.index]))
for strain in strains:
    # markerType is fixed here, and shouldn't be passed on to the next python run anyway.
    markerType = next(markerTypes)

    # strainSamples connects directly to strain variable, then data is generated from getting strainSamples:
    strainSamples = [sample for sample in samples if
                     sample.split('_')[0] == strain]
    xData = pca2Plot.loc[strainSamples, 'PC1']
    yData = pca2Plot.loc[strainSamples, 'PC2']
    # See pictures below, data is correctly identified from source

    # both scatter and legend instance use the same fixed markerType
    ax.scatter(xData, yData, c=drawColors[strainSamples],
               s=40, marker=markerType, zorder=3)
    strainLegends.append(Line2D([0], [0], marker=markerType, color='k',
                                markersize=10,
                                linewidth=0, label=strain))
    # print([i for i in ax.get_children() if isinstance(i, PathCollection)])

ax.legend(handles=strainLegends)

如您所见,markerTypestrain数据与数据相关。

对于bash中python3 my_code.py的第一次运行,它会创建正确的图片:看到圆圈代表A,正方形代表B see the circle represents A, square represents B A =圆,B =正方形。参见(-3, -3.8)周围的正方形,该数据点来自数据集B。

当我在同一终端python3 my_code.py中再次运行代码时 enter image description here 注意A和B完全聚集在一起,不相关。 现在作为图例:A =正方形,B =圆形。再次查看来自数据集B的数据点(-3, -3.8),现在标注为A。

如果再次运行代码,则可能会产生另一个结果。

这是我用来生成注释的代码:

dictColor = {ax: pd.Series(index=pca2Plot.index), }
HoverClick = interactionHoverClick(
    dictColor, fig, ax)
fig.canvas.mpl_connect("motion_notify_event", HoverClick.hover)
fig.canvas.mpl_connect("button_press_event", HoverClick.click)

HoverClick班上,我有

def hover(self, event):
    if event.inaxes != None:
        ax = event.inaxes
        annot = self.annotAxs[ax]
        # class matplotlib.collections.PathCollection, here refere to the scatter plotting event (correct?)
        drawingNum = sum(isinstance(i, PathCollection)
                         for i in ax.get_children())
        # print([i for i in ax.get_children() if isinstance(i, PathCollection)])

        plotSeq = 0
        jump = []
        indInd = []
        indIndInstances = []
        for i in range(drawingNum):
            sc = ax.get_children()[i]
            cont, ind = sc.contains(event)
            jump.append(len(sc.get_facecolor()))
            indIndInstances.append(ind['ind'])
            if cont:
                plotSeq = i
                indInd.extend(ind['ind'])

        # here plotSeq is the index of last PathCollection instance that program find my mouse hovering on a datapoint of it.
        sc = ax.get_children()[plotSeq]
        cont, ind = sc.contains(event)

        if cont:
            try:
                exist = (indInd[0] in self.hovered)
            except:
                exist = False
            if not exist:
                hovered = indInd[0]
                pos = sc.get_offsets()[indInd[0]]

                textList = []
                for num in range(plotSeq + 1):
                    singleJump = sum(jump[:num])
                    textList.extend([self.colorDict[ax].index[i + singleJump]
                                     for i in indIndInstances[num]])
                text = '\n'.join(textList)
                annot.xy = pos
                annot.set_text(text)
                annot.set_visible(True)
                self.fig.canvas.draw_idle()
        else:
            if annot.get_visible():
                annot.set_visible(False)
                self.fig.canvas.draw_idle()
# hover

请注意,我注释了用于打印每个实例的代码。这是经过测试的,因为我认为可能是实例的顺序在整个代码的其他部分已更改。但是结果显示在正确和错误的情况下,顺序都没有改变。

有人知道发生了什么吗? 有人曾经经历过吗? 如果需要在代码末尾清理内存,该怎么办?

2 个答案:

答案 0 :(得分:1)

由于您的代码不完整,因此很难确定,但是cycle迭代器似乎混淆了标记的顺序。您为什么不尝试:

markerTypes = ['o', 's', '^']
strainLegends = []

for strain, markerType in zip(strains, markerTypes):
    strainSamples = [sample for sample in samples if sample.split('_')[0] == strain]
    xData = pca2Plot.loc[strainSamples, 'PC1']
    yData = pca2Plot.loc[strainSamples, 'PC2']
    ax.scatter(xData, yData, c=drawColors[strainSamples], s=40, marker=markerType, zorder=3)
    strainLegends.append(Line2D([0], [0], marker=markerType, color='k',
                                markersize=10,
                                linewidth=0, label=strain))
ax.legend(handles=strainLegends)

这当然假定strainsmarkerTypes的长度相同,并且标记在列表中与要为其分配的应变值位于相同的位置。

答案 1 :(得分:0)

我发现此问题是由我在strains中进行的重复复制过程引起的。

# wrong code:
strains = list(set([idx.split('_')[0] for idx in pca2Plot.index]))

# correct code:
strains = list(OrderedDict.fromkeys([idx.split('_')[0] for idx in pca2Plot.index]))

因此,我提出的问题不是有效的问题。谢谢大家,对此深表歉意。