Инструмент наведения мыши не отображает всплывающую подсказку, когда он связан с сегментными глифами - PullRequest
0 голосов
/ 14 марта 2019

Я проверил много ответов на подобные вопросы, но ни один не связан.Для меня инструмент наведения включен, но независимо от того, как далеко я масштабируюсь, чтобы изолировать элемент от всех остальных (без наложения), подсказка никогда не отображается.Теперь я работаю над другим приложением, использующим глиф сегмента, но line_width = 12 (x), и когда масштаб увеличивается, сегмент расширяется (y), и в конце концов появляется подсказка.Там, где это не работает, line_width = 1 (много данных), сегмент представляет собой горизонтальную линию (то же значение y для y0, y1).Я думал, что это может быть связано с слишком маленькой линией line_width.Но даже если его значение очень велико (20), увеличивать и устранять все перекрытия, подсказка не отображается.Вот мой тестовый код:

from bokeh.io import output_file
from bokeh.models.ranges import Range1d
from bokeh.models import ColumnDataSource
from bokeh.plotting import figure, show
from bokeh.models.tools import HoverTool
import random

def build_test_data(dataSeries2gen, count2gen, series2gen):
    # test data
    vectorSeries = []
    if dataSeries2gen == "horizontal":
        # gen random seed numbers for X and Y but always use same Y
        for nSeries in range(0, series2gen):
            sameY = [random.randint(1, 4000) for y in range(4000)]
            randX1 = [random.randint(1, 51200) for x in range(51200)]
            randX2 = [random.randint(1, 51200) for x in range(51200)]
            nextSeries = []
            for nextSeed in range(1, count2gen):
                yIdx = random.randint(1, 3999)
                xIdx = random.randint(1, 51999)
                nextSegment = [randX1[xIdx], sameY[yIdx],\ 
                               randX2[xIdx], sameY[yIdx]]
                nextSeries.append(nextSegment)
            vectorSeries.append(nextSeries)
    else:
        for nSeries in range(0, series2gen):
            randY1 = [random.randint(1, 4000) for y in range(4000)]
            randY2 = [random.randint(1, 4000) for y in range(4000)]
            randX1 = [random.randint(1, 51200) for x in range(51200)]
            randX2 = [random.randint(1, 51200) for x in range(51200)]
            nextSeries = []
            for nextSeed in range(1, count2gen):
                nextSegment = [randX1[nextSeed], randY1[nextSeed],\
                              [randX2[nextSeed], randY2[nextSeed]]
                nextSeries.append(nextSegment)
            vectorSeries.append(nextSeries)

    plot_segments_withSource(vectorSeries)

def plot_segments_withSource(theData):

    colorPalette = ["red", "green", "blue", "yellow", "orange"]

    output_file("test.html", mode='inline')
    xRange = Range1d(1, 51200)
    yRange = Range1d(1, 4000)

    p = figure(plot_width=700, plot_height=750, x_range=xRange,\
               y_range=yRange, output_backend="webgl")
    colorIdx = -1
    for nSeries in theData:
        colorIdx += 1
        color2use = colorPalette[colorIdx]
        x0 = []
        y0 = []
        x1 = []
        y1 = []
        for vPoints in nSeries:
            x0.append(vPoints[0])
            y0.append(vPoints[1])
            x1.append(vPoints[2])
            y1.append(vPoints[3])
        source = ColumnDataSource(dict(
            x0 = x0,
            y0 = y0,
            x1 = x1,
            y1 = y1
            )
        )
        p.segment(x0="01", y0="y0", x1="x1", y1="y1",\
                  line_color=color2use, source=source, line_width=1)

    # invert yAxis where 0 is at the top
    p.y_range = Range1d(4000, 0)

    hover = HoverTool()
    hover.tooltips = [("x0,y0", "$x0,$y0"),
                      ("x1,y1", "$x1,$y1")]
    hover.point_policy = "snap_to_data"
    hover.line_policy = "nearest"

    p.add_tools(hover)

    p.title.text = "This is a test"
    p.legend.location = "top_right"
    p.xaxis.axis_label = "Occurrences"
    p.yaxis.axis_label = "Time"

    show(p)

if __name__ == "__main__":
    dataSeries2gen = "horizontal"
    count2gen = 100000
    series2gen = 2
    build_test_data(dataSeries2gen, count2gen, series2gen)

Мне нужно, чтобы это работало как для представления данных, так и для настройки пользовательского JavaScript (событие щелчка мыши) для выполнения других задач.Но если инструмент наведения мыши не определяет, что это за элемент, событие щелчка также вряд ли сработает.

Спасибо

1 Ответ

1 голос
/ 15 марта 2019

В вашем коде найдено 2 проблемы:

1) Определенно существует проблема с наведением сегмента, который не работает на перевернутой оси (в данном случае ось Y). Это может быть проблемой Bokeh (пожалуйста, проверьте / отправьте вопрос)

