Holoviews(散景)图的辅助轴

Bra*_*wed 5 plot axis python-3.x bokeh holoviews

我试图绘制一组图形,上面覆盖着一个显示它们之间百分比差异的图。

我用于绘图的代码:

%%output size = 200
%%opts Curve[height=200, width=400,show_grid=True,tools=['hover','box_select'], xrotation=90]
%%opts Curve(line_width=1)


from bokeh.models import Range1d, LinearAxis

new_df = new_df.astype('float')
percent_diff_df = percent_diff_df.astype('float')

def twinx(plot, element):
    # Setting the second y axis range name and range
    start, end = (element.range(1))
    label = element.dimensions()[1].pprint_label
    plot.state.extra_y_ranges = {"foo": Range1d(start=0, end=150)}
    # Adding the second axis to the plot. 
    linaxis = LinearAxis(axis_label='% Difference', y_range_name='foo')
    plot.state.add_layout(linaxis, 'right')

wavelength = hv.Dimension('wavelength', label = 'Wavelength', unit = 'nm')
radiance = hv.Dimension('radiance', label = 'Radiance', unit = 'W/m^2/sr/nm')
curve = hv.Curve((new_df['Wave'], new_df['Level_9']), wavelength, radiance,label = 'Level_9', group = 'Requirements')*\
    hv.Curve((new_df['gcal_wave'],new_df['gcal_9']),wavelength, radiance,label = 'GCAL_9', group = 'Requirements')
curve2 = hv.Curve((percent_diff_df['pdiff_wave'],percent_diff_df['pdiff_9']), label = '% Difference', group = 'Percentage Difference').opts(plot=dict(finalize_hooks=[twinx]), style=dict(color='purple'))
curve * curve2
Run Code Online (Sandbox Code Playgroud)

结果如下所示: 在此处输入图片说明

扁平的蓝色图表实际上应该是这样的: 在此处输入图片说明

我需要在两个尺度上绘制这两个图。我似乎能够添加一个比例,但不能将任何图附加到比例上。

Ada*_*sky 5

您的解决方案几乎完成。要实际使用您在钩子中创建的范围和轴,您需要访问底层散景字形并设置其 y_range_name。

一般示例如下所示:

import pandas as pd
import holoviews as hv
from bokeh.models.renderers import GlyphRenderer

hv.extension('bokeh')

def apply_formatter(plot, element):

    p = plot.state

    # create secondary range and axis
    p.extra_y_ranges = {"twiny": Range1d(start=0, end=35)}
    p.add_layout(LinearAxis(y_range_name="twiny"), 'right')

    # set glyph y_range_name to the one we've just created
    glyph = p.select(dict(type=GlyphRenderer))[0]
    glyph.y_range_name = 'twiny'

dts = pd.date_range('2015-01-01', end='2015-01-10').values

c_def = hv.Curve((dts, np.arange(10)), name='default_axis').options(color='red', width=300)
c_sec = hv.Curve((dts, np.arange(10)), name='secondary_axis').options(color='blue',width=300, hooks=[apply_formatter])
c_def + c_def * c_sec + c_sec
Run Code Online (Sandbox Code Playgroud)

有关更多详细信息,请参阅此处的原始 github 问题:https : //github.com/pyviz/holoviews/issues/396

已编辑 - 高级示例

自从原始问题得到回答以来已经有一段时间了,随着 github 上的线程的进展,我想交叉发布一个更高级的示例,以解决原始答案中显示的一些不一致问题。我仍然鼓励您通过 github 上的线程深入了解细节,因为全息视图中的多轴图目前需要了解散景如何处理多轴。

import pandas as pd
import streamz
import streamz.dataframe
import holoviews as hv
from holoviews import opts
from holoviews.streams import Buffer
from bokeh.models import Range1d, LinearAxis

hv.extension('bokeh')

def plot_secondary(plot, element):
    ''' 
    A hook to put data on secondary axis
    '''
    p = plot.state

    # create secondary range and axis
    if 'twiny' not in [t for t in p.extra_y_ranges]:
        # you need to manually recreate primary axis to avoid weird behavior if you are going to 
        # use secondary_axis in your plots. From what i know this also relates to the way axis
        # behave in bokeh and unfortunately cannot be modified from hv unless you are 
        # willing to rewrite quite a bit of code
        p.y_range = Range1d(start=0, end=10)
        p.y_range.name = 'default'
        p.extra_y_ranges = {"twiny": Range1d(start=0, end=10)}
        p.add_layout(LinearAxis(y_range_name="twiny"), 'right')

    # set glyph y_range_name to the one we've just created
    glyph = p.renderers[-1]
    glyph.y_range_name = 'twiny'

    # set proper range
    glyph = p.renderers[-1]
    vals = glyph.data_source.data['y'] # ugly hardcoded solution, see notes below
    p.extra_y_ranges["twiny"].start = vals.min()* 0.99
    p.extra_y_ranges["twiny"].end = vals.max()* 1.01

# define two streamz random dfs to sim data for primary and secondary plots
simple_sdf = streamz.dataframe.Random(freq='10ms', interval='100ms')
secondary_sdf = streamz.dataframe.Random(freq='10ms', interval='100ms')

# do some transformation
pdf = (simple_sdf-0.5).cumsum()
sdf = (secondary_sdf-0.5).cumsum()

# create streams for holoviews from these dfs
prim_stream = Buffer(pdf.y)
sec_stream = Buffer(sdf.y)

# create dynamic maps to plot streaming data
primary = hv.DynamicMap(hv.Curve, streams=[prim_stream]).opts(width=400, show_grid=True, framewise=True)
secondary = hv.DynamicMap(hv.Curve, streams=[sec_stream]).opts(width=400, color='red', show_grid=True, framewise=True, hooks=[plot_secondary])
secondary_2 = hv.DynamicMap(hv.Curve, streams=[prim_stream]).opts(width=400, color='yellow', show_grid=True, framewise=True, hooks=[plot_secondary])

# plot these maps on the same figure
primary * secondary * secondary_2
Run Code Online (Sandbox Code Playgroud)