predict-idlab / plotly-resampler

Visualize large time series data with plotly.py
https://predict-idlab.github.io/plotly-resampler/latest
MIT License
1.03k stars 68 forks source link

✨ trace adjustment example #159

Open jonasvdd opened 1 year ago

jonasvdd commented 1 year ago

Related: #18

juan11iguel commented 1 year ago

Hey! Thank you so much Jonas for putting the work. I have studied the code extensively 🧐 to try and apply it in my use case. I wanted to extend the example to be able to dynamically generate plots/subplots that update its data based on user interaction, that is, using pattern-matching callbacks.

I attach a minimal (non) working example built taking clues from 03_minimal_cache_dynamic and your PR. So far I have managed to have a plot generated dynamically that after some user input updates its data. The problem is that contrary to yours, the callback responsible for refreshing the graph in the front end is not triggering the trace_updater, though if I moved or zoomed the plot the data did get refreshed. I then modified the callback to include as an output the relayout, this makes the trace_updater callback get triggered (not like in your code where is not necessary) , and even though the inputs given to the callback seem correct, the browser throws a weird r[m] is undefined.

A couple of observations:

I am not sure if this is the right way of sharing the code but pasting it here felt like would be too much: app_minimal.zip

jonasvdd commented 1 year ago

Hi!

I see that you are a researcher (as well! 😄), on what time series data are you working, if I may ask?

I glanced at your minimal_app.py and got it working without the r[m] bug. I propose you take a look at the changes I made via a difftool. (ps. I formatted the code with black (line-width=88) b4 altering the code).

main diff: removing the relayoutData output from the process_and_update_figure method.

kind regards, Jonas

app_minimal.zip

juan11iguel commented 1 year ago

Yeah a PhD student trying to do too many things at the same time, I am quite sure my supervisors would not like to know I am spending my time doing this (so please don't tell them 😅)

I mainly work with signals from a thermal desalination process (temperatures, pressures, levels, flows, etc). I am trying to implement a variation of a steady state identification algorithm from the literature but I found the parameter calibration process to be quite un-intuitive. So I am trying to develop an online interactive tool to see in real time the effect of the parameter values and export the results. Later I want to implement the algorithm to work online in the real plant using directly the file generated from the tool.

I plan on publishing both things open-source, once I do I will let you know (and of course reference the project in any publication it might yield.

I am not sure if I am doing something wrong out of excitement but, is the modified code in the zip you attached? It states that it was modified yesterday and when I diff it, it shows no differences 😥

jonasvdd commented 1 year ago

Whoops, my bad, this is the zip i intended to send you! 🙈

minimal_app_review.zip

jonasvdd commented 1 year ago

I also remarked that in my updated version the app_minimal.py kinda works (after either resizing the dash app browser window, or performing a relayout on the graph (e.g., zooming/panning)).

However, when you update the parameters rather quickly, for some reason the traces become invisible, see 📷 ⬇️ (remark how you can see a hovertext, but no traces). I honestly have no idea what part of the code causes this (maybe this is even not related to plotly-resampler; and is a plotly.js bug? 🤷🏼).

image

Regarding your research, really cool stuff!

Fyi: My work, next to developing code, encompasses toying with large wearable datasets; e.g., data from a wrist worn wearable from over 90 days (monitored on patients who are diagnosed with chronic headache disorders). But due to ethical constraints I cannot make any of that data open access. 😒

Kind regards, Jonas

juan11iguel commented 1 year ago

How do you like ugly hacks? I got it working (except for the part of disappearing traces when updating too fast. I modified the relayout dict to make sure we trigger the trace updater in the following way:

        # 2. Alter the relayout dict to make sure that `construct_update_data` will
        #    trigger (and thus not return `dash.no_update`)
        for ax in fig.layout.to_plotly_json().keys():
            if not ax.startswith("xaxis"):
                continue

            # Current axis relayout
            if f"{ax}.range[0]" in relayout:
                print('current relayout')
                relayout.update({f"{ax}.range[0]":relayout[f"{ax}.range[0]"]-1, 
                                 f"{ax}.range[1]":relayout[f"{ax}.range[1]"]+1})

            # Past axis relayout
            elif f"{ax}.range" in relayout:
                print('sustained relayout')
                relayout.update({f"{ax}.range[0]":relayout[f"{ax}.range"][0]-1, 
                                 f"{ax}.range[1]": relayout[f"{ax}.range"][1]+1})
                relayout.pop(f"{ax}.range")

            # No axis relayouts
            else:
                print('no relayouts')
                axes = [trace['xaxis'] for trace in fig.data]
                if ax[-1].isnumeric():
                    trace_idx=axes.index(f'x{ax[-1]}')
                else:
                    trace_idx=axes.index('x')
                    relayout = {}

                relayout.update({f"{ax}.range[0]":fig.hf_data[ trace_idx ]["x"][0]-1,
                                 f"{ax}.range[1]":fig.hf_data[ trace_idx ]["x"][-1]+1})

Maybe the problem is the relayout is being performed before the server-sided cache figure had time to update its data? I added a half a second delay in the trace-updater callback and that seems to go away with most of the disappearing traces. When I have time I will create a post in the Plotly forum, usually they are very helpful and maybe can point us to a better way of handling this ..

Let me get back to you tomorrow to answer your questions (it's late here and still did not have dinner 😥 (or took a shower if we are being completely honest 🙉)).

app_minimal_review_of_the_review.zip

EDIT: Maybe the ±1 offsets are not really necessary, need to also check that