Skip to content

Commit

Permalink
Get all plottable data
Browse files Browse the repository at this point in the history
  • Loading branch information
manthey committed May 20, 2024
1 parent 7d53d99 commit e033774
Show file tree
Hide file tree
Showing 2 changed files with 298 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
from girder.utility import JsonEncoder
from girder.utility.progress import setResponseTimeLimit

from .. import constants
from .. import constants, utils
from ..models.annotation import Annotation, AnnotationSchema
from ..models.annotationelement import Annotationelement

Expand Down Expand Up @@ -65,6 +65,8 @@ def __init__(self):
self.route('GET', ('item', ':id'), self.getItemAnnotations)
self.route('POST', ('item', ':id'), self.createItemAnnotations)
self.route('DELETE', ('item', ':id'), self.deleteItemAnnotations)
self.route('POST', ('item', ':id', 'plot', 'list'), self.getItemPlottableElements)
self.route('POST', ('item', ':id', 'plot', 'data'), self.getItemPlottableData)
self.route('GET', ('folder', ':id'), self.returnFolderAnnotations)
self.route('GET', ('folder', ':id', 'present'), self.existFolderAnnotations)
self.route('GET', ('folder', ':id', 'create'), self.canCreateFolderAnnotations)
Expand Down Expand Up @@ -617,6 +619,43 @@ def deleteItemAnnotations(self, item):
count += 1
return count

@autoDescribeRoute(
Description('Get a list of plottable data related to an item and its annotations.')
.modelParam('id', model=Item, level=AccessType.READ)
.jsonParam('annotations', 'A JSON list of annotation IDs that should '
'be included. An entry of __all__ will include all '
'annotations.', paramType='formData', requireArray=True,
required=False)
.errorResponse('ID was invalid.')
.errorResponse('Read access was denied for the item.', 403),
)
@access.public(cookie=True, scope=TokenScope.DATA_READ)
def getItemPlottableElements(self, item, annotations):
user = self.getCurrentUser()
data = utils.PlottableItemData(user, item, annotations=annotations)
return data.columns

Check warning on line 636 in girder_annotation/girder_large_image_annotation/rest/annotation.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/rest/annotation.py#L634-L636

Added lines #L634 - L636 were not covered by tests

@autoDescribeRoute(
Description('Get plottable data related to an item and its annotations.')
.modelParam('id', model=Item, level=AccessType.READ)
.param('adjacentItems', 'Whether to include adjacent item data.',
required=False, default=True, dataType='boolean')
.param('keys', 'A comma separated list of data keys to retrieve (not json).',
required=True)
.jsonParam('annotations', 'A JSON list of annotation IDs that should '
'be included. An entry of __all__ will include all '
'annotations.', paramType='formData', requireArray=True,
required=False)
.errorResponse('ID was invalid.')
.errorResponse('Read access was denied for the item.', 403),
)
@access.public(cookie=True, scope=TokenScope.DATA_READ)
def getItemPlottableData(self, item, keys, adjacentItems, annotations):
user = self.getCurrentUser()
data = utils.PlottableItemData(user, item, annotations=annotations,

Check warning on line 655 in girder_annotation/girder_large_image_annotation/rest/annotation.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/rest/annotation.py#L654-L655

Added lines #L654 - L655 were not covered by tests
adjacentItems=adjacentItems)
return data.data(keys)

Check warning on line 657 in girder_annotation/girder_large_image_annotation/rest/annotation.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/rest/annotation.py#L657

Added line #L657 was not covered by tests

def getFolderAnnotations(self, id, recurse, user, limit=False, offset=False, sort=False,
sortDir=False, count=False):

Expand Down
258 changes: 258 additions & 0 deletions girder_annotation/girder_large_image_annotation/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import json
import math
import re

from bson.objectid import ObjectId

from girder.constants import AccessType
from girder.models.folder import Folder


class AnnotationGeoJSON:
Expand Down Expand Up @@ -334,3 +340,255 @@ def isGeoJSON(annotation):
'Feature', 'FeatureCollection', 'GeometryCollection', 'Point',
'LineString', 'Polygon', 'MultiPoint', 'MultiLineString',
'MultiPolygon'}


class PlottableItemData:
maxItems = 1000
maxAnnotationElements = 10000
maxDistinct = 20
allowedTypes = (str, bool, int, float)

