Package omero :: Package util :: Module figureUtil
[hide private]
[frames] | no frames]

Source Code for Module omero.util.figureUtil

  1  #!/usr/bin/env python 
  2  # -*- coding: utf-8 -*- 
  3  """ 
  4   components/tools/OmeroPy/src/omero/util/figureUitl.py 
  5   
  6  ----------------------------------------------------------------------------- 
  7    Copyright (C) 2006-2009 University of Dundee. All rights reserved. 
  8   
  9   
 10    This program is free software; you can redistribute it and/or modify 
 11    it under the terms of the GNU General Public License as published by 
 12    the Free Software Foundation; either version 2 of the License, or 
 13    (at your option) any later version. 
 14    This program is distributed in the hope that it will be useful, 
 15    but WITHOUT ANY WARRANTY; without even the implied warranty of 
 16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 17    GNU General Public License for more details. 
 18     
 19    You should have received a copy of the GNU General Public License along 
 20    with this program; if not, write to the Free Software Foundation, Inc., 
 21    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 
 22   
 23  ------------------------------------------------------------------------------ 
 24   
 25  A collection of utility methods used by Figure scripts for producing  
 26  publication type of figures.  
 27   
 28  @author  William Moore      
 29  <a href="mailto:will@lifesci.dundee.ac.uk">will@lifesci.dundee.ac.uk</a> 
 30  @author  Jean-Marie Burel &nbsp;&nbsp;&nbsp;&nbsp; 
 31  <a href="mailto:j.burel@dundee.ac.uk">j.burel@dundee.ac.uk</a> 
 32  @author Donald MacDonald &nbsp;&nbsp;&nbsp;&nbsp; 
 33  <a href="mailto:donald@lifesci.dundee.ac.uk">donald@lifesci.dundee.ac.uk</a> 
 34  @version 3.0 
 35  <small> 
 36  (<b>Internal version:</b> $Revision: $Date: $) 
 37  </small> 
 38  @since 3.0-Beta4.1 
 39    
 40  """ 
 41   
 42  try: 
 43      from PIL import Image, ImageDraw, ImageFont # see ticket:2597 
 44  except ImportError: 
 45      import Image, ImageDraw, ImageFont # see ticket:2597 
 46   
 47  WHITE = (255,255,255) 
 48   
 49  SECS_MILLIS = "SECS_MILLIS" 
 50  SECS = "SECS" 
 51  MINS = "MINS" 
 52  HOURS = "HOURS" 
 53  MINS_SECS = "MINS_SECS" 
 54  HOURS_MINS = "HOURS_MINS" 
 55  HOURS_MINS_SECS = "HOURS_MINS_SECS" 
 56  HOURS_MINS_SECS_MILLIS = "HOURS_MINS_SECS_MILLIS" 
 57  TIME_UNITS = [SECS_MILLIS, SECS, MINS, HOURS, MINS_SECS, HOURS_MINS, HOURS_MINS_SECS, HOURS_MINS_SECS_MILLIS] 
 58   
