Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 137 additions & 34 deletions omero/figure_scripts/Thumbnail_Figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,36 @@ def log(text):
""" Adds lines of text to the logLines list, so they can be collected into a figure legend. """
print text
logLines.append(text)


def sortImagesByTag(tagIds, imgTags):

# prepare list of {'iid': imgId, 'tagKey' : stringToSort }
# E.g. if tagIds = [5, 3, 9], we map to 'a', 'b', 'c',
# so an Image with tags 3 & 9 will have 'tagKey': "bc"
letters = 'abcdefghijklmnopqrstuvwxyz' # assume we have less than 26 tags!
sortedImages = []
for iid, tagIdList in imgTags.items():
orderedIndexes = []
orderedTags = []
for i, tid in enumerate(tagIds):
if tid in tagIdList:
orderedIndexes.append( letters[i] )
orderedTags.append(tid)
if len(orderedIndexes) > 0:
tagKey = "".join(orderedIndexes)
else:
tagKey = "z"
sortedImages.append({'iid': iid, 'tagKey': tagKey, 'tagIds':orderedTags})

sortedImages.sort(key=lambda x:x['tagKey'])

# clean up our 'z' sorting hack above.
for i in sortedImages:
if i['tagKey'] == "z":
i['tagKey'] = ""

return sortedImages


