Repository: arviz-devs/arviz

Issue:
Tests `test_plot_ppc_discrete...` fail with `kde`.
**Describe the bug**
The following tests fail on both the latest verion (0.16.1) and master.
- `arviz/tests/base_tests/test_plots_matplotlib.py::test_plot_ppc_discrete[True-kde]`
- `arviz/tests/base_tests/test_plots_matplotlib.py::test_plot_ppc_discrete_save_animation[kde]`

**To Reproduce**
Steps to reproduce the behavior. Ideally a self-contained snippet of code, or link to a notebook or external code. Please include screenshots/images produced with ArviZ here, or the stacktrace including `arviz` code to help.
```sh
git clone  git@github.com:arviz-devs/arviz.git
cd arviz
git checkout v0.16.1

# Setup the environment
python -m venv venv
source venv/bin/activate
pip install .
pip install ".[test]"
pip install pytest
pip install numba torch jax

pytest --strict -rsf --durations=20 -p no:warnings "arviz/tests/base_tests/test_plots_matplotlib.py::test_plot_ppc_discrete[True-kde]"
pytest --strict -rsf --durations=20 -p no:warnings "arviz/tests/base_tests/test_plots_matplotlib.py::test_plot_ppc_discrete_save_animation[kde]"
```

**Expected behavior**
The tests pass.

**Additional context**
Error logs:
<details>

```
e = TypingError('Failed in nopython mode pipeline (step: nopython frontend)\nNo implementation of function Function(<funct...=None):\n    <source elided>\n    """\n    hist, bin_edges = np.histogram(data, bins=bins, range=range_hist)\n    ^\n')
issue_type = 'typing'

    def error_rewrite(e, issue_type):
        """
        Rewrite and raise Exception `e` with help supplied based on the
        specified issue_type.
        """
        if config.SHOW_HELP:
            help_msg = errors.error_extras[issue_type]
            e.patch_message('\n'.join((str(e).rstrip(), help_msg)))
        if config.FULL_TRACEBACKS:
            raise e
        else:
>           raise e.with_traceback(None)
E           numba.core.errors.TypingError: Failed in nopython mode pipeline (step: nopython frontend)
E           No implementation of function Function(<function histogram at 0x7f5091b139a0>) found for signature:
E            
E            >>> histogram(array(int64, 1d, C), bins=unicode_type, range=none)
E            
E           There are 2 candidate implementations:
E             - Of which 2 did not match due to:
E             Overload in function 'np_histogram': File: numba/np/arraymath.py: Line 3912.
E               With argument(s): '(array(int64, 1d, C), bins=unicode_type, range=none)':
E              Rejected as the implementation raised a specific error:
E                TypingError: Failed in nopython mode pipeline (step: nopython frontend)
E              No implementation of function Function(<built-in function le>) found for signature:
E               
E               >>> le(unicode_type, int64)
E               
E              There are 22 candidate implementations:
E                    - Of which 18 did not match due to:
E                    Overload of function 'le': File: <numerous>: Line N/A.
E                      With argument(s): '(unicode_type, int64)':
E                     No match.
E                    - Of which 2 did not match due to:
E                    Operator Overload in function 'le': File: unknown: Line unknown.
E                      With argument(s): '(unicode_type, int64)':
E                     No match for registered cases:
E                      * (bool, bool) -> bool
E                      * (int8, int8) -> bool
E                      * (int16, int16) -> bool
E                      * (int32, int32) -> bool
E                      * (int64, int64) -> bool
E                      * (uint8, uint8) -> bool
E                      * (uint16, uint16) -> bool
E                      * (uint32, uint32) -> bool
E                      * (uint64, uint64) -> bool
E                      * (float32, float32) -> bool
E                      * (float64, float64) -> bool
E                    - Of which 2 did not match due to:
E                    Overload in function 'set_issubset': File: numba/cpython/setobj.py: Line 1623.
E                      With argument(s): '(unicode_type, int64)':
E                     Rejected as the implementation raised a specific error:
E                       TypingError: All arguments must be Sets, got (unicode_type, int64)
E                raised from /scratch/alya/galepage/temp/arviz/venv/lib/python3.10/site-packages/numba/cpython/setobj.py:108
E              
E              During: typing of intrinsic-call at /scratch/alya/galepage/temp/arviz/venv/lib/python3.10/site-packages/numba/np/arraymath.py (3974)
E              
E              File "venv/lib/python3.10/site-packages/numba/np/arraymath.py", line 3974:
E                      def histogram_impl(a, bins=10, range=None):
E                          <source elided>
E                                  v = view.item()
E                                  if not bin_min <= v <= bin_max:
E                                  ^
E           
E             raised from /scratch/alya/galepage/temp/arviz/venv/lib/python3.10/site-packages/numba/core/typeinfer.py:1086
E           
E           During: resolving callee type: Function(<function histogram at 0x7f5091b139a0>)
E           During: typing of call at /scratch/alya/galepage/temp/arviz/arviz/stats/density_utils.py (979)
E           
E           
E           File "arviz/stats/density_utils.py", line 979:
E           def histogram(data, bins, range_hist=None):
E               <source elided>
E               """
E               hist, bin_edges = np.histogram(data, bins=bins, range=range_hist)
E               ^

venv/lib/python3.10/site-packages/numba/core/dispatcher.py:409: TypingError
```

</details>

Versions and environmens:
<details>

```
aiohttp==3.8.6
aiosignal==1.3.1
appdirs==1.4.4
-e git+ssh://git@github.com/arviz-devs/arviz.git@4a8eb07c287d3efd3852309fc12ae49d747dda8c#egg=arviz
asciitree==0.3.3
astor==0.8.1
async-timeout==4.0.3
attrs==23.1.0
beanmachine==0.2.0
black==22.3.0
botorch==0.6.6
charset-normalizer==3.3.0
click==8.1.7
clikit==0.6.2
cloudpickle==2.2.1
cmake==3.27.6
cmdstanpy==1.2.0
contourpy==1.1.1
crashtest==0.3.1
cycler==0.12.1
emcee==3.1.4
exceptiongroup==1.1.3
fasteners==0.19
ffmpeg==1.4
filelock==3.12.4
fonttools==4.43.1
frozenlist==1.4.0
fsspec==2023.9.2
functorch==2.0.0
gpytorch==1.8.1
graphviz==0.20.1
h5netcdf==1.2.0
h5py==3.9.0
httpstan==4.10.1
idna==3.4
iniconfig==2.0.0
jax==0.4.18
jaxlib==0.4.18
Jinja2==3.1.2
joblib==1.3.2
kiwisolver==1.4.5
lit==17.0.2
llvmlite==0.41.0
MarkupSafe==2.1.3
marshmallow==3.20.1
matplotlib==3.8.0
ml-dtypes==0.3.1
mpmath==1.3.0
multidict==6.0.4
multipledispatch==1.0.0
mypy-extensions==1.0.0
networkx==3.1
numba==0.58.0
numcodecs==0.12.0
numpy==1.25.2
numpyro==0.13.2
nvidia-cublas-cu11==11.10.3.66
nvidia-cublas-cu12==12.1.3.1
nvidia-cuda-cupti-cu11==11.7.101
nvidia-cuda-cupti-cu12==12.1.105
nvidia-cuda-nvrtc-cu11==11.7.99
nvidia-cuda-nvrtc-cu12==12.1.105
nvidia-cuda-runtime-cu11==11.7.99
nvidia-cuda-runtime-cu12==12.1.105
nvidia-cudnn-cu11==8.5.0.96
nvidia-cudnn-cu12==8.9.2.26
nvidia-cufft-cu11==10.9.0.58
nvidia-cufft-cu12==11.0.2.54
nvidia-curand-cu11==10.2.10.91
nvidia-curand-cu12==10.3.2.106
nvidia-cusolver-cu11==11.4.0.1
nvidia-cusolver-cu12==11.4.5.107
nvidia-cusparse-cu11==11.7.4.91
nvidia-cusparse-cu12==12.1.0.106
nvidia-nccl-cu11==2.14.3
nvidia-nccl-cu12==2.18.1
nvidia-nvjitlink-cu12==12.2.140
nvidia-nvtx-cu11==11.7.91
nvidia-nvtx-cu12==12.1.105
opt-einsum==3.3.0
packaging==23.2
pandas==2.1.1
pastel==0.2.1
pathspec==0.11.2
patsy==0.5.3
Pillow==10.0.1
platformdirs==3.11.0
plotly==5.17.0
pluggy==1.3.0
pylev==1.4.0
pyparsing==3.1.1
pyro-api==0.1.2
pyro-ppl==1.8.6
Pyro5==5.14
pysimdjson==5.0.2
pystan==3.7.0
pytest==7.4.2
python-dateutil==2.8.2
pytz==2023.3.post1
scikit-learn==1.3.1
scipy==1.11.3
serpent==1.41
six==1.16.0
stanio==0.3.0
statsmodels==0.14.0
sympy==1.12
tenacity==8.2.3
threadpoolctl==3.2.0
tomli==2.0.1
torch==2.0.1
tqdm==4.66.1
triton==2.0.0
typing_extensions==4.8.0
tzdata==2023.3
webargs==8.3.0
xarray==2023.9.0
xarray-datatree==0.0.12
xarray-einstats==0.6.0
yarl==1.9.2
zarr==2.16.1
```

