微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何将六角形matplotlib图转换为交互式bokeh图?

如何解决如何将六角形matplotlib图转换为交互式bokeh图?

我一直在使用出色的minisom软件包,并希望交互式地绘制六边形地图,以反映自组织地图训练过程的结果。已经有一个代码示例,该示例使用matplotlib静态地执行此操作,但为了交互地执行此操作,我想使用bokeh。这就是我在努力的地方。

这是用于生成简化的matplotlib示例的代码,其示例已包含在软件包page中:

from minisom import MiniSom
import pandas as pd
import numpy as np

import matplotlib.pyplot as plt
from matplotlib.patches import Regularpolygon
from matplotlib import cm

from bokeh.plotting import figure
from bokeh.io import save,show,output_file,output_notebook

output_notebook()

data = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/00236/seeds_dataset.txt',names=['area','perimeter','compactness','length_kernel','width_kernel','asymmetry_coefficient','length_kernel_groove','target'],sep='\t+')
t = data['target'].values
data = data[data.columns[:-1]]
# data normalisation
data = (data - np.mean(data,axis=0)) / np.std(data,axis=0)
data = data.values

# initialisation and training
som = MiniSom(15,15,data.shape[1],sigma=1.5,learning_rate=.7,activation_distance='euclidean',topology='hexagonal',neighborhood_function='gaussian',random_seed=10)

som.train(data,1000,verbose=True)

# plot hexagonal topology
f = plt.figure(figsize=(10,10))
ax = f.add_subplot(111)

ax.set_aspect('equal')

xx,yy = som.get_euclidean_coordinates()
umatrix = som.distance_map()
weights = som.get_weights()

for i in range(weights.shape[0]):
    for j in range(weights.shape[1]):
        wy = yy[(i,j)]*2/np.sqrt(3)*3/4
        hex = Regularpolygon((xx[(i,j)],wy),numVertices=6,radius=.95/np.sqrt(3),facecolor=cm.Blues(umatrix[i,j]),alpha=.4,edgecolor='gray')
        ax.add_patch(hex)
for x in data:
    w = som.winner(x) 
    # place a marker on the winning position for the sample xx
    wx,wy = som.convert_map_to_euclidean(w) 
    wy = wy * 2 / np.sqrt(3) * 3 / 4
    plt.plot(wx,wy,markerfacecolor='None',markeredgecolor='black',markersize=12,markeredgewidth=2)

plt.show()

matplotlib hexagonal topology plot

我已经尝试将代码转换bokeh,但是生成的十六进制图(对我来说,本来就是)看起来需要垂直翻转到这些点上,并且要弄平歪斜。

tile_centres_column = []
tile_centres_row = []
colours = []
for i in range(weights.shape[0]):
    for j in range(weights.shape[1]):
        wy = yy[(i,j)] * 2 / np.sqrt(3) * 3 / 4
        tile_centres_column.append(xx[(i,j)])
        tile_centres_row.append(wy)
        colours.append(cm.Blues(umatrix[i,j]))
        
weight_x = []
weight_y = []
for x in data:
    w = som.winner(x)
    wx,wy = som.convert_map_to_euclidean(xy=w)
    wy = wy * 2 / np.sqrt(3) * 3/4
    weight_x.append(wx)
    weight_y.append(wy)

# plot hexagonal topology
plot = figure(plot_width=800,plot_height=800,match_aspect=True) 
plot.hex_tile(q=tile_centres_column,r=tile_centres_row,size=.95 / np.sqrt(3),color=colours,fill_alpha=.4,line_color='black')
plot.dot(x=weight_x,y=weight_y,fill_color='black',size=12)

show(plot)

bokeh hexagonal topology plot

如何将其转换为散景图?

解决方法

在联系minisom软件包作者寻求帮助后,了解了如何执行此操作。完整的代码可用here

from bokeh.colors import RGB
from bokeh.io import curdoc,show,output_notebook
from bokeh.transform import factor_mark,factor_cmap
from bokeh.models import ColumnDataSource,HoverTool
from bokeh.plotting import figure,output_file

hex_centre_col,hex_centre_row = [],[]
hex_colour = []
label = []

# define labels
SPECIES = ['Kama','Rosa','Canadian']

for i in range(weights.shape[0]):
    for j in range(weights.shape[1]):
        wy = yy[(i,j)] * 2 / np.sqrt(3) * 3 / 4
        hex_centre_col.append(xx[(i,j)])
        hex_centre_row.append(wy)
        hex_colour.append(cm.Blues(umatrix[i,j]))

weight_x,weight_y = [],[]
for cnt,i in enumerate(data):
    w = som.winner(i)
    wx,wy = som.convert_map_to_euclidean(xy=w)
    wy = wy * 2 / np.sqrt(3) * 3 / 4
    weight_x.append(wx)
    weight_y.append(wy)
    label.append(SPECIES[t[cnt]-1])
    
# convert matplotlib colour palette to bokeh colour palette
hex_plt = [(255 * np.array(i)).astype(int) for i in hex_colour]
hex_bokeh = [RGB(*tuple(rgb)).to_hex() for rgb in hex_plt]

output_file("resulting_images/som_seed_hex.html")

# initialise figure/plot
fig = figure(title="SOM: Hexagonal Topology",plot_height=800,plot_width=800,match_aspect=True,tools="wheel_zoom,save,reset")

# create data stream for plotting
source_hex = ColumnDataSource(
    data = dict(
        x=hex_centre_col,y=hex_centre_row,c=hex_bokeh
    )
)

source_pages = ColumnDataSource(
    data=dict(
        wx=weight_x,wy=weight_y,species=label
    )
)

# define markers
MARKERS = ['diamond','cross','x']

# add shapes to plot
fig.hex(x='y',y='x',source=source_hex,size=100 * (.95 / np.sqrt(3)),alpha=.4,line_color='gray',fill_color='c')

fig.scatter(x='wy',y='wx',source=source_pages,legend_field='species',size=20,marker=factor_mark(field_name='species',markers=MARKERS,factors=SPECIES),color=factor_cmap(field_name='species',palette='Category10_3',factors=SPECIES))

# add hover-over tooltip
fig.add_tools(HoverTool(
    tooltips=[
        ("label",'@species'),("(x,y)",'($x,$y)')],mode="mouse",point_policy="follow_mouse"
))

show(fig)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。