Repository: napari/napari

Issue:
Incorrect interpretation of dimensions for viewing multichannel data
## 🐛 Bug

When loading data with multiple channels, napari selects the first dimension as the channels dimension even when it represents rows, not channels

## To Reproduce

Steps to reproduce the behavior:

```
randoms = np.random.randint(0, 20, 1024*1024*5)
channels_first = randoms.reshape((5, 1024, 1024))
channels_last = randoms.reshape((1024, 1024, 5))

# example code for trying out napari functionality
with napari.gui_qt():
    viewer = napari.view_image(channels_last, rgb=False, name='channels_last')

```
## Expected behavior

Instead of displaying the data as 1024 distinct slices of size 5x1024, it should be displayed as 5 stacks fo 1024x1024. I imagine there is going to be a huge range of different shapes and data formats supplied to napari from different users, and setting up the exact logic to guess correctly is infeasible. Perhaps supplying a channels idx as an argument?

## Environment

 - napari Version (e.g., 1.0): 0.2


## Additional context

<!-- Add any other context about the problem here. -->
![image](https://user-images.githubusercontent.com/13770365/66705484-10c7ca80-ecdc-11e9-83f3-37b528dd2282.png)

![image](https://user-images.githubusercontent.com/13770365/66705490-289f4e80-ecdc-11e9-85c4-ee22e929c32d.png)



Discussion:
Indeed that would probably be a good keyword argument to have. Right now you'd either need to click the "roll dimensions" button which is the button with the cube and the arrow on it near the bottom left, or you'd need to add a line to your code as follows:

```
import numpy as np
import napari


randoms = np.random.randint(0, 20, 1024*1024*5)
channels_first = randoms.reshape((5, 1024, 1024))
channels_last = randoms.reshape((1024, 1024, 5))

# example code for trying out napari functionality
with napari.gui_qt():
    viewer = napari.view_image(channels_last, rgb=False, name='channels_last')
    viewer.dims.order = [2, 0, 1]
```

That `order` parameter will do what you want, but right now it's not exposed on `view_image` or any of our `view_*` methods. It is exposed on `Viewer` which creates an empty Viewer object.

Proposal for @jni to consider - maybe we expose all the keyword args that are on `Viewer` right now (so `ndisplay`, `order`, and `title`), and put them on all our `napari.view_*` methods, so that the above could be done in one line. I would not add the `Viewer` keyword args to our `viewer.add_*` methods as they don't make sense there. If you like that proposal I can quickly implement it


Resolving patch:
diff --git a/napari/components/viewer_model.py b/napari/components/viewer_model.py
--- a/napari/components/viewer_model.py
+++ b/napari/components/viewer_model.py
@@ -19,7 +19,7 @@ class ViewerModel(KeymapMixin):
     ----------
     title : string
         The title of the viewer window.
-    ndisplay : int
+    ndisplay : {2, 3}
         Number of displayed dimensions.
     order : tuple of int
         Order in which dimensions are displayed where the last two or last
diff --git a/napari/view_layers.py b/napari/view_layers.py
--- a/napari/view_layers.py
+++ b/napari/view_layers.py
@@ -20,6 +20,9 @@ def view_image(
     opacity=1,
     blending='translucent',
     visible=True,
+    title='napari',
+    ndisplay=2,
+    order=None,
 ):
     """Create a viewer and add an image layer.
 
@@ -70,13 +73,21 @@ def view_image(
         {'opaque', 'translucent', and 'additive'}.
     visible : bool
         Whether the layer visual is currently being displayed.
+    title : string
+        The title of the viewer window.
+    ndisplay : {2, 3}
+        Number of displayed dimensions.
+    tuple of int
+        Order in which dimensions are displayed where the last two or last
+        three dimensions correspond to row x column or plane x row x column if
+        ndisplay is 2 or 3.
 
     Returns
     -------
     viewer : :class:`napari.Viewer`
         The newly-created viewer.
     """
-    viewer = Viewer()
+    viewer = Viewer(title=title, ndisplay=ndisplay, order=order)
     viewer.add_image(
         data,
         rgb=rgb,
@@ -111,6 +122,9 @@ def view_multichannel(
     opacity=1,
     blending='additive',
     visible=True,
+    title='napari',
+    ndisplay=2,
+    order=None,
 ):
     """Create a viewer and add images layers expanding along one axis.
 
@@ -153,13 +167,21 @@ def view_multichannel(
         {'opaque', 'translucent', and 'additive'}.
     visible : bool
         Whether the layer visual is currently being displayed.
+    title : string
+        The title of the viewer window.
+    ndisplay : {2, 3}
+        Number of displayed dimensions.
+    tuple of int
+        Order in which dimensions are displayed where the last two or last
+        three dimensions correspond to row x column or plane x row x column if
+        ndisplay is 2 or 3.
 
     Returns
     -------
     viewer : :class:`napari.Viewer`
         The newly-created viewer.
     """
-    viewer = Viewer()
+    viewer = Viewer(title=title, ndisplay=ndisplay, order=order)
 
     viewer.add_multichannel(
         image,
@@ -195,6 +217,9 @@ def view_points(
     opacity=1,
     blending='translucent',
     visible=True,
+    title='napari',
+    ndisplay=2,
+    order=None,
 ):
     """Create a viewer and add a points layer.
 
@@ -235,6 +260,14 @@ def view_points(
         {'opaque', 'translucent', and 'additive'}.
     visible : bool
         Whether the layer visual is currently being displayed.
+    title : string
+        The title of the viewer window.
+    ndisplay : {2, 3}
+        Number of displayed dimensions.
+    tuple of int
+        Order in which dimensions are displayed where the last two or last
+        three dimensions correspond to row x column or plane x row x column if
+        ndisplay is 2 or 3.
 
     Returns
     -------
@@ -246,7 +279,7 @@ def view_points(
     See vispy's marker visual docs for more details:
     http://api.vispy.org/en/latest/visuals.html#vispy.visuals.MarkersVisual
     """
-    viewer = Viewer()
+    viewer = Viewer(title=title, ndisplay=ndisplay, order=order)
     viewer.add_points(
         data,
         symbol=symbol,
@@ -280,6 +313,9 @@ def view_labels(
     opacity=0.7,
     blending='translucent',
     visible=True,
+    title='napari',
+    ndisplay=2,
+    order=None,
 ):
     """Create a viewer and add a labels (or segmentation) layer.
 
@@ -318,13 +354,21 @@ def view_labels(
         {'opaque', 'translucent', and 'additive'}.
     visible : bool
         Whether the layer visual is currently being displayed.
+    title : string
+        The title of the viewer window.
+    ndisplay : {2, 3}
+        Number of displayed dimensions.
+    tuple of int
+        Order in which dimensions are displayed where the last two or last
+        three dimensions correspond to row x column or plane x row x column if
+        ndisplay is 2 or 3.
 
     Returns
     -------
     viewer : :class:`napari.Viewer`
         The newly-created viewer.
     """
-    viewer = Viewer()
+    viewer = Viewer(title=title, ndisplay=ndisplay, order=order)
     viewer.add_labels(
         data,
         is_pyramid=is_pyramid,
@@ -357,6 +401,9 @@ def view_shapes(
     opacity=0.7,
     blending='translucent',
     visible=True,
+    title='napari',
+    ndisplay=2,
+    order=None,
 ):
     """Create a viewer and add a shapes layer.
 
@@ -411,13 +458,21 @@ def view_shapes(
         {'opaque', 'translucent', and 'additive'}.
     visible : bool
         Whether the layer visual is currently being displayed.
+    title : string
+        The title of the viewer window.
+    ndisplay : {2, 3}
+        Number of displayed dimensions.
+    tuple of int
+        Order in which dimensions are displayed where the last two or last
+        three dimensions correspond to row x column or plane x row x column if
+        ndisplay is 2 or 3.
 
     Returns
     -------
     viewer : :class:`napari.Viewer`
         The newly-created viewer.
     """
-    viewer = Viewer()
+    viewer = Viewer(title=title, ndisplay=ndisplay, order=order)
     viewer.add_shapes(
         data,
         shape_type=shape_type,
@@ -448,6 +503,9 @@ def view_surface(
     opacity=1,
     blending='translucent',
     visible=True,
+    title='napari',
+    ndisplay=2,
+    order=None,
 ):
     """Create a viewer and add a surface layer.
 
@@ -485,13 +543,21 @@ def view_surface(
         {'opaque', 'translucent', and 'additive'}.
     visible : bool
         Whether the layer visual is currently being displayed.
+    title : string
+        The title of the viewer window.
+    ndisplay : {2, 3}
+        Number of displayed dimensions.
+    tuple of int
+        Order in which dimensions are displayed where the last two or last
+        three dimensions correspond to row x column or plane x row x column if
+        ndisplay is 2 or 3.
 
     Returns
     -------
     viewer : :class:`napari.Viewer`
         The newly-created viewer.
     """
-    viewer = Viewer()
+    viewer = Viewer(title=title, ndisplay=ndisplay, order=order)
     viewer.add_surface(
         data,
         colormap=colormap,
@@ -520,6 +586,9 @@ def view_vectors(
     opacity=0.7,
     blending='translucent',
     visible=True,
+    title='napari',
+    ndisplay=2,
+    order=None,
 ):
     """Create a viewer and add a vectors layer.
 
@@ -553,13 +622,21 @@ def view_vectors(
         {'opaque', 'translucent', and 'additive'}.
     visible : bool
         Whether the layer visual is currently being displayed.
+    title : string
+        The title of the viewer window.
+    ndisplay : {2, 3}
+        Number of displayed dimensions.
+    tuple of int
+        Order in which dimensions are displayed where the last two or last
+        three dimensions correspond to row x column or plane x row x column if
+        ndisplay is 2 or 3.
 
     Returns
     -------
     viewer : :class:`napari.Viewer`
         The newly-created viewer.
     """
-    viewer = Viewer()
+    viewer = Viewer(title=title, ndisplay=ndisplay, order=order)
     viewer.add_vectors(
         data,
         edge_width=edge_width,
diff --git a/napari/viewer.py b/napari/viewer.py
--- a/napari/viewer.py
+++ b/napari/viewer.py
@@ -10,9 +10,9 @@ class Viewer(ViewerModel):
     ----------
     title : string
         The title of the viewer window.
-    ndisplay : int
+    ndisplay : {2, 3}
         Number of displayed dimensions.
-    tuple of int
+    order : tuple of int
         Order in which dimensions are displayed where the last two or last
         three dimensions correspond to row x column or plane x row x column if
         ndisplay is 2 or 3.


Test patch: