2014-10-03 14 views
32

HINWEIS: Diese Frage betrifft den Bokeh-Server der "ersten Generation", der seit mehreren Jahren nicht mehr verwendet wird. Nichts in dieser Frage und ihre Antworten ist relevant für jede Version von Bokeh> = 0,11Mehrere Fragen mit objektorientiertem Bokeh




Ich versuche Bokeh für eine interaktive App zu verstehen, dass ich baue. Ich schaue auf die Bokeh examples, und ich sehe, dass die meisten Beispiele alle im globalen Namespace geschrieben sind, aber die im Unterverzeichnis "app" sind in einem schönen, objektorientierten Stil geschrieben, wo die Hauptklasse eingibt Eine Property-Klasse wie HBox.

Dies wird ein Mischmasch von Fragen sein, denn ich denke nicht, dass diese Art der Programmierung von Bokeh sehr gut dokumentiert wurde. Das erste, was mir dabei auffiel, war, dass die Handlung nicht gezeichnet wurde, wenn ich nicht extra_generated_classes einschloss.

  1. Was bedeutet extra_generated_classes tun?

    Zweitens sieht es so aus, als ob die Ereignisschleife setup_events beim Start vor create aufgerufen wird und anschließend jedes Mal, wenn der Plot ein Ereignis auslöst.

  2. Warum müssen setup_events Callbacks jedes Mal registrieren, wenn ein Ereignis ausgelöst wird? Und warum wartet es nicht darauf, dass create beendet wird, bevor es versucht wird, sie beim ersten Mal zu registrieren?

    Das letzte, worüber ich mir nicht sicher bin, ist, wie man eine Neuzeichnung einer Glyph hier erzwingt. Das Slider-Demo funktioniert für mich, und ich versuche im Prinzip das Gleiche zu tun, außer mit einem Streudiagramm anstelle einer Linie.

    stellte ich eine pdb Spur am Ende meines update_data, und ich kann garantieren, dass self.sourceself.plot.renderers[-1].data_source zueinander passen und dass beide von ihnen haben von Anfang an gezwickt worden. self.plot selbst ändert sich jedoch nicht.

  3. Was entspricht der objektorientierte Ansatz dem Aufruf von store_objects, um den Plot zu aktualisieren?

    Ich bin besonders verwirrt durch diese dritte, weil es nicht so aussieht wie das sliders_app-Beispiel so etwas braucht.Zur Verdeutlichung, versuche ich, eine variable Anzahl von Widgets/Schieber zu machen, so ist dies, was mein Code wie folgt aussieht:

Klasse Attribute:

extra_generated_classes = [['ScatterBias', 'ScatterBias', 'HBox']] 
maxval = 100.0 

inputs = Instance(bkw.VBoxForm) 
outputs = Instance(bkw.VBoxForm) 
plots = Dict(String, Instance(Plot)) 
source = Instance(ColumnDataSource) 


cols = Dict(String, String) 
widgets = Dict(String, Instance(bkw.Slider)) 
# unmodified source 
df0 = Instance(ColumnDataSource) 

Methode initialize

@classmethod 
def create(cls): 
    obj = cls() 

    ############################## 
    ## load DataFrame 
    ############################## 
    df = pd.read_csv('data/crime2013_tagged_clean.csv', index_col='full_name') 
    obj.cols = {'x': 'Robbery', 
      'y': 'Violent crime total', 
      'pop': 'Population' 
      } 

    cols = obj.cols 

    # only keep interested values 
    df2= df.ix[:, cols.values()] 

    # drop empty rows 
    df2.dropna(axis=0, inplace=True) 

    df0 = df2.copy() 
    df0.reset_index(inplace=True) 
    # keep copy of original data 
    obj.source = ColumnDataSource(df2) 
    obj.df0 = ColumnDataSource(df0) 

    ############################## 
    ## draw scatterplot 
    ############################## 

    obj.plots = { 
      'robbery': scatter(x=cols['x'], 
       y=cols['y'], 
       source=obj.source, 
       x_axis_label=cols['x'], 
       y_axis_label=cols['y']), 
      'pop': scatter(x=cols['pop'], 
       y=cols['y'], 
       source=obj.source, 
       x_axis_label=cols['pop'], 
       y_axis_label=cols['y'], 
       title='%s by %s, Adjusted by by %s'%(cols['y'], 
        cols['pop'], cols['pop'])), 
     } 

    obj.update_data() 
    ############################## 
    ## draw inputs 
    ############################## 
    # bokeh.plotting.scatter 
    ## TODO: refactor so that any number of control variables are created 
    # automatically. This involves subsuming c['pop'] into c['ctrls'], which 
    # would be a dictionary mapping column names to their widget titles 
    pop_slider = obj.make_widget(bkw.Slider, dict(
      start=-obj.maxval, 
      end=obj.maxval, 
      value=0, 
      step=1, 
      title='Population'), 
     cols['pop']) 

    ############################## 
    ## make layout 
    ############################## 
    obj.inputs = bkw.VBoxForm(
      children=[pop_slider] 
      ) 

    obj.outputs = bkw.VBoxForm(
      children=[obj.plots['robbery']] 
     ) 

    obj.children.append(obj.inputs) 
    obj.children.append(obj.outputs) 

    return obj 

update_data

def update_data(self): 
    """Update y by the amount designated by each slider""" 
    logging.debug('update_data') 
    c = self.cols 
    ## TODO:: make this check for bad input; especially with text boxes 
    betas = { 
      varname: getattr(widget, 'value')/self.maxval 
      for varname, widget in self.widgets.iteritems() 
      } 

    df0 = pd.DataFrame(self.df0.data) 
    adj_y = [] 
    for ix, row in df0.iterrows(): 
     ## perform calculations and generate new y's 
     adj_y.append(self.debias(row)) 

    self.source.data[c['y']] = adj_y 
    assert len(adj_y) == len(self.source.data[c['x']]) 
    logging.debug('self.source["y"] now contains debiased data') 

    import pdb; pdb.set_trace() 

Beachten Sie, dass ich sicher bin, dass der Event-Handler ordnungsgemäß eingerichtet und ausgelöst wird. Ich weiß einfach nicht, wie man die geänderten Quelldaten im Streudiagramm wiedergibt.

+0

Haben Sie eine Lösung für dieses Problem gefunden, insbesondere für das Rendern von Streuung? Ich forsche nach Bokeh für etwas Ähnliches. –

+10

Versuchen Sie, Ihre Fragen in kleinere Stücke zu teilen, wenn Sie Antworten wünschen. – sorin

Antwort

3

Ich suche nach den gleichen Antworten (fehlende Dokumentation macht es schwierig).

In Antwort auf Frage # 1, was die Nützlichkeit des "extra_generated_classes":

tl; dr extra_generated_classes eine modul definiert, Klassennamen und Parent in Vorlage verwendet js/HTML-Code zu erzeugen, und erstreckt sich Die Elternklasse wurde in die App-Klasse übernommen (normalerweise HBox oder VBox in den Beispielen).

Längere Antwort. Sehen Sie sich den Quellcode in bokeh/server/utils/plugins.py an. Dies ist der Code, der auf Code ausgeführt wird, der an bokeh-server übergeben wird, indem das Befehlszeilenargument -script verwendet wird. Am Ende von plugins.py können Sie sehen, dass extra_generated_classes an die flask-Methode render_template übergeben wird, die eine Vorlage Jinja2 rendert. Der Suche in der Vorlage, oneobj.html, extra_generated_classes ist ein Array von Arrays von drei Dinge: Modulname, Klassennamen und Parentname, der in bokeh.server.generatejs geben werden:

{% block extra_scripts %} 
    {% for modulename, classname, parentname in extra_generated_classes %} 
    <script 
    src="{{ url_for('bokeh.server.generatejs', modulename=modulename, classname=classname, parentname=parentname) }}" 
    ></script> 
    {% endfor %} 
{% endblock %} 

bokeh.server.generatejs a ist Python-Code in bokeh/server/views/plugins.py und ruft nur render_template für eine Vorlage app.js auf, die Sie in bokeh/server/templates finden. Diese Vorlage verwendet den Modulnamen, den Klassennamen und den Parentnamen und erstellt im Grunde Js-Code, der den Parentnamen (z. B. HBox oder VBox) auf den Klassennamen (Ihre App) erweitert.