Hello, all!

I’m trying to understand exactly how layer scaling is performed in napari. I thought maybe that it was being done just by multiplying the image array by the scale array, but this appears not to be the case: either something else is going on, or there appears to be some translation happening as well.

As an example, the following code calculates a random Bezier curve and then draws it three times in a 3d viewer – once with scaling performed by napari, once with scaling performed manually by multiplying the Bezier points with the scaling array, and once with scaling performed manually by multiplying the Bezier points with the scaling array and then adding a scalar.

```
import bezier
import napari
import numpy as np
mean = np.random.choice(11, size=3) * 1.
control_0, control_1 = None, None
while np.equal(mean, control_0).all() or np.equal(mean, control_1).all() or np.equal(control_0, control_1).all():
control_0 = np.random.choice(11, size=3) * 1.
control_1 = np.random.choice(11, size=3) * 1.
bez_nodes = np.array([mean - control_0, mean - control_0 - control_1, mean - control_1]).T
curve = bezier.Curve(bez_nodes, degree=2)
terminus = (mean - control_1).reshape(-1, 1)
terminus = curve.locate(terminus)
bez_s_vals = np.linspace(0, terminus)
bez_points = curve.evaluate_multi(bez_s_vals).T
scale = np.random.choice(11, size=3)
with napari.gui_qt():
viewer = napari.Viewer(ndisplay=3)
viewer.add_shapes([bez_points], edge_width=0.1, shape_type='path', blending='translucent', edge_color=['yellow'], name='napari_scaling', scale=scale)
bez_points *= scale
viewer.add_shapes([bez_points], edge_width=0.1, shape_type='path', blending='translucent', edge_color=['cyan'], name='manual_scaling_no_translation')
bez_points += scale // 2
viewer.add_shapes([bez_points], edge_width=0.1, shape_type='path', blending='translucent', edge_color=['magenta'], name='manual_scaling_with_translation')
```

I’ve included a screenshot of the output from this script below. As we can see, the magenta curve, which is the one that was both manually scaled and translated, fits within the yellow one, which is the one that was scaled by napari; the cyan one, which was only manually scaled without translation, does not. What’s the story here? (Please ignore black screenshot artifacts near bends of cyan and yellow curves.)

For the translation scalar, `scale // 2`

seems to work well for the examples that I’ve tried, but I’m not sure whether this is just a fluke.