2015-11-18 6 views
6

ich diese beiden Beispiele in Bokeh zu kombinieren versuchen:Bokeh: custom Javascript in einem Bild Plot Umsetzung

http://bokeh.pydata.org/en/latest/docs/gallery/image.html http://bokeh.pydata.org/en/latest/docs/user_guide/interaction/callbacks.html#customjs-for-widgets

Die Idee scheint einfach. Ich möchte das Bild in der ersten Link angezeigt plotten und dann variieren die Frequenz der Sinusfunktion einen interaktiven Slider mit:

import numpy as np 

from bokeh.plotting import figure, show, output_file 
from bokeh.models import CustomJS, ColumnDataSource, Slider 
from bokeh.io import vform 


N = 10 

x = np.linspace(0, 10, N) 
y = np.linspace(0, 10, N) 
xx, yy = np.meshgrid(x, y) 
d = np.sin(xx)*np.cos(yy) 

output_file("image.html", title="image.py example") 

source = ColumnDataSource(data={'d': d, 'x': x, 'y': y}) 

p = figure(x_range=[0, 10], y_range=[0, 10]) 
p.image([source.data['d']], x=[0], y=[0], dw=[10], dh=[10], palette="Spectral11") 

callback = CustomJS(args=dict(source=source), code=""" 
     var data = source.get('data'); 
     var f = cb_obj.get('value') 
     x = data['x'] 
     y = data['y'] 
     d = data['d'] 
     for (i = 0; i < x.length; i++) { 
      for (i = 0; i < x.length; i++){ 
       d[i][j] = Math.sin(f*x[i])*Math.cos(y[j]) 
     } 
     source.trigger('change'); 
    """) 

slider = Slider(start=0.1, end=4, value=1, step=.1, title="angular frequency", callback=callback) 

layout = vform(slider, p) 

show(layout) 

das Diagramm Plots rechts, aber das Bild nie Updates. Das Problem besteht fast sicher, wie ich das Bild am Plotten:

p.image([source.data['d']], x=[0], y=[0], dw=[10], dh=[10], palette="Spectral11") 

Ich glaube nicht, das ist, wie man richtig ein Grundstück zu einem Quellobjekt anhängen. Ich gebe gerade ein Array ein, was erklärt, warum das Diagramm nicht aktualisiert wird, wenn sich die Quelle ändert, aber ich bin mir nicht sicher, was die richtige Methode für die Bildfunktion ist. Wenn ich die Anweisung ändere in:

p.image(['d'], x=[0], y=[0], dw=[10], dh=[10], source=source, palette="Spectral11") 

Es wird nicht korrekt dargestellt. Ich bin mir nicht sicher, ob das nur ein Syntaxproblem oder ein tiefergehendes Problem ist. Alle Hinweise würden geschätzt werden. Danke im Voraus.

Antwort

8

Ich hatte ein ähnliches Problem für ein paar Tage. Endlich habe ich es zum Laufen gebracht. Beachten Sie zuerst die Klammern [] in der ColumnDataSource-Funktion. Die Daten ermöglichen mehrere Bilder. Innerhalb der Callback-Funktion sollten Sie also [0] verwenden, um die Daten für ein Bild zu erhalten. Auch die Verwendung von 'x' und 'y' in der Quelle für das Bild steht in Konflikt mit der Position des Bildes x = [0] und y [0], also habe ich xx und yy verwendet. Ich möchte erwähnen, dass ich Code von einem Beispiel von Tobyhodges geliehen color_sliders.py: eine Möglichkeit, Slider-Informationen zu einer Callback-Funktion, die bereits definiert wurde schieben. Hier ist der Code:

import numpy as np 
from bokeh.plotting import figure, show, output_file 
from bokeh.models import CustomJS, ColumnDataSource, Slider 
from bokeh.io import vform 

N = 100 

x = np.linspace(0, 10, N) 
y = np.linspace(0, 10, N) 
xx, yy = np.meshgrid(x, y) 
d = np.sin(xx)*np.cos(yy) 

output_file("image.html", title="image.py example") 

source = ColumnDataSource(data={'d': [d], 'xx': [x], 'yy': [y]}) 

p = figure(x_range=[0, 10], y_range=[0, 10]) 
p.image(image="d", x=[0], y=[0], dw=[10], dh=[10], palette="Spectral11",source=source) 

callback = CustomJS(args=dict(source=source), code=""" 
     var xx = source.get('data')['xx'][0]; 
     var yy = source.get('data')['yy'][0]; 
     var d = source.get('data')['d'][0]; 
     var f = slider.get('value'); 
     for (var i = 0; i < xx.length; i++) { 
      for (var j = 0; j < yy.length; j++){ 
       d[i][j] = Math.sin(f * xx[i]) * Math.cos(yy[j]); 
      } 
     } 
     source.trigger('change'); 
    """) 

slider = Slider(start=0.1, end=4, value=1, step=.1, title="angular frequency", callback=callback) 
callback.args['slider'] = slider 
layout = vform(slider, p) 
show(layout) 

Um deprecation Warnungen in der neuesten Version von Bokeh zu vermeiden (die Version, die ich gerade installiert ist 0.12.3) I geändert haben diesen Code wie folgt. In diesem Code verwende ich keine Datenquelle für das Bild. Inside CustomJS übergebe ich das Bild Handle "im" und bekomme die Datenquelle als im.data_source.

import numpy as np 
import bokeh 
import bokeh.plotting 

N = 100 

x = np.linspace(0, 10, N) 
y = np.linspace(0, 10, N) 
xx, yy = np.meshgrid(x, y) 
d = np.sin(xx)*np.cos(yy) 

source = bokeh.models.ColumnDataSource(data={'x': [x], 'y': [y]}) 

p = bokeh.plotting.figure(x_range=[0, 10], y_range=[0, 10]) 
im = p.image(image=[d], x=[0], y=[0], dw=[10], dh=[10], palette="Spectral11") 

callback = bokeh.models.CustomJS(args=dict(source=source,im=im), code=""" 
     var x = source.data['x'][0]; 
     var y = source.data['y'][0]; 
     var image_source = im.data_source; 
     var d = image_source.data['image'][0]; 
     var f = slider.value; 
     for (var i = 0; i < x.length; i++) { 
      for (var j = 0; j < y.length; j++){ 
       d[i][j] = Math.sin(f * x[i]) * Math.cos(f * y[j]); 
      } 
     } 
     image_source.trigger('change'); 
    """) 

slider = bokeh.models.Slider(start=0.1, end=4, value=1, step=.1, 
          title="angular frequency", callback=callback) 
callback.args['slider'] = slider 
layout = bokeh.models.layouts.Column(slider, p) 

bokeh.io.output_file("image.html", title="image.py example") 
bokeh.io.save(layout) 

Update für Bokeh Version 0.12.4:

Änderungen: die Ausgabe ist jetzt ein Jupyter Notebook. Folgen Sie einfach den vorherigen Versionen, um die HTML-Seite zu erhalten. Neu in dieser Bokeh-Version: Das Array auf JavaScript ist jetzt ein 1D-Array.

import numpy as np 
import bokeh 
import bokeh.plotting 

N = 100 

x = np.linspace(0, 10, N) 
y = np.linspace(0, 10, N) 
xx, yy = np.meshgrid(x, y) 
d = np.sin(xx)*np.cos(yy) 

source = bokeh.models.ColumnDataSource(data={'x': [x], 'y': [y]}) 

p = bokeh.plotting.figure(plot_width=300, plot_height=300,x_range=[0, 10], y_range=[0, 10]) 
im = p.image(image=[d], x=[0], y=[0], dw=[10], dh=[10], palette="Spectral11") 

callback = bokeh.models.CustomJS(args=dict(source=source,im=im), code=""" 
     var x = source.data['x'][0]; 
     var y = source.data['y'][0]; 
     var image_source = im.data_source; 
     var d = image_source.data['image'][0]; 
     var f = slider.value; 
     for (var j = 0; j < y.length; j++){ 
      for (var i = 0; i < x.length; i++) { 
       d[j*y.length + i] = Math.sin(f * x[i]) * Math.cos(f * y[j]); 
      } 
     } 
     image_source.trigger('change'); 
    """) 

slider = bokeh.models.Slider(start=0.1, end=4, value=1, step=.1, 
          title="angular frequency",callback=callback) 
callback.args['slider'] = slider 
layout = bokeh.models.layouts.Row(p,slider) 

bokeh.io.output_notebook() 
bokeh.io.show(layout) 

enter image description here

+0

Du bist der Mann. Danke Freund. Ich schätze es sehr. Wenn ich die Fehler sehe, die ich gemacht habe, kann ich viel besser verstehen, was mit den Datenquellen passiert. –