重新排序散景图例

问题描述

我对以下情节的图例有明显的问题:

Plot

我理解这个问题,python 正在将 '2A' > '10 B' 评估为 True,但我不知道如何解决它(也许使用 natsort 包?)。我想强调的是,重新排序过程必须是自动的,因为我不知道我将来会有多少样本。 代码在这里

from bokeh.models import ColumnDataSource,Label,LabelSet,Range1d
from bokeh.plotting import figure,output_file,show
from bokeh.models import HoverTool
import pandas as pd

df = pd.DataFrame({'pc1': range(11),'pc2': range(10,-1,-1),'Muestra': ['A']*6+['B']*5,'color':['#cf0c0c']*6+['#0dab51']*5},index=range(11))
ID = ['{} {}'.format(i+1,j) for i,j in enumerate(df.Muestra)]


# Tools
TOOLS="hover,crosshair,pan,wheel_zoom,zoom_in,zoom_out,Box_zoom,undo,redo,reset,tap,save,Box_select,poly_select,lasso_select"

source = ColumnDataSource(data=dict(pc1=df.pc1,pc2=df.pc2,color=df.color,ID=ID,names=df.index))

x_min,x_max = min(df.pc1)-abs(min(df.pc1))*0.1,max(df.pc1)+abs(max(df.pc1))*0.1 
y_min,y_max = min(df.pc2)-abs(min(df.pc2))*0.1,max(df.pc2)+abs(max(df.pc2))*0.1 

p = figure(title='Principal Component Analysis',x_range=Range1d(x_min,x_max),y_range=Range1d(y_min,y_max),tools=TOOLS,height=650,width=1000)

p.scatter(x='pc1',y='pc2',size=15,fill_color='color',fill_alpha=0.6,line_color=None,legend_group='ID',source=source)
p.xaxis[0].axis_label = 'Principal Component 1'
p.yaxis[0].axis_label = 'Principal Component 2'

labels = LabelSet(x='pc1',text='names',x_offset=5,y_offset=5,source=source,render_mode='canvas')

p.add_layout(p.legend[0],'right')
p.add_layout(labels)
    
show(p)

解决方法

我想有多种方法:

一种可能是手动对图例进行排序。在您的情况下,图例是图形对象 [0]right 侧的第一项 p。图例本身是一个列表,因此您可以popappend 要移动的元素。在您的情况下,列表的第二个和第一个元素。请在致电 show(p) 之前执行此操作。

_11 = p.right[0].items.pop(2)
_10 = p.right[0].items.pop(1)
p.right[0].items.append(_10)
p.right[0].items.append(_11)

编辑

另一种可能的选择是以正确排序的方式修改变量 ID。这将导致图例顺序正确但条目错误。

ID = ['{:>02d} {}'.format(i+1,j) for i,j in enumerate(df.Muestra)]
>>>
['01 A','02 A','03 A','04 A','05 A','06 A','07 B','08 B','09 B','10 B','11 B']

就在 show(p) 调用之前,您可以遍历每个项目并删除您之前需要的零。

for i in range(len(p.right[0].items)):
    p.right[0].items[i].label['value'] = re.sub('^[0]+','',p.right[0].items[i].label['value'])

对于我的解决方案,您必须import re,这是一个负面影响。也许其他一些解决方案在没有额外包的情况下退出。