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

Time reference and decimal places #481

Merged
merged 35 commits into from
Nov 30, 2022
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
b6c99ab
DeltaT offset from T idx (1-based)
Tom-TBT Aug 22, 2022
e6bd374
JS DeltaT offset from T idx(1-based)
Tom-TBT Aug 22, 2022
42449a2
Renamed dT offset parameter
Tom-TBT Aug 22, 2022
d2726ca
Merge branch 'ome:master' into dT_offset
Tom-TBT Sep 9, 2022
0148cd4
Default to 0 when shift with no timestamps
Tom-TBT Sep 9, 2022
7a10b1d
Added precision param to time and XYZWH labels
Tom-TBT Sep 9, 2022
33a4156
Refactoring code
Tom-TBT Sep 12, 2022
146d300
Bug fix in text between dynamic label
Tom-TBT Sep 12, 2022
18e6259
Dec prec bug fix
Tom-TBT Sep 13, 2022
c174fcb
updated tip window
Tom-TBT Sep 13, 2022
76f2897
updated format spec
Tom-TBT Sep 13, 2022
a5a27ec
limit behavior js/pdf fix
Tom-TBT Sep 13, 2022
0b9719d
Added label tests
Tom-TBT Sep 13, 2022
f5c848f
dec_prec fix when 0 with a view property
Tom-TBT Sep 13, 2022
6473162
removed alias from label tips
Tom-TBT Sep 13, 2022
40b3ffa
Removed bug fix for a separate PR
Tom-TBT Sep 13, 2022
14a6167
added mixed example to tips
Tom-TBT Sep 14, 2022
0c44a12
Updated image JSON in test
Tom-TBT Sep 14, 2022
3f05340
z.unit label bug fix for 2d images
Tom-TBT Sep 14, 2022
0870664
Merge branch 'ome:master' into dT_offset
Tom-TBT Sep 14, 2022
29d0fe1
0 default on X.unit when px size not set
Tom-TBT Sep 14, 2022
62ceba4
Merge branch 'dT_offset' of https://github.com/Tom-TBT/omero-figure i…
Tom-TBT Sep 14, 2022
55891b7
test json None px_size handling
Tom-TBT Sep 14, 2022
cbee1da
improved label tip description
Tom-TBT Sep 14, 2022
c3318df
Prettifying conditional operators
Tom-TBT Sep 14, 2022
59a4ca7
Label-parameter format change to readable
Tom-TBT Oct 4, 2022
d8c2580
style fix
Tom-TBT Oct 4, 2022
377c620
X/Y with precision 0 bug fix
Tom-TBT Oct 5, 2022
98e4439
Changed tip window on label parameter
Tom-TBT Oct 5, 2022
711920b
Bug fix of default view label precision
Tom-TBT Oct 5, 2022
0c5cf6d
Updated doc
Tom-TBT Oct 5, 2022
b06c9d2
More pythony key in dict handling
Tom-TBT Oct 6, 2022
765df8c
Initializing variables explicitly
Tom-TBT Oct 13, 2022
fd5c427
Bug fix, dataset ID
Tom-TBT Oct 13, 2022
eac902e
Style and stability adjustments
Tom-TBT Nov 3, 2022
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
9 changes: 9 additions & 0 deletions docs/figure_file_format.rst
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,15 @@ Optional settings for each panel::
"size": "12",
"position": "topright",
"color": "FFFFFF"
},
{
// for 'time', 'x', 'y', 'width' and 'height', decimal precision
// can be specified in 3rd position (here 2)
// 'time' can also be given a frame index as the zero timepoint after a '-' sign
"text": "Time (s): [time.secs.2-3]",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just as a heads up, my inclination is that this format won't be readily understandable by users. Sorry if I missed it, but was there any discussion of the cost/benefit trade-off on having a larger but more self-documenting format

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Brainstorming:

  • time[3].{unit:.2f} (more python-y)
  • [time.unit;offset=3;precision=2] (more readable)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[time.unit;offset=3;precision=2] I like that one. It's readable, won't be much effort to implement and we don't need to worry about the order of parameter

"size": "12",
"position": "topright",
"color": "FFFFFF"
}
],

Expand Down
71 changes: 52 additions & 19 deletions omero_figure/scripts/omero/figure_scripts/Figure_To_Pdf.py
Original file line number Diff line number Diff line change
Expand Up @@ -1087,34 +1087,36 @@ def get_crop_region(self, panel):

return {'x': cropx, 'y': cropy, 'width': tile_w, 'height': tile_h}

def get_time_label_text(self, delta_t, format):
def get_time_label_text(self, delta_t, format, dec_prec):
jburel marked this conversation as resolved.
Show resolved Hide resolved
""" Gets the text for 'live' time-stamp labels """
# format of "secs" by default
is_negative = delta_t < 0
delta_t = abs(delta_t)
text = "%d s" % int(round(delta_t))
npad = 2 + dec_prec + (dec_prec > 0)
if format in ["milliseconds", "ms"]:
text = "%s ms" % int(round(delta_t * 1000))
text = "%.*f ms" % (dec_prec, delta_t * 1000)
elif format in ["secs", "seconds", "s"]:
text = "%d s" % int(round(delta_t))
text = "%.*f s" % (dec_prec, delta_t)
elif format in ["mins", "minutes", "m"]:
text = "%s mins" % int(round(delta_t / 60))
text = "%.*f mins" % (dec_prec, delta_t / 60)
elif format in ["mins:secs", "m:s"]:
m = int(delta_t // 60)
s = round(delta_t % 60)
text = "%s:%02d" % (m, s)
s = delta_t % 60
text = "%s:%0*.*f" % (m, npad, dec_prec, s)
elif format in ["hrs:mins", "h:m"]:
h = int(delta_t // 3600)
m = int(round((delta_t % 3600) / 60))
text = "%s:%02d" % (h, m)
m = (delta_t % 3600) / 60
text = "%s:%0*.*f" % (h, npad, dec_prec, m)
elif format in ["hrs:mins:secs", "h:m:s"]:
h = int(delta_t // 3600)
m = (delta_t % 3600) // 60
s = round(delta_t % 60)
text = "%s:%02d:%02d" % (h, m, s)
s = delta_t % 60
text = "%s:%02d:%0*.*f" % (h, m, npad, dec_prec, s)
else: # Format unknown
return ""
if text in ["0 s", "0:00", "0 mins", "0:00:00"]:
dec_str = "" if dec_prec == 0 else "." + "0" * dec_prec
if text in ["0"+dec_str+" s", "0:00"+dec_str,
"0"+dec_str+" mins", "0:00:00"+dec_str]:
is_negative = False
return ('-' if is_negative else '') + text

Expand Down Expand Up @@ -1165,18 +1167,42 @@ def draw_labels(self, panel, page):
expr = item.group()[1:-1].split(".")
label_value = ""

tmp = expr[-1].split("-")
expr[-1] = tmp[0]
ref_idx = None
if len(tmp) > 1:
try:
ref_idx = int(tmp[1])
except ValueError:
pass

dec_prec = None
if len(expr) > 2:
try:
dec_prec = int(expr[2])
except ValueError:
pass

if expr[0] in ["time", "t"]:
the_t = panel['theT']
timestamps = panel.get('deltaT')
# default to index
if len(expr) == 1 or expr[1] == "index":
label_value = str(the_t + 1)
else:
d_t = 0
if timestamps and the_t < len(timestamps):
d_t = timestamps[the_t]
else:
d_t = 0
label_value = self.get_time_label_text(d_t, expr[1])
if ref_idx is not None:
if 1 <= ref_idx <= len(timestamps):
d_t -= timestamps[ref_idx-1]

# Set the default precision value (0) if not given
dec_prec = 0 if dec_prec is None else dec_prec

label_value = self.get_time_label_text(d_t,
expr[1],
dec_prec)

elif expr[0] == "image":
format = expr[1] if len(expr) > 1 else "name"
Expand Down Expand Up @@ -1215,6 +1241,9 @@ def draw_labels(self, panel, page):
elif prop == "rot":
prop = "rotation"

# Set the default precision value (2) if not given
dec_prec = 2 if dec_prec is None else dec_prec

if prop == "z":
size_z = panel.get('sizeZ')
pixel_size_z = panel.get('pixel_size_z')
Expand All @@ -1229,8 +1258,10 @@ def draw_labels(self, panel, page):
label_value = (str(z_start + 1) + "-"
+ str(z_end + 1))
elif format == "unit" and size_z:
z_start = f"{(z_start * pixel_size_z):.2f}"
z_end = f"{(z_end * pixel_size_z):.2f}"
z_start = "%.*f" % (dec_prec,
(z_start * pixel_size_z))
z_end = "%.*f" % (dec_prec,
(z_end * pixel_size_z))
label_value = (z_start + " " + z_symbol + " - "
+ z_end + " " + z_symbol)
else:
Expand All @@ -1239,7 +1270,8 @@ def draw_labels(self, panel, page):
label_value = str(the_z + 1)
elif (format == "unit" and size_z
and the_z < size_z):
z_pos = f"{(the_z * pixel_size_z):.2f}"
z_pos = "%.*f" % (dec_prec,
(the_z * pixel_size_z))
label_value = (z_pos + " " + z_symbol)

elif prop == "rotation":
Expand All @@ -1255,7 +1287,8 @@ def draw_labels(self, panel, page):
scale = panel['pixel_size_x']
elif prop in ['y', 'height']:
scale = panel['pixel_size_y']
rounded = f"{(value * scale):.2f}"
rounded = "%.*f" % (dec_prec,
(value * scale))
label_value = ("" + rounded +
" " + panel['pixel_size_x_symbol'])

Expand Down
17 changes: 16 additions & 1 deletion omero_figure/templates/figure/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ <h4 class="modal-title" id="addImagesLabel">Import from JSON</h4>
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
<h4 class="modal-title">Label Formatting</h4>
</div>
<div class="modal-body" style="max-height:518px">
<div class="modal-body" style="max-height:542px">
<h4>Markdown formatting</h4>
<p>
You can use "Markdown" syntax to add formatting to plain text. For example,
Expand Down Expand Up @@ -580,6 +580,21 @@ <h4>Dynamic properties</h4>
<td>*Height*: **[height.pixel]**</td>
<td><i>Height</i>: <strong>300</strong></td>
</tr>
<tr>
<th>Width with decimal precision of 3</th>
<td>Width: [width.unit.3]</td>
<td>Width: 4.450 µm</td>
jburel marked this conversation as resolved.
Show resolved Hide resolved
</tr>
<tr>
<th>Time with frame n°3 as the "zero"</th>
Tom-TBT marked this conversation as resolved.
Show resolved Hide resolved
<td>Time: [time.milliseconds-3]</td>
<td>Time: -58 ms</td>
</tr>
<tr>
<th>Time with decimal precision (2) and "zero" (3)</th>
Tom-TBT marked this conversation as resolved.
Show resolved Hide resolved
<td>Time: [time.seconds.2-3]</td>
<td>Time: -0.058 s</td>
Tom-TBT marked this conversation as resolved.
Show resolved Hide resolved
</tr>
<tr>
<th>Image ID</th>
<td>Image ID: [image.id]</td>
Expand Down
39 changes: 25 additions & 14 deletions src/js/models/panel_model.js
Original file line number Diff line number Diff line change
Expand Up @@ -285,42 +285,50 @@
return this.get('deltaT')[theT] || 0;
},

get_time_label_text: function(format) {
get_time_label_text: function(format, ref_idx, dec_prec) {
var pad = function(digit) {
var d = digit + "";
return d.length === 1 ? ("0"+d) : d;
};
var theT = this.get('theT'),
deltaT = this.get('deltaT')[theT] || 0,
isNegative = (deltaT < 0),
text = "", h, m, s;

if (ref_idx){
jburel marked this conversation as resolved.
Show resolved Hide resolved
shift = this.get('deltaT')[parseInt(ref_idx)-1];
deltaT = shift==null?deltaT:deltaT-shift;
}
var isNegative = (deltaT < 0);
deltaT = Math.abs(deltaT);

var padlen = dec_prec>0 ? dec_prec+3 : 2;
if (format === "index") {
isNegative = false;
text = "" + (theT + 1);
} else if (['milliseconds', 'ms'].includes(format)) {
text = Math.round(deltaT*1000) + " ms";
text = (deltaT*1000).toFixed(dec_prec) + " ms";
} else if (['seconds', 'secs', 's'].includes(format)) {
text = Math.round(deltaT) + " s";
text = deltaT.toFixed(dec_prec) + " s";
} else if (['minutes', 'mins', 'm'].includes(format)) {
text = Math.round(deltaT / 60) + " mins";
text = (deltaT / 60).toFixed(dec_prec) + " mins";
} else if (["mins:secs", "m:s"].includes(format)) {
m = parseInt(deltaT / 60);
s = pad(Math.round(deltaT % 60));
s = ((deltaT % 60).toFixed(dec_prec)).padStart(padlen, "0");
text = m + ":" + s;
} else if (["hrs:mins", "h:m"].includes(format)) {
h = parseInt(deltaT / 3600);
m = pad(Math.round((deltaT % 3600) / 60));
m = (((deltaT % 3600) / 60).toFixed(dec_prec)).padStart(padlen, "0");
text = h + ":" + m;
} else if (["hrs:mins:secs", "h:m:s"].includes(format)) {
h = parseInt(deltaT / 3600);
m = pad(parseInt((deltaT % 3600) / 60));
s = pad(Math.round(deltaT % 60));
s = ((deltaT % 60).toFixed(dec_prec)).padStart(padlen, "0");
text = h + ":" + m + ":" + s;
} else { // Format unknown
return ""
}
if (["0 s", "0:00", "0 mins", "0:00:00"].indexOf(text) > -1) {
var dec_str = dec_prec>0 ? "."+"0".repeat(dec_prec) : "";
if (["0"+dec_str+" s", "0"+dec_str+" mins", "0:00"+dec_str, "0:00:00"+dec_str].indexOf(text) > -1) {
isNegative = false;
}
return (isNegative ? '-' : '') + text;
Expand All @@ -345,7 +353,7 @@
return text;
},

get_view_label_text: function(property, format) {
get_view_label_text: function(property, format, dec_prec) {
if (format === "px") format = "pixel";

if (property === "w") property = "width";
Expand All @@ -361,6 +369,9 @@
z_size = this.get('pixel_size_z');
z_size = z_size?z_size:0

dec_prec = parseInt(dec_prec)
dec_prec = dec_prec==null?2:dec_prec; // 2 is the default precision

var text = "";
if (property === "z") {
if (this.get('z_projection')) {
Expand All @@ -369,8 +380,8 @@
if (format === "pixel") {
text = "" + (start+1) + " - " + (end+1);
} else if (format === "unit"){
start = (start * z_size).toFixed(2)
end = (end * z_size).toFixed(2)
start = (start * z_size).toFixed(dec_prec)
end = (end * z_size).toFixed(dec_prec)
text = ""+ start +" "+ z_symbol
+ " - " + end +" "+ z_symbol
}
Expand All @@ -380,7 +391,7 @@
if (format === "pixel") {
text = "" + (theZ + 1);
} else if (format === "unit"){
text = ""+ (theZ * z_size).toFixed(2) +" "+ z_symbol
text = ""+ (theZ * z_size).toFixed(dec_prec) +" "+ z_symbol
}
}
return text
Expand All @@ -393,7 +404,7 @@
return ""+parseInt(value);
} else if (format === "unit") {
scale = ['x', 'width'].includes(property) ? x_size : y_size
text = ""+ (value * scale).toFixed(2) +" "+ x_symbol
text = ""+ (value * scale).toFixed(dec_prec) +" "+ x_symbol
}
return text
},
Expand Down
10 changes: 8 additions & 2 deletions src/js/views/panel_view.js
Original file line number Diff line number Diff line change
Expand Up @@ -198,14 +198,20 @@
var new_text = new_text + ljson.text.slice(last_idx, match.index);
expr = match[0].slice(1,-1).split(".");
var label_value = ""

ref_idx = expr[expr.length-1].split("-");
expr[expr.length-1] = ref_idx[0];

if (['time', 't'].includes(expr[0])) {
label_value = self.model.get_time_label_text(expr[1] ? expr[1] : "index");
dec_prec = (expr[2] ? parseInt(expr[2]) : 0); // decimal places matters only when the format isn't default
label_value = self.model.get_time_label_text(expr[1] ? expr[1] : "index", ref_idx[1], dec_prec);
} else if (['image', 'dataset'].includes(expr[0])){
label_value = self.model.get_name_label_text(expr[0], expr[1] ? expr[1] : "name");
//Escape the underscore for markdown
label_value = label_value.replaceAll("_", "\\_");
} else if (['x', 'y', 'z', 'width', 'height', 'w', 'h', 'rotation', 'rot'].includes(expr[0])){
label_value = self.model.get_view_label_text(expr[0], expr[1] ? expr[1] : "pixel");
dec_prec = (expr[2] ? parseInt(expr[2]) : 2); // decimal places matters only when the format isn't default
label_value = self.model.get_view_label_text(expr[0], expr[1] ? expr[1] : "pixel", dec_prec);
} else if (['channels', 'c'].includes(expr[0])) {
label_value = self.model.get_channels_label_text();
}
Expand Down
Loading