Plotly not handling NA's well for Bar charts. Where shall I address that?

Viewed 100

I want to create a bar-chart with the plotly backend. I use the aggregate-function to count the number of items in each category. Let me show an example. First I create some test-data:

import holoviews as hv
hv.extension('plotly')
import numpy as np
import pandas as pd
samples = 100

pets = ['Cat', 'Dog', 'Hamster', 'Rabbit']
genders = ['Female', 'Male']

pets_sample = np.random.choice(pets, samples)
gender_sample = np.random.choice(genders, samples)
df=pd.DataFrame(data={'pet':pets_sample,'gender':gender_sample,})
df['pet']=pd.Categorical(df['pet'])
df['gender']=pd.Categorical(df['gender'])
# Delete male hamsters so we have an empty category-combination
df=df[~((df['pet']=='Hamster') & (df['gender']=='Male'))]
df['name']=['Animal #'+str(i) for i in range(len(df))]
df=df[['name','pet','gender']]
df

dataframe

When I try to plot this, using

bars = hv.Bars(df, kdims=['pet', 'gender'],vdims='name').aggregate(function=np.count_nonzero)

bars.opts(width=1000,multi_level=False)

I get the following error: ValueError: Out of range float values are not JSON compliant.

The reason for that is (I think) that there is one NA in the aggregated table:

hv.Table(df, kdims=['pet', 'gender'],vdims='name').aggregate(function=np.count_nonzero)

returns

Aggregated table

You can solve this problem by adding a new column to the dataframe, just consisting of ones and use np.sum instead of np.count_nonzero and then everything works:

df['ones']=1
bars=hv.Bars(df, kdims=['pet', 'gender'],vdims=[('ones','count')]).aggregate(function=np.sum)
bars.opts(width=1000,multi_level=False)

bar-chart

I think NA's should default to zero when making Bar-charts. My original approach works fine if I use bokeh as backend. I would like to know where would be a good place to address this issue. The github of holoviews of plotly?

1 Answers

To be honest, I looked into the traceback and this seems to be an issue of bokeh, because

  1. holoviews uses
  2. panel which calls
  3. bokeh to generates a json which
  4. should be rendered with plotly

In this process somewhere this line is called inside bokeh,

json.dumps(
    obj,
    cls=BokehJSONEncoder,
    allow_nan=False,
    indent=indent,
    separators=separators,
    sort_keys=True,
    **kwargs
)

where allow_nan is set to False.

I quote from the documentation of the bokeh BokehJSONEncoder

If allow_nan is true (default), then NaN, Infinity, and -Infinity will be encoded as such. This behavior is not JSON specification compliant, but is consistent with most JavaScript based encoders and decoders. Otherwise, it will be a ValueError to encode such floats.

because this is the class used by the python json bulid-in.

I do not know the reason why this is deactivated, but it looks like it is on purpose, beacuse this can not be set.

I think because it is hard to get a overview about this topic and all the relationships, you should address you problem in the holoviz forum. This seems to be the place where all the experts are.

An alternative could also be the bokeh forum.

Related