Open sofroniewn opened 2 years ago
from @tlambert03 in zulip
my first thought of a place for it is: 1) a new item in the layerlist context menu. right-click and it brings up a widget to modify the affine info 2) an as-of-yet-uncreated Layer menu, that would provide similar access to all of the stuff in the context menu. (let's start with the context menu maybe, will be easy to add there later)
I'm in favor of exposing only scale, translation, and maybe rotation. From my experience shear and affine are more complex and are usually computed programmatically.
Yeah, I'll flag I think the most challenging aspect of this design will be how to handle the "nD" data case. Do we want one combobox per axis? Can we use a simple QForm? Does the ideal solution for dim < 5 look different then ideal dim >= 5 (h/t @tlambert03). Just some questions that aren't clear to me
Thanks for the @! I'm totally unfamiliar with this part of napari, so I've been reading the docs to get a better sense of layers and these transformations. I first have some questions to make sure I'm working in the right direction.
There should be some dialog, combobox/ textbox?
Is there a reason this needs to be outside of the layer controls (maybe the "nD" case you mentioned above where it could make the layer controls very long)? My early thoughts are that a combobox in the layer controls might be a good fit.
P.S. if anyone wants to show off their super cool layer transformations or something I'd be happy to schedule time to watch how people use this in the wild.
2. Do these parameters exist with some kind of null value before a user decides to transform it, or does the parameter get added to a layer once a user chooses so?
They get default identity-like values if they are not specified. E.g. image = Image(np.ones((64, 128))
will create a 2D image layer where image.translate == [0, 0]
and image.scale == [1, 1]
.
3. Scale and rotate seem to have operations per dimension of the image. Does translation operate the same?
Yes, there's a translation value per dimension.
4. Translated layers are translated relative to other layers (as mentioned in the image layer tutorial). Is there a unit that's important to these relative distances?
No units (yet). The translations are actually relative to a fixed origin that all layers share - each layer's translation values kind of specifies an origin for that layer. But you can set those values to describe relative translations between layers.
@isabela-pf : I also highly recommend running napari examples/interaction_box_image.py
, which should give a familiar graphical interaction scheme (e.g. powerpoint) for translating, scaling, and rotating a layer (in this case an image layer).
Is there a reason this needs to be outside of the layer controls (maybe the "nD" case you mentioned above where it could make the layer controls very long)? My early thoughts are that a combobox in the layer controls might be a good fit.
Yeah my fear here is that the layer controls will just get too long and crowded. This is also functionality that will work with all of our layer types. We might need a new "transform widget"
@MBPhys has done some cool work on cropping/ adjusting scales/ translates here https://www.napari-hub.org/plugins/napari-nd-cropper we should maybe think about folding this into core or make people aware of this. See the widget on the right. It scales to nD too I think - @MBPhys let me know what you think
In this comment, I have two things I’m proposing UI for:
Full disclosure, this is the part I’m least confident in. I’ve read what I think are the attributes of each on the API reference. I also referenced the screenshot of @MBPhys’ plugin posted above for translate.
I expect I’ve missed (or misunderstood) something along the way, though, so please let me know what else I should be accounting for.
As far as I can tell, this has two properties (is there a more accurate word for this?) to account for.
First, a translation value per image dimension (three shown here) as a drop down combo box. This means users may manually type in a value, or select from standard values. I felt like this allowed for the same amount of control as the sliders pictured above, but would also show a range of valid values without needing to move a slider to both extremes.
Second is type. Type is a standard drop down. I do not know what options go in here at all; I chose a drop down because the options sounded discrete.
The only value I found for scale was the scale factor. I matched this pattern to an existing UI I found in the default labels layer controls. Like its inspiration, numbers can be typed in manually as well as manipulated to whole numbers with the plus and minus buttons.
Quick notes that apply to all layer controls mockups:
Perhaps the most familiar option, this adds a list of layer controls as icons to a sidebar. I do expect we’d need some kind of overflow section for this long term. All layer controls available for that layer could appear by default.
Instead of making space on the UI for the many layer controls I expect will eventually become available in the viewer, you could switch controls via a drop down. This is similar to the Adobe workspace switcher we discussed at one of the community meetings (example shown from InDesign):
This might scale better in terms of UI real estate since drop downs often have a scroll, or even a search to accommodate long lists.
This version is a list of layer controls that can be expanded/collapsed. The key change is that not all layer controls are visible in the list by default. Users add layer controls they want to see for that layer by searching and selecting in the top input box.
This behavior was inspired by Adobe AfterEffects, where all components on screen have a set of (very many) default properties that do not appear on screen until the user chooses to either expand that component or edit that property any way. I think this can reduce the cognitive load of having so many options on a screen by default by prioritizing what the user is actually working with.
All layer controls would still be discoverable because they appear in the input box list.
To avoid users having to add a control one-by-one, we may want to have an add all layer controls
option (or something similar).
I got feedback on the above proposal at one of the community meetings. Here's a summary:
Decisions made
Next steps
more
tab to account for overflow)(self-assigned)@sofroniewn
Thanks. This would be cool in core:) Just for clarification There a two plugins:
This works in nd for all modes except the interaction box. Perhaps, we can update this into the nd-space in the future. The nd-cropper works in data-space, but take into account the world representation.
All this happens in the world space. In order to convert the world to the data space, I wrote the World2Data plugin.
I think napari makes it very good to push unique the data representation with the metadata to a world space (where image registrations lives, too) and separate the underlying data into a data space. Nonetheless my expression was in the past that many peoples ( in particular GUI users), who are not so familiar with this concept, are very confused unfortunately... Therefore I think, it is a very good idea @sofroniewn to make people aware of this and show the people the advantages of this. Do I understand this here correctly @sofroniewn?
Altogether this means just to notice that the Partial-Aligner do not fit to the nd-space, since shear/rotations will be very complex in nd and was not necessary for our and other real-life applications.
However I think that there are no problems to just extend the translation/scale to nd. In my opinion, there should be two modes for the users (SpinBox and Sliders) selecting by own preferences and their related tasks
@isabela-pf I love your solution and layout :smiley: Very beautiful. To add a mode with a slider should not be very complicated, or? What do you think about? Is this an opportunity?
To add a mode with a slider should not be very complicated, or?
I think a slider works fine. I think you'd know better than I what the most useful interaction is, so I'll defer to your advice. Thanks for asking @MBPhys!
What I showed was me thinking that sliders seem like they don't allow for quite the degree of fine-tuning that some of the other options have, but based on how many are currently in napari viewer and your plugin, I think it's the best option here.
Hi! From what I see above, it looks like we want tabs in place on the layer control panel, so I was going to start getting those in place with the translate and scale options added. If anyone has any objections to that, please let me know! thanks. :)
@ppwadhwa that sounds correct to me! I have some time freed up from bundled app issues, so I will put it on my list to make some more relevant mockups incorporating the latest feedback. I think this will make will make it clear how we want scale and transform to be represented specifically.
Hi there, I gave this a check and started exploring adding a slider/spinbox per value in the scale attribute over the layer controls. The controls could look something like the following:
QDoubleSpinBox
:QLabeledDoubleSlider
:Where the label before the spinbox/slider widget marks the dimension the slider/spinbox affects.
Also, my guess is that a similar approach can be used to create controls for the translate
property?
Edit - Implementing a popup widget for the scale following the contrast limits control functionality could look something like this:
Edit 2: A branch with the described controls (using sliders) - https://github.com/napari/napari/compare/main...dalthviz:napari:scale_controls
Hi there, thinking again about this, maybe adding a button for the Transform mode could help too? I think the mode is already accesible via keybindings so maybe having it as an actual button could be useful? For example, with an image layer which transform mode is activated pressing 2
, you could have something like:
Using API you could easily reset view. Interface should also allow reset transforms.
I like the idea of a way to activate transform
mode from the GUI--I bet a lot of people don't know it exists.
Not sure every layer needs its own button vs. a viewer button at the bottom? 🤔 Not sure there's room really.
But maybe in the layer controls is better, since most of the other layers already have the double-arrow for Pan/Zoom...
Using API you could easily reset view. Interface should also allow reset transforms.
Maybe having then the button but also a control? So, using as an example the scale
attribute from the affine
transform:
Not sure every layer needs its own button vs. a viewer button at the bottom? 🤔
Since the button activates a mode and also the given shortcut is the last number in the sequence from the modes a layer offers, probably makes sense to put it over the layer controls around the buttons for changing modes. For example, over a Shapes layer (where the transform mode is activated with 7
via keyboard) you could see something like:
Also, seems like the transform mode uses the layer affine
attribute (physical2world
transform) while the individual layer attributes like scale
, translate
, etc use the data2physical
transform. I don't really know the difference between using one or the other 😅 but probably something to check
Yeah, thinking further it's per layer so the layer controls makes the most sense.
I can't say I love the scale sliders in the layer controls -- feel like something that should be in its own widget and more thought as to how to expose? I think the first step would be a button to activate the transform mode. And then some way to reset the transforms -- maybe Alt-click the butto -- with a confirmation dialog? 😬
I can't say I love the scale sliders in the layer controls -- feel like something that should be in its own widget and more thought as to how to expose?
Something to further think about for sure :+1:
I think the first step would be a button to activate the transform mode.
Makes sense to me :+1:
And then some way to reset the transforms -- maybe Alt-click the butto -- with a confirmation dialog? 😬
I thought about a similar idea, although more like a right-click or something that shows the pop up with the reset option. So something like:
Will try to explore the alt-click idea too :+1:
Also, seems like the transform mode uses the layer
affine
attribute (physical2world
transform) while the individual layer attributes likescale
,translate
, etc use thedata2physical
transform. I don't really know the difference between using one or the other 😅 but probably something to check
The intent was to separate out the transforms associated with the pixel/sample space (data2physical, similar to ITK's spacing) and then a transform applied on top of that (physical2world) which might align on image with another.
In the long term, I think napari could benefit from a more flexible approach allowing any chain of transforms (including 0 or 1 transforms), but that asks more complicated design questions too.
yeah, one thing I will say is that these shouldn't be "always on" in the layer controls, because e.g. you could have a 5D image so that's a lot of vertical space when you account for scale, translate, and rotate.
This could be something that uses @andy-sweet's metadata plugin and is included in builtins, perhaps — that is, it opens in a new side panel rather than be part of the standard controls. Either that or it's a collapsible section, I guess. Either way, it's going to be tricky to make the layout look good and be flexible for any number of dimensions...
Just in case, some further exploration of the transform mode button idea using an alt-click/right-click to show a way to reset the transform. Checked with a popup and a dialog showing both a similar set of reset buttons (for scale, rotate and translate properties as well as a full reset):
I like the contextual style menu a lot better than the floating dialog. I think that looks pretty good. I think if it's to make a menu, it should be a right-click. This is just the most intuitive thing for a contextual menu. The other option is a simple option-click the button to reset everything -- boom!
Either way I think the first pass should be to expose the layer transform mode in the layer tools (analogous to the keybinds being in each layer) and then we can think about enabling more granular widgets that let you use a slider or such to control the rotation, vs. just rotating stuff.
I do think this is pretty high value stuff for people working with multiple modalities of the same "stuff".
The other option is a simple option-click the button to reset everything -- boom!
Oh I think I now understand the dialog idea you had! So showing after and alt-click something like:
right?
Either way I think the first pass should be to expose the layer transform mode in the layer tools (analogous to the keybinds being in each layer) and then we can think about enabling more granular widgets that let you use a slider or such to control the rotation, vs. just rotating stuff.
I do think this is pretty high value stuff for people working with multiple modalities of the same "stuff".
Will try opening a PR adding the transform mode button then :+1: Not totally sure if there are any other ideas for the reset behavior besides the alt-click with dialog confirmation or righ-click popup with reset buttons or option-click full reset (and probably worthy to note that it's possible to have all of those alternatives at the same time too) so maybe doing some more exploration over that could be worthy
Yeah, that's basically it @dalthviz as a simpler alternative. And 💯 with @jni that there needs to be a good icon for transform mode. Here's a couple I saw: https://fontawesome.com/icons/group-arrows-rotate?f=classic&s=solid (and related) the pivot table ones (lol) kinda look like resize and rotate: https://fontawesome.com/icons/table-pivot?f=classic&s=duotone
Regarding the icon, I put the current one shown in the previews as a place holder using the available icons and following the names for icons available (so putting for the pan-zoom button the pan_zoom
name which make available the pan
name), but I think too that a better icon should be defined. Maybe @isabela-pf could suggest icon alternatives and in general give some feedback/new ideas about what has been discussed
Hi there! The most common icon I have seen used for transform features is similar to the one we currently use for adding a rectangle on a shape layer (rectangle with vertices marked). Keeping something that references the handles in the transform controls would be my recommendation, but I think it will be a balance to differentiate it from the existing rectangle icon.
My first proposal is branching from the previously mentioned expand icon, adding the handles back in for transforms, and turning it on its side to reference the rotation element.
And here it is in @dalthviz’s image from above (thank you for that!) to see it in context.
Let me know if this seems like the right idea or not. I’ll export it as a proper SVG when we make a decision.
I like that, it's simple. Being a diamond evokes rotation to me.
I got some feedback off the issue and want to throw another potential icon into the ring. This one is built from existing iconography, but it distinguishes itself from the add rectangle by including the cursor. If matching the existing icons is the greatest priority, I'd recommend this version.
And here it is in @dalthviz’s image again to see it in context.
Ooo! I like that one too, the cursor indicates interaction!
Thanks @isabela-pf for bring up more options! From my side both icons look nice but indeed the second one kind resembles more how other icons available look (in fact I would say it reminds me the buttons in the Shapes layer) :thinking:
Just in case, here a preview to contrast icons when you have a Shapes layer:
Option | Preview |
---|---|
Maybe we should link this over Zulip or some other place to get more feedback?
More feedback is definitely a good idea. I do love the 2nd icon, but it strikes me now that the other icons with the arrow affect individual shapes, while the new one affects the layer. So it's a bit tricky. I wonder if we should give those layer-mode icons a different tint or something?
More feedback is definitely a good idea.
:+1:
I do love the 2nd icon, but it strikes me now that the other icons with the arrow affect individual shapes, while the new one affects the layer. So it's a bit tricky. I wonder if we should give those layer-mode icons a different tint or something?
That's a good point, kind of tricky indeed 🤔 Maybe the tint you mention could be linked with the highlight color? The modes available that affect individual shapes use the highlight color while the transform mode doesn't (and the box to do the transformation differs also using squares instead of circles for the handles):
Also, after thinking for a while what about merging the two icons? So something like:
Maybe in that way the button can differenciate enough to not give a wrong idea (like the button affects a single shape/item) and still preserve some level of match with current icons available?
I like that! It makes it looks like like the pointer is over a shape. What if we kept the diamond orientation? 🤔
What if we kept the diamond orientation? 🤔
Maybe something like one of these?:
I'm not totally sure how to handle the lines superposition 😅
1 or 2 for me, maybe small preference to 2?
What do you think @isabela-pf ? Maybe there is a better way to handle lines superposition for a merge between the two initial icons suggested (the diamond shape one + a pointer)?
Also, just in case, a summary of the options that have been created until now:
1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|
Seeing all options shared up to this moment, I would say I lean towards (5):
I'd vote 5 as well. 2 looks too much like shape manipulation, rather than layer manipulation. Ironically it's more evocative than the existing shape selection tool icon...
Thanks for spelling this out so clearly, @dalthviz! I think I'd vote for 3 or 5 based on what you have above. I still like those the best and do think they have enough difference in design as well as having different tool tips.
If we are still worried about the square shape looking too close to the Add Rectangle and the rotated square looking too close to Add Ellipses, we can also squash the layer to get a different shape and imply it's on the layer level since this is not used elsewhere. It would look like the following.
I do want to reiterate I think 3 and 5 are still good options.
I like 5 the best. I appreciate the suggestion @isabela-pf but to me the squished shape looks like it's a bug in the rendering, ie it was square and it's gotten squished on its way to the UI. 😂
Just a quick +1 here for number 5.
But it's supposed to be squished because in transform mode you can squish your layers!!
(I like the new squished version 😭 )
@psobolewskiPhD that transformation is actually an axis-aligned scaling plus a shear — can the transform interaction box actually do shear? I see no indication of that in the above. In which case, it's actually misleading. 😉
I don't think you need to encode all possible transforms in the logo, only the possibility of a transform.
Although option 5 seems like the prefered one, as a summary of the comments above, I would say these are now the possible options:
3 | 5 | 7 |
---|---|---|
Also, thinking about the new squished version suggested by @isabela-pf (thanks for that!), we could potencially have an icon per state of the button. So, for example, one icon when is unchecked and another icon when is checked. As an illustration, without using the actual icons but to give an idea of the behavior:
Maybe we could use for the unchecked state option 5 and for the checked state option 7 (the squished version), or maybe some other combination? Not sure if that could add some unnecesary complexity and we just should go ahead and use option 5 but sharing the idea just in case :)
Maybe we could use for the unchecked state option 5 and for the checked state option 7 (the squished version),
This is a good idea to point out! While this is something that some interfaces definitely do, off the top of my head I can't think of precedent for this in the viewer. Because of this, I still think I'd recommend picking one. These icons will stay on this issue if we change out mind later. I'm good with 5!
The icon switch is cute but for now confusing. In fact we do have one more icon that does this, the ndisplay (2D or 3D) button in the viewer — and I find it confusing as heck. 😂 Because the button shows what you would change to if you clicked it, rather than the current state. I'm thinking maybe we should change that to a toggle, with the square/cube icons on either side.
But, that's beside the point — point is, let's not do dynamic icons for now, but thanks for the idea! It could be part of a bigger overhaul in the future.
Thanks for all the feedback! Then I think option 5 it is :) will check with @isabela-pf the SVG file for the icon so we can add it to #6794
I've cleaned up option 5 and made it to size of the other SVG napari icons. Let me know if there's any issues or changes needed. Thank you all for you feedback!
(Yes, it looks like it was made for ants when previewed. 😆)
🚀 Feature
Layer transforms - in particular scale and translate should be settable via GUI elements
Motivation
GUI users want to be able to set layer scale and translate too.
Pitch
There should be some dialog, combobox/ textbox? that allows the properties of the layer transforms to be set. these include scale and translate, but could also include rotation, shear, or a full affine
Alternatives
These are only settable via the API, which limits GUI users
Additional context
Curious which layer transform properties need to be exposed? Is it just scale/ translate - or also rotation, shear, affine etc. What do @jni @andy-sweet @JoOkuma and others think?
Maybe this is something @isabela-pf can begin some design work for and then @ppwadhwa could implement when we have a design