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
[Feature request] Reset cytoscape component to its original display #33
Comments
Could you elaborate on what kind of interaction would be expected? At the moment it would be pretty straightforward to add a button and manually reset the |
If there's a non-intrusive way to do it, this would be a very interesting idea! I just have a bit of trouble thinking of how to approach that. |
hmm what about an anchor element ( |
Have you tried adding that using dash html components? https://dash.plot.ly/dash-html-components |
You can probably using the "n_clicks" props of |
I think we mean different things by reset. By what I meant by reset is not just to reset the zooming, but also to re-establish every node to its original position, center the screen to the cytoscape component in case the user has moved around or to redraw nodes if they were removed somehow. Or maybe this is a complete redraw of the component? Well, I think we will develop the corresponding callbacks to suit our needs, at least the un-zoom feature. |
I think I understand what you are referring to! I think that this could be accomplished with a rerendering of the Cytoscape's current properties (i.e. without taking into account the change in state). I can create a usage example and save it in the demos directory so people can use it. I will bring this suggestion up with the product team and see if it can be added easily. If others believe this could be an interesting addition, feel free to add your thoughts in this issue. I'll leave it open for now! |
Hi, |
(Just as a background note, @FRYoussef and I are working in an webapp which does a heavy usage of dash-cytoscape) |
@FRYoussef could you share a gist or paste the callback here? |
Sure!! import dash
import dash_cytoscape as cyto
import dash_html_components as html
from dash.dependencies import Input, Output, State
app = dash.Dash(__name__)
app.layout = html.Div([
html.Button('Reset', id='bt-reset'),
cyto.Cytoscape(
id='cytoscape',
elements=[
{'data': {'id': 'one', 'label': 'Node 1'}, 'position': {'x': 50, 'y': 50}},
{'data': {'id': 'two', 'label': 'Node 2'}, 'position': {'x': 200, 'y': 200}},
{'data': {'source': 'one', 'target': 'two','label': 'Node 1 to 2'}}
],
layout={'name': 'cose'}
)
])
@app.callback(
Output('cytoscape', 'layout'),
[Input('bt-reset', 'n_clicks')],
[State('cytoscape', 'layout')]
)
def reset_layout(n_clicks, layout):
print('click')
return layout
if __name__ == '__main__':
app.run_server(debug=True) |
In your callback, try to return elements, or even zoom instead of layout. If that doesn't work, try to return all 3 of them at the same time using the new multioutput feature (i.e. Output to "layout", "elements", and "zoom") |
I had already tested it with zoom and elements, but it doesn't work. I think this isn't going to work because elements and layout refresh the layout just with a new state, and zoom in the documentation is referenced as the initial value of the graph so you couldn't use it in a callback. @app.callback(
[Output('cytoscape', 'zoom'),
Output('cytoscape', 'layout'),
Output('cytoscape', 'elements')],
[Input('bt-reset', 'n_clicks')],
[State('cytoscape', 'layout'),
State('cytoscape', 'elements')]
)
def reset_layout(n_clicks, layout, elements):
print('click')
return [1, layout, elements] |
@FRYoussef Were you able to fix this issue? Could you share a minimum working Dash app with the issue? |
No, I wasn't able. |
Indeed, that's something that should be fixed. In theory, your method should work, as discussed in this issue. We'll investigate this further, and try to get it fixed in 0.1.0 or 0.1.1 |
A current workaround is to initialize elements outside of the graph, and use it as an input to the callback (rather than using the state of """
An example to show how to reset the position, zoom level, and layout of a Cytoscape graph, using a
button attached to a callback.
"""
import dash
import dash_cytoscape as cyto
import dash_html_components as html
from dash.dependencies import Input, Output
elements = [
{'data': {'id': 'one', 'label': 'Node 1'}, 'position': {'x': 50, 'y': 50}},
{'data': {'id': 'two', 'label': 'Node 2'}, 'position': {'x': 200, 'y': 200}},
{'data': {'source': 'one', 'target': 'two', 'label': 'Node 1 to 2'}}
]
layout = {'name': 'grid'}
app = dash.Dash(__name__)
app.layout = html.Div([
html.Button('Reset', id='bt-reset'),
cyto.Cytoscape(
id='cytoscape',
elements=elements,
layout=layout
)
])
@app.callback(
[Output('cytoscape', 'zoom'),
Output('cytoscape', 'elements')],
[Input('bt-reset', 'n_clicks')]
)
def reset_layout(n_clicks):
print(n_clicks, 'click')
return [1, elements]
if __name__ == '__main__':
app.run_server(debug=True) This effectively works since the ID of the edges are not defined, so are generated every time you are updating the callback. However, as you pointed out (and as I dicussed with Max in the issue linked above), Cytoscape.js only refreshes when it finds a difference in the elements that are sent to it. |
That's works good for me !!, |
Thank you. Upon reflections, I believe that it is better not to perform an automatic position reset for elements when you update As for the |
Seems like this is not an issue. Upon further tests, I realized that Here's an example of modifying the zoom using a slider: import dash
import dash_cytoscape as cyto
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output, State
from copy import deepcopy
default_elements = [
{'data': {'id': 'one', 'label': 'Node 1'}, 'position': {'x': 50, 'y': 50}},
{'data': {'id': 'two', 'label': 'Node 2'}, 'position': {'x': 200, 'y': 200}},
{'data': {'source': 'one', 'target': 'two', 'label': 'Node 1 to 2'}}
]
layout = {'name': 'grid'}
app = dash.Dash(__name__)
app.layout = html.Div([
html.Button('Reset', id='bt-reset'),
dcc.Slider(id='slider', min=0.5, max=2, step=0.1),
cyto.Cytoscape(
id='cytoscape',
elements=default_elements,
zoomingEnabled=True,
zoom=2,
layout=layout
)
])
@app.callback(Output('cytoscape', 'zoom'),
[Input('slider', 'value')])
def update_zoom(value):
print(value)
return value
if __name__ == '__main__':
app.run_server(debug=True) |
@FRYoussef Can I close this issue? |
Ooh I'm sorry, sure, that works for me. |
Hi.
So imagine that the user does a combination of zooming, moving around and nodes dragging. And then they want to reestablish the network to its original display.
We are missing for an incorporated control that would redraw the cytoscape component to the original place, size and shape that it had before any user interaction was made.
Similarly to this, plotly graphs has this feature of double-clicking on them to reset them to their original configuration.
The text was updated successfully, but these errors were encountered: