Repository: holoviz/holoviews

Issue:
Rendering an NdOverlay with bool kdim raises TypeError
<details>

<summary>
The conda environment's packages are collapsed here.
</summary>

```
# Name                    Version                   Build  Channel
abseil-cpp                20210324.2           hd77b12b_0
aom                       3.3.0                h0e60522_1    conda-forge
argon2-cffi               21.3.0             pyhd3eb1b0_0
argon2-cffi-bindings      21.2.0          py310h2bbff1b_0
arrow-cpp                 7.0.0           py310he67c4b2_4_cpu    conda-forge
asttokens                 2.0.5              pyhd3eb1b0_0
atomicwrites              1.4.0                      py_0
attrs                     21.4.0             pyhd3eb1b0_0
aws-c-cal                 0.5.11               he19cf47_0    conda-forge
aws-c-common              0.6.2                h2bbff1b_0
aws-c-event-stream        0.2.7               h70e1b0c_13    conda-forge
aws-c-io                  0.10.5               h2fe331c_0    conda-forge
aws-checksums             0.1.11               h1e232aa_7    conda-forge
aws-sdk-cpp               1.8.186              hb0612c5_3    conda-forge
backcall                  0.2.0              pyhd3eb1b0_0
beautifulsoup4            4.11.1          py310haa95532_0
blas                      1.0                         mkl
bleach                    4.1.0              pyhd3eb1b0_0
blosc                     1.21.0               h19a0ad4_1
bokeh                     2.4.2           py310haa95532_1
bottleneck                1.3.4           py310h9128911_0
brotli                    1.0.9                ha925a31_2
brotli-python             1.0.9           py310h8a704f9_7    conda-forge
brotlipy                  0.7.0           py310h2bbff1b_1002
bzip2                     1.0.8                he774522_0
c-ares                    1.18.1               h2bbff1b_0
c-blosc2                  2.1.1                hdf67494_2    conda-forge
ca-certificates           2022.4.26            haa95532_0
certifi                   2022.6.15       py310haa95532_0
cffi                      1.15.0          py310h2bbff1b_1
cfitsio                   4.1.0                h5a969a9_0    conda-forge
cftime                    1.5.1.1         py310h9128911_0
chardet                   4.0.0           py310haa95532_1003
charls                    2.3.4                h39d44d4_0    conda-forge
charset-normalizer        2.0.4              pyhd3eb1b0_0
click                     8.0.4           py310haa95532_0
cloudpickle               2.0.0              pyhd3eb1b0_0
codecov                   2.1.11             pyhd3eb1b0_0
colorama                  0.4.4              pyhd3eb1b0_0
colorcet                  3.0.0                      py_0    pyviz
conda                     4.13.0          py310haa95532_0
conda-build               3.21.9          py310h5588dad_0    conda-forge
conda-package-handling    1.8.1           py310h8cc25b3_0
coverage                  6.3.2           py310h2bbff1b_0
cryptography              37.0.1          py310h21b164f_0
curl                      7.82.0               h2bbff1b_0
cycler                    0.11.0             pyhd3eb1b0_0
cytoolz                   0.11.0          py310h2bbff1b_0
dash                      1.19.0             pyhd3eb1b0_0
dash-core-components      1.3.1                      py_0
dash-html-components      1.0.1                      py_0
dash-renderer             1.1.2                      py_0
dash-table                4.4.1              pyhd3eb1b0_0
dask                      2022.5.0        py310haa95532_0
dask-core                 2022.5.0        py310haa95532_0
dataclasses               0.8                pyh6d0b6a4_7
datashader                0.14.1                     py_0    pyviz
datashape                 0.5.4           py310haa95532_1
debugpy                   1.5.1           py310hd77b12b_0
decorator                 5.1.1              pyhd3eb1b0_0
defusedxml                0.7.1              pyhd3eb1b0_0
distributed               2022.5.0        py310haa95532_0
doit                      0.33.1          py310haa95532_0
entrypoints               0.4             py310haa95532_0
executing                 0.8.3              pyhd3eb1b0_0
ffmpeg                    4.2.2                he774522_0
filelock                  3.6.0              pyhd3eb1b0_0
flake8                    4.0.1              pyhd3eb1b0_1
flask                     2.0.3              pyhd3eb1b0_0
flask-compress            1.10.1             pyhd3eb1b0_0
fonttools                 4.25.0             pyhd3eb1b0_0
freetype                  2.10.4               hd328e21_0
fsspec                    2022.3.0        py310haa95532_0
future                    0.18.2          py310haa95532_1
geos                      3.8.0                h33f27b4_0
gflags                    2.2.2                ha925a31_0
giflib                    5.2.1                h62dcd97_0
glob2                     0.7                pyhd3eb1b0_0
glog                      0.6.0                h4797de2_0    conda-forge
grpc-cpp                  1.43.2               he33f7c1_3    conda-forge
hdf4                      4.2.13               h712560f_2
hdf5                      1.10.6               h7ebc959_0
heapdict                  1.0.1              pyhd3eb1b0_0
holoviews                 1.14.4.post130+g221a99471           dev_0    <develop>
icc_rt                    2019.0.0             h0cc432a_1
icu                       68.1                 h6c2663c_0
idna                      3.3                pyhd3eb1b0_0
imagecodecs               2022.2.22       py310h7653d06_3    conda-forge
imagecodecs-lite          2019.12.3       py310h2873277_5    conda-forge
imageio                   2.9.0              pyhd3eb1b0_0
importlib-metadata        4.11.3          py310haa95532_0
iniconfig                 1.1.1              pyhd3eb1b0_0
intel-openmp              2022.0.0          haa95532_3663
ipykernel                 6.9.1           py310haa95532_0
ipython                   8.3.0           py310haa95532_0
ipython_genutils          0.2.0              pyhd3eb1b0_1
itsdangerous              2.0.1              pyhd3eb1b0_0
jbig                      2.1               h8d14728_2003    conda-forge
jedi                      0.18.1          py310haa95532_1
jinja2                    3.0.3              pyhd3eb1b0_0
jpeg                      9e                   h2bbff1b_0
jsonschema                4.4.0           py310haa95532_0
jupyter_client            7.2.2           py310haa95532_0
jupyter_core              4.10.0          py310haa95532_0
jupyterlab_pygments       0.1.2                      py_0
jxrlib                    1.1                  he774522_2
kiwisolver                1.4.2           py310hd77b12b_0
lcms2                     2.12                 h83e58a3_0
lerc                      3.0                  hd77b12b_0
libaec                    1.0.6                h39d44d4_0    conda-forge
libarchive                3.5.2                hb45042f_1    conda-forge
libavif                   0.10.0               h8ffe710_1    conda-forge
libbrotlicommon           1.0.9                h8ffe710_7    conda-forge
libbrotlidec              1.0.9                h8ffe710_7    conda-forge
libbrotlienc              1.0.9                h8ffe710_7    conda-forge
libclang                  11.1.0          default_h5c34c98_1    conda-forge
libcrc32c                 1.1.2                h0e60522_0    conda-forge
libcurl                   7.82.0               h86230a5_0
libdeflate                1.10                 h8ffe710_0    conda-forge
libffi                    3.4.2                h604cdb4_1
libgoogle-cloud           1.35.0               h7f3f1e6_2    conda-forge
libiconv                  1.16                 h2bbff1b_2
liblief                   0.11.5               hd77b12b_1
libnetcdf                 4.6.1                hf59b723_4
libpng                    1.6.37               h2a8f88b_0
libprotobuf               3.19.4               h7755175_0    conda-forge
libssh2                   1.10.0               hcd4344a_0
libthrift                 0.16.0               h636ae23_1    conda-forge
libtiff                   4.4.0                hc4061b1_0    conda-forge
libutf8proc               2.7.0                hcb41399_0    conda-forge
libwebp                   1.2.2                h2bbff1b_0
libwebp-base              1.2.2                h2bbff1b_0
libxml2                   2.9.14               h0ad7f3c_0
libzlib                   1.2.12               h8ffe710_0    conda-forge
libzopfli                 1.0.3                ha925a31_0
llvmlite                  0.38.0          py310h23ce68f_0
locket                    1.0.0           py310haa95532_0
lz4                       3.1.3           py310h2bbff1b_0
lz4-c                     1.9.3                h2bbff1b_1
lzo                       2.10                 he774522_2
m2-msys2-runtime          2.5.0.17080.65c939c               3
m2-patch                  2.7.5                         2
markdown                  3.3.4           py310haa95532_0
markupsafe                2.1.1           py310h2bbff1b_0
matplotlib                3.5.1           py310haa95532_1
matplotlib-base           3.5.1           py310hd77b12b_1
matplotlib-inline         0.1.2              pyhd3eb1b0_2
mccabe                    0.7.0              pyhd3eb1b0_0
menuinst                  1.4.17          py310h59b6b97_0
mistune                   0.8.4           py310h2bbff1b_1000
mkl                       2021.4.0           h0e2418a_729    conda-forge
mkl-service               2.4.0           py310h2bbff1b_0
mkl_fft                   1.3.1           py310ha0764ea_0
mkl_random                1.2.2           py310h4ed8f06_0
mock                      4.0.3              pyhd3eb1b0_0
msgpack-python            1.0.3           py310h59b6b97_0
msys2-conda-epoch         20160418                      1
multipledispatch          0.6.0           py310haa95532_0
munkres                   1.1.4                      py_0
nbclient                  0.5.13          py310haa95532_0
nbconvert                 6.4.4           py310haa95532_0
nbformat                  5.3.0           py310haa95532_0
nbsmoke                   0.6.0                      py_0    pyviz
nest-asyncio              1.5.5           py310haa95532_0
netcdf4                   1.5.7           py310h2805cc6_0
networkx                  2.7.1              pyhd3eb1b0_0
notebook                  6.4.11          py310haa95532_0
numba                     0.55.1          py310h4ed8f06_0
numexpr                   2.8.1           py310hb57aa6b_1
numpy                     1.21.5          py310h6d2d95c_3
numpy-base                1.21.5          py310h206c741_3
openjpeg                  2.4.0                h4fc8c34_0
openssl                   1.1.1q               h2bbff1b_0
packaging                 21.3               pyhd3eb1b0_0
pandas                    1.4.2           py310hd77b12b_0
pandocfilters             1.5.0              pyhd3eb1b0_0
panel                     0.13.1                     py_0    pyviz
param                     1.12.1                     py_0    pyviz
parquet-cpp               1.5.1                h34088ae_4
parso                     0.8.3              pyhd3eb1b0_0
partd                     1.2.0              pyhd3eb1b0_1
path                      16.2.0             pyhd3eb1b0_0
path.py                   12.5.0               hd3eb1b0_0
pickleshare               0.7.5           pyhd3eb1b0_1003
pillow                    9.0.1           py310hdc2b20a_0
pip                       21.2.4          py310haa95532_0
pkginfo                   1.8.2              pyhd3eb1b0_0
plotly                    5.6.0              pyhd3eb1b0_0
pluggy                    1.0.0           py310haa95532_1
prometheus_client         0.13.1             pyhd3eb1b0_0
prompt-toolkit            3.0.20             pyhd3eb1b0_0
psutil                    5.8.0           py310h2bbff1b_1
pure_eval                 0.2.2              pyhd3eb1b0_0
py                        1.11.0             pyhd3eb1b0_0
py-lief                   0.11.5          py310hd77b12b_1
pyarrow                   7.0.0           py310h4115056_4_cpu    conda-forge
pycodestyle               2.8.0              pyhd3eb1b0_0
pycosat                   0.6.3           py310h2bbff1b_0
pycparser                 2.21               pyhd3eb1b0_0
pyct                      0.4.8                      py_0    pyviz
pyct-core                 0.4.8                      py_0    pyviz
pyctdev                   0.7.0                      py_0    pyviz
pyflakes                  2.4.0              pyhd3eb1b0_0
pygments                  2.11.2             pyhd3eb1b0_0
pyopenssl                 22.0.0             pyhd3eb1b0_0
pyparsing                 3.0.4              pyhd3eb1b0_0
pyqt                      5.12.3          py310h5588dad_8    conda-forge
pyqt-impl                 5.12.3          py310h8a704f9_8    conda-forge
pyqt5-sip                 4.19.18         py310h8a704f9_8    conda-forge
pyqtchart                 5.12            py310h8a704f9_8    conda-forge
pyqtwebengine             5.12.1          py310h8a704f9_8    conda-forge
pyrsistent                0.18.0          py310h2bbff1b_0
pysocks                   1.7.1           py310haa95532_0
pytest                    7.1.2           py310haa95532_0
pytest-cov                3.0.0              pyhd3eb1b0_0
python                    3.10.4               hbb2ffb3_0
python-dateutil           2.8.2              pyhd3eb1b0_0
python-fastjsonschema     2.15.1             pyhd3eb1b0_0
python-libarchive-c       2.9                pyhd3eb1b0_1
python_abi                3.10                    2_cp310    conda-forge
pytz                      2021.3             pyhd3eb1b0_0
pyviz_comms               2.2.0                      py_0    pyviz
pywavelets                1.3.0           py310h2bbff1b_0
pywin32                   302             py310h2bbff1b_2
pywinpty                  2.0.2           py310h5da7b33_0
pyyaml                    6.0             py310h2bbff1b_0
pyzmq                     22.3.0          py310hd77b12b_2
qt                        5.12.9               h5909a2a_4    conda-forge
re2                       2022.02.01           h0e60522_0    conda-forge
requests                  2.27.1             pyhd3eb1b0_0
ripgrep                   12.1.1                        0
ruamel_yaml               0.15.100        py310h2bbff1b_0
scikit-image              0.19.2          py310h4ed8f06_0
scipy                     1.7.3           py310h6d2d95c_0
send2trash                1.8.0              pyhd3eb1b0_1
setuptools                61.2.0          py310haa95532_0
shapely                   1.7.0           py310h723df8e_0
sip                       6.5.1           py310hd77b12b_0
six                       1.16.0             pyhd3eb1b0_1
snappy                    1.1.9                h6c2663c_0
sortedcontainers          2.4.0              pyhd3eb1b0_0
soupsieve                 2.3.1              pyhd3eb1b0_0
sqlite                    3.38.3               h2bbff1b_0
stack_data                0.2.0              pyhd3eb1b0_0
streamz                   0.6.3              pyhd3eb1b0_0
tbb                       2021.5.0             h59b6b97_0
tblib                     1.7.0              pyhd3eb1b0_0
tenacity                  8.0.1           py310haa95532_0
terminado                 0.13.1          py310haa95532_0
testpath                  0.5.0              pyhd3eb1b0_0
tifffile                  2021.7.2           pyhd3eb1b0_2
tk                        8.6.12               h2bbff1b_0
toml                      0.10.2             pyhd3eb1b0_0
tomli                     1.2.2              pyhd3eb1b0_0
toolz                     0.11.2             pyhd3eb1b0_0
tornado                   6.1             py310h2bbff1b_0
tqdm                      4.64.0          py310haa95532_0
traitlets                 5.1.1              pyhd3eb1b0_0
typing-extensions         4.1.1                hd3eb1b0_0
typing_extensions         4.1.1              pyh06a4308_0
tzdata                    2022a                hda174b7_0
urllib3                   1.26.9          py310haa95532_0
vc                        14.2                 h21ff451_1
vs2015_runtime            14.27.29016          h5e58377_2
wcwidth                   0.2.5              pyhd3eb1b0_0
webencodings              0.5.1           py310haa95532_1
werkzeug                  2.0.3              pyhd3eb1b0_0
wheel                     0.37.1             pyhd3eb1b0_0
win_inet_pton             1.1.0           py310haa95532_0
wincertstore              0.2             py310haa95532_2
winpty                    0.4.3                         4
xarray                    0.20.1             pyhd3eb1b0_1
xz                        5.2.5                h8cc25b3_1
yaml                      0.2.5                he774522_0
zfp                       0.5.5                hd77b12b_6
zict                      2.0.0              pyhd3eb1b0_0
zipp                      3.8.0           py310haa95532_0
zlib                      1.2.12               h8ffe710_0    conda-forge
zlib-ng                   2.0.6                h8ffe710_0    conda-forge
zstd                      1.5.2                h6255e5f_0    conda-forge
```