</details>



Discussion:
Note: the tests don't fail when `numba` is not installed.
I think I know the reason, will try to fix it asap (might be next week or so).

We have a "conditional_jit" version of np.histogram, which uses numba's one if numba is installed. Here https://github.com/arviz-devs/arviz/blob/main/arviz/plots/backends/matplotlib/ppcplot.py#L417 we use `"auto"` as `bins` which is valid in numpy but not supported in numba (looks like by looking at the source code). My guess is that this used to silenly fall back to python mode and use numpy, but now the behaviour is more strict and it fails. 

We could probably use our own "get_bins" function within https://github.com/arviz-devs/arviz/blob/main/arviz/stats/density_utils.py#L958 if bins is "auto" before passing the arguments down to numba
Thank you for the explanation !
In the meantime, we will disable those tests on our side as they are not indicating a critical bug of arviz.

Resolving patch:
diff --git a/arviz/plots/backends/matplotlib/ppcplot.py b/arviz/plots/backends/matplotlib/ppcplot.py
--- a/arviz/plots/backends/matplotlib/ppcplot.py
+++ b/arviz/plots/backends/matplotlib/ppcplot.py
@@ -412,15 +412,20 @@ def animate(i):
 
         else:
             vals = pp_sampled_vals[0]
-            _, y_vals, x_vals = histogram(vals, bins="auto")
+            bins = get_bins(vals)
+            _, y_vals, x_vals = histogram(vals, bins=bins)
             (line,) = ax.plot(x_vals[:-1], y_vals, **plot_kwargs)
 
-            max_max = max(max(histogram(pp_sampled_vals[i], bins="auto")[1]) for i in range(length))
+            max_max = max(
+                max(histogram(pp_sampled_vals[i], bins=get_bins(pp_sampled_vals[i]))[1])
+                for i in range(length)
+            )
 
             ax.set_ylim(0, max_max)
 
             def animate(i):
-                _, y_vals, x_vals = histogram(pp_sampled_vals[i], bins="auto")
+                pp_vals = pp_sampled_vals[i]
+                _, y_vals, x_vals = histogram(pp_vals, bins=get_bins(pp_vals))
                 line.set_data(x_vals[:-1], y_vals)
                 return (line,)
 


Test patch: