Search code examples
pythonplotlyiterable

Plot iterable classes with Plotly


I'm having some problems with the plot of some iterable classes in Python. The idea is to use plotly to plot lines obtained from the iterator of a class. Here is an example of the class:

class example_class:
    ## Constructor
    def __init__(self, n):
        self.int_part = np.random.randint(0, 1023, size=n, dtype=np.uint16)
        self.dec_part = np.random.randint(0, 127, size=n, dtype=np.uint16)
        self.current = 0
        self.n = n

    ## Iterator
    def __iter__(self):
        return self

    ## Next element during the iteration
    def __next__(self):
        if self.current < self.n:
            v = self.int_part[self.current] + self.dec_part[self.current]/100
            self.current += 1
            return v
        raise StopIteration

    ## Length
    def __len__(self):
        return self.n

There is not problem to plot just one instance of the class. For example, the following code generate a correct line plot

import numpy as np
import plotly.express as px

C = example_class(100)
fig = px.line(C)
fig.show()

enter image description here

But if I want to add more lines, like this

import numpy as np
import plotly.express as px

C = example_class(100)
D = example_class(100)
E = example_class(100)

fig = px.line(x=np.arange(0,100), y=[D,E])
fig.show()

I get the following error

Traceback (most recent call last):
File "test.py", line 34, in <module>
    fig.show()
  File "/home/jose/anaconda3/lib/python3.7/site-packages/plotly/basedatatypes.py", line 3409, in show
    return pio.show(self, *args, **kwargs)
  File "/home/jose/anaconda3/lib/python3.7/site-packages/plotly/io/_renderers.py", line 403, in show
    renderers._perform_external_rendering(fig_dict, renderers_string=renderer, **kwargs)
  File "/home/jose/anaconda3/lib/python3.7/site-packages/plotly/io/_renderers.py", line 340, in _perform_external_rendering
    renderer.render(fig_dict)
  File "/home/jose/anaconda3/lib/python3.7/site-packages/plotly/io/_base_renderers.py", line 759, in render
    validate=False,
  File "/home/jose/anaconda3/lib/python3.7/site-packages/plotly/io/_html.py", line 144, in to_html
    jdata = to_json_plotly(fig_dict.get("data", []))
  File "/home/jose/anaconda3/lib/python3.7/site-packages/plotly/io/_json.py", line 143, in to_json_plotly
    json.dumps(plotly_object, cls=PlotlyJSONEncoder, **opts), _swap_json
  File "/home/jose/anaconda3/lib/python3.7/json/__init__.py", line 238, in dumps
    **kw).encode(obj)
  File "/home/jose/anaconda3/lib/python3.7/site-packages/_plotly_utils/utils.py", line 59, in encode
    encoded_o = super(PlotlyJSONEncoder, self).encode(o)
  File "/home/jose/anaconda3/lib/python3.7/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/home/jose/anaconda3/lib/python3.7/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/home/jose/anaconda3/lib/python3.7/site-packages/_plotly_utils/utils.py", line 136, in default
    return _json.JSONEncoder.default(self, obj)
  File "/home/jose/anaconda3/lib/python3.7/json/encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type example_class is not JSON serializable

I tried many alternatives without success.

Anyone has an idea how to solve it?

Thanks! José


Solution

  • When building different figures (in particular line) plotly performs a lot of different checks which, among of others, include casting, sanitizing and, in case of generators/iterators, materializing those with constructing a new index (or so-called placement) - the sizes between them may diverge in such cases.
    To handle/automate index preparation (for x axis) you can pass pd.DataFrame and specify the needed df columns for y axis:

    import numpy as np
    import pandas as pd
    import plotly.express as px
    
    fig = px.line(pd.DataFrame({'D': example_class(100), 
                                'E': example_class(100)}), y=['D', 'E'])
    fig.show()
    

    enter image description here