</details>

Although one may construct an `NdOverlay` that has a key dimension of type `bool`, attempting to render it raises `TypeError: sequence item 0: expected str instance, bool found`.

For example, within a Jupyter notebook, the following constructs and renders a `HoloMap` by grouping over a `bool` dimension in the data, and the rendering sensibly shows string representations of the `bool` values in both the chart title and selector:

``` python
import holoviews

holoviews.extension("bokeh")

holomap = (
    holoviews.Scatter([(0, 2, False), (1, 1, True)], "u", ["v", "odd"])
    .groupby("odd")
)
holomap
```

![image](https://user-images.githubusercontent.com/38358698/182908678-ace50ea3-3316-4af0-8c59-f0b87e77d895.png)

Also, an `NdLayout` derived from the `HoloMap` shows string representations in the chart titles:

``` python
holomap.layout()
```

![image](https://user-images.githubusercontent.com/38358698/182908794-4a3599b5-3dbf-46b6-a57f-0954cb018805.png)

One may construct an `NdOverlay` without error:

``` python
ndoverlay = holomap.overlay()
```

However, rendering it raises a `TypeError`:

``` python
ndoverlay
```

> ``` python
> Traceback (most recent call last):
> 
>   File ...\IPython\core\formatters.py:973 in __call__
>     return method(include=include, exclude=exclude)
> 
>   File ...\holoviews\core\dimension.py:1294 in _repr_mimebundle_
>     return Store.render(self)
> 
>   File ...\holoviews\core\options.py:1405 in render
>     ret = hook(obj)
> 
>   File ...\holoviews\ipython\display_hooks.py:282 in pprint_display
>     return display(obj, raw_output=True)
> 
>   File ...\holoviews\ipython\display_hooks.py:252 in display
>     output = element_display(obj)
> 
>   File ...\holoviews\ipython\display_hooks.py:146 in wrapped
>     mimebundle = fn(element, max_frames=max_frames)
> 
>   File ...\holoviews\ipython\display_hooks.py:192 in element_display
>     return render(element)
> 
>   File ...\holoviews\ipython\display_hooks.py:68 in render
>     return renderer.components(obj, **kwargs)
> 
>   File ...\holoviews\plotting\renderer.py:398 in components
>     return self._render_panel(plot, embed, comm)
> 
>   File ...\holoviews\plotting\renderer.py:405 in _render_panel
>     model = plot.layout._render_model(doc, comm)
> 
>   File ...\panel\viewable.py:507 in _render_model
>     model = self.get_root(doc, comm)
> 
>   File ...\panel\viewable.py:558 in get_root
>     root = self._get_model(doc, comm=comm)
> 
>   File ...\panel\layout\base.py:146 in _get_model
>     objects = self._get_objects(model, [], doc, root, comm)
> 
>   File ...\panel\layout\base.py:131 in _get_objects
>     child = pane._get_model(doc, root, model, comm)
> 
>   File ...\panel\pane\holoviews.py:248 in _get_model
>     plot = self._render(doc, comm, root)
> 
>   File ...\panel\pane\holoviews.py:324 in _render
>     return renderer.get_plot(self.object, **kwargs)
> 
>   File ...\holoviews\plotting\bokeh\renderer.py:70 in get_plot
>     plot = super().get_plot(obj, doc, renderer, **kwargs)
> 
>   File ...\holoviews\plotting\renderer.py:240 in get_plot
>     plot.update(init_key)
> 
>   File ...\holoviews\plotting\plot.py:956 in update
>     return self.initialize_plot()
> 
>   File ...\holoviews\plotting\bokeh\element.py:2318 in initialize_plot
>     child = subplot.initialize_plot(ranges, plot, plots)
> 
>   File ...\holoviews\plotting\bokeh\element.py:1384 in initialize_plot
>     self._init_glyphs(plot, element, ranges, source)
> 
>   File ...\holoviews\plotting\bokeh\element.py:1340 in _init_glyphs
>     properties = self._glyph_properties(plot, style_element, source, ranges, style)
> 
>   File ...\holoviews\plotting\bokeh\element.py:1193 in _glyph_properties
>     legend = ', '.join([d.pprint_value(v, print_unit=True) for d, v in
> 
> TypeError: sequence item 0: expected str instance, bool found
> 
> :NdOverlay   [odd]
>    :Scatter   [u]   (v,odd)
> ```

(For brevity, I've used a plain traceback and abbreviated the paths.)

The `TypeError` arises from the key dimension's `pprint_value` method returning `bool` output for `bool` input:

``` python
{val: ndoverlay.kdims[0].pprint_value(val) for val in [False, True]}
```

> ``` python
> {False: False, True: True}
> ```

That behavior arrived with PR #4946, specifically with the removal of a `unicode` call within `Dimension.pprint_value` that coerced anything to a string.  Prior to that PR, `pprint_value` returned a string, and rendering succeeded.  The bug might be resolved by again coercing the formatted output to a string, by adding `Dimension.type_formatters[bool] = str` to "holoviews/core/\_\_init__.py", or with other approaches.

One work-around is to add a value formatter to the key dimension by re-dimensioning the `NdOverlay`:

``` python
ndoverlay.redim(**{"odd": dict(value_format=str)})
```

![image](https://user-images.githubusercontent.com/38358698/182909220-b828c2c8-08c5-4491-b29a-98e5ba6aed91.png)



Discussion:
To summarize, a change in how reprs are formatted to string means legend generation is failing. I think we need to register a general formatter for booleans or figure out whether that `unicode` (or `str`) call should be reintroduced. 

At any rate, `pprint_value` should never return anything except strings!

Resolving patch:
diff --git a/holoviews/core/dimension.py b/holoviews/core/dimension.py
--- a/holoviews/core/dimension.py
+++ b/holoviews/core/dimension.py
@@ -416,7 +416,7 @@ def pprint_value(self, value, print_unit=False):
                 else:
                     formatted_value = formatter % value
         else:
-            formatted_value = bytes_to_unicode(value)
+            formatted_value = str(bytes_to_unicode(value))
 
         if print_unit and self.unit is not None:
             formatted_value = formatted_value + ' ' + bytes_to_unicode(self.unit)


Test patch:
diff --git a/holoviews/tests/core/test_dimensions.py b/holoviews/tests/core/test_dimensions.py
--- a/holoviews/tests/core/test_dimensions.py
+++ b/holoviews/tests/core/test_dimensions.py
@@ -77,6 +77,12 @@ def test_name_dimension_repr_params_eval_equality(self):
         dim = Dimension('test', label='Test Dimension', unit='m')
         self.assertEqual(eval(repr(dim)) == dim, True)
 
+    def test_pprint_value_boolean(self):
+        # https://github.com/holoviz/holoviews/issues/5378
+        dim = Dimension('test')
+        self.assertEqual(dim.pprint_value(True), 'True')
+        self.assertEqual(dim.pprint_value(False), 'False')
+
 
 class DimensionEqualityTest(ComparisonTestCase):