Package omeroweb :: Package webtest :: Module views
[hide private]
[frames] | no frames]

Source Code for Module omeroweb.webtest.views

  1  #!/usr/bin/env python 
  2  # -*- coding: utf-8 -*- 
  3  from django.http import HttpResponseRedirect, HttpResponse 
  4  from django.core.urlresolvers import reverse 
  5  from django.shortcuts import render_to_response 
  6  from omeroweb.webgateway import views as webgateway_views 
  7  from omeroweb.connector import Server 
  8   
  9  from omeroweb.webclient.decorators import login_required, render_response 
 10  from omeroweb.connector import Connector 
 11   
 12  from cStringIO import StringIO 
 13   
 14  import settings 
 15  import logging 
 16  import traceback 
 17  import omero 
 18  from omero.rtypes import rint, rstring 
 19  import omero.gateway 
 20  import random 
 21   
 22   
 23  logger = logging.getLogger(__name__)     
 24   
 25   
 26  try: 
 27      from PIL import Image 
 28  except: #pragma: nocover 
 29      try: 
 30          import Image 
 31      except: 
 32          logger.error('No PIL installed, line plots and split channel will fail!') 
33 34 35 @login_required() # wrapper handles login (or redirects to webclient login). Connection passed in **kwargs 36 -def dataset(request, datasetId, conn=None, **kwargs):
37 """ 'Hello World' example from tutorial on http://trac.openmicroscopy.org.uk/ome/wiki/OmeroWeb """ 38 ds = conn.getObject("Dataset", datasetId) # before OMERO 4.3 this was conn.getDataset(datasetId) 39 return render_to_response('webtest/dataset.html', {'dataset': ds}) # generate html from template
40
41 42 @login_required() # wrapper handles login (or redirects to webclient login). Connection passed in **kwargs 43 -def index(request, conn=None, **kwargs):
44 # use Image IDs from request... 45 if request.REQUEST.get("Image", None): 46 imageIds = request.REQUEST.get("Image", None) 47 ids = [int(iid) for iid in imageIds.split(",")] 48 images = list(conn.getObjects("Image", ids)) 49 else: 50 # OR find a random image and dataset to display & can be used in links to other pages 51 all_images = list(conn.getObjects("Image")) 52 img = random.choice(all_images) 53 images = [img] 54 55 imgIds = ",".join([str(img.getId()) for img in images]) 56 57 # get a random dataset (making sure we get one that has some images in it) 58 all_datasets = list(conn.getObjects("Dataset")) 59 dataset = random.choice(all_datasets) 60 attempts = 0 61 while (dataset.countChildren() == 0 and attempts < 10): 62 dataset = random.choice(all_datasets) 63 attempts += 1 64 65 return render_to_response('webtest/index.html', {'images': images, 'imgIds': imgIds, 'dataset': dataset})
66
67 68 @login_required() 69 -def channel_overlay_viewer(request, imageId, conn=None, **kwargs):
70 """ 71 Viewer for overlaying separate channels from the same image or different images 72 and adjusting horizontal and vertical alignment of each 73 """ 74 image = conn.getObject("Image", imageId) 75 default_z = image.getSizeZ()/2 76 77 # try to work out which channels should be 'red', 'green', 'blue' based on rendering settings 78 red = None 79 green = None 80 blue = None 81 notAssigned = [] 82 channels = [] 83 for i, c in enumerate(image.getChannels()): 84 channels.append( {'name':c.getName()} ) 85 if c.getColor().getRGB() == (255, 0, 0) and red == None: 86 red = i 87 elif c.getColor().getRGB() == (0, 255, 0) and green == None: 88 green = i 89 elif c.getColor().getRGB() == (0, 0, 255) and blue == None: 90 blue = i 91 else: 92 notAssigned.append(i) 93 # any not assigned - try assigning 94 for i in notAssigned: 95 if red == None: red = i 96 elif green == None: green = i 97 elif blue == None: blue = i 98 99 # see if we have z, x, y offsets already annotated on this image 100 # added by javascript in viewer. E.g. 0|z:1_x:0_y:0,1|z:0_x:10_y:0,2|z:0_x:0_y:0 101 ns = "omero.web.channel_overlay.offsets" 102 comment = image.getAnnotation(ns) 103 if comment == None: # maybe offset comment has been added manually (no ns) 104 for ann in image.listAnnotations(): 105 if isinstance(ann, omero.gateway.CommentAnnotationWrapper): 106 if ann.getValue().startswith("0|z:"): 107 comment = ann 108 break 109 if comment != None: 110 offsets = comment.getValue() 111 for o in offsets.split(","): 112 index,zxy = o.split("|",1) 113 if int(index) < len(channels): 114 keyVals = zxy.split("_") 115 for kv in keyVals: 116 key, val = kv.split(":") 117 if key == "z": val = int(val) + default_z 118 channels[int(index)][key] = int(val) 119 120 return render_to_response('webtest/demo_viewers/channel_overlay_viewer.html', { 121 'image': image, 'channels':channels, 'default_z':default_z, 'red': red, 'green': green, 'blue': blue})
122
123 124 @login_required() 125 -def render_channel_overlay (request, conn=None, **kwargs):
126 """ 127 Overlays separate channels (red, green, blue) from the same image or different images 128 manipulating each indepdently (translate, scale, rotate etc? ) 129 """ 130 # request holds info on all the planes we are working on and offset (may not all be visible) 131 # planes=0|imageId:z:c:t$x:shift_y:shift_rot:etc,1|imageId... 132 # E.g. planes=0|2305:7:0:0$x:-50_y:10,1|2305:7:1:0,2|2305:7:2:0&red=2&blue=0&green=1 133 planes = {} 134 p = request.REQUEST.get('planes', None) 135 if p is None: 136 return HttpResponse("Request needs plane info to render jpeg. E.g. ?planes=0|2305:7:0:0$x:-50_y:10,1|2305:7:1:0,2|2305:7:2:0&red=2&blue=0&green=1") 137 for plane in p.split(','): 138 infoMap = {} 139 plane_info = plane.split('|') 140 key = plane_info[0].strip() 141 info = plane_info[1].strip() 142 shift = None 143 if info.find('$')>=0: 144 info,shift = info.split('$') 145 imageId,z,c,t = [int(i) for i in info.split(':')] 146 infoMap['imageId'] = imageId 147 infoMap['z'] = z 148 infoMap['c'] = c 149 infoMap['t'] = t 150 if shift != None: 151 for kv in shift.split("_"): 152 k, v = kv.split(":") 153 infoMap[k] = v 154 planes[key] = infoMap 155 156 # from the request we need to know which plane is blue, green, red (if any) by index 157 # E.g. red=0&green=2 158 red = request.REQUEST.get('red', None) 159 green = request.REQUEST.get('green', None) 160 blue = request.REQUEST.get('blue', None) 161 162 # kinda like split-view: we want to get single-channel images... 163 # red... 164 redImg = None 165 166 def translate(image, deltaX, deltaY): 167 168 xsize, ysize = image.size 169 mode = image.mode 170 bg = Image.new(mode, image.size) 171 x = abs(min(deltaX, 0)) 172 pasteX = max(0, deltaX) 173 y = abs(min(deltaY, 0)) 174 pasteY = max(0, deltaY) 175 176 part = image.crop((x, y, xsize-deltaX, ysize-deltaY)) 177 bg.paste(part, (pasteX, pasteY)) 178 return bg
179 180 def getPlane(planeInfo): 181 """ Returns the rendered plane split into a single channel (ready for merging) """ 182 img = conn.getObject("Image", planeInfo['imageId']) 183 img.setActiveChannels((planeInfo['c']+1,)) 184 img.setGreyscaleRenderingModel() 185 rgb = img.renderImage(planeInfo['z'], planeInfo['t']) 186 187 # somehow this line is required to prevent an error at 'rgb.split()' 188 rgb.save(StringIO(), 'jpeg', quality=90) 189 190 r,g,b = rgb.split() # go from RGB to L 191 192 x,y = 0,0 193 if 'x' in planeInfo: 194 x = int(planeInfo['x']) 195 if 'y' in planeInfo: 196 y = int(planeInfo['y']) 197 198 if x or y: 199 r = translate(r, x, y) 200 return r 201 202 redChannel = None 203 greenChannel = None 204 blueChannel = None 205 if red != None and red in planes: 206 redChannel = getPlane(planes[red]) 207 if green != None and green in planes: 208 greenChannel = getPlane(planes[green]) 209 if blue != None and blue in planes: 210 blueChannel = getPlane(planes[blue]) 211 212 if redChannel != None: 213 size = redChannel.size 214 elif greenChannel != None: 215 size = greenChannel.size 216 elif blueChannel != None: 217 size = blueChannel.size 218 219 black = Image.new('L', size) 220 redChannel = redChannel and redChannel or black 221 greenChannel = greenChannel and greenChannel or black 222 blueChannel = blueChannel and blueChannel or black 223 224 merge = Image.merge("RGB", (redChannel, greenChannel, blueChannel)) 225 # convert from PIL back to string image data 226 rv = StringIO() 227 compression = 0.9 228 merge.save(rv, 'jpeg', quality=int(compression*100)) 229 jpeg_data = rv.getvalue() 230 231 rsp = HttpResponse(jpeg_data, mimetype='image/jpeg') 232 return rsp 233
234 235 @login_required() 236 -def add_annotations (request, conn=None, **kwargs):
237 """ 238 Creates a L{omero.gateway.CommentAnnotationWrapper} and adds it to the images according 239 to variables in the http request. 240 241 @param request: The django L{django.core.handlers.wsgi.WSGIRequest} 242 - imageIds: A comma-delimited list of image IDs 243 - comment: The text to add as a comment to the images 244 - ns: Namespace for the annotation 245 - replace: If "true", try to replace existing annotation with same ns 246 247 @return: A simple html page with a success message 248 """ 249 idList = request.REQUEST.get('imageIds', None) # comma - delimited list 250 if idList: 251 imageIds = [long(i) for i in idList.split(",")] 252 else: imageIds = [] 253 254 comment = request.REQUEST.get('comment', None) 255 ns = request.REQUEST.get('ns', None) 256 replace = request.REQUEST.get('replace', False) in ('true', 'True') 257 258 updateService = conn.getUpdateService() 259 ann = omero.model.CommentAnnotationI() 260 ann.setTextValue(rstring( str(comment) )) 261 if ns != None: 262 ann.setNs(rstring( str(ns) )) 263 ann = updateService.saveAndReturnObject(ann) 264 annId = ann.getId().getValue() 265 266 images = [] 267 for iId in imageIds: 268 image = conn.getObject("Image", iId) 269 if image == None: continue 270 if replace and ns != None: 271 oldComment = image.getAnnotation(ns) 272 if oldComment != None: 273 oldComment.setTextValue(rstring( str(comment) )) 274 updateService.saveObject(oldComment) 275 continue 276 l = omero.model.ImageAnnotationLinkI() 277 parent = omero.model.ImageI(iId, False) # use unloaded object to avoid update conflicts 278 l.setParent(parent) 279 l.setChild(ann) 280 updateService.saveObject(l) 281 images.append(image) 282 283 return render_to_response('webtest/util/add_annotations.html', {'images':images, 'comment':comment})
284
285 286 @login_required() 287 -def split_view_figure (request, conn=None, **kwargs):
288 """ 289 Generates an html page displaying a number of images in a grid with channels split into different columns. 290 The page also includes a form for modifying various display parameters and re-submitting 291 to regenerate this page. 292 If no 'imageIds' parameter (comma-delimited list) is found in the 'request', the page generated is simply 293 a form requesting image IDs. 294 If there are imageIds, the first ID (image) is used to generate the form based on channels of that image. 295 296 @param request: The django L{http request <django.core.handlers.wsgi.WSGIRequest>} 297 298 @return: The http response - html page displaying split view figure. 299 """ 300 query_string = request.META["QUERY_STRING"] 301 302 303 idList = request.REQUEST.get('imageIds', None) # comma - delimited list 304 idList = request.REQUEST.get('Image', idList) # we also support 'Image' 305 if idList: 306 imageIds = [long(i) for i in idList.split(",")] 307 else: 308 imageIds = [] 309 310 split_grey = request.REQUEST.get('split_grey', None) 311 merged_names = request.REQUEST.get('merged_names', None) 312 proj = request.REQUEST.get('proj', "normal") # intmean, intmax, normal 313 try: 314 w = request.REQUEST.get('width', 0) 315 width = int(w) 316 except: 317 width = 0 318 try: 319 h = request.REQUEST.get('height', 0) 320 height = int(h) 321 except: 322 height = 0 323 324 # returns a list of channel info from the image, overridden if values in request 325 def getChannelData(image): 326 channels = [] 327 i = 0; 328 channel_data = image.getChannels() 329 if channel_data is None: # E.g. failed import etc 330 return None 331 for i, c in enumerate(channel_data): 332 name = request.REQUEST.get('cName%s' % i, c.getLogicalChannel().getName()) 333 # if we have channel info from a form, we know that checkbox:None is unchecked (not absent) 334 if request.REQUEST.get('cName%s' % i, None): 335 active = (None != request.REQUEST.get('cActive%s' % i, None) ) 336 merged = (None != request.REQUEST.get('cMerged%s' % i, None) ) 337 else: 338 active = True 339 merged = True 340 colour = c.getColor() 341 if colour is None: 342 return None # rendering engine problems 343 colour = colour.getHtml() 344 start = request.REQUEST.get('cStart%s' % i, c.getWindowStart()) 345 end = request.REQUEST.get('cEnd%s' % i, c.getWindowEnd()) 346 render_all = (None != request.REQUEST.get('cRenderAll%s' % i, None) ) 347 channels.append({"name": name, "index": i, "active": active, "merged": merged, "colour": colour, 348 "start": start, "end": end, "render_all": render_all}) 349 return channels
350 351 channels = None 352 images = [] 353 for iId in imageIds: 354 image = conn.getObject("Image", iId) 355 if image == None: continue 356 default_z = image.getSizeZ()/2 # image.getZ() returns 0 - should return default Z? 357 # need z for render_image even if we're projecting 358 images.append({"id":iId, "z":default_z, "name": image.getName() }) 359 if channels is None: 360 channels = getChannelData(image) 361 if height == 0: 362 height = image.getSizeY() 363 if width == 0: 364 width = image.getSizeX() 365 366 if channels is None: 367 return HttpResponse("Couldn't load channels for this image") 368 size = {"height": height, "width": width} 369 c_strs = [] 370 if channels: # channels will be none when page first loads (no images) 371 indexes = range(1, len(channels)+1) 372 c_string = ",".join(["-%s" % str(c) for c in indexes]) # E.g. -1,-2,-3,-4 373 mergedFlags = [] 374 for i, c, in enumerate(channels): 375 if c["render_all"]: 376 levels = "%s:%s" % (c["start"], c["end"]) 377 else: levels = "" 378 if c["active"]: 379 onFlag = str(i+1) + "|" 380 onFlag += levels 381 if split_grey: onFlag += "$FFFFFF" # E.g. 1|100:505$0000FF 382 c_strs.append( c_string.replace("-%s" % str(i+1), onFlag) ) # E.g. 1,-2,-3 or 1|$FFFFFF,-2,-3 383 if c["merged"]: 384 mergedFlags.append("%s|%s" % (i+1, levels)) # E.g. '1|200:4000' 385 else: mergedFlags.append("-%s" % (i+1)) # E.g. '-1' 386 # turn merged channels on in the last image 387 c_strs.append( ",".join(mergedFlags) ) 388 389 template = kwargs.get('template', 'webtest/demo_viewers/split_view_figure.html') 390 return render_to_response(template, {'images':images, 'c_strs': c_strs,'imageIds':idList, 391 'channels': channels, 'split_grey':split_grey, 'merged_names': merged_names, 'proj': proj, 'size': size, 'query_string':query_string}) 392
393 394 @login_required() 395 -def dataset_split_view (request, datasetId, conn=None, **kwargs):
396 """ 397 Generates a web page that displays a dataset in two panels, with the option to choose different 398 rendering settings (channels on/off) for each panel. It uses the render_image url for each 399 image, generating the full sized image which is scaled down to view. 400 401 The page also includes a form for editing the channel settings and display size of images. 402 This form resubmits to this page and displays the page again with updated parameters. 403 404 @param request: The django L{http request <django.core.handlers.wsgi.WSGIRequest>} 405 @param datasetId: The ID of the dataset. 406 @type datasetId: Number. 407 408 @return: The http response - html page displaying split view figure. 409 """ 410 dataset = conn.getObject("Dataset", datasetId) 411 412 try: 413 size = request.REQUEST.get('size', 100) 414 size = int(size) 415 except: 416 size = 100 417 418 # returns a list of channel info from the image, overridden if values in request 419 def getChannelData(image): 420 channels = [] 421 i = 0; 422 chs = image.getChannels() 423 if chs is None: 424 return [] 425 for i, c in enumerate(chs): 426 if c is None: 427 continue 428 name = c.getLogicalChannel().getName() 429 # if we have channel info from a form, we know that checkbox:None is unchecked (not absent) 430 if request.REQUEST.get('cStart%s' % i, None): 431 active_left = (None != request.REQUEST.get('cActiveLeft%s' % i, None) ) 432 active_right = (None != request.REQUEST.get('cActiveRight%s' % i, None) ) 433 else: 434 active_left = True 435 active_right = True 436 colour = c.getColor() 437 if colour is None: 438 continue # serious rendering engine problems 439 colour = colour.getHtml(); 440 start = request.REQUEST.get('cStart%s' % i, c.getWindowStart()) 441 end = request.REQUEST.get('cEnd%s' % i, c.getWindowEnd()) 442 render_all = (None != request.REQUEST.get('cRenderAll%s' % i, None) ) 443 channels.append({"name": name, "index": i, "active_left": active_left, "active_right": active_right, 444 "colour": colour, "start": start, "end": end, "render_all": render_all}) 445 return channels
446 447 images = [] 448 channels = None 449 450 for image in dataset.listChildren(): 451 if channels == None or len(channels) == 0: 452 channels = getChannelData(image) 453 default_z = image.getSizeZ()/2 # image.getZ() returns 0 - should return default Z? 454 # need z for render_image even if we're projecting 455 images.append({"id":image.getId(), "z":default_z, "name": image.getName() }) 456 457 if channels is None: 458 return HttpResponse("<p class='center_message'>No Images in Dataset<p>") 459 460 indexes = range(1, len(channels)+1) 461 c_string = ",".join(["-%s" % str(c) for c in indexes]) # E.g. -1,-2,-3,-4 462 463 leftFlags = [] 464 rightFlags = [] 465 for i, c, in enumerate(channels): 466 if c["render_all"]: 467 levels = "%s:%s" % (c["start"], c["end"]) 468 else: levels = "" 469 if c["active_left"]: 470 leftFlags.append("%s|%s" % (i+1, levels)) # E.g. '1|200:4000' 471 else: leftFlags.append("-%s" % (i+1)) # E.g. '-1' 472 if c["active_right"]: 473 rightFlags.append("%s|%s" % (i+1, levels)) # E.g. '1|200:4000' 474 else: rightFlags.append("-%s" % (i+1)) # E.g. '-1' 475 476 c_left = ",".join(leftFlags) 477 c_right = ",".join(rightFlags) 478 479 template = kwargs.get('template', 'webtest/webclient_plugins/dataset_split_view.html') 480 481 return render_to_response(template, {'dataset': dataset, 'images': images, 482 'channels':channels, 'size': size, 'c_left': c_left, 'c_right': c_right}) 483
484 485 @login_required() 486 -def image_dimensions (request, imageId, conn=None, **kwargs):
487 """ 488 Prepare data to display various dimensions of a multi-dim image as axes of a grid of image planes. 489 E.g. x-axis = Time, y-axis = Channel. 490 """ 491 image = conn.getObject("Image", imageId) 492 if image is None: 493 return render_to_response('webtest/demo_viewers/image_dimensions.html', {}) 494 495 mode = request.REQUEST.get('mode', None) and 'g' or 'c' 496 dims = {'Z':image.getSizeZ(), 'C': image.getSizeC(), 'T': image.getSizeT()} 497 498 default_yDim = 'Z' 499 500 xDim = request.REQUEST.get('xDim', 'C') 501 if xDim not in dims.keys(): 502 xDim = 'C' 503 504 yDim = request.REQUEST.get('yDim', default_yDim) 505 if yDim not in dims.keys(): 506 yDim = 'Z' 507 508 xFrames = int(request.REQUEST.get('xFrames', 5)) 509 xSize = dims[xDim] 510 yFrames = int(request.REQUEST.get('yFrames', 10)) 511 ySize = dims[yDim] 512 513 xFrames = min(xFrames, xSize) 514 yFrames = min(yFrames, ySize) 515 516 xRange = range(xFrames) 517 yRange = range(yFrames) 518 519 # 2D array of (theZ, theC, theT) 520 grid = [] 521 for y in yRange: 522 grid.append([]) 523 for x in xRange: 524 iid, theZ, theC, theT = image.id, 0,None,0 525 if xDim == 'Z': 526 theZ = x 527 if xDim == 'C': 528 theC = x 529 if xDim == 'T': 530 theT = x 531 if yDim == 'Z': 532 theZ = y 533 if yDim == 'C': 534 theC = y 535 if yDim == 'T': 536 theT = y 537 538 grid[y].append( (iid, theZ, theC is not None and theC+1 or None, theT) ) 539 540 541 size = {"height": 125, "width": 125} 542 543 return render_to_response('webtest/demo_viewers/image_dimensions.html', {'image':image, 'grid': grid, 544 "size": size, "mode":mode, 'xDim':xDim, 'xRange':xRange, 'yRange':yRange, 'yDim':yDim, 545 'xFrames':xFrames, 'yFrames':yFrames})
546
547 548 @login_required() 549 -def image_rois (request, imageId, conn=None, **kwargs):
550 """ Simply shows a page of ROI thumbnails for the specified image """ 551 roiService = conn.getRoiService() 552 result = roiService.findByImage(long(imageId), None, conn.SERVICE_OPTS) 553 roiIds = [r.getId().getValue() for r in result.rois] 554 return render_to_response('webtest/demo_viewers/image_rois.html', {'roiIds':roiIds})
555
556 557 -def webgateway_templates (request, base_template):
558 """ Simply return the named template. Similar functionality to django.views.generic.simple.direct_to_template """ 559 template_name = 'webtest/webgateway/%s.html' % base_template 560 return render_to_response(template_name, {})
561
562 @login_required() 563 @render_response() 564 -def webclient_templates (request, base_template, **kwargs):
565 """ Simply return the named template. Similar functionality to django.views.generic.simple.direct_to_template """ 566 template_name = 'webtest/webgateway/%s.html' % base_template 567 return {'template': template_name}
568
569 570 @login_required() 571 -def image_viewer (request, iid=None, conn=None, **kwargs):
572 """ This view is responsible for showing pixel data as images. Delegates to webgateway, using share connection if appropriate """ 573 574 if iid is None: 575 iid = request.REQUEST.get('image') 576 577 template = 'webtest/webclient_plugins/center_plugin.fullviewer.html' 578 579 return webgateway_views.full_viewer(request, iid, _conn=conn, template=template, **kwargs)
580
581 @login_required() 582 -def stack_preview (request, imageId, conn=None, **kwargs):
583 """ Shows a subset of Z-planes for an image """ 584 image = conn.getObject("Image", imageId) 585 image_name = image.getName() 586 sizeZ = image.getSizeZ() 587 z_indexes = [0, int(sizeZ*0.25), int(sizeZ*0.5), int(sizeZ*0.75), sizeZ-1] 588 return render_to_response('webtest/stack_preview.html', {'imageId':imageId, 'image_name':image_name, 'z_indexes':z_indexes})
589
590 @login_required() 591 -def render_performance (request, obj_type, id, conn=None, **kwargs):
592 """ Test rendering performance for all planes in an image """ 593 context = {} 594 if obj_type == 'image': 595 image = conn.getObject("Image", id) 596 image._prepareRenderingEngine() 597 598 # If a 'BIG Image' 599 if image._re.requiresPixelsPyramid(): 600 MAX_TILES = 50 601 tileList = [] 602 tile_w, tile_h = image._re.getTileSize() 603 cols = image.getSizeX() / tile_w 604 rows = image.getSizeY() / tile_h 605 tileList = [ {'col':c, 'row':r} for r in range(rows) for c in range(cols)] 606 if (len(tileList) > 2*MAX_TILES): 607 tileList = tileList[ (len(tileList)/2):] # start in middle of list (looks nicer!) 608 tileList = tileList[:MAX_TILES] 609 context = {'tileList': tileList, 'imageId':id} 610 # A regular Image 611 else: 612 zctList = [] 613 for z in range(image.getSizeZ()): 614 for c in range(image.getSizeC()): 615 for t in range(image.getSizeT()): 616 zctList.append({'z':z, 'c':c+1, 't':t}) 617 context = {'zctList':zctList, 'imageId':id} 618 # A Plate 619 elif obj_type == 'plate': 620 imageIds = [] 621 plate = conn.getObject("Plate", id) 622 for well in plate._listChildren(): 623 for ws in well.copyWellSamples(): 624 imageIds.append(ws.image.id.val) 625 context = {'plate':plate, 'imageIds':imageIds} 626 627 elif obj_type == "dataset": 628 dataset = conn.getObject("Dataset", id) 629 imageIds = [i.getId() for i in dataset.listChildren()] 630 context = {'imageIds':imageIds} 631 632 return render_to_response('webtest/demo_viewers/render_performance.html', context)
633