def paintDatasetCanvas(conn, images, title, tagIds=None, showUntagged = False, colCount = 10, length = 100):
Expand Down Expand Up @@ -115,9 +145,11 @@ def paintDatasetCanvas(conn, images, title, tagIds=None, showUntagged = False, c

# if we have a list of tags, then sort images by tag
if tagIds:
log(" Sorting images by tags")
tagIds = [int(tagId) for tagId in tagIds] # Cast to int since List can be any type
log(" Sorting images by tags: %s" % tagIds)
tagNames = {}
taggedImages = {} # a map of tagId: list-of-image-Ids
imgTags = {} # a map of imgId: list-of-tagIds
for tagId in tagIds:
taggedImages[tagId] = []

Expand All @@ -126,37 +158,106 @@ def paintDatasetCanvas(conn, images, title, tagIds=None, showUntagged = False, c
annotations = metadataService.loadAnnotations("Image", dsImageIds, types, None, None)
#filter images by annotation...
for imageId, tags in annotations.items():
imgTagIds = []
for tag in tags:
tagId = tag.getId().getValue()
if tagId in tagIds: # if image has multiple tags, it will be display more than once
taggedImages[tagId].append(imageId) # add the image id to the appropriate list
if imageId in dsImageIds:
dsImageIds.remove(imageId) # remember which we've picked already
if tagId not in tagNames.keys():
tagNames[tagId] = tag.getTextValue().getValue() # make a dict of tag-names

# if we want to show remaining images in dataset (not picked by tag)...
tagNames[tagId] = tag.getTextValue().getValue() # make a dict of tag-names
print " Tag:", tagId, tagId in tagIds
imgTagIds.append(tagId)
imgTags[imageId] = imgTagIds

# get a sorted list of {'iid': iid, 'tagKey': tagKey, 'tagIds':orderedTags}
sortedThumbs = sortImagesByTag(tagIds, imgTags)

if not showUntagged:
sortedThumbs = [t for t in sortedThumbs if len(t['tagIds'])>0]

# Need to group sets of thumbnails by FIRST tag.
toptagSets = []
groupedPixelIds = []
showSubsetLabels = False
currentTagStr = None
for i, img in enumerate(sortedThumbs):
tagIds = img['tagIds']
if len(tagIds) == 0:
tagString = "Not Tagged"
else:
tagString = tagNames[tagIds[0]]
if tagString == currentTagStr or currentTagStr is None:
# only show subset labels (later) if there are more than 1 subset
if (len(tagIds) > 1):
showSubsetLabels = True
groupedPixelIds.append({'pid':imagePixelMap[img['iid']], 'tagIds':tagIds})
else:
toptagSets.append({'tagText':currentTagStr, 'pixelIds':groupedPixelIds, 'showSubsetLabels':showSubsetLabels})
showSubsetLabels = len(tagIds) > 1
groupedPixelIds = [ {'pid':imagePixelMap[img['iid']], 'tagIds':tagIds} ]
currentTagStr = tagString
toptagSets.append({'tagText':currentTagStr, 'pixelIds':groupedPixelIds, 'showSubsetLabels':showSubsetLabels})

# Find the indent we need
maxTagNameWidth = max( [font.getsize(ts['tagText'])[0] for ts in toptagSets] )
if showUntagged:
tagIds.append("noTag")
taggedImages["noTag"] = [untaggedId for untaggedId in dsImageIds]
tagNames["noTag"] = "Untagged"

# print results and convert image-id to pixel-id
# make a canvas for each tag
for tagId in tagIds:
if tagId not in tagNames.keys(): # no images with this tag
continue
leftLabel = tagNames[tagId]
log(" Tag: %s (contains %d images)" % (leftLabel, len(taggedImages[tagId])))
pixelIds = []
for imageId in taggedImages[tagId]:
log(" Name: %s ID: %d" % (imageNames[imageId], imageId))
pixelIds.append(imagePixelMap[imageId])
print 'pixelIds', pixelIds
tagCanvas = imgUtil.paintThumbnailGrid(thumbnailStore, length, spacing, pixelIds, colCount, leftLabel=leftLabel)
maxTagNameWidth = max(maxTagNameWidth, font.getsize("Not Tagged")[0])

print "toptagSets", toptagSets

tagSubPanes = []
# make a canvas for each tag combination
def makeTagsetCanvas(tagString, tagsetPixIds, showSubsetLabels):
log(" Tagset: %s (contains %d images)" % (tagString, len(tagsetPixIds)))
if not showSubsetLabels:
tagString = None
subCanvas = imgUtil.paintThumbnailGrid(thumbnailStore, length, spacing, tagsetPixIds, colCount, topLabel=tagString)
tagSubPanes.append(subCanvas)

for toptagSet in toptagSets:
tagText = toptagSet['tagText']
showSubsetLabels = toptagSet['showSubsetLabels']
imageData = toptagSet['pixelIds']
# loop through all thumbs under TAG, grouping into subsets.
tagsetPixIds = []
currentTagStr = None
for i, img in enumerate(imageData):
tag_ids = img['tagIds']
pid = img['pid']
tagString = ", ".join( [tagNames[tid] for tid in tag_ids] )
if tagString == "":
tagString = "Not Tagged"
# Keep grouping thumbs under similar tag set (if not on the last loop)
if tagString == currentTagStr or currentTagStr is None:
tagsetPixIds.append(pid)
else:
# Process thumbs added so far
makeTagsetCanvas(currentTagStr, tagsetPixIds, showSubsetLabels)
# reset for next tagset
tagsetPixIds = [ pid ]
currentTagStr = tagString

makeTagsetCanvas(currentTagStr, tagsetPixIds, showSubsetLabels)

maxWidth = max([c.size[0] for c in tagSubPanes])
totalHeight = sum([c.size[1] for c in tagSubPanes])

# paste them into a single canvas for each Tag

leftSpacer = spacing + maxTagNameWidth + 2*spacing # Draw vertical line to right
size = (leftSpacer + maxWidth, totalHeight)
tagCanvas = Image.new(mode, size, WHITE)
pX = leftSpacer
pY = 0
for pane in tagSubPanes:
imgUtil.pasteImage(pane, tagCanvas, pX, pY)
pY += pane.size[1]
if tagText is not None:
draw = ImageDraw.Draw(tagCanvas)
tt_w, tt_h = font.getsize(tagText)
h_offset = (totalHeight - tt_h)/2
draw.text((spacing, h_offset), tagText, font=font, fill=(50,50,50))
# draw vertical line
draw.line((leftSpacer-spacing, 0, leftSpacer-spacing, totalHeight), fill=(0,0,0))
tagPanes.append(tagCanvas)
maxWidth = max(maxWidth, tagCanvas.size[0])
totalHeight += tagCanvas.size[1]
tagSubPanes = []

else:
leftSpacer = spacing
Expand All @@ -166,17 +267,18 @@ def paintDatasetCanvas(conn, images, title, tagIds=None, showUntagged = False, c
pixelIds.append(imagePixelMap[imageId])
figCanvas = imgUtil.paintThumbnailGrid(thumbnailStore, length, spacing, pixelIds, colCount)
tagPanes.append(figCanvas)
maxWidth = max(maxWidth, figCanvas.size[0])
totalHeight += figCanvas.size[1]


# paste them into a single canvas
tagsetSpacer = length / 3
maxWidth = max([c.size[0] for c in tagPanes])
totalHeight = totalHeight + sum([c.size[1]+tagsetSpacer for c in tagPanes]) - tagsetSpacer
size = (maxWidth, totalHeight)
fullCanvas = Image.new(mode, size, WHITE)
pX = 0
pY = topSpacer
for pane in tagPanes:
imgUtil.pasteImage(pane, fullCanvas, pX, pY)
pY += pane.size[1]
pY += pane.size[1] + tagsetSpacer

# create dates for the image timestamps. If dates are not the same, show first - last.
firstdate = timestampMin
Expand All @@ -191,8 +293,9 @@ def paintDatasetCanvas(conn, images, title, tagIds=None, showUntagged = False, c
dateY = spacing
dateX = fullCanvas.size[0] - spacing - dateWidth
draw.text((leftSpacer, dateY), title, font=font, fill=(0,0,0)) # title
if (leftSpacer+titleWidth) < dateX: # if there's enough space...
draw.text((dateX, dateY), figureDate, font=font, fill=(0,0,0)) # add date
# Don't show dates: see https://github.com/openmicroscopy/openmicroscopy/pull/1002
# if (leftSpacer+titleWidth) < dateX: # if there's enough space...
# draw.text((dateX, dateY), figureDate, font=font, fill=(0,0,0)) # add date

return fullCanvas

Expand Down