2016-04-06 5 views
2

Ich benutze Pythons Data Spyre, um eine einfache Webanwendung zu erstellen, um einige Daten und Diagramme anzuzeigen, und ich wollte auch einige der Widgets von Bokeh nutzen. Ich habe in der Lage Bokeh Plots erfolgreich ist, aber sobald ich das Multiselect-Tool hinzugefügt Ich habe die folgende Fehlermeldung erhalten:Wie kann ich Bokeh-Plots mit Widgets in Data Spyre rendern?

(index):10137 Uncaught Error: Module `MultiSelect' does not exists. The problem may be two fold. Either a model was requested that's available in an extra bundle, e.g. a widget, or a custom model was requested, but it wasn't registered before first usage. 

Ich habe nicht in der Lage gewesen, um herauszufinden, was diesen Fehler zu schaffen. Ich konnte vorher den Bokeh-Code in einem Jupyter-Notebook testen und alles wie erwartet wiedergeben. Ich bin nicht sicher, was bricht, wenn ich es zu Spyre portiere.

Hier ist der Code, den ich unten testen bin:

from spyre import server 

import numpy as np 
import pandas as pd 
from bokeh.plotting import figure 

from bokeh.resources import INLINE, CDN 
from bokeh.embed import components 
from bokeh.models.sources import ColumnDataSource 
from bokeh.models import CustomJS, MultiSelect 
import bokeh.models as bkm 
from bokeh import palettes 
from bokeh.io import vform 

class SimpleApp(server.App): 
    title = "Bokeh Test" 
    inputs = [{ "type":"text", 
       "key":"factor", 
       "value":5, 
       "label":"factor", 
       "action_id":"line_plot"}] 
    tabs=["Plot","Data"] 
    outputs = [{"type":"html", 
       "id":"bokeh_plot", 
       "tab":"Plot", 
       "control_id":"line_plot"}, 
       {"type":"table", 
       "id":"bokeh_data", 
       "tab":"Data", 
       "control_id":"line_plot"}] 
    controls = [{"type":"HIDDEN", 
       "id":"line_plot"}] 
    def getHTML(self, params): 
     df=self.getData(params) 


     _tools_to_show = 'box_zoom,pan,save,resize,reset,tap,wheel_zoom' 
     p=figure(plot_width=600, plot_height=600,x_axis_type='datetime',tools=_tools_to_show) 

     colors=palettes.Spectral11 
     colori=0 

     #create source 
     source_dict={} 

     source_dict['Date']=df.index.format() 
     for col in df.columns.tolist(): 
      source_dict['xaxis_'+col]=df.index.values 
      source_dict['Date_'+col]=df.index.format() 

      source_dict['yaxis_'+col]=df[col].values 
      source_dict['yname_'+col]=np.tile(col, [len(df.index),1]) 

      source_dict['yaxisdup_'+col]=df[col].values 

     source=ColumnDataSource(source_dict) 

     #print source.data 

     #source_dict={} 
     for col in df.columns: 
      #source= ColumnDataSource({'x': df.index.values, 'y': df[col].values, 'series_name': col, 'Date': df.index.format()}) 
      p.line('xaxis_'+col,'yaxis_'+col,source=source, legend=col,color=colors[colori],line_width=3) 
      colori+=1 



     colori=0 
     scatlist=[] 
     for col in df.columns.tolist(): 

      subdict = {'xaxis_'+col:source.data['xaxis_'+col], 'Date_'+col:source.data['Date_'+col], 'yname_'+col:source.data['yname_'+col],'yaxis_'+col:source.data['yaxis_'+col]} 
      tempsource = ColumnDataSource(subdict) 
      scat=p.scatter('xaxis_'+col, 'yaxis_'+col, source = source, fill_alpha=0, line_alpha=0.8, line_color=colors[colori],line_width=8) 
      colori+=1 
      scatlist.append(scat) 
      g1_hover = bkm.HoverTool(renderers=[scat], tooltips=[("Series", "@yname_"+col), ("Date", "@Date_"+col), ("Value", "@yaxis_"+col+"{0.00%}")])  
      g1_hover.mode='mouse' 
      p.add_tools(g1_hover) 



     p.background_fill_color='black' 
     p.background_fill_alpha=0.9 


     codestr=""" 
       var data = source.get('data'); 
       var f = cb_obj.get('value') 

       cols="""+"['"+"','".join([col for col in df.columns.tolist()])+"']"+""" 
       for (var i = 0; i < cols.length; i++) { 
        if (f.indexOf(cols[i])> -1) { 
         data['yaxis_'+cols[i]]=data['yaxisdup_'+cols[i]] 
        } 
        else { 
         data['yaxis_'+cols[i]]='nan' 
        } 

       } 
       source.trigger('change'); 
      """ 
     callback = CustomJS(args=dict(source=source), code=codestr) 

     multi_select = MultiSelect(title="Lines to plot:", \ 
     value=df.columns.tolist(), \ 
     options=df.columns.tolist(), callback=callback) 
     layout = vform(multi_select, p) 

     script,div=components(layout,CDN) 
     html = "%s\n%s"%(div, script) 


     html='<center>'+html+'</center>' 
     return html 

    def getData(self,params): 
     f=int(params['factor']) 
     dr=pd.date_range('1-1-2010','12-31-2010',freq='D') 
     vals=[i*f for i in range(len(dr))] 
     df=pd.DataFrame(vals,index=dr,columns=['data']) 

     return df 
    def getCustomJS(self): 
     return INLINE.js_raw[0] 

    def getCustomCSS(self): 
     css=INLINE.css_raw[0] 
     return css 
if __name__ == '__main__': 
    app = SimpleApp() 
    app.launch() 

LÖSUNG: Dank für die Identifizierung dieser bigreddot. Ich musste auch das Widget js einbinden. Meine benutzerdefinierte JS-Funktion sieht nun so aus:

def getCustomJS(self): 
    INLINE.js_raw[0]+INLINE.js_raw[1] 
+0

denke ich das Problem Ihr 'getCustomJS' Funktion ist. BokehJS ist eine ziemlich große JS-Bibliothek. Es wurde vor kurzem aufgeteilt, so dass es nur notwendig ist, den gesamten Widget-JS-Code zu "bezahlen", wenn Sie ihn tatsächlich benutzen. Wenn Sie Widgets verwenden. Hier ist jetzt ein separates 'bokeh-widgets.js', das entweder inline oder von CDN geladen werden muss. Dies wird normalerweise automatisch gehandhabt, aber es sieht so aus, als ob Sie es überschreiben, immer nur den ersten Block von 'js_raw' zurückzugeben, was bedeutet, dass Sie wahrscheinlich das notwendige zusätzliche Stück vermissen. – bigreddot

+0

Wenn Spyre Sie darauf beschränkt, eine einzelne Zeichenfolge in dieser Methode zurückzugeben, können Sie versuchen, alle Teile von 'INLINE.js_raw' selbst zu verketten. Alternativ könnten CDN-Ressourcen einfacher sein. – bigreddot

+0

Ich war mir der Trennung von bokeh-widgets.js nicht bewusst. Ich werde sehen, ob ich damit arbeiten kann, danke für den Vorschlag. – PM8K

Antwort

0

LÖSUNG: Danke an bigreddot für die Identifizierung. Ich musste auch das Widget js einbinden, da es sich in einem separaten Skript in js_raw befindet. Da Data Spyre seine eigenen eingebauten JavaScript-Funktionen hat, die Sie überschreiben müssen, habe ich am Ende eine verkettete Zeichenfolge der rohen Javascript-Elemente in meiner Funktion zurückgegeben.

Meine benutzerdefinierten JS-Funktion sieht nun wie folgt aus:

def getCustomJS(self): 
    INLINE.js_raw[0]+INLINE.js_raw[1] 
Verwandte Themen