def __init__(self, user, item, annotations=None, adjacentItems=False):
"""
Get plottable data associated with an item.
:param user: authenticating user.
:param item: the item record.
:param annotations: None, a list of annotation ids, or __all__. If
adjacent items are included, the most recent annotation with the
same name will also be included.
:param adjacentItems: if True, include data other items in the same
folder.
"""
self.user = user
self._columns = None
self._datacolumns = None
self._data = None
self._findItems(item, adjacentItems)
self._findAnnotations(annotations)

Check warning on line 368 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L363-L368

Added lines #L363 - L368 were not covered by tests

def _findItems(self, item, adjacentItems=False):
self._columns = None
self.item = item
self.folder = Folder().load(id=item['folderId'], user=self.user, level=AccessType.READ)
self.items = [item]

Check warning on line 374 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L371-L374

Added lines #L371 - L374 were not covered by tests
if adjacentItems:
for entry in Folder().childItems(self.folder):
if len(self.items) >= self.maxItems:
break

Check warning on line 378 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L378

Added line #L378 was not covered by tests
if entry['_id'] != item['_id']:
# skip if item doesn't have appropriate metadata or
# annotations. If skipping, add to list to check if
# dataframe
# TODO: DWM::
self.items.append(entry)

Check warning on line 384 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L384

Added line #L384 was not covered by tests
# TODO: find csv/xlsx/dataframe items in the folder, exclude them from
# the item list but include them in general

def _findAnnotations(self, annotations):
from ..models.annotation import Annotation

Check warning on line 389 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L389

Added line #L389 was not covered by tests

self._columns = None

Check warning on line 391 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L391

Added line #L391 was not covered by tests
if isinstance(annotations, str):
annotations = annotations.split(',')
self.annotations = None

Check warning on line 394 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L393-L394

Added lines #L393 - L394 were not covered by tests
if annotations and len(annotations):
self.annotations = []
query = {'_active': {'$ne': False}, 'itemId': self.item['_id']}

Check warning on line 397 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L396-L397

Added lines #L396 - L397 were not covered by tests
if annotations[0] != '__all__':
query['_id'] = {'$in': [ObjectId(annotId) for annotId in annotations]}
self.annotations.append(list(Annotation().find(

Check warning on line 400 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L400

Added line #L400 was not covered by tests
query, limit=0, sort=[('_version', -1)])))
if not len(self.annotations[0]):
self.annotations = None

Check warning on line 403 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L403

Added line #L403 was not covered by tests
# Find adjacent annotations
if annotations and len(self.items) > 1:
names = {}

Check warning on line 406 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L406

Added line #L406 was not covered by tests
for idx, annot in enumerate(self.annotations[0]):
if annot['annotation']['name'] not in names:
names[annot['annotation']['name']] = idx

Check warning on line 409 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L409

Added line #L409 was not covered by tests
for adjitem in self.items[1:]:
query = {'_active': {'$ne': False}, 'itemId': adjitem['_id']}
annotList = [None] * len(self.annotations[0])

Check warning on line 412 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L411-L412

Added lines #L411 - L412 were not covered by tests
for annot in Annotation().find(query, limit=0, sort=[('_version', -1)]):
if annot['annotation']['name'] in names and annotList[
names[annot['annotation']['name']]] is None:
annotList[names[annot['annotation']['name']]] = annot
self.annotations.append(annotList)

Check warning on line 417 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L416-L417

Added lines #L416 - L417 were not covered by tests

def _addColumn(self, columns, fullkey, title, root, key, source):
if fullkey not in columns:
columns[fullkey] = {

Check warning on line 421 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L421

Added line #L421 was not covered by tests
'key': fullkey,
'type': 'number',
'where': [[root, key, source]], 'title': title,
'count': 0, 'distinct': set(), 'min': None,
'max': None}
return 0

Check warning on line 427 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L427

Added line #L427 was not covered by tests
elif [root, key, source] not in columns[fullkey]['where']:
columns[fullkey]['where'].append([root, key, source])
return len(columns[fullkey]['where']) - 1
return columns[fullkey]['where'].index([root, key, source])

Check warning on line 431 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L429-L431

Added lines #L429 - L431 were not covered by tests

def _columnKey(self, source, root, key):
if not hasattr(self, '_columnKeyCache'):
self._columnKeyCache = {}
hashkey = (source, root, key)

Check warning on line 436 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L435-L436

Added lines #L435 - L436 were not covered by tests
if hashkey in self._columnKeyCache:
return self._columnKeyCache[hashkey]
fullkey = f'{root}.{key}.{source}'.lower()
title = f'{root} {key}'
keymap = {

Check warning on line 441 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L438-L441

Added lines #L438 - L441 were not covered by tests
r'(?i)(item|image)_(id|name)$': {'key': '_0_item.name', 'title': 'Item Name'},
r'(?i)(low|min)(_|)x': {'key': '_bbox.x0', 'title': 'Bounding Box Low X'},
r'(?i)(low|min)(_|)y': {'key': '_bbox.y0', 'title': 'Bounding Box Low Y'},
r'(?i)(high|max)(_|)x': {'key': '_bbox.x1', 'title': 'Bounding Box High X'},
r'(?i)(high|max)(_|)y': {'key': '_bbox.y1', 'title': 'Bounding Box High Y'},
}
for k, v in keymap.items():
if re.match(k, key):
fullkey = v['key']
title = v['title']
break
self._columnKeyCache[hashkey] = fullkey, title
return fullkey, title

Check warning on line 454 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L450-L454

Added lines #L450 - L454 were not covered by tests

def _scanColumnByKey(self, result, key, entry, where=0):
if result['type'] == 'number':
try:

Check warning on line 458 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L458

Added line #L458 was not covered by tests
[float(record[key]) for record in entry
if isinstance(record.get(key), self.allowedTypes)]
except Exception:
result['type'] = 'string'

Check warning on line 462 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L461-L462

Added lines #L461 - L462 were not covered by tests
result['distinct'] = {str(v) for v in result['distinct']}
for ridx, record in enumerate(entry):
v = record.get(key)

Check warning on line 465 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L465

Added line #L465 was not covered by tests
if not isinstance(v, self.allowedTypes):
continue
result['count'] += 1
v = float(v) if result['type'] == 'number' else str(v)

Check warning on line 469 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L467-L469

Added lines #L467 - L469 were not covered by tests
if len(result['distinct']) <= self.maxDistinct:
result['distinct'].add(v)

Check warning on line 471 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L471

Added line #L471 was not covered by tests
if result['type'] == 'number':
if result['min'] is None:
result['min'] = result['max'] = v
result['min'] = min(result['min'], v)
result['max'] = max(result['max'], v)

Check warning on line 476 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L474-L476

Added lines #L474 - L476 were not covered by tests
if self._datacolumns and result['key'] in self._datacolumns:
self._datacolumns[result['key']][(where, ridx)] = v

Check warning on line 478 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L478

Added line #L478 was not covered by tests

def _scanColumn(self, meta, source, columns, auxmeta=None):
for root, entry in meta.items():
if not isinstance(entry, list) or not len(entry) or not isinstance(entry[0], dict):
continue

Check warning on line 483 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L483

Added line #L483 was not covered by tests
for key in entry[0]:
if not isinstance(entry[0][key], self.allowedTypes):
continue
fullkey, title = self._columnKey(source, root, key)
where = self._addColumn(columns, fullkey, title, root, key, source)
result = columns[fullkey]
self._scanColumnByKey(result, key, entry, where)

Check warning on line 490 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L486-L490

Added lines #L486 - L490 were not covered by tests
if auxmeta:
for aux in auxmeta:
if (isinstance(aux.get(root), list) and
len(aux[root]) and
isinstance(aux[root][0], dict) and
key in aux[root][0]):
self._scanColumnByKey(result, key, aux[root], where)

Check warning on line 497 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L497

Added line #L497 was not covered by tests

@property
def columns(self):
"""
Get a sorted list of plottable columns with some metadata for each.
Each data entry contains
:fullkey: a unique string. This is a good first-order sort
:root: the root data array
:key: the specific data tag
:source: the source of the data (folder, item, annotation,
annotationelement, file)
:type: string or number
:title: a human readable title
:[distinct]: a list of distinct values if there are less than some
maximum number of distinct values. This might not include i
values from adjacent items
:[min]: for number data types, the lowest value present
:[max]: for number data types, the highest value present
:returns: a sorted list of data entries.
"""
if self._columns is not None:
return self._columns
columns = {}
self._addColumn(

Check warning on line 524 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L522-L524

Added lines #L522 - L524 were not covered by tests
columns, '_0_item.name', 'Item Name', 'Item', 'name', 'base')
self._addColumn(

Check warning on line 526 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L526

Added line #L526 was not covered by tests
columns, '_2_item.id', 'Item ID', 'Item', '_id', 'base')
self._scanColumn(self.folder.get('meta', {}), 'folder', columns)

