2015-11-18 9 views
6

sto cercando di combinare questi due esempi in Bokeh:Bokeh: attuazione javascript personalizzato in una trama immagine

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

L'idea sembra semplice. Voglio tracciare l'immagine mostrata nel primo link e poi variare la frequenza della funzione seno utilizzando un cursore interattivo:

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) 

Le grafico trame giuste, ma l'immagine non aggiorna mai. Il problema quasi certamente esiste come sto tramando l'immagine:

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

Non penso che è come si collega correttamente un complotto per un oggetto di origine. Sto solo passando una matrice, il che spiega perché la trama non si aggiorna quando la sorgente cambia, ma non sono sicuro di quale sia il metodo corretto per la funzione immagine. Se cambio la dichiarazione in:

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

Non verrà tracciato correttamente. Non sono sicuro che si tratti solo di un problema di sintassi o di un problema più profondo. Qualsiasi suggerimento sarebbe apprezzato. Grazie in anticipo.

risposta

8

Avevo a che fare con un problema simile per un paio di giorni. Finalmente l'ho fatto funzionare. Innanzitutto, notare le parentesi [] nella funzione ColumnDataSource. I dati consentono più immagini. Quindi, all'interno della funzione di callback dovresti usare [0] per ottenere i dati per un'immagine. Anche l'uso di 'x' e 'y' nella sorgente dell'immagine è in conflitto con la posizione dell'immagine x = [0] e y [0], quindi ho usato xx e yy. Voglio menzionare che ho preso in prestito il codice da un esempio di tobyhodges color_sliders.py: un modo per inviare le informazioni del cursore a una funzione di callback che è già stata definita. Ecco il codice:

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) 

Per evitare warning di deprecazione nella versione più recente del bokeh (la versione che ho appena installata è 0.12.3) Ho modificato questo codice come segue. In questo codice, non utilizzo l'origine dati per l'immagine. Dentro lo CustomJS ho passato l'handle dell'immagine "im" e ho ricevuto l'origine dati come 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) 

Aggiornamento per il bokeh versione 0.12.4:

modifiche: l'uscita è ora per un notebook Jupyter. Per ottenere la pagina html, basta seguire le versioni precedenti. Novità in questa versione bokeh: l'array su JavaScript è ora un array 1D.

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

sei l'uomo. Grazie amico. Lo apprezzo molto. Vedere gli errori che ho fatto mi fa capire molto meglio cosa sta succedendo con le fonti di dati. –

Problemi correlati