Giter Site home page Giter Site logo

Comments (22)

xhluca avatar xhluca commented on May 22, 2024 3

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!

from dash-cytoscape.

Akronix avatar Akronix commented on May 22, 2024 2

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?
I believed this could be an interesting add-on for every user though, and it could come along with the dash-cytoscape component (with the option to opt-out of course).

Well, I think we will develop the corresponding callbacks to suit our needs, at least the un-zoom feature.
Feel free to close this if you find so appropriate.

from dash-cytoscape.

FRYoussef avatar FRYoussef commented on May 22, 2024 1

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.
In addition, I've tried the multioutput but it didn't work.
Here the code I've used:

@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]

from dash-cytoscape.

FRYoussef avatar FRYoussef commented on May 22, 2024 1

No, I wasn't able.
It seems like cytoscape component is only allowed to refresh with a new state, so if you try sending its own elements, layout, etc... in a dash callback it won't update.

from dash-cytoscape.

xhluca avatar xhluca commented on May 22, 2024 1

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

from dash-cytoscape.

FRYoussef avatar FRYoussef commented on May 22, 2024 1

That's works good for me !!,
thanks, good job.

from dash-cytoscape.

xhluca avatar xhluca commented on May 22, 2024 1

Thank you.

Upon reflections, I believe that it is better not to perform an automatic position reset for elements when you update Cytoscape with a callback (for example when you output to "layout" or to "elements"). This is because it might bring unintentional position changes when you are updating other props, e.g. "stylesheet", since there is no way on the React side to detect why it was updated (i.e. whether "elements" prop was fired, or whether the "stylesheet" prop was fired).

As for the zoom prop, it should definitely change when you update it with a callback. We will try to address this in 0.1.0, or else in 0.1.1.

from dash-cytoscape.

FRYoussef avatar FRYoussef commented on May 22, 2024 1

Ooh I'm sorry, sure, that works for me.

from dash-cytoscape.

xhluca avatar xhluca commented on May 22, 2024

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 Cytoscape parameters with a callback. Double-clicking on the network would break the consistency with Cytoscape.js (i.e. it will have a different behavior than what the developer/user expects).

from dash-cytoscape.

xhluca avatar xhluca commented on May 22, 2024

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.

from dash-cytoscape.

Akronix avatar Akronix commented on May 22, 2024

hmm what about an anchor element (<a>) reading "Reset" in an overlying <div>?

from dash-cytoscape.

xhluca avatar xhluca commented on May 22, 2024

Have you tried adding that using dash html components? https://dash.plot.ly/dash-html-components

from dash-cytoscape.

xhluca avatar xhluca commented on May 22, 2024

You can probably using the "n_clicks" props of html.A as an input to a callback that will reset the zoom parameter of Cytoscape

from dash-cytoscape.

FRYoussef avatar FRYoussef commented on May 22, 2024

Hi,
I think it's a great idea, because sometimes I lose the network involuntarily when zooming or dragging.
I've tried to place a button whose callback gets the cytoscape layout and returns it in order to reset the zoom and the network position, but it hasn't worked

from dash-cytoscape.

Akronix avatar Akronix commented on May 22, 2024

(Just as a background note, @FRYoussef and I are working in an webapp which does a heavy usage of dash-cytoscape)

from dash-cytoscape.

xhluca avatar xhluca commented on May 22, 2024

@FRYoussef could you share a gist or paste the callback here?

from dash-cytoscape.

FRYoussef avatar FRYoussef commented on May 22, 2024

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)

from dash-cytoscape.

xhluca avatar xhluca commented on May 22, 2024

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")

from dash-cytoscape.

xhluca avatar xhluca commented on May 22, 2024

@FRYoussef Were you able to fix this issue? Could you share a minimum working Dash app with the issue?

from dash-cytoscape.

xhluca avatar xhluca commented on May 22, 2024

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 Cytoscape elements):

"""
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.

from dash-cytoscape.

xhluca avatar xhluca commented on May 22, 2024

Seems like this is not an issue. Upon further tests, I realized that userZoomingEnabled was set to False by default (shouldn't be). This will be changed to True by default in future release.

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)

from dash-cytoscape.

xhluca avatar xhluca commented on May 22, 2024

@FRYoussef Can I close this issue?

from dash-cytoscape.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.