2) Неверный синтаксис подсказок. Согласно документации Bokeh допускается только следующий синтаксис

:$index: index of hovered point in the data source
:$name: value of the ``name`` property of the hovered glyph renderer
:$x: x-coordinate under the cursor in data space
:$y: y-coordinate under the cursor in data space
:$sx: x-coordinate under the cursor in screen (canvas) space
:$sy: y-coordinate under the cursor in screen (canvas) space
:$color: color data from data source

То есть $x0,$x1,$y0,$y1 не понимаются HoverTool и не могут быть использованы. Я заменил их на @x0,@y0,@x1,@y1, что эквивалентно $x,$y в случае, если ваш курсор указывает на начало или конец сегмента. Я также добавил ("x,y", "$sx,$sy"), чтобы показать координаты экрана под курсором.

Чтобы правильно отображать всплывающие подсказки, я сделал трюк, скрыв исходную ось Y и вставив дополнительную перевернутую ось. Это работает, но на самом деле не имеет смысла, поскольку ось инвертирована, а диапазон y - нет. Во всяком случае, я надеюсь, что это поможет.

from bokeh.io import output_file
from bokeh.models.ranges import Range1d
from bokeh.models import ColumnDataSource, LinearAxis
from bokeh.plotting import figure, show
from bokeh.models.tools import HoverTool
import random

def build_test_data(dataSeries2gen, count2gen, series2gen):
    # test data
    vectorSeries = []
    if dataSeries2gen == "horizontal":
        # gen random seed numbers for X and Y but always use same Y
        for nSeries in range(0, series2gen):
            sameY = [random.randint(1, 4000) for y in range(4000)]
            randX1 = [random.randint(1, 51200) for x in range(51200)]
            randX2 = [random.randint(1, 51200) for x in range(51200)]
            nextSeries = []
            for nextSeed in range(1, count2gen):
                yIdx = random.randint(1, 3999)
                xIdx = random.randint(1, 51199)
                nextSegment = [randX1[xIdx], sameY[yIdx], randX2[xIdx], sameY[yIdx]]
                nextSeries.append(nextSegment)
            vectorSeries.append(nextSeries)
    else:
        for nSeries in range(0, series2gen):
            randY1 = [random.randint(1, 4000) for y in range(4000)]
            randY2 = [random.randint(1, 4000) for y in range(4000)]
            randX1 = [random.randint(1, 51200) for x in range(51200)]
            randX2 = [random.randint(1, 51200) for x in range(51200)]
            nextSeries = []
            for nextSeed in range(1, count2gen):
                nextSegment = [randX1[nextSeed], randY1[nextSeed], randX2[nextSeed], randY2[nextSeed]]
                nextSeries.append(nextSegment)
            vectorSeries.append(nextSeries)
    plot_segments_withSource(vectorSeries)

def plot_segments_withSource(theData):
    colorPalette = ["red", "green", "blue", "yellow", "orange"]
    output_file("test.html", mode = 'inline')
    p = figure(plot_width = 700, plot_height = 750, output_backend = "webgl", y_axis_location = None)
    colorIdx = -1
    for nSeries in theData:
        colorIdx += 1
        color2use = colorPalette[colorIdx]
        x0, y0, x1, y1 = [], [], [], []
        for vPoints in nSeries:
            x0.append(vPoints[0])
            y0.append(vPoints[1])
            x1.append(vPoints[2])
            y1.append(vPoints[3])
        source = ColumnDataSource(dict(x0 = x0,y0 = y0,x1 = x1,y1 = y1))
        p.segment(x0 = "x0", y0 = "y0", x1 = "x1", y1 = "y1", line_color = color2use, source = source, line_width = 1)

    # insert inverted extra yAxis where 0 is at the top
    p.extra_y_ranges = {"Time Extra Axis": Range1d(start = 4000, end = 0) }
    p.add_layout(LinearAxis(y_range_name = "Time Extra Axis", axis_label = 'Time'), 'left')
    hover = HoverTool()
    hover.tooltips = [("x0,y0", "@x0,@y0"), ("x1,y1", "@x1,@y1"), ("x,y", "$sx,$sy")]
    hover.point_policy = "snap_to_data"
    hover.line_policy = "nearest"
    p.add_tools(hover)
    p.title.text = "This is a test"
    p.xaxis.axis_label = "Occurrences"
    p.yaxis.axis_label = "Time"
    show(p)

if __name__ == "__main__":
    dataSeries2gen = "horizontal"
    count2gen = 10
    series2gen = 2
    build_test_data(dataSeries2gen, count2gen, series2gen)

Результат:

enter image description here

...