简体   繁体   中英

Multiline axis label with CategoricalAxis in Bokeh?

I'm working on a Bokeh plot, and have got it almost the way I want it. However, I'm struggling with adding multi-line axis labels.

Here's what I have so far:

import bokeh.io
from bokeh.plotting import gridplot, figure, output_file, show, output_notebook
from bokeh.models import ColumnDataSource, BoxAnnotation, CategoricalAxis, FactorRange
from bokeh.embed import components

x = ['label1','label2','label3','label4','label5','label6','label7', 'Trying for a multiline label']
y = [1.0, 2.7, 1.2, 4.5, 1.5, 2.2, 1.8, 4.6]
p = figure(x_range=[*x], y_range=(0, 5), plot_height=400, plot_width=550)
dots = p.circle(x=x, y=y, color='black',size=10)
line = p.line(x=x, y=y, color='black')

numbers = [str(x) for x in y]
p.extra_x_ranges = {"extra_numbers": FactorRange(factors=numbers)}
p.add_layout(CategoricalAxis(x_range_name="extra_numbers"), 'below')
p.title.text = 'Plot'
p.title.text_font_size = "25px"
p.title.text_color = "black"
p.title.align = "center"

low_box = BoxAnnotation(top=2, fill_alpha=0.1, fill_color='green')
mid_box = BoxAnnotation(bottom=2, top=3, fill_alpha=0.1, fill_color='orange')
high_box = BoxAnnotation(bottom=3, fill_alpha=0.1, fill_color='red')

p.add_layout(low_box)
p.add_layout(mid_box)
p.add_layout(high_box)

show(p)

The above code yields the following plot: 在此处输入图像描述

You can clearly see that the last label didn't wrap properly, and I have not managed to figure our how to make it wrap and create a multi-line axis label. Is there an easy way to do this? The best alternative solution I came up with was trying to use vertical labels, but as you can see, they don't look very nice, and mess up the second axis below the text:

from bokeh.models import CategoricalAxis, FactorRange
from bokeh.plotting import figure, show
from math import pi

x = ['label1','label2','label3','label4','label5','label6','label7', 'Trying for a multiline label']
y = [1.0, 2.7, 1.2, 4.5, 1.5, 2.2, 1.8, 4.6]
p = figure(x_range=[*x], y_range=(0, 5), plot_height=900)
dots = p.circle(x=x, y=y, color='black',size=10)
line = p.line(x=x, y=y, color='black')
p.xaxis.major_label_orientation = pi/2
p.xaxis.major_label_text_font_size = "1.4em"

p.xaxis.axis_line_width = 2
p.yaxis.axis_line_width = 2
numbers = [str(x) for x in y]
p.extra_x_ranges = {"extra_numbers": FactorRange(factors=numbers)}
p.add_layout(CategoricalAxis(x_range_name="extra_numbers"), 'below')
show(p)

Now the graph looks like this: 在此处输入图像描述

An easy fix is, of course, switching the order of the axes so that the numbers are on top and the labels are below; however, that is still a haphazard solution, and isn't really what I'm going for. I would really like text wrapping in the label. For instance, the plot below is similar to what I want to accomplish (the code for this non-Bokeh graph below can be found here ). 在此处输入图像描述

Any help or advice would be greatly appreciated!

Multiline labels are not possible with the stock Bokeh axes models. In order to achieve this, you'd have to create a custom Axis subclass and manage all the wrapping yourself because canvas context doesn't support it in any way.

As an alternative, you can try angled labels. A downside of such approach is having to figure out the right offsets of the plot to make sure that the labels are not cut off.

Multi-line labels have been working in bokeh since the past couple of releases (Since 3.3, I believe). You need to add new line characters '\n' yourself in appropriate locations in the label strings.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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