Repository: yt-project/yt

Issue:
symlog plots for dataset bounds of zero inclusive (ValueError: Maximum allowed size exceeded)
### Bug report

**Bug summary**

If your data has zero as the minimum value yt crashes when it tries to take a log(data.min()) on line 178 of `yt/visualization/base_plot_types.py` (I also assume this would be the case if data.max() is zero too)

````
# line 178 of yt/visualization/base_plot_types.py
yticks = list(-10**np.arange(np.floor(np.log10(-data.min())),\
                          np.rint(np.log10(cblinthresh))-1, -1)) + [0] + \
                     list(10**np.arange(np.rint(np.log10(cblinthresh)),\
                          np.ceil(np.log10(data.max()))+1))
````

I've hacked in a catch in my version. 
````
# if data.min() == data.max() == 0, you got other problems.
if data.min().v >= 0.0: # I assume cblinthresh >= abs(data.min().v) is checked elsewhere to set cbnorm = 'symlog'
  yticks = [data.min().v] + list(10**np.arange( np.rint(np.log10(cblinthresh)),\  
                np.ceil(np.log10(data.max()))+1))
elif data.max().v <= 0.0:
  yticks = list(-10**np.arange(np.floor(np.log10(-data.min())),\
                          np.rint(np.log10(cblinthresh))-1, -1)) + [data.max().v]
else: 
  yticks = list(-10**np.arange(np.floor(np.log10(-data.min())),\
                          np.rint(np.log10(cblinthresh))-1, -1)) + [0] + \
                     list(10**np.arange(np.rint(np.log10(cblinthresh)),\
                          np.ceil(np.log10(data.max()))+1))
````

**Code for reproduction**

Grab my vtk:
`curl -JO http://use.yt/upload/2be2d0bf`

You can grab the script too or copy from below:
`curl -JO http://use.yt/upload/40eb6c4a`

```python
#!/usr/bin/env python
import yt

def _neutral(field, data):
  return (data['scalar[0]'] * yt.units.g/yt.units.cm**3)

def _ions(field, data):
  return (data['density']-data['neutral'])

ds = yt.load('./bug.vtk')
ds.add_field(('gas','neutral'), function=_neutral, units=ds.unit_system["density"])
ds.add_field(('gas','ionized'), function=_ions, units=ds.unit_system["density"])

p = yt.SlicePlot(ds, 'z', 'ionized')
p.set_zlim('ionized', ds.all_data().min('ionized'), ds.all_data().max('ionized'))
p.set_log('ionized', True, linthresh=1.e-25)
p.save('bug.png')
```

Run with
`./plot.py`

**Actual outcome**

Without fix

![bug_report_19072017](https://user-images.githubusercontent.com/13424519/28392624-95b93b24-6c97-11e7-8bd7-32f7d0444ed8.png)


**Expected outcome**

With fix

![bug_fix19072017](https://user-images.githubusercontent.com/13424519/28392748-2003c9ca-6c98-11e7-83b2-2e082cc77456.png)

Looks like there might need to be additional catches in `plot_container.py`

**Version Information**
  * Python Version: 2.7.12
  * yt version: 3.3.5 (conda-forge)


symlog plots for dataset bounds of zero inclusive (ValueError: Maximum allowed size exceeded)
### Bug report

**Bug summary**

If your data has zero as the minimum value yt crashes when it tries to take a log(data.min()) on line 178 of `yt/visualization/base_plot_types.py` (I also assume this would be the case if data.max() is zero too)

````
# line 178 of yt/visualization/base_plot_types.py
yticks = list(-10**np.arange(np.floor(np.log10(-data.min())),\
                          np.rint(np.log10(cblinthresh))-1, -1)) + [0] + \
                     list(10**np.arange(np.rint(np.log10(cblinthresh)),\
                          np.ceil(np.log10(data.max()))+1))
````

I've hacked in a catch in my version. 
````
# if data.min() == data.max() == 0, you got other problems.
if data.min().v >= 0.0: # I assume cblinthresh >= abs(data.min().v) is checked elsewhere to set cbnorm = 'symlog'
  yticks = [data.min().v] + list(10**np.arange( np.rint(np.log10(cblinthresh)),\  
                np.ceil(np.log10(data.max()))+1))
elif data.max().v <= 0.0:
  yticks = list(-10**np.arange(np.floor(np.log10(-data.min())),\
                          np.rint(np.log10(cblinthresh))-1, -1)) + [data.max().v]
else: 
  yticks = list(-10**np.arange(np.floor(np.log10(-data.min())),\
                          np.rint(np.log10(cblinthresh))-1, -1)) + [0] + \
                     list(10**np.arange(np.rint(np.log10(cblinthresh)),\
                          np.ceil(np.log10(data.max()))+1))
````

**Code for reproduction**

Grab my vtk:
`curl -JO http://use.yt/upload/2be2d0bf`

You can grab the script too or copy from below:
`curl -JO http://use.yt/upload/40eb6c4a`

```python
#!/usr/bin/env python
import yt

def _neutral(field, data):
  return (data['scalar[0]'] * yt.units.g/yt.units.cm**3)

def _ions(field, data):
  return (data['density']-data['neutral'])

ds = yt.load('./bug.vtk')
ds.add_field(('gas','neutral'), function=_neutral, units=ds.unit_system["density"])
ds.add_field(('gas','ionized'), function=_ions, units=ds.unit_system["density"])

p = yt.SlicePlot(ds, 'z', 'ionized')
p.set_zlim('ionized', ds.all_data().min('ionized'), ds.all_data().max('ionized'))
p.set_log('ionized', True, linthresh=1.e-25)
p.save('bug.png')
```

Run with
`./plot.py`

**Actual outcome**

Without fix

![bug_report_19072017](https://user-images.githubusercontent.com/13424519/28392624-95b93b24-6c97-11e7-8bd7-32f7d0444ed8.png)


**Expected outcome**

With fix

![bug_fix19072017](https://user-images.githubusercontent.com/13424519/28392748-2003c9ca-6c98-11e7-83b2-2e082cc77456.png)

Looks like there might need to be additional catches in `plot_container.py`

**Version Information**
  * Python Version: 2.7.12
  * yt version: 3.3.5 (conda-forge)




Discussion:
Okay another fix for `plot_container.py`. In this case `get_symlog_minorticks()` was calling `get_log_minorticks()` and feeding it zero (bad). This caused the figures that were output to have no minor log ticks.

***Current code***

````python
#what 128 of plot_container.py is in current release
if vmin >= 0 or vmax =< 0:
        return get_log_minorticks(vmin, vmax)
else:
        return np.hstack( (-get_log_minorticks(linthresh,-vmin)[::-1], 0,
                            get_log_minorticks(linthresh, vmax)) )
````

***Bugged output***

![fixed](https://user-images.githubusercontent.com/13424519/28393706-1b7fcc0a-6c9d-11e7-993a-55d85b400188.png)
 
***New code***

````python
#change line 128 of plot_container.py
if vmin > 0 or vmax < 0:
        return get_log_minorticks(vmin, vmax)
    elif vmin == 0:
        return np.hstack( (0, get_log_minorticks(linthresh, vmax)) )
    elif vmax == 0:
        return np.hstack( (-get_log_minorticks(linthresh,-vim)[::-1], 0) )
    else:
        return np.hstack( (-get_log_minorticks(linthresh,-vmin)[::-1], 0,
                            get_log_minorticks(linthresh, vmax)) )
````

***Fixed output***

![fixed2](https://user-images.githubusercontent.com/13424519/28393711-279ee55c-6c9d-11e7-9d65-dc99add57f1a.png)

Okay another fix for `plot_container.py`. In this case `get_symlog_minorticks()` was calling `get_log_minorticks()` and feeding it zero (bad). This caused the figures that were output to have no minor log ticks.

***Current code***

````python
#what 128 of plot_container.py is in current release
if vmin >= 0 or vmax =< 0:
        return get_log_minorticks(vmin, vmax)
else:
        return np.hstack( (-get_log_minorticks(linthresh,-vmin)[::-1], 0,
                            get_log_minorticks(linthresh, vmax)) )
````

***Bugged output***

![fixed](https://user-images.githubusercontent.com/13424519/28393706-1b7fcc0a-6c9d-11e7-993a-55d85b400188.png)
 
***New code***

````python
#change line 128 of plot_container.py
if vmin > 0 or vmax < 0:
        return get_log_minorticks(vmin, vmax)
    elif vmin == 0:
        return np.hstack( (0, get_log_minorticks(linthresh, vmax)) )
    elif vmax == 0:
        return np.hstack( (-get_log_minorticks(linthresh,-vim)[::-1], 0) )
    else:
        return np.hstack( (-get_log_minorticks(linthresh,-vmin)[::-1], 0,
                            get_log_minorticks(linthresh, vmax)) )
````

***Fixed output***

![fixed2](https://user-images.githubusercontent.com/13424519/28393711-279ee55c-6c9d-11e7-9d65-dc99add57f1a.png)


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
@@ -229,10 +229,23 @@ def _init_image(self, data, cbnorm, cblinthresh, cmap, extent, aspect):
                 **formatter_kwargs)
             self.cb = self.figure.colorbar(
                 self.image, self.cax, format=formatter)
-            yticks = list(-10**np.arange(np.floor(np.log10(-data.min())),\
-                          np.rint(np.log10(cblinthresh))-1, -1)) + [0] + \
-                     list(10**np.arange(np.rint(np.log10(cblinthresh)),\
-                          np.ceil(np.log10(data.max()))+1))
+            if data.min() >= 0.0:
+                yticks = [data.min().v] + list(
+                    10**np.arange(np.rint(np.log10(cblinthresh)),
+                                  np.ceil(np.log10(data.max())) + 1))
+            elif data.max() <= 0.0:
+                yticks = list(
+                    -10**np.arange(
+                        np.floor(np.log10(-data.min())),
+                        np.rint(np.log10(cblinthresh)) - 1, -1)) + \
+                    [data.max().v]
+            else:
+                yticks = list(
+                    -10**np.arange(np.floor(np.log10(-data.min())),
+                                   np.rint(np.log10(cblinthresh))-1, -1)) + \
+                    [0] + \
+                    list(10**np.arange(np.rint(np.log10(cblinthresh)),
+                                       np.ceil(np.log10(data.max()))+1))
             self.cb.set_ticks(yticks)
         else:
             self.cb = self.figure.colorbar(self.image, self.cax)
diff --git a/yt/visualization/plot_container.py b/yt/visualization/plot_container.py
--- a/yt/visualization/plot_container.py
+++ b/yt/visualization/plot_container.py
@@ -142,11 +142,15 @@ def get_symlog_minorticks(linthresh, vmin, vmax):
         the maximum value in the colorbar
 
     """
-    if vmin >= 0 or vmax <= 0:
+    if vmin > 0 or vmax < 0:
         return get_log_minorticks(vmin, vmax)
+    elif vmin == 0:
+        return np.hstack((0, get_log_minorticks(linthresh, vmax)))
+    elif vmax == 0:
+        return np.hstack((-get_log_minorticks(linthresh,-vmin)[::-1], 0) )
     else:
-        return np.hstack( (-get_log_minorticks(linthresh,-vmin)[::-1], 0,
-                            get_log_minorticks(linthresh, vmax)) )
+        return np.hstack((-get_log_minorticks(linthresh,-vmin)[::-1], 0,
+                          get_log_minorticks(linthresh, vmax)))
 
 field_transforms = {}
 


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
@@ -525,3 +525,26 @@ def test_plot_2d():
     slc = SlicePlot(ds, "theta", ["density"], width=(30000.0, "km"))
     slc2 = plot_2d(ds, "density", width=(30000.0, "km"))
     assert_array_equal(slc.frb['density'], slc2.frb['density'])
+
+def test_symlog_colorbar():
+    ds = fake_random_ds(16)
+
+    def _thresh_density(field, data):
+        wh = data['density'] < 0.5
+        ret = data['density']
+        ret[wh] = 0
+        return ret
+
+    def _neg_density(field, data):
+        return -data['threshold_density']
+
+    ds.add_field('threshold_density', function=_thresh_density,
+                 units='g/cm**3', sampling_type='cell')
+    ds.add_field('negative_density', function=_neg_density, units='g/cm**3',
+                 sampling_type='cell')
+
+    for field in ['density', 'threshold_density', 'negative_density']:
+        plot = SlicePlot(ds, 2, field)
+        plot.set_log(field, True, linthresh=0.1)
+        with tempfile.NamedTemporaryFile(suffix='png') as f:
+            plot.save(f.name)