Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rois pagination #422

Merged
merged 9 commits into from
Feb 19, 2021
Merged
Show file tree
Hide file tree
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
20 changes: 12 additions & 8 deletions omero_figure/templates/figure/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -151,13 +151,16 @@ <h4 class="modal-title" style="float: left; padding-right: 20px;">
</div>
</div>
</div>
<div id="roiModalSidebar" class="col-xs-4"
style="padding:0; height:600px; overflow-y:auto">
<div id="roiModalRoiList">
<table style="width: 100%" class="table table-hover table-condensed"></table>
<div id="roiModalSidebar" class="col-xs-4" style="padding: 0">
<span id="roiPageControls" style="color: #999; line-height: 30px;">
</span>
<div style="clear:both; padding: 5px"></div>
<div style="padding:0; height:550px; overflow-y:auto">
<div id="roiModalRoiList">
<table style="width: 100%" class="table table-hover table-condensed"></table>
</div>
<p id="roiModalTip" style="position:absolute; top:0"></p>
</div>
<p id="roiModalTip"></p>
<p id="roiModalTip"></p>
</div>
</div>
<div class="modal-footer" style="margin-top: 0">
Expand Down Expand Up @@ -309,8 +312,9 @@ <h4>ROIs:</h4>
<!-- ROIs loaded here... -->
</tbody>
</table>
<!-- Additional message depends on whether we have any ROIs or not -->
<p id='cropRoiMessage'></p>
<button style="float: right" class="btn btn-sm btn-default loadRoiRects">Load More...</button>
<!-- Additional message/status -->
<p style="color: #999; margin: 10px" id='cropRoiMessage'></p>
</div>
<div class="col-xs-8">
<div id="cropViewer">
Expand Down
3 changes: 3 additions & 0 deletions omero_figure/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@
url(r'^roiCount/(?P<image_id>[0-9]+)/$', views.roi_count,
name='figure_roiCount'),

url(r'^roiRectangles/(?P<image_id>[0-9]+)/$', views.roi_rectangles,
name='figure_roiRectangles'),

# POST to change figure to new group with ann_id and group_id
url(r'chgrp/$', views.chgrp, name='figure_chgrp'),

Expand Down
45 changes: 45 additions & 0 deletions omero_figure/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from omero.model.enums import UnitsLength
from omero.cmd import ERR, OK
import omero
from omero_marshal import get_encoder

from io import BytesIO

Expand Down Expand Up @@ -543,6 +544,50 @@ def unit_conversion(request, value, from_unit, to_unit, conn=None, **kwargs):
return HttpResponse(json.dumps(rsp), content_type='application/json')


@login_required()
def roi_rectangles(request, image_id, conn=None, **kwargs):
jburel marked this conversation as resolved.
Show resolved Hide resolved
"""
Load ROIs that have Rectangles and marshal with omero_marshal

Returns similar JSON to /api/ rois, with meta.totalCount
Supports pagination with ?offset and ?limit
"""

params = omero.sys.ParametersI()
params.addLong('image_id', image_id)
limit = request.GET.get('limit')
offset = request.GET.get('offset', 0)
if limit is not None:
params.page(int(offset), int(limit))
query = """select roi from Roi roi join fetch
roi.details.owner as owner join fetch roi.details.creationEvent
left outer join fetch roi.shapes as shapes
where roi.image.id = :image_id
and shapes.class = Rectangle
order by roi.id"""

rois = conn.getQueryService().findAllByQuery(
query, params, conn.SERVICE_OPTS)

json_data = []
for roi in rois:
encoder = get_encoder(roi.__class__)
json_data.append(encoder.encode(roi))

count_query = """select count(distinct roi) from Roi roi
left outer join roi.shapes as shapes
where roi.image.id = :image_id
and shapes.class = Rectangle"""
params = omero.sys.ParametersI()
params.addLong('image_id', image_id)
result = conn.getQueryService().projection(count_query, params,
conn.SERVICE_OPTS)
total_count = result[0][0].val

return JsonResponse({'data': json_data,
'meta': {'totalCount': total_count}})


