Repository: yt-project/yt

Issue:
BUG: set_zlim does not set vmax as expected
<!--To help us understand and resolve your issue, please fill out the form to
the best of your ability.-->
<!--You can feel free to delete the sections that do not apply.-->

### Bug report

**Bug summary**

The actual vmax of a plot does not match the vmax specified in `set_zlim`.

**Code for reproduction**

<!--A minimum code snippet required to reproduce the bug, also minimizing the
number of dependencies required.-->

<!-- If you need to use a data file to trigger the issue you're having, consider
using one of the datasets from the yt data hub (http://yt-project.org/data). If
your issue cannot be triggered using a public dataset, you can use the yt
curldrop (https://docs.hub.yt/services.html#curldrop) to share data
files. Please include a link to the dataset in the issue if you use the
curldrop.-->

```python
import yt
import numpy as np

shape = (32, 16, 1)
a = np.linspace(-1, 1, 16)
b = np.ones((32, 16))
c = np.reshape(a*b, shape)
data = {("gas", "density"): c}

ds = yt.load_uniform_grid(
    data,
    shape,
    bbox=np.array([[0.0, 5.0], [0, 1], [-0.1, +0.1]]),
)
p = yt.SlicePlot(ds,"x",("gas", "density"))
p.set_zlim(("gas", "density"), -10, 10)
p.save("zmax.png")
```

**Actual outcome**

![zmax](https://user-images.githubusercontent.com/93188557/161748458-add8c3e0-b6d5-40b0-a752-ff0cd8729b5b.png)


**Version Information**
<!--Please specify your platform and versions of the relevant libraries you are
using:-->
  * Operating System: Debian 5.10.106-1 x86_64 GNU/Linux
  * Python Version: 3.9.9
  * yt version: 4.0.2 (through `pip install yt`)


<!--Please tell us how you installed yt and python e.g., from source,
pip, conda. If you installed from conda, please specify which channel you used
if not the default-->



Discussion:
Thank you for reporting !
So, the good news is that the problem you're reporting is already fixed on the main banch (as well as on the backport branch)... the bad news is that the resulting image is now also less useful because the linthresh is autoset to zmax (or maybe -zmin)
![zmax](https://user-images.githubusercontent.com/14075922/161825931-bd5f8bf7-6123-4b43-ba22-ed0aae193b5d.png)

I note that with 5e480b72 (part of the backport branch between 4.0.2 and the current tip) we get the best of both worlds

![zmax](https://user-images.githubusercontent.com/14075922/161827077-a58a5452-ba5e-4415-b737-ada6e0da9f5e.png)

The problematic change bisects to #3859
I'll try to find a better solution that still fixes #3858 without the undesirable side effect.

Resolving patch:
diff --git a/yt/visualization/base_plot_types.py b/yt/visualization/base_plot_types.py
--- a/yt/visualization/base_plot_types.py
+++ b/yt/visualization/base_plot_types.py
@@ -219,22 +219,22 @@ def _init_image(self, data, cbnorm, cblinthresh, cmap, extent, aspect):
 
         if cbnorm == "symlog":
             # if cblinthresh is not specified, try to come up with a reasonable default
-            min_abs_val, max_abs_val = np.sort(np.abs((zmin, zmax)))
+            min_abs_val, max_abs_val = np.sort(
+                np.abs((np.nanmin(data), np.nanmax(data)))
+            )
             if cblinthresh is not None:
-                pass
+                if zmin * zmax > 0 and cblinthresh < min_abs_val:
+                    # see https://github.com/yt-project/yt/issues/3564
+                    warnings.warn(
+                        f"Cannot set a symlog norm with linear threshold {cblinthresh} "
+                        f"lower than the minimal absolute data value {min_abs_val} . "
+                        "Switching to log norm."
+                    )
+                    cbnorm = "log10"
             elif min_abs_val > 0:
                 cblinthresh = min_abs_val
-            elif zmin * zmax > 0 and cblinthresh < min_abs_val:
-                warnings.warn(
-                    f"Cannot set a symlog norm with linear threshold {cblinthresh} "
-                    f"lower than the minimal absolute data value {min_abs_val} . "
-                    "Switching to log norm."
-                )
-                cbnorm = "log10"
             else:
                 cblinthresh = max_abs_val / 1000
-            if cblinthresh is None:
-                cblinthresh = np.nanmin(np.absolute(data)[data != 0])
 
         if cbnorm == "log10":
             cbnorm_cls = matplotlib.colors.LogNorm


Test patch:
diff --git a/yt/visualization/tests/test_plotwindow.py b/yt/visualization/tests/test_plotwindow.py
--- a/yt/visualization/tests/test_plotwindow.py
+++ b/yt/visualization/tests/test_plotwindow.py
@@ -722,6 +722,43 @@ def _neg_density(field, data):
             plot.save(f.name)
 
 
+def test_symlog_min_zero():
+    # see https://github.com/yt-project/yt/issues/3791
+    shape = (32, 16, 1)
+    a = np.linspace(0, 1, 16)
+    b = np.ones((32, 16))
+    c = np.reshape(a * b, shape)
+    data = {("gas", "density"): c}
+
+    ds = load_uniform_grid(
+        data,
+        shape,
+        bbox=np.array([[0.0, 5.0], [0, 1], [-0.1, +0.1]]),
+    )
+
+    p = SlicePlot(ds, "z", "density")
+    im_arr = p["gas", "density"].image.get_array()
+
+    # check that no data value was mapped to a NaN (log(0))
+    assert np.all(~np.isnan(im_arr))
+    # 0 should be mapped to itself since we expect a symlog norm
+    assert np.min(im_arr) == 0.0
+
+
+def test_symlog_extremely_small_vals():
+    # check that the plot can be constructed without crashing
+    # see https://github.com/yt-project/yt/issues/3858
+    shape = (64, 64, 1)
+    arr = np.full(shape, 5.0e-324)
+    arr[0, 0] = -1e12
+    arr[1, 1] = 200
+    d = {"scalar": arr}
+
+    ds = load_uniform_grid(d, shape)
+    p = SlicePlot(ds, "z", ("stream", "scalar"))
+    p["stream", "scalar"]
+
+
 def test_nan_data():
     data = np.random.random((16, 16, 16)) - 0.5
     data[:9, :9, :9] = np.nan