Closed CorBer closed 5 years ago
Hello James,
Thanks for chiming in, unfortunately this does not help at all ... I tried to use plot=plot.options(xlim=(2500, 2900), ylim=(1000, 1200), clone=False) but the plot does not change. I guess it is due to the fact that the plot is part of an interactive setup. Just a case of ... trying something that is not very much the default approach. Thanks again for answering.
regards Cor
That FAQ is addressing why you didn't find redim.range to do anything. Above, you don't need "plot=" if you do clone=False, and in any case clone=False is the default for .opts, so just use that one for setting options.
Well I first tried without clone and nothing happened also ... I thought this would be a very simple thing to do ... just set the plotting range for X and Y programmatically ... turns out to be something that was not ment to be done.
Don't worry; setting the plotting range programatically is very common indeed; I'm just pointing out a few issues I see immediately, without having time on a Sunday to look at your full example...
No problem, I am enjoying the fact that jupyter notebooks and the libraries give me the freedom to build stuff using python I have not been able to do before. I hope you can provide more advice during the week
Found a way forward based on code from http://holoviews.org/user_guide/Responding_to_Events.html
%%opts Image {+framewise}
# Styles and plot options used in this user guide
ls = np.linspace(0, 10, 200)
xx, yy = np.meshgrid(ls, ls)
XY = Stream.define('limits',xl=0.1,yl=0.3,xh=0.4,yh=0.6)
def img(xl,yl,xh,yh):
extents=(xl,yl,xh,yh)
return hv.Image(np.sin(xx)*np.cos(yy), extents=extents)
dmap = hv.DynamicMap(img, streams=[XY()])
dmap
after this I can call dmap.event(xl=0,yl=0,xh=1,yh=1) and it will zoom to that area !
Now I only need change the way I use interact probably
Unfortunately this does not work as easy as I was hoping. When using several elements in a plot (inside the img_routine and combined using * at the end, the moment I add my markers to the plot the call to dmap.event does not update the plot anymore.
So I am back to my previous code, I am sharing it below together with a screenshot after starting the code. To make clear what my issue is: the code allows the user to draw a box using the box-edit function from the bokeh-menu. What I then want to do is save that box (allready implemented) and from that moment directly allow the user to zoom to this section of the plot the moment the user presses a button (not implemented yet) ideally without reloading the whole graph.
regards Cor
import numpy as np
import pandas as pd
from ipywidgets import interact
from ipywidgets import HBox, Button, Output
import holoviews as hv
from holoviews import opts
from holoviews import streams
import imageio
import os
import csv
hv.extension('bokeh')
#setup debugger
debug_view = Output(layout={'border': '1px solid black'})
#load filenames
path = '.'
imgs = list(filter(lambda fn:fn.lower().endswith('.jpg'), os.listdir(path)))
xdim,ydim=0,0
############################################## LABELS
dummy_data=list()
lbls=['N','T','L','R','F','G','H','J','1','2','3','4','5','6','7','8','9']
# routine to give markers a default colour based on the labels
def lbl2col(csv_label):
col='black' #wrong labeled will be shown in black
if csv_label=='N':
col='red'
if csv_label=='T':
col='lightgreen'
if csv_label in ['L','R']:
col='yellow'
if csv_label in ['F','G']:
col='lightblue'
if csv_label in ['H','J']:
col='orange'
if csv_label in ['1','2','3','4','5','6','7','8','9']:
col='white'
return col
############################################## LOAD BOX
def load_box(file):
global xdim,ydim, xmax,xmin,ymax,ymin, dummy_data
filecsv=str(file).split('.')[0]+'.box'
try:
with open(filecsv) as csv_file:
csv_reader = csv.reader(csv_file)
next(csv_reader, None) #skip the CSVheader
#load the box Xmin, Ymin, Xmax, Ymax
val=next(csv_reader,None)
xmin=int(float(val[0]))
val=next(csv_reader,None)
ymax=ydim-int(float(val[0]))
val=next(csv_reader,None)
xmax=int(float(val[0]))
val=next(csv_reader,None)
ymin=ydim-int(float(val[0]))
except:
xmin,ymin=0,0
xmax,ymax=xdim,ydim
dummy_data=list()
yheight=(ymax-ymin )/20 #20 steps
y=ydim-ymin
x=xmin
for csv_label in lbls:
colr=lbl2col(csv_label)
y=y-yheight
dummy_data.append([x,y,colr,csv_label])
############################################## LOAD CSV
@debug_view.capture()
def load_csv(file):
import csv
#filecsv='DJI_0002.csv'
#create the filename and try to load the data
filecsv=str(file).split('.')[0]+'.csv'
#print(filecsv
data=list()
count=0
xmin,ymin=xdim,ydim
xmax,ymax=0,0
try:
with open(filecsv) as csv_file:
csv_reader = csv.reader(csv_file)
next(csv_reader, None) # skip the header
moredata=True
while moredata:
try:
csvdata=next(csv_reader,None)
csv_x=int(float(csvdata[0]))
csv_y=int(float(csvdata[1]))
#keep track of the margins
if csv_x>0:
if csv_y>0:
if csv_x<xmin:
xmin=csv_x
if csv_x>xmax:
xmax=csv_x
if csv_y<ymin:
ymin=csv_y
if csv_y>ymax:
ymax=csv_y
csv_label=csvdata[3]
col=lbl2col(csv_label)
data.append([csv_x,csv_y,col,csv_label])
count=count+1
except:
moredata=False
except:
print('error in csv')
xmin,ymin=0,0
xmax,ymax=xdim,ydim
data=dummy_data #fallback to dummy
return data
############################################## SET BOUNDS
def setimagebounds():
global xmax,xmin,ymax,ymin
width=(xmax-xmin) #prepare for zooming out
height=(ymax-ymin)
ratio=xdim/ydim # original image ratio
#keep centre, keep image ratio and zoom 20% out
if xmin>0:
h_width=(height*ratio/2)*1.2
h_height=(height/2)*1.2
else:
h_width=height*ratio/2
h_height=height/2
centerX=(width)*0.5+xmin
centerY=(height)*0.5+ymin
xmax=centerX+h_width
ymax=centerY+h_height
xmin=centerX-h_width
ymin=centerY-h_height
def hook(plot, element):
global xmin, ymin, xmax, ymax
plot.handles['x_range'].start = xmin
plot.handles['x_range'].end = xmax
plot.handles['y_range'].start = ydim-ymax
plot.handles['y_range'].end = ydim-ymin
#plot.handles['xaxis'].visible=False
#plot.handles['yaxis'].visible=False
############################################## LOAD_IMAGE
def load_image(file):
global img, table,points,xdim,ydim
img = imageio.imread(file)
nimg = np.asarray(img)
ydim, xdim, chans = nimg.shape
img=hv.Image(nimg[::1], bounds=(0,0,xdim,ydim))
return img
data=list()
lastfile=''
labelcount=15
############################################## INTERACTIVE LOADIMAGE
@debug_view.capture(clear_output=True)
def I_loadimg(file):
global lastfile
lastfile=file
global plot, box, point_stream, img, bounds
img=load_image(file)
load_box(file)
data=load_csv(file)
# Declare a Bounds stream and DynamicMap to get box_select geometry and draw it
box = streams.BoundsXY(source=img, bounds=(0,0,0,0))
bounds = hv.DynamicMap(lambda bounds: hv.Bounds(bounds), streams=[box]).opts(color='white', line_width=2)
setimagebounds()
points = hv.Points(data, vdims=['color','label']).redim.range(x=(0,xdim), y=(0,ydim)).opts( color='color')
point_stream = streams.PointDraw(data=points.columns(), num_objects=labelcount+20, source=points, empty_value='XX')
plot=((img*points * bounds).opts(
opts.Image(cmap='viridis', hooks=[hook], width=800, height=600),
opts.Points(tools=['hover'],marker='x', fill_color='color', fill_alpha=0.1, line_width=2, size=10 ),
))
display(plot.opts(framewise=True))
############################################## GUI
button = Button(description="Save CSV")
@debug_view.capture()
def on_button_clicked(b):
df=pd.DataFrame(point_stream.element.data)
df=df[['x','y','color','label']]
fname=lastfile.split('.')[0]+'.csv'
df.to_csv(fname, index=False)
button.description='Saved CSV'
button.on_click(on_button_clicked)
Zbutton = Button(description="Save ZoomBox")
@debug_view.capture()
def on_Zbutton_clicked(b):
Zbutton.description='Saved Zoom'
df=pd.DataFrame(box.bounds)
fname=lastfile.split('.')[0]+'.box'
df.to_csv(fname, index=False)
Zbutton.on_click(on_Zbutton_clicked)
display(HBox([button,Zbutton]))
display(debug_view)
interact(I_loadimg ,file=imgs)
Closing, did not find a solution
This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.
Hi,
I have create a plot combining 3 different elements(box, points, image) and can zoom in/out, pan etc using the default functionality from Bokeh ( hv.extension('bokeh'). But I cant seem to find a way where I can directly control the zoom of the whole plot. This is a snippet of my code, i am creating a global variable called plot which (I thought) would allow me to control the X and Y ranges. I was thinking that I could use plot.redim.range(x=(xx,xx)) but that does not do anything.