bokeh selected.on_change не работает для моей текущей настройки - PullRequest
0 голосов
/ 12 января 2019

По сути, это интерактивная тепловая карта, но суть в том, что источник обновляется путем чтения значений из файла, который регулярно обновляется.

не беспокойтесь о классе "генератор", он просто предназначен для хранения данных и регулярно работает с потоками

убедитесь, что файл с именем «Server_dump.txt» существует в том же каталоге скрипта с одним числом больше 0, прежде чем выполнять скрипт bokeh.

, что в основном происходит, я изменяю число внутри файла с именем «Server_dump.txt», используя echo 4 > Server_dump.txt на bash, Вы можете поставить любое число, отличное от 4, и скрипт автоматически проверит файл и построит новую точку.

если вы не используете bash, вы можете использовать текстовый редактор, заменить число и сохранить, и все будет так же.

Функция запуска внутри класса генератора - это та, которая проверяет, был ли изменен этот файл, считывает число, преобразует его в координаты x & y и увеличивает число нажатий, связанных с этими координатами, и выдает source x, y. , нажимает значения на основе этого числа.

хорошо, что функция работает нормально, и каждый раз, когда я отображаю число, отображается правильный прямоугольник, но,

  • теперь я хочу добавить функциональность, когда щелчок определенного прямоугольника вызывает обратный вызов для построения второго графика, основанного на координатах прямоугольника, по которому щелкнули, но я даже не могу заставить его срабатывать, хотя я пробовал другие примеры. с selected.on_change в них, и они работали нормально.

* если я увеличу self.taps для определенного прямоугольника, записав число в файл несколько раз, цвет обновится, но если я наведу курсор мыши на прямоугольник, он покажет мне прошлые значения, а не только последнее значение.

моя версия боке - 1.0.4

from functools import partial
from random import random,randint
import threading 
import time
from tornado import gen
from os.path import getmtime
from math import pi
import pandas as pd
from random import randint, random
from bokeh.io import show
from bokeh.models import LinearColorMapper, BasicTicker, widgets, PrintfTickFormatter, ColorBar, ColumnDataSource, FactorRange
from bokeh.plotting import figure, curdoc
from bokeh.layouts import row, column, gridplot

source = ColumnDataSource(data=dict(x=[], y=[], taps=[]))

doc = curdoc()

#sloppy data receiving function to change data to a plottable shape 
class generator(threading.Thread):
    def __init__(self):
        super(generator, self).__init__()
        self.chart_coords = {'x':[],'y':[],'taps':[]}
        self.Pi_coords = {}  
        self.coord = 0
        self.pos = 0
        self.col = 0
        self.row = 0
        self.s = 0
        self.t = 0

    def chart_dict_gen(self,row, col):
        self.col = col
        self.row = row+1
        self.chart_coords['x'] = [i for i in range(1,cla.row)]
        self.chart_coords['y'] = [i for i in range(cla.col, 0, -1)] #reversed list because chart requires that
        self.chart_coords['taps']= [0]*(row * col)
        self.taps = [[0 for y in range(col)] for x in range(row)]

    def Pi_dict_gen(self,row,col):
        key = 1
       for x in range(1,row):
           for y in range(1,col):
               self.Pi_coords[key] = (x,y)
               key = key + 1

    def Pi_to_chart(self,N):
        x,y = self.Pi_coords[N][0],  self.Pi_coords[N][1]
       return x,y

    def run(self):
      while True:
        if(self.t == 0):
            self.t=1
            continue
        time.sleep(0.1)

        h = getmtime("Server_dump.txt")
        if self.s != h:
            self.s = h
             with open('Server_dump.txt') as f:
                 m = next(f)
                 y,x = self.Pi_to_chart(int(m))
                 self.taps[x][y] += 1 
                 # but update the document from callback 
                doc.add_next_tick_callback(partial(update, x=x, y=y, taps=self.taps[x][y]))


cla = generator()
cla.chart_dict_gen(15,15)
cla.Pi_dict_gen(15, 15)

x = cla.chart_coords['x']
y = cla.chart_coords['y']
taps = cla.chart_coords['taps']

@gen.coroutine
def update(x, y, taps):
    taps += taps
    print(x,y,taps)
    source.stream(dict(x=[x], y=[y], taps=[taps]))

colors = ["#CCEBFF","#B2E0FF","#99D6FF","#80CCFF","#66c2FF","#4DB8FF","#33ADFF","#19A3FF", "#0099FF", "#008AE6", "#007ACC","#006BB2", "#005C99", "#004C80", "#003D66", "#002E4C", "#001F33", "#000F1A", "#000000"]
mapper = LinearColorMapper(palette=colors, low= 0, high= 15) #low = min(cla.chart_coords['taps']) high = max(cla.chart_coords['taps'])

TOOLS = "hover,save,pan,box_zoom,reset,wheel_zoom"


p = figure(title="Tou",
           x_range=list(map(str,x)),
           y_range=list(map(str,reversed(y))),
           x_axis_location="above",
           plot_width=900, plot_height=400,
           tools=TOOLS, toolbar_location='below',
           tooltips=[('coords', '@y @x'), ('taps', '@taps%')])

p.grid.grid_line_color = "#ffffff"
p.axis.axis_line_color = "#ef4723"
p.axis.major_tick_line_color = "#af0a36"
p.axis.major_label_text_font_size = "7pt"
p.xgrid.grid_line_color = None
p.ygrid.grid_line_color = None

p.rect(x="x", y="y",
       width=0.9, height=0.9,
       source=source,
       fill_color={'field': 'taps', 'transform': mapper},
       line_color = "#ffffff",
)

color_bar = ColorBar(color_mapper=mapper,
                     major_label_text_font_size="7pt",
                     ticker=BasicTicker(desired_num_ticks=len(colors)),
                     formatter=PrintfTickFormatter(format="%d%%"),
                     label_standoff=6, border_line_color=None, location=(0, 0))

curdoc().theme = 'dark_minimal'

def ck(attr, old, new):
    print('here') #doesn't even print hi in the terminal if i click anywhere 

source.selected.on_change('indices', ck)


p.add_layout(color_bar, 'right')

doc.add_root(p)

thread = cla
thread.start()

Я даже хотел получить напечатанный привет в терминале, но ничего

1 Ответ

0 голосов
/ 12 января 2019

На самом деле вы вообще не добавили никаких инструментов выделения на свой график, поэтому выбор никогда не производится. Вы указали:

TOOLS = "hover,save,pan,box_zoom,reset,wheel_zoom"

Это единственные инструменты, которые будут добавлены, и ни один из них не сделает выбор, потому что ничто не приведет к обновлению source.selection.indices. Если вы ищете выборки на основе крана, вы должны добавить TapTool, например, с

TOOLS = "hover,save,pan,box_zoom,reset,wheel_zoom,tap"

Обратите внимание, что повторных обратных вызовов не будет, если вы нажмете один и тот же прямоугольник несколько раз. Обратный вызов срабатывает только тогда, когда выбор меняет , и дважды щелкая один и тот же глиф подряд, получается идентичный выбор.

...