我正在尝试做一些我通常认为微不足道的事情,但在散景中似乎很困难:在绘图中添加垂直颜色条,然后使颜色条的标题(也就是颜色映射后面的变量)出现在一侧颜色栏的位置,但与水平方向顺时针旋转90度。
从我能看到的bokeh ColorBar()接口(同时查看文档和对该元素使用python解释器的help()函数)来看,这是不可能的。无奈之下,我添加了自己的基于Label()的注释。这可行,但很笨拙,并且在散景服务情况下部署时显示奇怪的行为-情节上数据窗口的宽度与标题颜色栏标题字符串的长度成反比。
下面,我包括了bokeh服务器mpg示例的修改版本。抱歉,因为它很复杂,但是我认为这是使用bokeh附带的基础结构/数据来说明问题的最佳方法。对于不熟悉bokeh服务的用户,此代码段需要保存到目录中名为main.py的文件中(为了便于说明,我们假设使用CrossFilter2-,而在CrossFilter2的父目录中,则需要调用该命令)
bokeh serve --show CrossFilter2
Run Code Online (Sandbox Code Playgroud)
然后它将显示在浏览器窗口(localhost:5006 / CrossFilter2)中,如果您使用颜色选择小部件,您将明白我的意思,即简短的变量名(例如“ hp”或“ mpg”)会产生更宽的数据显示窗口的时间要比变量名(例如“ accel”或“ weight”)更长。我怀疑标签元素的大小可能存在错误-它们的x和y尺寸已互换-并且散景不了解标签元素是否已旋转。
我的问题是:
如果必须在示例代码中看到麻烦,是否可以通过其他方法避免数据窗口宽度问题?
import numpy as np
import pandas as pd
from bokeh.layouts import row, widgetbox
from bokeh.models import Select
from bokeh.models import HoverTool, ColorBar, LinearColorMapper, Label
from bokeh.palettes import Spectral5
from bokeh.plotting import curdoc, figure, ColumnDataSource
from bokeh.sampledata.autompg import autompg_clean as df
df = df.copy()
SIZES = list(range(6, 22, 3))
COLORS = Spectral5
# data cleanup
df.cyl = df.cyl.astype(str)
df.yr = df.yr.astype(str)
columns = sorted(df.columns)
discrete = [x for x in columns if df[x].dtype == object]
continuous = [x for x in columns if x not in discrete]
quantileable = [x for x in continuous if len(df[x].unique()) > 20]
def create_figure():
xs = df[x.value].tolist()
ys = df[y.value].tolist()
x_title = x.value.title()
y_title = y.value.title()
name = df['name'].tolist()
kw = dict()
if x.value in discrete:
kw['x_range'] = sorted(set(xs))
if y.value in discrete:
kw['y_range'] = sorted(set(ys))
kw['title'] = "%s vs %s" % (y_title, x_title)
p = figure(plot_height=600, plot_width=800,
tools='pan,box_zoom,wheel_zoom,lasso_select,reset,save',
toolbar_location='above', **kw)
p.xaxis.axis_label = x_title
p.yaxis.axis_label = y_title
if x.value in discrete:
p.xaxis.major_label_orientation = pd.np.pi / 4
if size.value != 'None':
groups = pd.qcut(df[size.value].values, len(SIZES))
sz = [SIZES[xx] for xx in groups.codes]
else:
sz = [9] * len(xs)
if color.value != 'None':
coloring = df[color.value].tolist()
cv_95 = np.percentile(np.asarray(coloring), 95)
mapper = LinearColorMapper(palette=Spectral5,
low=cv_min, high=cv_95)
mapper.low_color = 'blue'
mapper.high_color = 'red'
add_color_bar = True
ninety_degrees = pd.np.pi / 2.
color_bar = ColorBar(color_mapper=mapper, title='',
#title=color.value.title(),
title_text_font_style='bold',
title_text_font_size='20px',
title_text_align='center',
orientation='vertical',
major_label_text_font_size='16px',
major_label_text_font_style='bold',
label_standoff=8,
major_tick_line_color='black',
major_tick_line_width=3,
major_tick_in=12,
location=(0,0))
else:
c = ['#31AADE'] * len(xs)
add_color_bar = False
if add_color_bar:
source = ColumnDataSource(data=dict(x=xs, y=ys,
c=coloring, size=sz, name=name))
else:
source = ColumnDataSource(data=dict(x=xs, y=ys, color=c,
size=sz, name=name))
if add_color_bar:
p.circle('x', 'y', fill_color={'field': 'c',
'transform': mapper},
line_color=None, size='size', source=source)
else:
p.circle('x', 'y', color='color', size='size', source=source)
p.add_tools(HoverTool(tooltips=[('x', '@x'), ('y', '@y'),
('desc', '@name')]))
if add_color_bar:
color_bar_label = Label(text=color.value.title(),
angle=ninety_degrees,
text_color='black',
text_font_style='bold',
text_font_size='20px',
x=25, y=300,
x_units='screen', y_units='screen')
p.add_layout(color_bar, 'right')
p.add_layout(color_bar_label, 'right')
return p
def update(attr, old, new):
layout.children[1] = create_figure()
x = Select(title='X-Axis', value='mpg', options=columns)
x.on_change('value', update)
y = Select(title='Y-Axis', value='hp', options=columns)
y.on_change('value', update)
size = Select(title='Size', value='None',
options=['None'] + quantileable)
size.on_change('value', update)
color = Select(title='Color', value='None',
options=['None'] + quantileable)
color.on_change('value', update)
controls = widgetbox([x, y, color, size], width=200)
layout = row(controls, create_figure())
curdoc().add_root(layout)
curdoc().title = "Crossfilter"
Run Code Online (Sandbox Code Playgroud)您可以在颜色栏上添加垂直标签,方法是将其绘制在单独的轴上并在该轴上添加标题。为了说明这一点,这是Bokeh标准Colorbar示例的修改版本(在此处找到):
import numpy as np
from bokeh.plotting import figure, output_file, show
from bokeh.models import LogColorMapper, LogTicker, ColorBar
from bokeh.layouts import row
plot_height = 500
plot_width = 500
color_bar_height = plot_height + 11
color_bar_width = 180
output_file('color_bar.html')
def normal2d(X, Y, sigx=1.0, sigy=1.0, mux=0.0, muy=0.0):
z = (X-mux)**2 / sigx**2 + (Y-muy)**2 / sigy**2
return np.exp(-z/2) / (2 * np.pi * sigx * sigy)
X, Y = np.mgrid[-3:3:100j, -2:2:100j]
Z = normal2d(X, Y, 0.1, 0.2, 1.0, 1.0) + 0.1*normal2d(X, Y, 1.0, 1.0)
image = Z * 1e6
color_mapper = LogColorMapper(palette="Viridis256", low=1, high=1e7)
plot = figure(x_range=(0,1), y_range=(0,1), toolbar_location=None,
width=plot_width, height=plot_height)
plot.image(image=[image], color_mapper=color_mapper,
dh=[1.0], dw=[1.0], x=[0], y=[0])
Run Code Online (Sandbox Code Playgroud)
现在,要制作颜色栏,请创建一个单独的虚拟绘图,将颜色栏添加到虚拟绘图并将其放置在主绘图旁边。添加颜色条标签作为虚拟图的标题,并适当地居中。
color_bar = ColorBar(color_mapper=color_mapper, ticker=LogTicker(),
label_standoff=12, border_line_color=None, location=(0,0))
color_bar_plot = figure(title="My color bar title", title_location="right",
height=color_bar_height, width=color_bar_width,
toolbar_location=None, min_border=0,
outline_line_color=None)
color_bar_plot.add_layout(color_bar, 'right')
color_bar_plot.title.align="center"
color_bar_plot.title.text_font_size = '12pt'
layout = row(plot, color_bar_plot)
show(layout)
Run Code Online (Sandbox Code Playgroud)
这给出了以下输出图像:
需要注意的一件事是color_bar_width设置得足够宽,可以合并Colorbar,其轴标签和Colorbar标签。如果宽度设置太小,则会出现错误,并且不会渲染图。
从 Bokeh 开始,0.12.10没有可用于颜色条的内置标签。除了您的方法或类似的方法之外,另一种可能性是自定义扩展,尽管这同样不是微不足道的。
顺便说一句,colobar 标签似乎是一个值得考虑的合理的事情。关于它应该是简单可用的概念,如果您对所有用户进行调查,了解他们认为什么应该是简单可用的,那么将会有数千种不同的建议来确定优先顺序。正如 OSS 世界中经常发生的情况一样,可做的事情远远多于执行这些任务的人数(在本例中少于 3 个)。因此,首先会建议GitHub Issue来请求该功能,其次,如果您有能力,请自愿帮助实现它。您的贡献将很有价值并受到许多人的赞赏。
| 归档时间: |
|
| 查看次数: |
1918 次 |
| 最近记录: |