-
-
Notifications
You must be signed in to change notification settings - Fork 72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Trying to make the resampler work with dynamic graphs #27
Comments
Great to see you toying around with our package! 😃 Your code does not work because of a (large) limitation of dash; it is not possible to dynamically add callbacks in a dash app. In your example, you try to do this in the To circumvent this, you should register the callbacks statically (and not dynamically in another callback function). A quick (but kinda dirty) fix for this is to create several dummy figures (i.e., See this working version of your minimalistic example """
Minimal dynamic dash app example.
"""
import numpy as np
import plotly.graph_objects as go
import trace_updater
from dash import Dash, Input, Output, State, dcc, html
from plotly_resampler import FigureResampler
from typing import List
x = np.arange(1_000_000)
noisy_sin = (3 + np.sin(x / 200) + np.random.randn(len(x)) / 10) * x / 1_000
app = Dash(
__name__,
suppress_callback_exceptions=True, # surpress unused ID warnings
)
# Create empty figures
max_nb_figures = 10 # NOTE, 10 is arbitrarily chosen
figs = [
FigureResampler()
for _ in range(max_nb_figures)
]
# Add the resampling callback to these empty figures
for n_clicks, f in enumerate(figs):
f.register_update_graph_callback(
app=app,
graph_id=f"graph-id-{n_clicks}",
trace_updater_id=f"trace-updater-id-{n_clicks}",
)
app.layout = html.Div(
[
html.Div(
children=[
html.Button("Add Chart", id="add-chart", n_clicks=0),
]
),
html.Div(id="container", children=[]),
]
)
@app.callback(
Output("container", "children"),
Input("add-chart", "n_clicks"),
State("container", "children"),
)
def display_graphs(n_clicks: int, div_children: List[html.Div]) -> List[html.Div]:
"""
This function is called when the button is clicked. It adds a new graph to the div.
"""
print(n_clicks)
global figs
# Select the n_clicks figure (with its already registered callbacks)
figure = figs[n_clicks]
# Add the data to the figure
figure.add_trace(go.Scatter(x=x, y=noisy_sin))
# NOTE, you could also use figure.replace(go.Figure(go.Scatter(x=x, y=noisy_sin)))
new_child = html.Div(
children=[
dcc.Graph(id=f"graph-id-{n_clicks}", figure=figure),
trace_updater.TraceUpdater(
id=f"trace-updater-id-{n_clicks}", gdID=f"graph-id-{n_clicks}"
),
],
)
div_children.append(new_child)
return div_children
if __name__ == "__main__":
app.run_server(debug=True) I hope this answer helps you! (@jonasvdd can you think of another / cleaner solution?) |
Okay, thanks for a quick response. But then it should be possible to use pattern matching callbacks? I will look into it and see if I can make that work. |
@prokie, I suppose it should! I will also look into this a little! Keep you posted! :) |
It probably needs some work done on the TraceUpdater. I assume that But the Error: |
Working on it! Already have a p.o.c. which does what I think you intend, I think we will have a new release at the end of this week with a Dash example for this use-case. I indeed had to make some changes to the |
WIP: see #35 |
Is now supported in v0.3.0 🎉 |
One issue that I have found (using the example) is that if I actually try to deploy the server it won't work as intended since we store the FigureResampler objects globally in the dictionary |
Maybe you can use |
Hey @prokie, {
"<user_uuid_str>": {
"<graph_uuid_str>": FigureResampler(...),
...
},
...
} I will give this later some more thought! |
Yes that should work aswell. |
@jonasvdd Tried using |
@prokie, |
Have been thinking about this for some time now. And I have not been able to store the FigureResampler object without it being serialized in the backend. I guess the way I would want it to work was that you could send the figure to the callback and then create a FigureResampler object from it each time you have to resample the trace.
But this does not work and I guess I will have to dig in the FYI: With a flask backend, it is possible to use your selected approach by retrieving the username using the request function. @jonasvdd
|
Is it still necessary to save the Figure objects globally with the latest plotly release? |
@prokie! This is still necessary! As for now this is a low-prio issue for us as it somehow works, and we are mostly using it for data exploration and not production ready apps. Always feel free to further dive into this or update this with additional insights! |
Hi @prokie, We are currently looking into serializing plotly-resampler objects (in #87 ); which would enable the use of Cheers, |
Hi Jonas! That would be awesome. I can make one! |
Hi again, I guess something like this should work. @jonasvdd
|
Hi @prokie, This example seems to start, but I get the following error. Traceback (most recent call last):
File "/home/jonas/.cache/pypoetry/virtualenvs/plotly-resampler-aW2rMSDw-py3.8/lib/python3.8/site-packages/dash_extensions/enrich.py", line 1112, in decorated_function
args[i] = serverside_output.backend.get(args[i], ignore_expired=True)
File "/home/jonas/.cache/pypoetry/virtualenvs/plotly-resampler-aW2rMSDw-py3.8/lib/python3.8/site-packages/dash_extensions/enrich.py", line 1216, in get
filename = self._get_filename(key)
File "/home/jonas/.cache/pypoetry/virtualenvs/plotly-resampler-aW2rMSDw-py3.8/lib/python3.8/site-packages/cachelib/file.py", line 202, in _get_filename
return os.path.join(self._path, bkey_hash)
UnboundLocalError: local variable 'bkey_hash' referenced before assignment It seems like it is the error from this issue: emilhe/dash-extensions#185, but as I'm not that acquainted with that codebase, it is rather hard to find out what I'm doing wrong. fyi: I'm working with the plotly-resampler code on the master branch, which normally has serialization support (not yet released in a PyPi version) Are you able to get this running? |
I can test it out tomorrow. I did not know that serialization support was done! Yes that error is related to flask_caching, I think the issue was fixed in 0.1.4 for dash_extensions, before you had to run with cachelib==0.6.0. But I will test tomorrow and get back to you. |
Hey! @prokie Just wanted to mention that I got it working! 🔥 Will share later on today my working example (It did require some small adjusting of the dash-extensions because I could not get the default lib working on my machine). |
Great looking forward to see it. I also made an example that works. I put it in your issue over at dash-extensions. |
So I made this minimal example but I can not figure out why I can't get the callbacks to work.
`
`
The text was updated successfully, but these errors were encountered: