Repository: yt-project/yt

Issue:
BUG: a regression in SlicePlot's API
### Bug report

**Bug summary**

Found another way (different than #3723) in which #3489 broke `SlicePlot`'s API

**Code for reproduction**

Here's a parametric test that exercise the broken cases

```python
import pytest
import numpy as np
from yt.testing import fake_amr_ds
from yt.visualization.plot_window import ProjectionPlot, SlicePlot

from itertools import product

@pytest.fixture(scope="module")
def ds():
    return fake_amr_ds(geometry="cartesian")

@pytest.mark.parametrize("plot_cls, normal", product([SlicePlot, ProjectionPlot], [(0, 0, 1), [0, 0, 1], np.array((0, 0, 1))]))
def test_normalplot_tuple_normal(ds, plot_cls, normal):
    # regression in SlicePlot
    plot_cls(ds, normal, fields=("stream", "Density"))
```

**Actual outcome**
On the main branch, all 6 tests fail. In yt 4.0.1, `SlicePlot` tests pass (but `ProjectionPlot` tests are also broken)


**Expected outcome**

All of them should pass.
I'm clearly responsible for this mess, so I'll be fixing this now.


Discussion:

Resolving patch:
diff --git a/yt/visualization/plot_window.py b/yt/visualization/plot_window.py
--- a/yt/visualization/plot_window.py
+++ b/yt/visualization/plot_window.py
@@ -1549,7 +1549,7 @@ def _validate_init_args(*, normal, axis, fields) -> None:
                 raise TypeError("Received incompatible arguments 'axis' and 'normal'")
             normal = axis
 
-        if (normal, fields) == (None, None):
+        if normal is fields is None:
             raise TypeError(
                 "missing 2 required positional arguments: 'normal' and 'fields'"
             )
@@ -1939,7 +1939,7 @@ def __init__(
             axis=axis,
             fields=fields,
         )
-
+        normal = self.sanitize_normal_vector(ds, normal)
         # this will handle time series data and controllers
         axis = fix_axis(normal, ds)
         (bounds, center, display_center) = get_window_parameters(
@@ -2160,6 +2160,7 @@ def __init__(
     ):
         # TODO: in yt 4.2, remove default values for normal and fields, drop axis kwarg
         normal = self._validate_init_args(normal=normal, fields=fields, axis=axis)
+        normal = self.sanitize_normal_vector(ds, normal)
 
         axis = fix_axis(normal, ds)
         if ds.geometry in (


Test patch:
diff --git a/yt/visualization/tests/test_normal_plot_api.py b/yt/visualization/tests/test_normal_plot_api.py
--- a/yt/visualization/tests/test_normal_plot_api.py
+++ b/yt/visualization/tests/test_normal_plot_api.py
@@ -1,3 +1,6 @@
+from itertools import product
+
+import numpy as np
 import pytest
 
 from yt._maintenance.deprecation import VisibleDeprecationWarning
@@ -78,3 +81,12 @@ def test_error_with_missing_fields_with_positional(ds, plot_cls):
         TypeError, match="missing required positional argument: 'fields'"
     ):
         plot_cls(ds, "z")
+
+
+@pytest.mark.parametrize(
+    "plot_cls, normal",
+    product([SlicePlot, ProjectionPlot], [(0, 0, 1), [0, 0, 1], np.array((0, 0, 1))]),
+)
+def test_normalplot_normal_array(ds, plot_cls, normal):
+    # see regression https://github.com/yt-project/yt/issues/3736
+    plot_cls(ds, normal, fields=("stream", "Density"))