如何正确处理 bokeh/holoviews 热图中的日期时间和分类轴?
How to properly handle datetime and categorical axes in bokeh/holoviews heatmap plot?
我正在尝试使用 bokeh/holoviews 绘制一个简单的热图。我的数据(pandas 数据框)有分类(在 y 上)和日期时间(在 x 上)。问题是分类元素的数量 > 3000,并且生成的图在 y 轴上出现混乱的重叠代码,这使得它完全无用。目前,在散景中是否有可靠的方法 select 仅基于缩放级别的代码子集?
我已经尝试过 plotly,结果看起来很完美,但是我需要使用 bokeh/holoviews 和数据着色器。我还想避免用数字代号代替分类。
我也试过这个 但实际上它不起作用 (bokeh 1.2.0)。
这是一个代表我的用例的玩具示例(实际上这里 #y 是 1000,但它给出了想法)
from datetime import datetime
import pandas as pd
import numpy as np
from bokeh.plotting import figure, show
from bokeh.transform import linear_cmap
from bokeh.io import output_notebook
output_notebook()
# build sample data
index = pd.date_range(start='1/1/2019', periods=1000, freq='T')
data = np.random.rand(1000,100)
columns = ['col'+ str(n) for n in range(100)]
# initial data format
df = pd.DataFrame(data=data, index=index, columns=columns)
# bokeh
df = df.stack().reset_index()
df.rename(columns={'level_0':'x','level_1':'y', 0:'z'},inplace=True)
df.sort_values(by=['y'],inplace=True)
x = [
date.to_datetime64().astype('M8[ms]').astype('O')
for date in df.x.to_list()
]
data = {
'value': df.z.to_list(),
'x': x,
'y': df.y.to_list(),
'date' : df.x.to_list()
}
p = figure(x_axis_type='datetime', y_range=columns, width=900, tooltips=[("x", "@date"), ("y", "@y"), ("value", "@value")])
p.rect(x='x', y='y', width=60*1000, height=1, line_color=None,
fill_color=linear_cmap('value', 'Viridis256', low=df.z.min(), high=df.z.max()), source=data)
show(p)
最后,我部分遵循了 James 的建议,并设法使用 python 代码回调使其正常工作。这个解决方案对我来说很难找到。我真的搜索了好几天所有的 Bokeh 文档、示例和源代码。
我的主要问题是文档中没有提到如何在自定义回调中使用 "ColumnDataSource" 对象。
最后,这帮了大忙:
所以,我将原代码修改如下,希望对大家有用:
from datetime import datetime
import pandas as pd
import numpy as np
from bokeh.plotting import figure, show
from bokeh.transform import linear_cmap
from bokeh.io import output_notebook
from bokeh.models import FuncTickFormatter
from bokeh.models import ColumnDataSource
output_notebook()
# build sample data
index = pd.date_range(start='1/1/2019', periods=1000, freq='T')
data = np.random.rand(1000,100)
columns_labels = ['col'+ str(n) for n in range(100)]
columns = [n for n in range(100)]
# initial data format
df = pd.DataFrame(data=data, index=index, columns=columns)
# bokeh
df = df.stack().reset_index()
df.rename(columns={'level_0':'x','level_1':'y', 0:'z'},inplace=True)
df.sort_values(by=['y'],inplace=True)
x = [
date.to_datetime64().astype('M8[ms]').astype('O')
for date in df.x.to_list()
]
data = {
'value': df.z.to_list(),
'x': x,
'y': df.y.to_list(),
'y_labels_tooltip' : [columns_labels[k] for k in df.y.to_list()],
'y_ticks' : columns_labels*1000,
'date' : df.x.to_list()
}
cd = ColumnDataSource(data=data)
def ticker(source=cd):
labels = source.data['y_ticks']
return "{}".format(labels[tick])
#p = figure(x_axis_type='datetime', y_range=columns, width=900, tooltips=[("x", "@date{%F %T}"), ("y", "@y_labels"), ("value", "@value")])
p = figure(x_axis_type='datetime', width=900, tooltips=[("x", "@date{%F %T}"), ("y", "@y_labels_tooltip"), ("value", "@value")])
p.rect(x='x', y='y', width=60*1000, height=1, line_color=None,
fill_color=linear_cmap('value', 'Viridis256', low=df.z.min(), high=df.z.max()), source=cd)
p.hover.formatters = {'date': 'datetime'}
p.yaxis.formatter = FuncTickFormatter.from_py_func(ticker)
p.yaxis[0].ticker.desired_num_ticks = 20
show(p)
结果是这样的:
我正在尝试使用 bokeh/holoviews 绘制一个简单的热图。我的数据(pandas 数据框)有分类(在 y 上)和日期时间(在 x 上)。问题是分类元素的数量 > 3000,并且生成的图在 y 轴上出现混乱的重叠代码,这使得它完全无用。目前,在散景中是否有可靠的方法 select 仅基于缩放级别的代码子集?
我已经尝试过 plotly,结果看起来很完美,但是我需要使用 bokeh/holoviews 和数据着色器。我还想避免用数字代号代替分类。
我也试过这个
这是一个代表我的用例的玩具示例(实际上这里 #y 是 1000,但它给出了想法)
from datetime import datetime
import pandas as pd
import numpy as np
from bokeh.plotting import figure, show
from bokeh.transform import linear_cmap
from bokeh.io import output_notebook
output_notebook()
# build sample data
index = pd.date_range(start='1/1/2019', periods=1000, freq='T')
data = np.random.rand(1000,100)
columns = ['col'+ str(n) for n in range(100)]
# initial data format
df = pd.DataFrame(data=data, index=index, columns=columns)
# bokeh
df = df.stack().reset_index()
df.rename(columns={'level_0':'x','level_1':'y', 0:'z'},inplace=True)
df.sort_values(by=['y'],inplace=True)
x = [
date.to_datetime64().astype('M8[ms]').astype('O')
for date in df.x.to_list()
]
data = {
'value': df.z.to_list(),
'x': x,
'y': df.y.to_list(),
'date' : df.x.to_list()
}
p = figure(x_axis_type='datetime', y_range=columns, width=900, tooltips=[("x", "@date"), ("y", "@y"), ("value", "@value")])
p.rect(x='x', y='y', width=60*1000, height=1, line_color=None,
fill_color=linear_cmap('value', 'Viridis256', low=df.z.min(), high=df.z.max()), source=data)
show(p)
最后,我部分遵循了 James 的建议,并设法使用 python 代码回调使其正常工作。这个解决方案对我来说很难找到。我真的搜索了好几天所有的 Bokeh 文档、示例和源代码。
我的主要问题是文档中没有提到如何在自定义回调中使用 "ColumnDataSource" 对象。
最后,这帮了大忙:
所以,我将原代码修改如下,希望对大家有用:
from datetime import datetime
import pandas as pd
import numpy as np
from bokeh.plotting import figure, show
from bokeh.transform import linear_cmap
from bokeh.io import output_notebook
from bokeh.models import FuncTickFormatter
from bokeh.models import ColumnDataSource
output_notebook()
# build sample data
index = pd.date_range(start='1/1/2019', periods=1000, freq='T')
data = np.random.rand(1000,100)
columns_labels = ['col'+ str(n) for n in range(100)]
columns = [n for n in range(100)]
# initial data format
df = pd.DataFrame(data=data, index=index, columns=columns)
# bokeh
df = df.stack().reset_index()
df.rename(columns={'level_0':'x','level_1':'y', 0:'z'},inplace=True)
df.sort_values(by=['y'],inplace=True)
x = [
date.to_datetime64().astype('M8[ms]').astype('O')
for date in df.x.to_list()
]
data = {
'value': df.z.to_list(),
'x': x,
'y': df.y.to_list(),
'y_labels_tooltip' : [columns_labels[k] for k in df.y.to_list()],
'y_ticks' : columns_labels*1000,
'date' : df.x.to_list()
}
cd = ColumnDataSource(data=data)
def ticker(source=cd):
labels = source.data['y_ticks']
return "{}".format(labels[tick])
#p = figure(x_axis_type='datetime', y_range=columns, width=900, tooltips=[("x", "@date{%F %T}"), ("y", "@y_labels"), ("value", "@value")])
p = figure(x_axis_type='datetime', width=900, tooltips=[("x", "@date{%F %T}"), ("y", "@y_labels_tooltip"), ("value", "@value")])
p.rect(x='x', y='y', width=60*1000, height=1, line_color=None,
fill_color=linear_cmap('value', 'Viridis256', low=df.z.min(), high=df.z.max()), source=cd)
p.hover.formatters = {'date': 'datetime'}
p.yaxis.formatter = FuncTickFormatter.from_py_func(ticker)
p.yaxis[0].ticker.desired_num_ticks = 20
show(p)
结果是这样的: