Repository: scikit-hep/hist

Issue:
[BUG] SVG repr doesn’t support Weight storage
**Describe the bug**

I've already talked with @henryiii and so he has identified the Issue as described in the title, but I would not have known this from inspection as naively I assumed this was about `dtype` conversion. @henryiii had mentioned that there was a similar issue on `boost-histogram` but I'm not sure which one that is, so cc @HDembinski here too. @jpivarski has mentioned this is a combined issue that also will need coordination with `uproot4`.

**To Reproduce**

I [made a Gist](https://gist.github.com/matthewfeickert/2afe18c6b06ed14d889c3102513a621a) but you can also demo all of it in Binder: [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gist/matthewfeickert/2afe18c6b06ed14d889c3102513a621a/master?urlpath=lab/tree/minimal-failing.ipynb)

```
$ git clone git@gist.github.com:2afe18c6b06ed14d889c3102513a621a.git hist-issue
$ cd hist-issue
$ python3 -m venv hist-issue
$ . hist-issue/bin/activate
(hist-issue) $ cat requirements.txt 
hist[plot]==2.0.1
uproot4==0.0.27
uproot~=3.12
jupyter~=1.0
jupyterlab~=2.2
(hist-issue) $ python -m pip install -q -r requirements.txt
(hist-issue) $ python minimal-failing.py
hists in file: ['mass;1']
Traceback (most recent call last):
  File "minimal-failing.py", line 100, in <module>
    main()
  File "minimal-failing.py", line 96, in main
    minimal_failing(root_file)
  File "minimal-failing.py", line 73, in minimal_failing
    hist_mass.plot()
  File "/home/feickert/.venvs/hist-issue/lib/python3.7/site-packages/hist/basehist.py", line 204, in plot
    return self.plot1d(*args, **kwargs)
  File "/home/feickert/.venvs/hist-issue/lib/python3.7/site-packages/hist/basehist.py", line 222, in plot1d
    return hist.plot.histplot(self, ax=ax, **kwargs)
  File "/home/feickert/.venvs/hist-issue/lib/python3.7/site-packages/mplhep/plot.py", line 132, in histplot
    h = np.asarray(h).astype(float)
TypeError: Cannot cast array data from dtype([('value', '<f8'), ('variance', '<f8')]) to dtype('float64') according to the rule 'unsafe'
```

where the TL;DR is

```python
import uproot4 as uproot
import hist
from hist import Hist

root_file = uproot.open("example.root")
hist_mass = root_file["mass"].to_hist()
hist_mass.plot()
```

errors and similarly in the Jupyter repr for

```python
hist_mass
```

one gets

```pytb
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
~/.venvs/JC-example/lib/python3.7/site-packages/IPython/core/formatters.py in __call__(self, obj)
    343             method = get_real_method(obj, self.print_method)
    344             if method is not None:
--> 345                 return method()
    346             return None
    347         else:

~/.venvs/JC-example/lib/python3.7/site-packages/hist/basehist.py in _repr_html_(self)
     64                 return str(html_hist(self, svg_hist_1d_c))
     65             else:
---> 66                 return str(html_hist(self, svg_hist_1d))
     67         elif self.ndim == 2:
     68             return str(html_hist(self, svg_hist_2d))

~/.venvs/JC-example/lib/python3.7/site-packages/hist/svgplots.py in html_hist(h, function)
     20 
     21 def html_hist(h, function):
---> 22     left_column = div(function(h), style="width:290px;")
     23     right_column = div(_desc_hist(h), style="flex=grow:1;")
     24 

~/.venvs/JC-example/lib/python3.7/site-packages/hist/svgplots.py in svg_hist_1d(h)
     53     (edges,) = h.axes.edges
     54     norm_edges = (edges - edges[0]) / (edges[-1] - edges[0])
---> 55     density = h.density()
     56     max_dens = np.max(density) or 1
     57     norm_vals = density / max_dens

~/.venvs/JC-example/lib/python3.7/site-packages/hist/basehist.py in density(self)
    187         Density numpy array.
    188         """
--> 189         total = self.sum() * functools.reduce(operator.mul, self.axes.widths)
    190         return self.view() / np.where(total > 0, total, 1)
    191 

TypeError: invalid type promotion
```

**Expected behavior**

The same output possible as 

```
(hist-issue) $ python minimal-failing.py pass
```

Discussion:

Patch:
diff --git a/README.md b/README.md
index fb17fe3..00c2c63 100644
--- a/README.md
+++ b/README.md
@@ -41,6 +41,8 @@ Hist currently provides everything boost-histogram provides, and the following e
 - The `Hist` class augments `bh.Histogram` with reduced typing construction:
   - Optional import-free construction system
   - `flow=False` is a fast way to turn off flow
+  - Storages can be given by string
+  - `storage=` can be omitted
 
 - Hist implements UHI+; an extension to the UHI (Unified Histogram Indexing) system designed for import-free interactivity:
   - Uses `j` suffix to switch to data coordinates in access or slices
diff --git a/docs/changelog.rst b/docs/changelog.rst
index 20da761..77c373c 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -4,12 +4,17 @@ Changelog
 Version 2.1.0
 --------------------
 
+* Support shortcuts for setting storages by string or position
+  `#129 <https://github.com/scikit-hep/hist/pull/129>`_
+
 Updated dependencies:
 
-- `boost-histogram` 0.11.0 to 0.13.0.
-    - major new features, including PlottableProtocol
-- `histoprint` >=1.4 to >=1.6.
-- `mplhep` >=0.2.16 when `[plot]` given
+* ``boost-histogram`` 0.11.0 to 0.13.0.
+    * Major new features, including PlottableProtocol
+
+* ``histoprint`` >=1.4 to >=1.6.
+
+* ``mplhep`` >=0.2.16 when ``[plot]`` given
 
 
 Version 2.0.1
diff --git a/src/hist/basehist.py b/src/hist/basehist.py
index c1c2bdf..26afbf1 100644
--- a/src/hist/basehist.py
+++ b/src/hist/basehist.py
@@ -2,6 +2,7 @@ from .axestuple import NamedAxesTuple
 from .quick_construct import MetaConstructor
 from .utils import set_family, HIST_FAMILY
 from .storage import Storage
+from .axis import AxisProtocol
 
 import warnings
 import functools
@@ -36,15 +37,31 @@ def _proc_kw_for_lw(kwargs):
 class BaseHist(bh.Histogram, metaclass=MetaConstructor):
     __slots__ = ()
 
-    def __init__(self, *args, storage: Optional[Storage] = None, metadata=None):
+    def __init__(
+        self,
+        *args: Union[AxisProtocol, Storage, str, Tuple[int, float, float]],
+        storage: Optional[Union[Storage, str]] = None,
+        metadata=None,
+    ):
         """
         Initialize BaseHist object. Axis params can contain the names.
         """
         self._hist: Any = None
         self.axes: NamedAxesTuple
 
-        if len(args):
-            if isinstance(storage, type):
+        if args and storage is None and isinstance(args[-1], (Storage, str)):
+            storage = args[-1]
+            args = args[:-1]
+
+        if args:
+            if isinstance(storage, str):
+                storage_str = storage.title()
+                if storage_str == "Atomicint64":
+                    storage_str = "AtomicInt64"
+                elif storage_str == "Weightedmean":
+                    storage_str = "WeightedMean"
+                storage = getattr(bh.storage, storage_str)()
+            elif isinstance(storage, type):
                 msg = (
                     f"Please use '{storage.__name__}()' instead of '{storage.__name__}'"
                 )
@@ -198,7 +215,7 @@ class BaseHist(bh.Histogram, metaclass=MetaConstructor):
         Density numpy array.
         """
         total = self.sum() * functools.reduce(operator.mul, self.axes.widths)
-        return self.view() / np.where(total > 0, total, 1)
+        return self.values() / np.where(total > 0, total, 1)
 
     def show(self, **kwargs):
         """
diff --git a/src/hist/plot.py b/src/hist/plot.py
index 1aef7c8..aa12e5c 100644
--- a/src/hist/plot.py
+++ b/src/hist/plot.py
@@ -168,9 +168,8 @@ def plot_pull(
         pull_ax = fig.add_subplot(grid[1], sharex=main_ax)
 
     # Computation and Fit
-    view = self.view()
-    values = view.value if hasattr(view, "value") else view
-    yerr = view.variance if hasattr(view, "variance") else np.sqrt(values)
+    values = self.values()
+    yerr = self.variances()
 
     # Compute fit values: using func as fit model
     popt, pcov = curve_fit(f=func, xdata=self.axes[0].centers, ydata=values)


Test patch:
diff --git a/tests/test_general.py b/tests/test_general.py
index b9495b5..627527e 100644
--- a/tests/test_general.py
+++ b/tests/test_general.py
@@ -1,4 +1,4 @@
-from hist import Hist, axis
+from hist import Hist, axis, storage
 
 import boost_histogram as bh
 import pytest
@@ -432,6 +432,19 @@ class TestGeneralStorageProxy:
         with pytest.raises(Exception):
             h.Double()
 
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), "double")._storage_type
+            == storage.Double
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage="DouBle")._storage_type
+            == storage.Double
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage.Double())._storage_type
+            == storage.Double
+        )
+
     def test_int64(self):
         h = Hist.new.Reg(10, 0, 1, name="x").Int64().fill([0.5, 0.5])
         assert h[0.5j] == 2
@@ -441,6 +454,19 @@ class TestGeneralStorageProxy:
         with pytest.raises(Exception):
             h.Int64()
 
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), "int64")._storage_type
+            == storage.Int64
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage="INT64")._storage_type
+            == storage.Int64
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage.Int64())._storage_type
+            == storage.Int64
+        )
+
     def test_atomic_int64(self):
         h = Hist.new.Reg(10, 0, 1, name="x").AtomicInt64().fill([0.5, 0.5])
         assert h[0.5j] == 2
@@ -450,6 +476,19 @@ class TestGeneralStorageProxy:
         with pytest.raises(Exception):
             h.AtomicInt64()
 
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), "atomicint64")._storage_type
+            == storage.AtomicInt64
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage="AtomicINT64")._storage_type
+            == storage.AtomicInt64
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage.AtomicInt64())._storage_type
+            == storage.AtomicInt64
+        )
+
     def test_weight(self):
         h = Hist.new.Reg(10, 0, 1, name="x").Weight().fill([0.5, 0.5])
         assert h[0.5j].variance == 2
@@ -459,6 +498,19 @@ class TestGeneralStorageProxy:
         with pytest.raises(Exception):
             h.Weight()
 
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), "WeighT")._storage_type
+            == storage.Weight
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage="weight")._storage_type
+            == storage.Weight
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage.Weight())._storage_type
+            == storage.Weight
+        )
+
     def test_mean(self):
         h = (
             Hist.new.Reg(10, 0, 1, name="x")
@@ -473,6 +525,18 @@ class TestGeneralStorageProxy:
         with pytest.raises(Exception):
             h.Mean()
 
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), "MEAn")._storage_type == storage.Mean
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage="mean")._storage_type
+            == storage.Mean
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage.Mean())._storage_type
+            == storage.Mean
+        )
+
     def test_weighted_mean(self):
         h = (
             Hist.new.Reg(10, 0, 1, name="x")
@@ -488,6 +552,19 @@ class TestGeneralStorageProxy:
         with pytest.raises(Exception):
             h.WeightedMean()
 
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), "WeighTEDMEAn")._storage_type
+            == storage.WeightedMean
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage="weightedMean")._storage_type
+            == storage.WeightedMean
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage.WeightedMean())._storage_type
+            == storage.WeightedMean
+        )
+
     def test_unlimited(self):
         h = Hist.new.Reg(10, 0, 1, name="x").Unlimited().fill([0.5, 0.5])
         assert h[0.5j] == 2
@@ -496,6 +573,19 @@ class TestGeneralStorageProxy:
         with pytest.raises(Exception):
             h.Unlimited()
 
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), "unlimited")._storage_type
+            == storage.Unlimited
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage="UNLImited")._storage_type
+            == storage.Unlimited
+        )
+        assert (
+            Hist(axis.Regular(10, 0, 1, name="x"), storage.Unlimited())._storage_type
+            == storage.Unlimited
+        )
+
 
 def test_general_transform_proxy():
     """