简体   繁体   English

当散景条图上的缩放级别变化时,是否可以保持相同数量的x轴刻度标签可见?

[英]Is it possible to keep the same amount of x axis tick labels visible as the zoom level changes on a bokeh bar plot?

I'm using Django and generating a bokeh bar plot using data from a database. 我正在使用Django并使用数据库中的数据生成散景条图。 I've put a basic code example below. 我在下面放了一个基本代码示例。 I'm generating x axis tick labels from a datetime variable to get a tick at every hour with a datetime formatted string. 我正在从datetime变量生成x轴刻度标签,以便在每小时使用日期时间格式化的字符串进行刻度。 This causes all the tick label to be visible all the time. 这会导致所有刻度标签始终可见。 It's fine when zoomed in but not pretty when zoomed out because the labels are on top of each other. 放大时很好但缩小时不漂亮,因为标签位于彼此之上。

Is there a way to make bokeh automatically adjust which tick labels are visible as the zoom level changes to keep a constant amount of ticks labels visible ? 有没有办法让散景自动调整哪些刻度标签可见,因为缩放级别变化以保持恒定数量的刻度标签可见?

views.py : views.py:

# -*- coding: utf-8 -*-
from django.shortcuts import render

from bokeh.plotting import *
from bokeh.resources import CDN
from bokeh.embed import components
from bokeh.charts import Bar
from bokeh.models import Range1d

from collections import OrderedDict
import datetime

def plot_1_bar(data, y, y_lab, title, xlab, ylab, yrange, palette):
    x0_list_str = []

    y_list = []

    # x_axis_type == "datetime":
    i_x = 'x1'
    i_y = y[0]
    for idx, val in enumerate(data):
        x0_list_str.append(val[i_x].strftime("%Y-%m-%d %H h"))
        y_list.append(val[i_y])

    data_x = x0_list_str    
    data_y = OrderedDict()
    data_y[y_lab[0]] = y_list

    plot = Bar(data_y, data_x, title=title, xlabel=xlab, 
               ylabel=ylab, stacked=True, continuous_range=yrange, 
               palette=palette, legend=True, height=400)
    return components(plot, CDN)

def plot1(request):

    script_bokeh = ""
    div_bokeh = ""

    data = []
    data.append({'x1': datetime.datetime(2015,1,1,8,0,0,0),'y1': 0})
    data.append({'x1': datetime.datetime(2015,1,1,9,0,0,0),'y1': 0})
    data.append({'x1': datetime.datetime(2015,1,1,10,0,0,0),'y1': 0})
    data.append({'x1': datetime.datetime(2015,1,1,11,0,0,0),'y1': 0})
    data.append({'x1': datetime.datetime(2015,1,1,12,0,0,0),'y1':8})
    data.append({'x1': datetime.datetime(2015,1,1,13,0,0,0),'y1':12})
    data.append({'x1': datetime.datetime(2015,1,1,14,0,0,0),'y1':0})
    data.append({'x1': datetime.datetime(2015,1,1,15,0,0,0),'y1':0})
    data.append({'x1': datetime.datetime(2015,1,1,16,0,0,0),'y1':0})
    data.append({'x1': datetime.datetime(2015,1,1,17,0,0,0),'y1':0})
    data.append({'x1': datetime.datetime(2015,1,1,18,0,0,0),'y1':2})
    data.append({'x1': datetime.datetime(2015,1,1,19,0,0,0),'y1':6})
    data.append({'x1': datetime.datetime(2015,1,1,20,0,0,0),'y1':4})
    data.append({'x1': datetime.datetime(2015,1,1,21,0,0,0),'y1':22})
    data.append({'x1': datetime.datetime(2015,1,1,22,0,0,0),'y1':36})
    data.append({'x1': datetime.datetime(2015,1,1,23,0,0,0),'y1':32})
    data.append({'x1': datetime.datetime(2015,1,2,0,0,0,0),'y1':21})
    data.append({'x1': datetime.datetime(2015,1,2,1,0,0,0),'y1':15})
    data.append({'x1': datetime.datetime(2015,1,2,2,0,0,0),'y1':4})
    data.append({'x1': datetime.datetime(2015,1,2,3,0,0,0),'y1':0})
    data.append({'x1': datetime.datetime(2015,1,2,4,0,0,0),'y1':0})
    data.append({'x1': datetime.datetime(2015,1,2,5,0,0,0),'y1':0})
    data.append({'x1': datetime.datetime(2015,1,2,6,0,0,0),'y1':45})
    data.append({'x1': datetime.datetime(2015,1,2,7,0,0,0),'y1':47})
    data.append({'x1': datetime.datetime(2015,1,2,8,0,0,0),'y1':52})
    data.append({'x1': datetime.datetime(2015,1,2,9,0,0,0),'y1':44})
    data.append({'x1': datetime.datetime(2015,1,2,10,0,0,0),'y1':0})
    data.append({'x1': datetime.datetime(2015,1,2,11,0,0,0),'y1':0})
    data.append({'x1': datetime.datetime(2015,1,2,12,0,0,0),'y1':0})
    data.append({'x1': datetime.datetime(2015,1,2,13,0,0,0),'y1':0})

    script_bokeh, div_bokeh = plot_1_bar(data, 
                                         ['y1'],
                                         ['y legend label'],
                                         "",
                                         'x label',
                                         'y label',
                                         Range1d(0, 70),
                                         ['red'])

    return render(request, 
                  'tests/plot1.html', 
                  {'script_bokeh': script_bokeh, 
                   'div_bokeh': div_bokeh})

plot1.html : plot1.html:

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>bokeh bar plot</title>
        <link rel="stylesheet" type="text/css" href="/static/tests/css/bokeh-0.9.2.min.css" />
        <script src="/static/tests/js/bokeh-0.9.2.min.js" type="text/javascript"></script>
    </head>
    <body>
        <h1>Bokeh bar plot</h1>
        <div id="div_graph">{{div_bokeh|safe}}{{script_bokeh|safe}}</div>
    </body>
</html>

x轴放大了

x轴缩小

First off, the bokeh.charts API, including Bar , was deprecated and removed in 2017 and should not be used. 首先, bokeh.charts API(包括Bar在2017年已弃用并删除,不应使用。 The stable and supported bokeh.plotting API can now be used to create many kinds of categorical and bar charts, and is more capable than bokeh.charts ever was. 稳定且受支持的bokeh.plotting API现在可用于创建多种分类和条形图,并且比bokeh.charts更强大。 See the User's Guide chapter Handling Categorical Data for many live examples with complete code 有关完整代码的许多实际示例,请参阅“用户指南”一章中的处理分类数据


There is no built in ticker that can be configured to do this, and there is not any CustomJSTicker (yet) either So, for now to do something like this you will have to resort to a custom extension . 没有内置的自动收报机可以配置为执行此操作,并且没有任何CustomJSTicker (尚未)所以,现在要做这样的事情,你将不得不求助于自定义扩展 Additionally, you will need CustomJS callbacks on the range, that set configure the custom ticker based on the policy that you want. 此外,您将需要该范围上的CustomJS回调,该组根据您所需的策略配置自定义代码。 Here is a complete script that shows one possible way (this code is tested with Bokeh 0.12.16 ): 这是一个完整的脚本,显示了一种可能的方法(此代码使用Bokeh 0.12.16进行测试):

from bokeh.core.properties import Int
from bokeh.models import  CategoricalTicker, CustomJS
from bokeh.io import show
from bokeh.plotting import figure

class MyTicker(CategoricalTicker):
    __implementation__ = """
    import {CategoricalTicker} from "models/tickers/categorical_ticker"
    import * as p from "core/properties"

    export class MyTicker extends CategoricalTicker
      type: "MyTicker"

      @define {
        nth: [ p.Int, 1 ]
      }

      get_ticks: (start, end, range, cross_loc) ->
        ticks = super(start, end, range, cross_loc)
        ticks.major = ticks.major.filter((element, index) => index % this.nth == 0)
        return ticks

    """

    nth = Int(default=1)

fruits = ['Apples', 'Pears', 'Nectarines', 'Plums', 'Grapes', 'Strawberries']

p = figure(x_range=fruits, plot_height=250, title="Fruit Counts",
           tools="xwheel_zoom")

p.vbar(x=fruits, top=[5, 3, 4, 2, 4, 6], width=0.9)

p.xgrid.grid_line_color = None
p.y_range.start = 0

p.xaxis.ticker = MyTicker(nth=1)

cb = CustomJS(args=dict(ticker=p.xaxis[0].ticker), code="""
    if (Math.abs(cb_obj.start-cb_obj.end) > 8) {
        ticker.nth = 2
    } else {
        ticker.nth = 1
    }
""")
p.x_range.js_on_change('start', cb)
p.x_range.js_on_change('end', cb)

show(p)

在此输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM