Skip to content

Commit

Permalink
Merge pull request #508 from Tom-TBT/inherit_annotation
Browse files Browse the repository at this point in the history
Inherit annotation support
  • Loading branch information
knabar authored Dec 19, 2023
2 parents 9b9de7e + 231b2d0 commit 3951209
Show file tree
Hide file tree
Showing 4 changed files with 256 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ var MapAnnsPane = function MapAnnsPane($element, opts) {
}

// convert objects to json data
ajaxdata = {"type": "map"};
ajaxdata = {"type": "map", "parents": "true"};
for (var i=0; i < objects.length; i++) {
var o = objects[i].split(/-(.+)/);
if (typeof ajaxdata[o[0]] !== 'undefined') {
Expand Down Expand Up @@ -132,18 +132,39 @@ var MapAnnsPane = function MapAnnsPane($element, opts) {
}, {});
}

// Populate experimenters within anns
var anns = data.annotations.map(function(ann){
var populate_experimenter = function(ann) {
if (data.experimenters.length > 0) {
ann.owner = experimenters[ann.owner.id];
}
if (ann.link && ann.link.owner) {
ann.link.owner = experimenters[ann.link.owner.id];
// AddedBy IDs for filtering
ann.addedBy = [ann.link.owner.id];
ann.addedBy = [ann.link.owner.id];
}
return ann;
});
};

// Populate experimenters within anns
var anns = data.annotations.map(populate_experimenter);

var inh_map_annotations = [];
if (data.hasOwnProperty("parents")){
data.parents.annotations.forEach(function(ann) {
ann = populate_experimenter(ann);
let class_ = ann.link.parent.class;
let id_ = '' + ann.link.parent.id;
children = data.parents.lineage[class_][id_];
class_ = children[0].class;
ann.childClass = class_.substring(0, class_.length - 1);
ann.childNames = [];
if (children[0].hasOwnProperty("name")){
for(j = 0; j < children.length; j++){
ann.childNames.push(children[j].name);
}
}
inh_map_annotations.push(ann);
});
}

// Sort map anns into 3 lists...
var client_map_annotations = [];
Expand Down Expand Up @@ -179,10 +200,13 @@ var MapAnnsPane = function MapAnnsPane($element, opts) {
// In batch_annotate view, we show which object each map is linked to
var showParent = batchAnn;
html = html + mapAnnsTempl({'anns': my_client_map_annotations, 'objCount': objects.length,
'showTableHead': showHead, 'showNs': false, 'clientMapAnn': true, 'showParent': showParent});
html = html + mapAnnsTempl({'anns': client_map_annotations,
'showTableHead': showHead, 'showNs': false, 'clientMapAnn': true, 'showParent': showParent,
'isInherited': false});
html = html + mapAnnsTempl({'anns': client_map_annotations, 'isInherited': false,
'showTableHead': false, 'showNs': false, 'clientMapAnn': true, 'showParent': showParent});
html = html + mapAnnsTempl({'anns': map_annotations,
html = html + mapAnnsTempl({'anns': map_annotations, 'isInherited': false,
'showTableHead': false, 'showNs': true, 'clientMapAnn': false, 'showParent': showParent});
html = html + mapAnnsTempl({'anns': inh_map_annotations, 'isInherited': true,
'showTableHead': false, 'showNs': true, 'clientMapAnn': false, 'showParent': showParent});
$mapAnnContainer.html(html);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
data-added-by="<%= WEBCLIENT.USER.id %>"
<% } %>
class="keyValueTable
<% if (!ann.id || (ann.permissions.canEdit && clientMapAnn)){ %> editableKeyValueTable <% } %>
<% if (!ann.id || (ann.permissions.canEdit && clientMapAnn && !isInherited)){ %> editableKeyValueTable <% } %>
">
<thead>
<% if (showNs && ann.ns) { %>
<% if (showNs && ann.ns && !isInherited) { %>
<tr title="<%- ann.ns %>">
<th colspan="2">
<%- ann.ns.slice(0, 50) %>
Expand All @@ -20,6 +20,9 @@
<tr class="tooltip">
<th colspan="2">
<% if (ann.id) { %>
<% if (isInherited) { %>
Added on <%- ann.link.parent.class.substring(0, ann.link.parent.class.length - 1) %> <%- ann.link.parent.name.slice(0, 30) %>
<% } else { %>
Added by: <%- ann.owner.firstName %> <%- ann.owner.lastName %>
<% if (showParent && ann.link.parent.name){ %>
<br>
Expand All @@ -30,14 +33,15 @@
<% } %>
<%- ann.parentNames ? (ann.parentNames.length + " objects") : ann.link.parent.name %>
<% } %>
<% } %>

<span class="tooltip_html" style='display:none'>
<!-- ann.parentNames is a property of grouped annotations -->
<% if (ann.parentNames) { %>
You are
<% print (ann.permissions.canEdit && clientMapAnn ? 'editing' : 'viewing') %>
<b><%- ann.parentNames.length %></b> identical Key-Value annotations:
<% } %>
<% if (!ann.parentNames && ann.link) { %>
<b><%- ann.parentNames.length %></b> identical Key-Value annotations:<br />
<% } else if (ann.link) { %>
<!-- If single object show e.g. Image ID: (slice ImageI -> Image) -->
<b><%- ann.link.parent.class.slice(0, ann.link.parent.class.length-1) %>
ID:</b> <%- ann.link.parent.id %><br />
Expand All @@ -50,13 +54,22 @@
<% }) %>
<% } %>
<% if (ann.owner) { %>
<b>Owner:</b> <%- ann.owner.firstName %> <%- ann.owner.lastName %>
<b>Owner:</b> <%- ann.owner.firstName %> <%- ann.owner.lastName %><br />
<% } %>
<% if (ann.link) { %>
<br /><b>Linked by:</b> <%- ann.link.owner.firstName %> <%- ann.link.owner.lastName %>
<b>Linked by:</b> <%- ann.link.owner.firstName %> <%- ann.link.owner.lastName %><br />
<% if (ann.link.date) { %>
<br /><b>On:</b> <% print(OME.formatDate(ann.link.date)) %>
<b>On:</b> <% print(OME.formatDate(ann.link.date)) %><br />
<% } %>
<% } %>
<% if (isInherited) { %>
<% if (showParent) { %>
<b>Inherited by:</b><br />
<% _.each(ann.childNames, function(cname) { %>
&nbsp <%- cname %><br />
<% }) %>
<% } %>
<b>Namespace:</b> <%- ann.ns.slice(0, 50) %><br />
<% } %>
</span>
<% } else if (objCount && objCount > 1) { %>
Expand Down
149 changes: 145 additions & 4 deletions omeroweb/webclient/tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@
import pytz
import omero
from builtins import bytes
from collections import defaultdict

from omero.rtypes import rlong, unwrap, wrap
from django.conf import settings
from datetime import datetime
from copy import deepcopy
from omero.gateway import _letterGridLabel

from omero.gateway import _letterGridLabel, _PlateWrapper

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -1907,8 +1907,17 @@ def _marshal_annotation(conn, annotation, link=None):
"id": link.parent.id.val,
"class": link.parent.__class__.__name__,
}
if hasattr(link.parent, "name"):
if hasattr(link.parent, "name") and link.parent.name:
ann["link"]["parent"]["name"] = unwrap(link.parent.name)
elif type(link.parent) is omero.model.PlateAcquisitionI:
# Name is optional for PlateAcquisition
ann["link"]["parent"]["name"] = f"Run {link.parent.id._val}"
elif type(link.parent) is omero.model.WellI:
# Well name constructed from plate
plate = _PlateWrapper(conn, link.parent.plate)
row = plate.getRowLabels()[link.parent.row._val]
col = plate.getColumnLabels()[link.parent.column._val]
ann["link"]["parent"]["name"] = f"{row}{col}"
linkCreation = link.details.creationEvent._time
ann["link"]["date"] = _marshal_date(unwrap(linkCreation))
p = link.details.permissions
Expand Down Expand Up @@ -2052,11 +2061,12 @@ def marshal_annotations(
left outer join fetch oal.child as ch
left outer join fetch oal.parent as pa
join fetch ch.details.creationEvent
join fetch ch.details.owner
join fetch ch.details.owner %s
left outer join fetch ch.file as file
where %s order by ch.ns
""" % (
dtype,
"join fetch pa.plate" if dtype == "Well" else "",
" and ".join(where_clause),
)

Expand All @@ -2074,3 +2084,134 @@ def marshal_annotations(
experimenters.sort(key=lambda x: x["id"])

return annotations, experimenters


def marshal_lineage(
conn,
project_ids=None,
dataset_ids=None,
image_ids=None,
screen_ids=None,
plate_ids=None,
run_ids=None,
well_ids=None,
):
def add_refs(
ref_, dataset=None, project=None, well=None, run=None, plate=None, screen=None
):
def _add_refs(obj_type, obj_id):
if obj_id:
all_obj_ids[obj_type].add(obj_id)
lineage_d[obj_type][obj_id].append(ref_)

_add_refs("DatasetI", dataset)
_add_refs("ProjectI", project)
_add_refs("PlateAcquisitionI", run)
_add_refs("WellI", well)
_add_refs("PlateI", plate)
_add_refs("ScreenI", screen)

def parse_hql_id(hql_ids):
return ("" if x is None else x.getValue() for x in hql_ids)

requested = {
"ImageI": image_ids,
"DatasetI": dataset_ids,
"ProjectI": project_ids,
"PlateAcquisitionI": run_ids,
"WellI": well_ids,
"PlateI": plate_ids,
"ScreenI": screen_ids,
}

child_ref_d = defaultdict(dict) # Children references dict
lineage_d, all_obj_ids = {}, {} # Result dictionnaries
for obj_type in [
"ImageI",
"DatasetI",
"ProjectI",
"PlateI",
"PlateAcquisitionI",
"WellI",
"ScreenI",
]:
lineage_d[obj_type] = defaultdict(list)
all_obj_ids[obj_type] = set(requested[obj_type])

if len(requested[obj_type]) > 0:
for o in conn.getObjects(obj_type[:-1], requested[obj_type]):
details = {"id": o.getId(), "class": obj_type}
if obj_type == "WellI":
name = o.getWellPos()
else:
name = o.getName()
if obj_type == "PlateAcquisitionI" and name is None:
name = f"Run {o.getId()}"
details["name"] = name
child_ref_d[obj_type][details["id"]] = details

service_opts = conn.SERVICE_OPTS.copy()
qs = conn.getQueryService()
hql_image = (
"select img.id, dset.id, pdl.parent.id, smp.well.id,"
" smp.plateAcquisition.id, plt.id, spl.parent.id"
" from Image img"
" left outer join img.datasetLinks dil"
" left outer join dil.parent dset"
" left outer join img.wellSamples smp"
" left outer join dset.projectLinks pdl"
" left outer join smp.well.plate plt"
" left outer join plt.screenLinks spl"
" where img.id in (:ids)"
)

hql_wellrun = (
"select child_o.id, plt.id, pdl.parent.id"
" from {} child_o"
" join child_o.plate plt"
" left outer join plt.screenLinks pdl"
" where child_o.id in (:ids)"
)

hql_dsetplate = (
"select child_o.id, opl.parent.id FROM {} child_o"
" left outer join child_o.{}Links opl "
" where child_o.id in (:ids)"
)

if len(requested["ImageI"]) > 0:
params = omero.sys.ParametersI()
params.addIds(requested["ImageI"])
for im, ds, pr, wl, rn, pl, sc in map(
parse_hql_id, qs.projection(hql_image, params, service_opts)
):
ref_ = child_ref_d["ImageI"][im]
add_refs(ref_, ds, pr, wl, rn, pl, sc)

for _type in ["WellI", "PlateAcquisitionI"]:
if len(requested[_type]) > 0:
params = omero.sys.ParametersI()
params.addIds(requested[_type])
for ob, pl, sc in map(
parse_hql_id,
qs.projection(hql_wellrun.format(_type[:-1]), params, service_opts),
):
ref_ = child_ref_d[_type][ob]
add_refs(ref_, plate=pl, screen=sc)

for _type, parent_type in zip(["PlateI", "DatasetI"], ["screen", "project"]):
if len(requested[_type]) > 0:
params = omero.sys.ParametersI()
params.addIds(requested[_type])
for ob, p in map(
parse_hql_id,
qs.projection(
hql_dsetplate.format(_type[:-1], parent_type), params, service_opts
),
):
ref_ = child_ref_d[_type][ob]
if _type == "PlateI":
add_refs(ref_, screen=p)
else:
add_refs(ref_, project=p)
return lineage_d, all_obj_ids
Loading

0 comments on commit 3951209

Please sign in to comment.