@login_required()
def roi_count(request, image_id, conn=None, **kwargs):
"""
Expand Down
56 changes: 41 additions & 15 deletions src/js/views/crop_modal_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,15 @@ var CropModalView = Backbone.View.extend({

roiTemplate: JST["src/templates/modal_dialogs/crop_modal_roi.html"],

model:FigureModel,
model: FigureModel,

roisPageSize: 200,
roisPage: 0,
roisCount: 0,
// not all these ROIs will contain Rects
roisLoaded: 0,
// Rectangles from ROIs
roiRects: [],

initialize: function() {

Expand Down Expand Up @@ -40,8 +48,11 @@ var CropModalView = Backbone.View.extend({
// disable submit until user chooses a region/ROI
self.enableSubmit(false);

// Load ROIs from OMERO...
self.loadRois();
// Reset ROIs from OMERO...
self.roiRects = [];
self.roisLoaded = 0;
self.roisPage = 0;
self.loadRoiRects();
// ...along with ROIs from clipboard or on this image in the figure
self.showClipboardFigureRois();
});
Expand Down Expand Up @@ -89,6 +100,7 @@ var CropModalView = Backbone.View.extend({

events: {
"click .roiPickMe": "roiPicked",
"click .loadRoiRects": "loadRoiRects",
"mousedown svg": "mousedown",
"mousemove svg": "mousemove",
"mouseup svg": "mouseup",
Expand Down Expand Up @@ -318,7 +330,7 @@ var CropModalView = Backbone.View.extend({
}
});
}
var msg = "[No Regions copied to clipboard]";
var msg = "No Regions copied to clipboard";
this.renderRois(clipboardRects, ".roisFromClipboard", msg);

// Show Rectangles from panels in figure
Expand All @@ -336,22 +348,29 @@ var CropModalView = Backbone.View.extend({
});
}
});
msg = "[No Rectangular ROIs on selected panel in figure]";
msg = "No Rectangular ROIs on selected panel in figure";
this.renderRois(figureRois, ".roisFromFigure", msg);
},

// Load Rectangles from OMERO and render them
loadRois: function() {
loadRoiRects: function(event) {
if (event) {
event.preventDefault();
}
var self = this,
iid = self.m.get('imageId');
$.getJSON(ROIS_JSON_URL + '?image=' + iid, function(rsp){
var offset = this.roisPageSize * this.roisPage;
var url = BASE_WEBFIGURE_URL + 'roiRectangles/' + iid + '/?limit=' + self.roisPageSize + '&offset=' + offset;
$.getJSON(url, function(rsp){
data = rsp.data;
self.roisLoaded += data.length;
self.roisPage += 1;
self.roisCount = rsp.meta.totalCount;
// get a representative Rect from each ROI.
// Include a z and t index, trying to pick current z/t if ROI includes a shape there
var currT = self.m.get('theT'),
currZ = self.m.get('theZ');
var rects = [],
cachedRois = {}, // roiId: shapes (z/t dict)
var cachedRois = {}, // roiId: shapes (z/t dict)
roi, roiId, shape, theT, theZ, z, t, rect, tkeys, zkeys,
minT, maxT,
shapes; // dict of all shapes by z & t index
Expand Down Expand Up @@ -407,7 +426,7 @@ var CropModalView = Backbone.View.extend({
z = zkeys[(zkeys.length/2)>>0]
}
shape = shapes[t][z]
rects.push({'theZ': shape.TheZ,
self.roiRects.push({'theZ': shape.TheZ,
'theT': shape.TheT,
'x': shape.X,
'y': shape.Y,
Expand All @@ -420,12 +439,20 @@ var CropModalView = Backbone.View.extend({
'zEnd': zkeys[zkeys.length-1]});
}
// Show ROIS from OMERO...
var msg = "[No rectangular ROIs found on this image in OMERO]";
self.renderRois(rects, ".roisFromOMERO", msg);
var msg = "No rectangular ROIs found on this image in OMERO";
self.renderRois(self.roiRects, ".roisFromOMERO", msg);

if (self.roisLoaded < self.roisCount) {
// Show the 'Load' button if more are available
$(".loadRoiRects", this.$el).show();
} else {
$(".loadRoiRects", this.$el).hide();
}
$("#cropRoiMessage").html(`Loaded ${self.roisLoaded} / ${self.roisCount} ROIs`);

self.cachedRois = cachedRois;
}).error(function(){
var msg = "[No rectangular ROIs found on this image in OMERO]";
var msg = "No rectangular ROIs found on this image in OMERO";
self.renderRois([], ".roisFromOMERO", msg);
});
},
Expand Down Expand Up @@ -490,7 +517,7 @@ var CropModalView = Backbone.View.extend({
html += this.roiTemplate(json);
}
if (html.length === 0) {
html = "<tr><td colspan='3'>" + msg + "</td></tr>";
html = "<tr><td colspan='3' style='color: #999'>" + msg + "</td></tr>";
}
$(target + " tbody", this.$el).html(html);

Expand All @@ -514,7 +541,6 @@ var CropModalView = Backbone.View.extend({

render: function() {
var scale = this.zoom / 100,
roi = this.currentROI,
w = this.m.get('orig_width'),
h = this.m.get('orig_height');
var newW = w * scale,
Expand Down
10 changes: 9 additions & 1 deletion src/js/views/roi_loader_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ var RoiLoaderView = Backbone.View.extend({
shapeTemplate: JST["src/templates/modal_dialogs/roi_modal_shape.html"],

initialize: function(options) {
this.render = _.debounce(this.render);
this.totalCount = options.totalCount;
this.panel = options.panel;
this.listenTo(this.collection, "add", this.render);
},

events: {
Expand Down Expand Up @@ -163,7 +166,12 @@ var RoiLoaderView = Backbone.View.extend({
// remove any rois from above with no shapes
json = json.filter(function(j) {return j});

var html = this.template({'rois': json});
var html = this.template({
rois: json,
showLoadMore: this.totalCount > this.collection.length,
totalCount: this.totalCount,
count: this.collection.length,
});
this.$el.html(html);

return this;
Expand Down
Loading