Check warning on line 528 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L528

Added line #L528 was not covered by tests
self._scanColumn(self.item.get('meta', {}), 'item', columns,
[item.get('meta', {}) for item in self.items[1:]])
for anidx, annot in enumerate(self.annotations[0] if self.annotations is not None else []):
self._scanColumn(
annot.get('attributes', {}), 'annotation', columns,
[itemannot[anidx].get('attributes', {})
for itemannot in self.annotations[1:]
if itemannot[anidx] is not None])
if not anidx:
self._addColumn(

Check warning on line 538 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L538

Added line #L538 was not covered by tests
columns, '_1_annotation.name', 'Annotation Name',
'Annotation', 'name', 'base')
self._addColumn(

Check warning on line 541 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L541

Added line #L541 was not covered by tests
columns, '_3_annotation.id', 'Annotation ID',
'Annotation', '_id', 'base')
self._addColumn(

Check warning on line 544 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L544

Added line #L544 was not covered by tests
columns, '_bbox.x0', 'Bounding Box Low X', 'bbox', 'lowx',
'annotationelement')
self._addColumn(

Check warning on line 547 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L547

Added line #L547 was not covered by tests
columns, '_bbox.y0', 'Bounding Box Low Y', 'bbox', 'lowy',
'annotationelement')
self._addColumn(

Check warning on line 550 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L550

Added line #L550 was not covered by tests
columns, '_bbox.x1', 'Bounding Box High X', 'bbox',
'highx', 'annotationelement')
self._addColumn(

Check warning on line 553 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L553

Added line #L553 was not covered by tests
columns, '_bbox.y1', 'Bounding Box High Y', 'bbox',
'highy', 'annotationelement')
# ##DWM:: add annotation elements
# ##DWM:: bbox could be from min/max query
# ##DWM:: Add csv
for result in columns.values():
if len(result['distinct']) <= self.maxDistinct:
result['distinct'] = sorted(result['distinct'])

Check warning on line 561 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L561

Added line #L561 was not covered by tests
else:
result.pop('distinct', None)

Check warning on line 563 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L563

Added line #L563 was not covered by tests
if result['type'] != 'number' or result['min'] is None:
result.pop('min', None)
result.pop('max', None)

Check warning on line 566 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L565-L566

Added lines #L565 - L566 were not covered by tests
self._columns = sorted(columns.values(), key=lambda x: x['key'])
return self._columns

Check warning on line 568 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L568

Added line #L568 was not covered by tests

def data(self, columns):
"""
Get plottable data.
"""
if not isinstance(columns, list):
columns = columns.split(',')

Check warning on line 575 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L575

Added line #L575 was not covered by tests
# TODO: Always augment columns with item id, annotation id?
self._datacolumns = {c: {} for c in columns}
rows = set()

Check warning on line 578 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L578

Added line #L578 was not covered by tests
# collects data as a side effect
collist = self.columns

Check warning on line 580 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L580

Added line #L580 was not covered by tests
for coldata in self._datacolumns.values():
rows |= set(coldata.keys())
rows = sorted(rows)

Check warning on line 583 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L582-L583

Added lines #L582 - L583 were not covered by tests
colsout = [col for col in collist if col['key'] in columns]
print(f'Gathering {len(self._datacolumns)} x {len(rows)} data')

Check warning on line 585 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L585

Added line #L585 was not covered by tests
data = [[None] * len(self._datacolumns) for _ in range(len(rows))]
for cidx, col in enumerate(colsout):
colkey = col['key']

Check warning on line 588 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L588

Added line #L588 was not covered by tests
if colkey in self._datacolumns:
for ridx, rowid in enumerate(rows):
data[ridx][cidx] = self._datacolumns[colkey].get(rowid, None)
return {

Check warning on line 592 in girder_annotation/girder_large_image_annotation/utils/__init__.py

View check run for this annotation

Codecov / codecov/patch

girder_annotation/girder_large_image_annotation/utils/__init__.py#L591-L592

Added lines #L591 - L592 were not covered by tests
'columns': colsout,
'data': data}

0 comments on commit e033774

Please sign in to comment.