How do I get a full-height vertical line with a legend label in holoviews + bokeh?

戏子无情 提交于 2020-01-24 14:45:29

问题


I want to plot a vertical line in holoviews with the bokeh backend which has a label that shows up in my legend. I need this line to be the full height of the plot, regardless of whether it is alone or overlaid with other elements. How can I achieve this?

Example

I'm adding in a curve plot in the example because otherwise even elements that can appear in a legend just use their label as a title.

import numpy as np
import holoviews as hv
hv.extension("bokeh")

x = np.linspace(0, 1)
curve = hv.Curve((x, np.sin(x)), label="sin(x)")
vline = hv.VLine(0.5, label="vline")
curve * vline

This gives the following plot:

which has no label for the vertical line. How do I get the label to show up?


回答1:


As mentioned in this issue but not yet in the docs, VLine and HLine don't appear in legends, and there is no plan to add support for them (basically, in bokeh they're created differently, so there's not an easy way to put them in the legend). One can use Spikes instead. However, as documented in another issue, spikes don't overlay well. In particular, they don't adjust their height to be the full height of the plot if given no explicit height. Here are two workarounds that I've come up with.

Workaround 1

You can explicitly find out the height of the other element that the vertical line should be overlaid with and use this to create a spike of the proper height. This works, but it's rather brittle because you need to adapt it with full knowledge of everything that could be overlaid with the spike.

import numpy as np
import holoviews as hv
hv.extension("bokeh")

x = np.linspace(0, 1)
curve = hv.Curve((x, np.sin(x)), label="sin(x)")
height = curve.data["y"].max() - curve.data["y"].min()
spikes = hv.Spikes(([0.5], [height]), vdims="height", label="mid")
spikes * curve

Workaround 2

This uses both a VLine and a Spikes. The spike won't be visible except that it will contribute an entry to the legend. The vline will be on top of the spike, and vlines already adjust themselves to fill the whole height of the figure. This requires creating an extra element, but it is more robust because you can overlay the product of this spike and vline with any other elements and still get a line that fills the height of the plot and appears in the legend. As the legend entry is based on the spike, though, it will only look like the vline if you make sure that they have a similar appearance (e.g. the vline and the spike have the same color).

# need to make sure the colors are the same for spikes/vlines
# would look a bit better if I adjusted the spike thickness too
spikes = hv.Spikes([0.5], label="mid").opts(color="black")
vline = hv.VLine(0.5).opts(color="black")

spikes * curve * vline

In the future, Spikes will hopefully scale themselves to be full-height when not explicitly given a height, and then these workarounds won't be needed.



来源:https://stackoverflow.com/questions/55050557/how-do-i-get-a-full-height-vertical-line-with-a-legend-label-in-holoviews-boke

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!