59 -def getDatasetsProjectsFromImages(queryService, imageIds):
60 """ 61 Query returns a map where each key is the imageId and the value is a list of (projectName, datasetName) tuples. 62 If the image does not have a Dataset AND Project, the map will hold an empty list for that imageId. 63 64 @param queryService: The Omero query service 65 @param imageIds: A list of image IDs. [long] 66 @return: A map imageId:[(projectName, datasetName)] 67 """ 68 ids = ",".join([str(i) for i in imageIds]) 69 70 query_string = "select i from Image i join fetch i.datasetLinks idl join fetch idl.parent d join fetch d.projectLinks pl join fetch pl.parent where i.id in (%s)" % ids 71 72 images = queryService.findAllByQuery(query_string, None) 73 results = {} 74 75 for i in images: # order of images not same as imageIds 76 pdList = [] 77 imageId = i.getId().getValue() 78 for link in i.iterateDatasetLinks(): 79 dataset = link.parent 80 dName = dataset.getName().getValue() 81 if dataset.sizeOfProjectLinks() == 0: 82 pdList.append(("", dName)) 83 for dpLink in dataset.iterateProjectLinks(): 84 project = dpLink.parent 85 pName = project.getName().getValue() 86 pdList.append((pName, dName)) 87 results[imageId] = pdList 88 89 # make sure the map contains all the imageIds 90 for iId in imageIds: 91 if iId not in results: 92 results[iId] = [] 93 return results
94 95
96 -def getTagsFromImages(metadataService, imageIds):
97 """ 98 Query returns a map of key = imageId, value = [tagNames] for the image 99 100 @param metadataService: The Omero metadata service 101 @param imageIds: A list of image IDs. [long] 102 @return: A map of imageId:[tagName] 103 """ 104 105 types = ["ome.model.annotations.TagAnnotation"] 106 annotations = metadataService.loadAnnotations("Image", imageIds, types, None, None) 107 108 tagsMap = {} 109 for i in imageIds: 110 annots = annotations[i] 111 tags = [a.getTextValue().getValue() for a in annots] 112 tagsMap[i] = tags 113 return tagsMap
114 115
116 -def getTimes(queryService, pixelsId, tIndexes, theZ=None, theC=None):
117 """ 118 Get the time in seconds (float) for the first plane (C = 0 & Z = 0) at 119 each time-point for the defined pixels. 120 Returns a map of tIndex: timeInSecs 121 122 @param queryService: The Omero queryService 123 @param pixelsId: The ID of the pixels object. long 124 @param tIndexes: List of time indexes. [int] 125 @param theZ: The Z plane index. Default is 0 126 @param theC: The Channel index. Default is 0 127 @return: A map of tIndex: timeInSecs 128 """ 129 if theZ == None: 130 theZ = 0 131 if theC == None: 132 theC = 0 133 indexes = ",".join([str(t) for t in tIndexes]) 134 query = "from PlaneInfo as Info where Info.theT in (%s) and Info.theZ in (%d) and Info.theC in (%d) and pixels.id='%d'" % (indexes, theZ, theC, pixelsId) 135 infoList = queryService.findAllByQuery(query,None) 136 timeMap = {} 137 for info in infoList: 138 tIndex = info.theT.getValue() 139 time = info.deltaT.getValue() 140 timeMap[tIndex] = time 141 return timeMap
142 143
144 -def formatTime(seconds, timeUnits):
145 """ 146 Returns a string formatting of the time (in seconds) 147 according to the chosen timeUnits: "SECS_MILLIS", "SECS", "MINS", "HOURS", "MINS_SECS", "HOURS_MINS", HOURS_MINS_SECS, HOURS_MINS_SECS_MILLIS 148 149 @param seconds: Time in seconds. float or int 150 @param timeUnits: A string denoting the format. One of the choices above. 151 @return: A string, such as "10" or "3:20" 152 """ 153 neg = False 154 if seconds < 0: 155 seconds = seconds * -1 156 neg = True 157 label = None 158 if timeUnits == "SECS_MILLIS": 159 label = "%.2f" % seconds 160 elif timeUnits == "SECS": 161 label = "%d" % int(round(seconds)) 162 elif timeUnits == "MINS": 163 mins = float(seconds) / float(60) 164 label = "%d" % int(round(mins)) 165 elif timeUnits == "HOURS": 166 hrs = float(seconds) / float(3600) 167 label = "%d" % int(round(hrs)) 168 elif timeUnits == "MINS_SECS": 169 mins = seconds / 60 170 secs = round(seconds % 60) 171 label = "%d:%02d" % (mins, secs) 172 elif timeUnits == "HOURS_MINS": 173 hrs = seconds / 3600 174 mins = round((seconds % 3600)/60) 175 label = "%d:%02d" % (hrs, mins) 176 elif timeUnits == "HOURS_MINS_SECS": 177 hrs = seconds / 3600 178 mins = (seconds % 3600)/60 179 secs = round(seconds % (3600 * 60)) 180 label = "%d:%02d:%02d" % (hrs, mins, secs) 181 elif timeUnits == "HOURS_MINS_SECS_MILLIS": 182 hrs = seconds / 3600 183 mins = (seconds % 3600)/60 184 secs = (seconds % (3600 * 60)) 185 label = "%d:%02d:%05.2f" % (hrs, mins, secs) 186 else: 187 label = "%.2f sec" % seconds 188 return neg and "-%s"%label or label
189 190
191 -def getTimeLabels(queryService, pixelsId, tIndexes, sizeT, timeUnits = None, showRoiDuration = False):
192 """ 193 Returns a list of time labels e.g. "10", "20" for the first plane at 194 each t-index (C=0 and Z=0). If no planeInfo is available, returns plane number/total e.g "3/10" 195 If time units are not specified, the most suitable units are chosen based on the max time. 196 The list of label returned includes the timeUnits as the last string in the list, in case you didn't specify it. 197 198 @param queryService: The Omero query service 199 @param pixelsId: The ID of the pixels you want info for 200 @param tIndexes: List of t-index to get the times for. Assumed to be in t order. 201 @param sizeT: The T dimension size of the pixels. Used if no plane info 202 @param timeUnits: Format choice of "SECS", "MINS", "HOURS", "MINS_SECS", "HOURS_MINS". String 203 @param showRoiDuration: if true, times shown are from the start of the ROI frames, otherwise use movie timestamp. 204 @return: A list of strings, ordered same as tIndexes 205 """ 206 secondsMap = getTimes(queryService, pixelsId, tIndexes) 207 208 if timeUnits == None and len(secondsMap) > 0: 209 maxSecs = max(secondsMap.values()) 210 if maxSecs > 3600: timeUnits = HOURS_MINS 211 elif maxSecs > 60: timeUnits = MINS_SECS 212 else: timeUnits = SECS_MILLIS 213 214 labels = [] 215 for t in tIndexes: 216 if t in secondsMap: 217 seconds = secondsMap[t] 218 if showRoiDuration: 219 seconds = seconds - secondsMap[tIndexes[0]] 220 labels.append(formatTime(seconds,timeUnits)) 221 else: 222 labels.append("%d/%d" % (t+1, sizeT)) 223 224 labels.append(timeUnits) 225 return labels
226
227 -def addScalebar(scalebar, xIndent, yIndent, image, pixels, colour):
228 """ 229 Adds a scalebar at the bottom right of an image, No text. 230 231 @param scalebar length of scalebar in microns 232 @param xIndent indent from the right of the image 233 @param yIndent indent from the bottom of the image 234 @param image the PIL image to add scalebar to 235 @param pixels the pixels object 236 @param colour colour of the overlay as r,g,b tuple 237 """ 238 draw = ImageDraw.Draw(image) 239 if pixels.getPhysicalSizeX() == None: 240 return False, " Failed to add scale bar: Pixel size not defined." 241 pixelSizeX = pixels.getPhysicalSizeX().getValue() 242 if pixelSizeX <= 0: 243 return False, " Failed to add scale bar: Pixel size not defined." 244 iWidth, iHeight = image.size 245 lineThickness = (iHeight//100) + 1 246 scaleBarY = iHeight - yIndent 247 scaleBarX = iWidth - scalebar//pixelSizeX - xIndent 248 scaleBarX2 = iWidth - xIndent 249 if scaleBarX<=0 or scaleBarX2<=0 or scaleBarY<=0 or scaleBarX2>iWidth: 250 return False, " Failed to add scale bar: Scale bar is too large." 251 for l in range(lineThickness): 252 draw.line([(scaleBarX,scaleBarY), (scaleBarX2,scaleBarY)], fill=colour) 253 scaleBarY -= 1 254 return True, " Scalebar added to the image."
255
256 -def getVerticalLabels(labels, font, textGap):
257 """ Returns an image with the labels written vertically with the given font, black on white background """ 258 259 maxWidth = 0 260 height = 0 261 textHeight = font.getsize("testq")[1] 262 for label in labels: 263 maxWidth = max(maxWidth, font.getsize(label)[0]) 264 if height > 0: height += textGap 265 height += textHeight 266 size = (maxWidth, height) 267 textCanvas = Image.new("RGB", size, WHITE) 268 textdraw = ImageDraw.Draw(textCanvas) 269 py = 0 270 for label in labels: 271 indent = (maxWidth - font.getsize(label)[0]) / 2 272 textdraw.text((indent, py), label, font=font, fill=(0,0,0)) 273 py += textHeight + textGap 274 return textCanvas.rotate(90)
275