Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Showing cropped image in bokeh

I am showing a picture in a figure in bokeh and am using the BoxSelectTool in order to draw a rectangle.

box_select = BoxSelectTool(callback=callback)

p2 = figure(x_range=(0,700), y_range=(0,500),plot_width=1100,plot_height=1100,tools=[box_select])
p2.image_url( url='url',
         x=1, y=1, w=700, h=500, anchor="bottom_left",source=im_src)

rect_source = ColumnDataSource(data=dict(x=[], y=[], width=[], height=[]))
callback = CustomJS(args=dict(rect_source=rect_source), code="""
    // get data source from Callback args
    var data = rect_source.data;

    /// get BoxSelectTool dimensions from cb_data parameter of Callback
    var geometry = cb_data['geometry'];

    /// calculate Rect attributes
    var width = geometry['x1'] - geometry['x0'];
    var height = geometry['y1'] - geometry['y0'];
    var x = geometry['x0'] + width/2;
    var y = geometry['y0'] + height/2;

    /// update data source with new Rect attributes
    data['x'].push(x);
    data['y'].push(y);
    data['width'].push(width);
    data['height'].push(height);

    rect_source.data = data;
    rect_source.change.emit();
'''

Now I want to show that image region as cropped in a different, smaller figure, after the rectangle is drawn, without clicking a button or anything:

d2 = figure(x_range=(0,200), y_range=(0,100),plot_width=200,plot_height=100)
d2.image( image='image',
         x=1, y=1, dw=100, dh=100, source=img)

img = ColumnDataSource( data=dict(image=[]))

So I need something like this in JS:

tmp_im = cv2.imread('static/' + str(im_nr) + '.jpg')
tmp_im = tmp_im[geometry['y0']:geometry['y1'],geometry['x0']:geometry['x1']]
tmp_im = cv2.cvtColor(tmp_im, cv2.COLOR_BGR2GRAY)
img.data = dict(image=[tmp_im])

How can I do that in JS + bokeh?

like image 560
TobSta Avatar asked Jul 27 '18 22:07

TobSta


1 Answers

I suggest to use the module holoviews (part of the pyviz ecosystem) for this task, which provides a high-level access to bokeh.

Holoviews provides so called streams, which can be used together with DynamicMaps to generate dynamic figures based on the (changing) values of the stream.

The module panel (also part of the pyviz ecosystem) can be used to define layouts for visualization.

import numpy as np
import holoviews as hv
from holoviews import opts
from holoviews.streams import BoundsXY
import panel as pn

pn.extension() # loading the panel extension for use with notebook
opts.defaults(opts.Image(tools=['box_select'])) # making sure, that box_select is available

minval, maxval = 0, 200

# x-y data
ls = np.linspace(minval, 10, maxval)
xx, yy = np.meshgrid(ls, ls)
# z-data, e.g. intensity
zz = xx*yy

# min and max, later used to recalibrate the colormapping
zzmin = zz.min()
zzmax = zz.max() 

bounds=(0,0, 1,1) # bounds used for the image
im = hv.Image(zz, bounds=bounds)

# stream, xy-data are provided by the box_select-tool
# As start values the same bounds as for the image are used.
box = BoundsXY(bounds=bounds) 

# The box-stream is used to draw a rectangle dynamically
# based on the current selection using the box_select-tool.
rect = hv.DynamicMap(
    lambda bounds: hv.Bounds(bounds),
    streams=[box])

# The box-stream is used to draw an image dynamically
# based on the current selection using the box_select-tool.
im_select = hv.DynamicMap(
    lambda bounds: im[bounds[0]:bounds[2],bounds[1]:bounds[3]],
    streams=[box])

# Arranging the layout.
# With redim.range we make sure the colormapping uses the original min- and max-values as in 'im',
# and not the min- and max-values from 'im_select'.
layout = pn.Row(im * rect \
                +\
                im_select.redim.range(z=(zzmin, zzmax))) 
layout.app()

enter image description here

like image 80
mdk Avatar answered Oct 20 '22 02:10

mdk