[PLOTLY RESAMPLE] What can I do to choose how much plotly resample samples?

I have a couple of questions about the plotly resample component

  • What can I do to change the sampling rate? I am using plotly resample Welcome to plotly-resampler’s documentation! — plotly-resampler "0.8.2" documentation in a dash app. I tried using this function (un)wrapping plotly figures — plotly-resampler "0.8.2" documentation but I don’t see any options to determine how much it samples. The out of the box sampling samples a bit too sparsely for my particular use case.

  • If I go the manual route, where can I select the number of samples? It looks like it might be the default_n_shown_samples in the figure resampler function. In my case, I’m wrapping go.make_subplots() with the argument. I’m wondering if I can choose different numbers for n for different traces. The docs say “This can be overridden within the add_trace() method.” but it’s not clear what argument to pass to do that.

  • Can I turn off resampling if I go the manual route? I want to have an option on my dashboard that says “turn off resampling”. My best guess is to pass convert_existing_traces = False to the FigureResampler but it’s not clear how I can update that argument on an existing figure object.

  • Do I no longer include the standard x = and y = arguments in my traces? I have a callback that updates the x and y arguments of my traces using the extendData argument and I’m wondering if that breaks if I use hf_x and hf_y.

  • What can I do to use the auto-scaling the y axis part of plotly resample? I couldn’t find an example of this in the docs but the feature sounds really cool.

  • Where do I fire register_update_graph_callback? I have a Dash file that has the app object and then I have a file that gets called and has all of my traces, figure logic, etc. It sounds like the register_update_graph_callback should be placed in the same part of the script where the figure is defined, but I don’t have the app object there. I could pass it along to the file, but I want to make sure that’s the right place for this function.

3 Likes

Hi @ibenok,

Thank you for taking such an interest in our toolkit, these are all really good questions! I will discuss the ones I cannot answer yet with my codeveloper and couple back the results.

So far:

  1. Regarding the first two bullets:

    changing the sampling rate on a trace-level granularity

    I think looking at the basic_example.ipynb might help you with this. More specifically, the section: Different downsampler & number of shown samples per trace. i.e. you need to use the max_n_samples argument. (also stated here in the docs)

  2. Regarding bullet 3:

    turning off resampling

    I need to look into that.

  3. Regarding bullet 4:

    Extending existing scatter traces their data

    High-frequency streaming data can be supported with plotly-resampler (I’ve created a minimal working example). We are planning to add such an example in the near future. It boils down towards using the hf_data property of the FigureResampler instances. Example of a streaming data dash callback:

@app.callback(
    [Output("trace-updater", "updateData"), Output("ts_store", "data")],
    [Input("interval", "n_intervals"), Input("graph-id", "relayoutData")],
    State("store", "data"),  # The server side cached FigureResampler per session
    State("ts_store", "data"),
    prevent_initial_call=True,
)
def update_fig(n_intervals, relayoutdata, fig, ts_ref):
    if fig is None:
        return no_update

    # We extend the hf-data of the figure
    ctx = callback_context
    if len(ctx.triggered) and "interval.n_intervals" in [
        trg["prop_id"] for trg in ctx.triggered
    ]:
        if ts_ref is None:
            ts_ref = datetime.now().timestamp()

        # update the end timestamp within ts_list
        td_end = pd.Timedelta(seconds=datetime.now().timestamp() - ts_ref)
        ecg_slice = df_ecg.loc[:df_ecg.index[0] + td_end]["ECG"]

        fig.hf_data[0]["y"] = ecg_slice.values
        fig.hf_data[0]["x"] = ecg_slice.index

        # update the figure
        return fig.construct_update_data(relayoutdata), ts_ref
    return no_update
  1. Regarding bullet 5:

    Auto scaling the y-axis

    I am not entirely sure what you mean with this, could you elaborate on this?

  2. Regarding the last bullet

    The callback function

    I hope these dash app examples might help you. These should be elaborate enough for most use-cases. If you find that something Is missing, please don’t hesitate to create an issue on GitHub!

Kind regards,
Jonas

2 Likes

Hi Jonas, thanks for the thoughtful response. I’ll add some responses here-

I thought I read something on your website that said there’s a function that auto-scales the y axis. The default behavior to autosize the y axis is sorta wonky. I maybe completely misremembering, but I thought I might ask.

I hope these dash app examples might help you. These should be elaborate enough for most use-cases. If you find that something Is missing, please don’t hesitate to create an issue on GitHub!

The examples are great, and I’m still sorta unsure about where I should place the register function. Do I place it in the code where I generate the initial figure, the code where I update the figure with new data or the code where I set the layout for my dashboard? My concern is that the first two places doesn’t have the app object (though I can change the code to send it)

1 Like

Hi Jonas,
Amazing project, nice work, it truly changes the game for visualization in dash.

Any update on the Realtime streaming updates?
I ahave attempted to get it working via the example you posted here but no luck so far.

I am basically looking for something similar to what you have written here. Basically, when new data comes in at a set interval,I want the data in the figure to append with the latest data through a callback rather than updating the entire figure each time. This would be similar to partial property updates via patch() that dash now officially supports.

Any pointers would be greatly appreciated as to where to look so that I could figure this out. My typical dataset that I am updating has >1M datapoints.

Cheers!
Wyatt