简体   繁体   English

Python Bokeh基本分组vbar-简化x轴

[英]Python Bokeh basic grouped vbar - simplify x-axis

The x-axis is unreadably cluttered for a grouped vbar plot for some very simple data, & I can't find how to fix it. 对于一些非常简单的数据,对于成组的vbar图,x轴非常混乱,而且我找不到解决方法。

The intent is to show on a single plot the # of tweets/hr over both the lifetime and last 90 days of a twitter acct. 目的是在单个图上显示Twitter帐户的生命周期和最后90天的每小时发推数。

I already have a working version for just the lifetime data which produces a suitably simple/tidy output. 我已经有一个仅适用于生存期数据的工作版本,可以产生适当的简单/整洁的输出。

For the grouped version I want show a simple ticker like the single version & use a colour legend to indicate data label for columns. 对于分组版本,我想显示一个简单的代码,例如单一版本,并使用颜色图例指示列的数据标签。

from bokeh.io import show, output_file, export_png
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource, FactorRange, Label, Title
from bokeh.transform import factor_cmap    

data = {'hours_active': {0: 11, 1: 0, 2: 0, 3: 0, 4: 0, 5: 2, 6: 15, 7: 27, 8: 75, 9: 96, 10: 205, 11: 278, 12: 241, 13: 238, 14: 236, 15: 184, 16: 232, 17: 164, 18: 211, 19: 236, 20: 197, 21: 199, 22: 253, 23: 97}, 'ninety_days_hours_active': {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 2, 6: 15, 7: 23, 8: 68, 9: 78, 10: 94, 11: 111, 12: 135, 13: 80, 14: 109, 15: 102, 16: 94, 17: 58, 18: 106, 19: 94, 20: 110, 21: 98, 22: 89, 23: 2}}

    hours = [str(i) for i in range(0, 24)]
    days =  ['all', '90']

    data = {'hours' : hours, 'all':list(data['hours_active'].values()), '90': list(data['ninety_days_hours_active'].values())}

    x = [ (str(hour), day) for hour in hours for day in days ]

    counts = sum(zip(data['all'], data['90']), ())

    colors = ['#ffff1a', '#191971']

    source = ColumnDataSource(data=dict(x=x, counts=counts))

    p = figure(x_range=FactorRange(*x), plot_width=500, plot_height=500, title="Tweets All/Last 90 Days", )

    p.toolbar_location = None
    p.xgrid.grid_line_color = None
    p.min_border = 40
    p.axis.axis_line_width = 2
    p.y_range.start = 0
    p.vbar(x='x', top='counts', width=0.9, source=source, fill_color=factor_cmap('x', palette=colors, factors=days, start=1, end=2))

    show(p)

Output from above code: 以上代码的输出:

Example with suitable x-axis 具有合适x轴的示例

I've chosen to avoid using pandas/dataframes because I want to keep the dependencies as minimal as I can & because it's another package to learn (I'm quite stupid & not a programmer); 我选择避免使用pandas / dataframes,因为我想尽量减少依赖性,因为这是另一个需要学习的软件包(我很傻,不是程序员)。 The data is a subdict of another dictionary that's being used in a bigger program. 数据是在更大程序中使用的另一个词典的替代物。

But I am not locked into the above code if there is a neater simpler way to do it. 但是,如果有一种更简洁的方法,我就不会被上述代码锁定。


UPDATE 更新

The suggestion to use dodges was just right. 使用闪避的建议是正确的。 The following code produces almost what I want, but see attached image as a couple of things are not rendering exactly as I'd wish. 下面的代码几乎产生了我想要的,但是将附件图像视为几件事并没有完全按照我的期望进行渲染。 I haven't bothered with a legend just yet. 我还没有打扰过一个传奇。

from bokeh.io import show, output_file
from bokeh.models import ColumnDataSource
from bokeh.plotting import figure
from bokeh.transform import dodge

with open('dsd_dict') as d:
    ddict = json.load(d)

hours = [str(i) for i in range(0, 24)]  # 'fruits'

data = {'hours' : hours, 'all':list(ddict['hours_active'].values()), '90': list(ddict['ninety_days_hours_active'].values()), '30': list(ddict['thirty_days_hours_active'].values())}

colors = ['#ffff1a', '#338dff', '#191971', 'firebrick']

source = ColumnDataSource(data=data)

p = figure(x_range=hours, plot_width=600, plot_height=500, title="Tweets All/Last 90/30 Days",  toolbar_location=None, tools="")

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

# X-AXIS SETTINGS #
p.xaxis[0].formatter = PrintfTickFormatter(format="%'02s")
p.xaxis.axis_label = '24 Hour Clock - UTC/GMT'
p.xaxis.axis_label_standoff = 10
p.xaxis.axis_label_text_font = 'dejavu sans'
p.xaxis.axis_label_text_font_size = '8pt'
p.xaxis.axis_label_text_color = 'black'
p.xaxis.axis_label_text_font_style = 'bold'

r = p.vbar(x=dodge('hours', 0.0, range=p.x_range), top='all', width=0.33, source=source, color=colors[0])

glyph = r.glyph
glyph.line_color = "black"
glyph.line_dash = 'solid'
glyph.line_width = 0.1

p.vbar(x=dodge('hours', 0.33, range=p.x_range), top='90', width=0.33, source=source, color=colors[1])

p.vbar(x=dodge('hours', 0.66, range=p.x_range), top='30', width=0.33, source=source, color=colors[3])

show(p)

Output from updated code 来自更新代码的输出

As we can see, the RHS end is crushed and doesn't show the third bar fully, and the columns don't locate vertically over the x-axis ticks clearly enough. 正如我们所看到的,RHS末端被压碎,没有完全显示出第三条,并且这些列没有足够垂直地位于x轴刻度线上。 I'd prefer them located between ticks so it's clear that the values are from (eg) 0100 - 0200. 我希望它们位于刻度之间,因此很明显值是(例如)0100-0200。

I'm guessing I just need to look into how to tweak the offsets for that, but any further pointers would be most welcome 我想我只需要研究如何调整偏移量,但是任何进一步的指针都是最欢迎的

One option would be to rotate the tick labels: 一种选择是旋转刻度线标签:

p.xaxis.major_label_orientation = "vertical" # or value in radians works too

But is sounds like you don't want the nested hierarchical axis at all. 但是听起来您根本根本不需要嵌套的层次结构轴。 In that case, you should use a Visual Dodge instead, so that there is only one level of labels on the axis. 在这种情况下,您应该改用Visual Dodge ,以便在轴上只有一层标签。 Here is a complete example: 这是一个完整的示例:

from bokeh.core.properties import value
from bokeh.io import show, output_file
from bokeh.models import ColumnDataSource
from bokeh.plotting import figure
from bokeh.transform import dodge

fruits = ['Apples', 'Pears', 'Nectarines', 'Plums', 'Grapes', 'Strawberries']
years = ['2015', '2016', '2017']

data = {'fruits' : fruits,
        '2015'   : [2, 1, 4, 3, 2, 4],
        '2016'   : [5, 3, 3, 2, 4, 6],
        '2017'   : [3, 2, 4, 4, 5, 3]}

source = ColumnDataSource(data=data)

p = figure(x_range=fruits, y_range=(0, 10), plot_height=250, title="Fruit Counts by Year",
           toolbar_location=None, tools="")

p.vbar(x=dodge('fruits', -0.25, range=p.x_range), top='2015', width=0.2, source=source,
       color="#c9d9d3", legend=value("2015"))

p.vbar(x=dodge('fruits',  0.0,  range=p.x_range), top='2016', width=0.2, source=source,
       color="#718dbf", legend=value("2016"))

p.vbar(x=dodge('fruits',  0.25, range=p.x_range), top='2017', width=0.2, source=source,
       color="#e84d60", legend=value("2017"))

p.x_range.range_padding = 0.1
p.xgrid.grid_line_color = None
p.legend.location = "top_left"
p.legend.orientation = "horizontal"

show(p)

在此处输入图片说明

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

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