簡體   English   中英

具有多個繪圖的 Bokeh HoverTool

[英]Bokeh HoverTool with multiple plots

我嘗試使用散景制作儀表板,但我的 hover 工具壞了,因為我嘗試在單個圖表中對數據進行 plot。 我找到了這個問題的一些答案,但不幸的是我無法適應我的代碼。 我希望能夠關閉和打開數據的可見性。 (另一個問題是,整個 plot 消失了,如果您將日期范圍更改為不存在值的區域,也許有人對此有解決方法。在舊版本中,當范圍在數據上時,我嘗試僅更改源發射,但這會導致其他問題。也許有人對此也有想法。)這是我的代碼的簡化最小工作版本:

import pandas as pd
import numpy as np
from datetime import datetime

from bokeh.models import Button, CheckboxGroup, ColumnDataSource, CustomJS, DatetimeTickFormatter, HoverTool
from bokeh.models.widgets import DateRangeSlider
from bokeh.layouts import layout, column, row
from bokeh.palettes import Category20
from bokeh.plotting import figure, output_file, show

datesX = pd.date_range(start='1/1/2018', periods=100) #incl. '2018-01-01' to '2018-04-10'
numbof = 3
datesX = datesX[0:10].union(datesX[20:100])
valuesY = pd.DataFrame(np.random.randint(0,25,size=(90, numbof)), columns=list((f'V{i}' for i in range(numbof))))
movingY = pd.DataFrame(np.random.randint(0,10,size=(90, numbof)), columns=list((f'M{i}' for i in range(numbof))))

preCDS ={}

for i in range(numbof):
    preCDS.update({f'x{i}': datesX})
    preCDS.update({f'y{i}': valuesY[f'V{i}']})
    preCDS.update({f'm{i}': movingY[f'M{i}']})
    
source = ColumnDataSource(preCDS) 
source2 = ColumnDataSource(preCDS)

# output to static HTML file
output_file('file.html')

# create a new plot with a title and axis labels
p = figure(
    title='file1', x_axis_label='Date', y_axis_label='yValue',
    y_range=(0, 30), x_axis_type='datetime',
    tools="pan, wheel_zoom, box_zoom, reset, save",
    plot_width=1800, plot_height=480)

ypsilon = [f'y{i}' for i in range(numbof)]
em = [f'm{i}' for i in range(numbof)]

hover = HoverTool(line_policy='nearest', names=ypsilon + em,
    tooltips=[('Timestamp', '@x{%Y-%m-%d %H:%M:%S}'), ('Wert', '@y')], ###what to do with @x and @y to make it iterable: x0, x1, x2, y0, ...
    formatters={'@x': 'datetime'})

p.add_tools(hover)

date_range_slider = DateRangeSlider(
    title="DateRange", start=datesX[0], end=datesX[89],
    value=(datesX[0], datesX[89]), width=800, bar_color = (32,120,180))

checkbox_vals = CheckboxGroup(labels=[f'Plot {i+1}' for i in range(numbof)], active=[i for i in range(numbof)])
checkbox_mova = CheckboxGroup(labels=[f'Plot {i+1}' for i in range(numbof)], active=[i for i in range(numbof)])

vals=[]
mova=[]

for i in range(numbof):
    vals.append(p.circle(x=f'x{i}', y=f'y{i}', source=source, color = Category20[20][2*i], size=3, name=f'y{i}'))
    mova.append(p.line(x=f'x{i}', y=f'm{i}', source=source, line_color = Category20[20][2*i+1], line_width=2, name=f'm{i}'))


rangeCallback = CustomJS(args=dict(source=source, ref_source=source2, dRs=date_range_slider), code="""
        
    // print out array of date from, date to
    //console.log(dRs.value); 

    // dates returned from slider are not at round intervals and include time
    const date_from = Date.parse(new Date(dRs.value[0]).toDateString());
    const date_to = Date.parse(new Date(dRs.value[1]).toDateString());
    //console.log(date_from, date_to)

    // Creating the Data Sources
    const data = source.data;
    const ref = ref_source.data;

    for (const [key, value] of Object.entries(data)) {
        console.log(key)
        // Creating new Array and appending correctly parsed dates
        if(key.indexOf("x") == 0){
            let new_ref = [];
            let from_pos = [];
            let to_pos = [];
            
            ref[key].forEach(elem => {
                elem = Date.parse(new Date(elem).toDateString()); 
                new_ref.push(elem);
            })
            
            // Creating Indices with new Array
            from_pos[key] = new_ref.indexOf(date_from);
            to_pos[key] = new_ref.indexOf(date_to) + 1;

            // re-create the source data from "reference"
            const dataKeyM = key.replace('x', 'm');
            const dataKeyY = key.replace('x', 'y');
            
            data[dataKeyM] = ref[dataKeyM].slice(from_pos[key], to_pos[key]);
            data[key] = ref[key].slice(from_pos[key], to_pos[key]);
            data[dataKeyY] = ref[dataKeyY].slice(from_pos[key], to_pos[key]);
        }
    }
    /*if (new_ref.includes(date_from) && new_ref.includes(date_to)) {
        source.change.emit();
    }*/
    source.change.emit();  
    
    """)

checkboxValsCallback = CustomJS(args=dict(vals=vals, checkboxVals=checkbox_vals), code="""

    var indexOf = [].indexOf || function(item) { 
        for (var i = 0, l = this.length; i < l; i++) { 
            if (i in this && this[i] === item) 
                return i; 
            } 
        return -1; 
    };
    
    //vals.visible = indexOf.call(checkboxVals.active,0)>=0;
    for (let i=0;i<vals.length;i++) {
        vals[i].visible = indexOf.call(checkboxVals.active,i)>=0;
    }
    
    """)

checkboxMovaCallback = CustomJS(args=dict(mova=mova, checkboxMova=checkbox_mova), code="""

    var indexOf = [].indexOf || function(item) { 
        for (var i = 0, l = this.length; i < l; i++) { 
            if (i in this && this[i] === item) 
                return i; 
            } 
        return -1; 
    };
    
    //mova.visible = indexOf.call(checkboxMova.active,0)>=0;
    for (let i=0;i<mova.length;i++) {
        mova[i].visible = indexOf.call(checkboxMova.active,i)>=0;
    }
    
    """)

checkbox_vals.js_on_change('active', checkboxValsCallback)
checkbox_mova.js_on_change('active', checkboxMovaCallback)
date_range_slider.js_on_change('value', rangeCallback)

b1 = Button(label="select all", max_width = 300, button_type="primary")
b1.js_on_click(CustomJS(args=dict(s=checkbox_vals, t=checkbox_mova), code="""
    s.active = [0,1,2]
    t.active = [0,1,2]
    """))

b2 = Button(label="unselect all", max_width = 300)
b2.js_on_click(CustomJS(args=dict(s=checkbox_vals, t=checkbox_mova), code="""
    s.active = []
    t.active = []
    """))

layout = column(p, row(checkbox_vals, checkbox_mova, date_range_slider), row(b1, b2))
show(layout)

先感謝您。

對於工具提示:您為 hover 指定了xy ,但是當您查看存儲在mova中的行字形的數據源時,您會看到沒有xy ,但有許多不同的字段。 我將工具提示更改為x1y0 ,但我不確定這是否是您想要的。 只需在某處放置一個斷點並查看例如在mova[0].data_source.data ,您將看到所有可用字段並為工具提示選擇您想要的字段。

hover = HoverTool(line_policy='nearest', names=ypsilon + em,
                  tooltips=[('Timestamp', '@x1{%Y-%m-%d %H:%M:%S}'), ('Wert', '@y0')],
                  formatters={'@x1': 'datetime'})

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM