I see plenty of great examples of how to update glyphs on a plot following an on change of a widget by altering the column data source object. My question is can we update an image in the same way? figure.image_rgba takes a numpy array, not a ColumnDataSource. Is it possible to just replot a new image by specifying a new numpy array when an on_change event is triggered? And if so is there any difference in this functionality compared to glyphs that use a ColumnDataSource? Thanks!
To the best of my knowledge, all the plotting glyphs should be compatible with column data source. With glyphs like image_rgba, you have to assign a list containing your array to a column of your column data source. Currently, this will only work if the column containing your image array is named ‘image’ — this is a closed issue and will be fixed in 0.12.5. From there, updating the plot follows the same pattern or altering the column data source model within a callback.
Here is an example illustrating updating an image_rgba glyph, using bokeh server. Largely borrowing from the example here.
from [bokeh.io](http://bokeh.io) import curdoc
from bokeh.layouts import column
from bokeh.models import ColumnDataSource, Slider
from bokeh.plotting import figure
import numpy as np
import pandas as pd
N = 20
img = np.empty((N, N), dtype=np.uint32)
view = img.view(dtype=np.uint8).reshape((N, N, 4
))
for i in range(N):
for j in range(N):
view[i, j, 0] = int(i/N*255 )
view[i, j, 1] = 158
view[i, j, 2] = int(j/N*255 )
view[i, j, 3] = 255
# assign a list containing our image to column data source column
source = ColumnDataSource({'image'
: [img]})
p = figure(x_range=(0,10), y_range=(0,10
))
p.image_rgba(image='image', x=0, y=0, dw=10, dh=10
, source=source)
slide = Slider(start=0, end=500, step=10, value=0
)
layout = column(p, slide)
# update image on callback
def update(attr, old, new):
# create a new image based on slider widget value
new_image = img
new_view = new_image.view(dtype=np.uint8).reshape((N, N, 4 ))
new_view[:, :, 0] = (new_view[:, :, 0] + slide.value) % 255
new_view[:, :, 2] = (new_view[:, :, 2] + slide.value) % 255
# update column data source
source.data = {'image'
: [new_image]}
slide.on_change('value'
, update)
curdoc().add_root(layout)
···
On Tue, Feb 14, 2017 at 3:40 PM, [email protected] wrote:
I see plenty of great examples of how to update glyphs on a plot following an on change of a widget by altering the column data source object. My question is can we update an image in the same way? figure.image_rgba takes a numpy array, not a ColumnDataSource. Is it possible to just replot a new image by specifying a new numpy array when an on_change event is triggered? And if so is there any difference in this functionality compared to glyphs that use a ColumnDataSource? Thanks!
–
You received this message because you are subscribed to the Google Groups “Bokeh Discussion - Public” group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/8478457a-9b5f-463f-9ed5-d8434cbe3b65%40continuum.io.
For more options, visit https://groups.google.com/a/continuum.io/d/optout.
Awesome thanks Tyler! Just for others, one small correction to make your script above work is it seems we still want to start the ColumnDataSource with an empty image, {‘image’:} and then update it with update. Thanks, again!
···
On Wednesday, February 15, 2017 at 11:48:02 AM UTC-8, Tyler Nickerson wrote:
To the best of my knowledge, all the plotting glyphs should be compatible with column data source. With glyphs like image_rgba, you have to assign a list containing your array to a column of your column data source. Currently, this will only work if the column containing your image array is named ‘image’ — this is a closed issue and will be fixed in 0.12.5. From there, updating the plot follows the same pattern or altering the column data source model within a callback.
Here is an example illustrating updating an image_rgba glyph, using bokeh server. Largely borrowing from the example here.
from [bokeh.io](http://bokeh.io) import curdoc from bokeh.layouts import column from bokeh.models import ColumnDataSource, Slider from bokeh.plotting import figure import numpy as np import pandas as pd N = 20 img = np.empty((N, N), dtype=np.uint32) view = img.view(dtype=np.uint8).reshape((N, N, 4 )) for i in range(N): for j in range(N): view[i, j, 0] = int(i/N*255 ) view[i, j, 1] = 158 view[i, j, 2] = int(j/N*255 ) view[i, j, 3] = 255 # assign a list containing our image to column data source column source = ColumnDataSource({'image' : [img]}) p = figure(x_range=(0,10), y_range=(0,10 )) p.image_rgba(image='image', x=0, y=0, dw=10, dh=10 , source=source) slide = Slider(start=0, end=500, step=10, value=0 ) layout = column(p, slide) # update image on callback def update(attr, old, new): # create a new image based on slider widget value new_image = img new_view = new_image.view(dtype=np.uint8).reshape((N, N, 4 )) new_view[:, :, 0] = (new_view[:, :, 0] + slide.value) % 255 new_view[:, :, 2] = (new_view[:, :, 2] + slide.value) % 255 # update column data source source.data = {'image' : [new_image]} slide.on_change('value' , update) curdoc().add_root(layout)
On Tue, Feb 14, 2017 at 3:40 PM, [email protected] wrote:
I see plenty of great examples of how to update glyphs on a plot following an on change of a widget by altering the column data source object. My question is can we update an image in the same way? figure.image_rgba takes a numpy array, not a ColumnDataSource. Is it possible to just replot a new image by specifying a new numpy array when an on_change event is triggered? And if so is there any difference in this functionality compared to glyphs that use a ColumnDataSource? Thanks!
–
You received this message because you are subscribed to the Google Groups “Bokeh Discussion - Public” group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/8478457a-9b5f-463f-9ed5-d8434cbe3b65%40continuum.io.
For more options, visit https://groups.google.com/a/continuum.io/d/optout.
I’m glad I could help. Sorry, about the example not working! I removed a line from the callback function that I thought was redundant, but it had the necessary side effect of assigning a copy of img
to new_img
… Adding the copy method to the first line of the callback function will fix the issue as well. This approach will work with initializing the the column data source with {'image': [img]}
. Here’s the modified callback function:
def update(attr, old, new):
# create a new image based on slider widget value
new_image = img.copy() new_view = new_image.view(dtype=np.uint8).reshape((N, N, 4 ))
new_view[:, :, 0] = (new_view[:, :, 0] + slide.value) % 255
new_view[:, :, 2] = (new_view[:, :, 2] + slide.value) % 255
# update column data source
source.data = {'image': [new_image]}
`
···
On Thu, Feb 16, 2017 at 9:01 AM, [email protected] wrote:
Awesome thanks Tyler! Just for others, one small correction to make your script above work is it seems we still want to start the ColumnDataSource with an empty image, {‘image’:} and then update it with update. Thanks, again!
On Wednesday, February 15, 2017 at 11:48:02 AM UTC-8, Tyler Nickerson wrote:
To the best of my knowledge, all the plotting glyphs should be compatible with column data source. With glyphs like image_rgba, you have to assign a list containing your array to a column of your column data source. Currently, this will only work if the column containing your image array is named ‘image’ — this is a closed issue and will be fixed in 0.12.5. From there, updating the plot follows the same pattern or altering the column data source model within a callback.
Here is an example illustrating updating an image_rgba glyph, using bokeh server. Largely borrowing from the example here.
from [bokeh.io](http://bokeh.io) import curdoc from bokeh.layouts import column from bokeh.models import ColumnDataSource, Slider from bokeh.plotting import figure import numpy as np import pandas as pd N = 20 img = np.empty((N, N), dtype=np.uint32) view = img.view(dtype=np.uint8).reshape((N, N, 4 )) for i in range(N): for j in range(N): view[i, j, 0] = int(i/N*255 ) view[i, j, 1] = 158 view[i, j, 2] = int(j/N*255 ) view[i, j, 3] = 255 # assign a list containing our image to column data source column source = ColumnDataSource({'image' : [img]}) p = figure(x_range=(0,10), y_range=(0,10 )) p.image_rgba(image='image', x=0, y=0, dw=10, dh=10 , source=source) slide = Slider(start=0, end=500, step=10, value=0 ) layout = column(p, slide) # update image on callback def update(attr, old, new): # create a new image based on slider widget value new_image = img new_view = new_image.view(dtype=np.uint8).reshape((N, N, 4 )) new_view[:, :, 0] = (new_view[:, :, 0] + slide.value) % 255 new_view[:, :, 2] = (new_view[:, :, 2] + slide.value) % 255 # update column data source source.data = {'image' : [new_image]} slide.on_change('value' , update) curdoc().add_root(layout)
On Tue, Feb 14, 2017 at 3:40 PM, [email protected] wrote:
I see plenty of great examples of how to update glyphs on a plot following an on change of a widget by altering the column data source object. My question is can we update an image in the same way? figure.image_rgba takes a numpy array, not a ColumnDataSource. Is it possible to just replot a new image by specifying a new numpy array when an on_change event is triggered? And if so is there any difference in this functionality compared to glyphs that use a ColumnDataSource? Thanks!
–
You received this message because you are subscribed to the Google Groups “Bokeh Discussion - Public” group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/8478457a-9b5f-463f-9ed5-d8434cbe3b65%40continuum.io.
For more options, visit https://groups.google.com/a/continuum.io/d/optout.
–
You received this message because you are subscribed to the Google Groups “Bokeh Discussion - Public” group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/3a8ca68e-f8d4-414a-9312-7112f9c4e574%40continuum.io.
For more options, visit https://groups.google.com/a/continuum.io/d/optout.
Ah ok this makes more sense. Thanks Tyler!
···
On Thursday, February 16, 2017 at 12:19:12 PM UTC-8, Tyler Nickerson wrote:
I’m glad I could help. Sorry, about the example not working! I removed a line from the callback function that I thought was redundant, but it had the necessary side effect of assigning a copy of
img
tonew_img
… Adding the copy method to the first line of the callback function will fix the issue as well. This approach will work with initializing the the column data source with{'image': [img]}
. Here’s the modified callback function:
def update(attr, old, new): # create a new image based on slider widget value new_image = img.copy() new_view = new_image.view(dtype=np.uint8).reshape((N, N, 4 )) new_view[:, :, 0] = (new_view[:, :, 0] + slide.value) % 255 new_view[:, :, 2] = (new_view[:, :, 2] + slide.value) % 255 # update column data source source.data = {'image': [new_image]} `
On Thu, Feb 16, 2017 at 9:01 AM, [email protected] wrote:
Awesome thanks Tyler! Just for others, one small correction to make your script above work is it seems we still want to start the ColumnDataSource with an empty image, {‘image’:} and then update it with update. Thanks, again!
On Wednesday, February 15, 2017 at 11:48:02 AM UTC-8, Tyler Nickerson wrote:
To the best of my knowledge, all the plotting glyphs should be compatible with column data source. With glyphs like image_rgba, you have to assign a list containing your array to a column of your column data source. Currently, this will only work if the column containing your image array is named ‘image’ — this is a closed issue and will be fixed in 0.12.5. From there, updating the plot follows the same pattern or altering the column data source model within a callback.
Here is an example illustrating updating an image_rgba glyph, using bokeh server. Largely borrowing from the example here.
from [bokeh.io](http://bokeh.io) import curdoc from bokeh.layouts import column from bokeh.models import ColumnDataSource, Slider from bokeh.plotting import figure import numpy as np import pandas as pd N = 20 img = np.empty((N, N), dtype=np.uint32) view = img.view(dtype=np.uint8).reshape((N, N, 4 )) for i in range(N): for j in range(N): view[i, j, 0] = int(i/N*255 ) view[i, j, 1] = 158 view[i, j, 2] = int(j/N*255 ) view[i, j, 3] = 255 # assign a list containing our image to column data source column source = ColumnDataSource({'image' : [img]}) p = figure(x_range=(0,10), y_range=(0,10 )) p.image_rgba(image='image', x=0, y=0, dw=10, dh=10 , source=source) slide = Slider(start=0, end=500, step=10, value=0 ) layout = column(p, slide) # update image on callback def update(attr, old, new): # create a new image based on slider widget value new_image = img new_view = new_image.view(dtype=np.uint8).reshape((N, N, 4 )) new_view[:, :, 0] = (new_view[:, :, 0] + slide.value) % 255 new_view[:, :, 2] = (new_view[:, :, 2] + slide.value) % 255 # update column data source source.data = {'image' : [new_image]} slide.on_change('value' , update) curdoc().add_root(layout)
On Tue, Feb 14, 2017 at 3:40 PM, [email protected] wrote:
I see plenty of great examples of how to update glyphs on a plot following an on change of a widget by altering the column data source object. My question is can we update an image in the same way? figure.image_rgba takes a numpy array, not a ColumnDataSource. Is it possible to just replot a new image by specifying a new numpy array when an on_change event is triggered? And if so is there any difference in this functionality compared to glyphs that use a ColumnDataSource? Thanks!
–
You received this message because you are subscribed to the Google Groups “Bokeh Discussion - Public” group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/8478457a-9b5f-463f-9ed5-d8434cbe3b65%40continuum.io.
For more options, visit https://groups.google.com/a/continuum.io/d/optout.
–
You received this message because you are subscribed to the Google Groups “Bokeh Discussion - Public” group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit https://groups.google.com/a/continuum.io/d/msgid/bokeh/3a8ca68e-f8d4-414a-9312-7112f9c4e574%40continuum.io.
For more options, visit https://groups.google.com/a/continuum.io/d/optout.
Thanks. Very useful. Here is a version where I control contrast and brightness with 2 sliders.
Any idea about how to update an image from a FileInput widget ?
Here a piece of code to run with bokeh server.
from bokeh.layouts import column
from bokeh.models import FileInput, Slider, LinearAxis
from bokeh.plotting import figure, curdoc, ColumnDataSource
import os
import cv2
#=============================================================
alphaLevel = 1.0 # Contrast control
betaLevel = 0 # Brightness control
#=============================================================
file_input = FileInput()
def upload_data(attr, old, new):
sourceImage.data = {'image': [file_input]}
# ???????
file_input.on_change('value', upload_data)
#=============================================================
imageFileName = 'myapp2/static/BEL17-2-2_1.66x_milieu0001.png'
img0 = cv2.imread(imageFileName)
img = cv2.flip(img0, 0) # https://github.com/bokeh/bokeh/issues/1666
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
adjusted = cv2.convertScaleAbs(gray, alpha=alphaLevel, beta=betaLevel)
sourceImage = ColumnDataSource({'image': [adjusted]})
#=============================================================
def callbackSliderAlphaBeta(attr, old, new):
alphaLevel = sliderAlpha.value
betaLevel = sliderBeta.value
print("Contrast level (1.0-3.0): %.1f" %(alphaLevel))
print("Brightness level: %d" %(betaLevel))
adjusted = cv2.convertScaleAbs(gray, alpha=alphaLevel, beta=betaLevel)
sourceImage.data = {'image': [adjusted]}
sliderAlpha = Slider(width=300, start=1.0, end=3.0, value=1.0, step=.1, title="Contrast") # Contrast control (1.0:3.0)
sliderAlpha.on_change('value', callbackSliderAlphaBeta)
sliderBeta = Slider(width=300, start=-100, end=100, value=0, step=5, title="Brightness") # Brightness control (-100:100)
sliderBeta.on_change('value', callbackSliderAlphaBeta)
#=============================================================
h, w, c = img.shape
print(w,h)
plot_width = 800
ratio = plot_width/w
plot = figure(
plot_width = plot_width,
plot_height = int(h*ratio),
x_range=(1,w),
y_range=(1,h),
tools = "pan,wheel_zoom,box_zoom,reset,save",
toolbar_location = "above",
active_scroll = "wheel_zoom",
sizing_mode = "fixed" ,
title = os.path.basename(imageFileName)
)
plot.add_layout(LinearAxis(), 'above')
plot.add_layout(LinearAxis(), 'right')
imagePlot = plot.image(image='image', source=sourceImage, x=0, y=0, dw=w, dh=h, palette='Greys256')
#=============================================================
curdoc().add_root(column(plot, sliderAlpha, sliderBeta, file_input))