✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
⚡️ Concerned about the grid? Kyle Baranko teaches how to predicting peak loads using XGBoost. Register for the August webinar!

📣 Dash Cytoscape v0.2.0 Release - Image generation (jpg/png/svg) and responsive graphs

Hello all! Today, I would like to announce the release of Dash Cytoscape v0.2.0.

This release brings important new features to Dash Cytoscape, as well as some important bug fixes! This is the result of exactly 100 commits and issues that the Dash Cytoscape community has contributed since 2019. It features two significant PRs lead by community contributors, namely PR #88 (which adds the option to save your graph as a png/jpg/svg), as well as PR #92 (which lets you enable responsive Cytoscape graphs). Additionally, the Cytoscape team has focused on fixing issues that concerns package distributions, default props, and security-related issues. You can find examples of the new features in the Dash Cytoscape User Guide , from our Dash Docs .

I’d like to thank Christian for starting the initial work for image exporting (in 2019), Ivo for taking over the PR and adding support for SVG, and Manfred for contributing the responsive property.

Added

  • Contributed initial build of R package.
  • Added access to cytoscape.js PNG and JPG image generation API through generateImage and
    imageData properties (PR #88).
  • Added ability to download image files generated with generateImage client-side without sending
    data to the server (PR #88).
  • Used the newly added generateImage and imageData properties to enable svg generation using cytoscape-svg.
  • Added responsive cytoscape.js graph feature toggled using the responsive property (PR #93).
  • Two new documentation pages covering these features:

Changed

  • Changed the official package manager from yarn to npm.
  • utils.Tree: v0.1.1 broke compatibility with Python 2. Therefore, modified code to be compatible
    with Python 2. Added props and edge_props properties to accept arguments passed directly to
    the node’s and edge’s dictionaries, respectively (e.g., ‘classes’, ‘positions’, etc.).
  • Removed Tree's method add_child, because it is redundant with add_children called with an
    argument of length 1.
  • setup.py: Remove dash-html-components and dash_renderer from install_requires.
  • usage-events.py: Fix the size of the cytoscape graph to 500px by 500px.
  • Upgrade react-cytoscape.js to latest.

Fixed

  • setup.py: Use packages=find_packages(include=[package_name, package_name + ".*"]) so that all
    subpackages like utils will be included when you pip install dash-cytoscape.
  • Issue where dash-cytoscape cannot read property of ‘length’ of undefined when elements is not specified.
  • tests.test_interactions.
2 Likes

Thank you for the new release.

I am looking for a way to implement a zoom to a specific level on a clicked node in the graph. Please let me know if it is possible to do through callbacks in the new version?

Hi @Zhabiz! Since 0.0.x you could control the zoom level through callbacks. In this specific case, perhaps you could move your node of interest to the center of the screen, or set the initial pan to be exactly onto the node of interest, and then zoom in?

Thank you @xhlu for your response.

I tried to apply your suggestion to the provided example with the preset layout.

import dash
import dash_cytoscape as cyto
import dash_html_components as html
from dash.dependencies import Input, Output

app = dash.Dash(__name__,prevent_initial_callbacks=True)
app.layout = html.Div([
 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'}}
 ],
 # pan= {'x': 200, 'y': 200},
 layout={'name': 'preset'}
 )
])


@app.callback(
 [Output("cytoscape", "pan"),
 Output("cytoscape", "zoom"),
 ],
 [
 Input("cytoscape", "tapNodeData"),
 ]
)
def update(tapNodeData):
 print(tapNodeData)
 return {'x': 200, 'y': 200},2

if __name__ == '__main__':
 app.run_server(debug=True)

But it resulted in the following output:

It didn’t place the clicked node to the center of screen.

In the cytoscape.js, the zooming can be possible by passing level, and position and renderedPosition options as it is mentioned here:(zoom). I don’t exactly know by changing the pan here whether we change position or renderedPosition.

Could you explain a little bit and let me know about a way to fix this issue?

Thanks,

This is a bit of a hack:

  • I know that position and rendered positions can be specified and updated inside a callback. If you pass the current position as a state to your callback, and the position as an output to your callback, then you can essentially “shift” all the positions in a way that the clicked node is in the center of your screen.

I’m actually not sure whether the default zoom prop in cytoscape.js accepts a JS object in the form of

{
  level: 2.0, // the zoom level
  renderedPosition: { x: 100, y: 100 }
}

If it’s indeed possible in Cytoscape.js, then I think it should be doable in Dash Cytoscape (although I haven’t actually tested this specific scenario). Otherwise, we would need to essentially change the Dash Cytoscape react code to update zoom as a prop, and call cy.zoom(...) whenever it is called inside a callback.

@xhlu it possible to change the stylesheet for the downloaded image (while preserving the stylesheet on the app)?

I have managed to write a (not very efficient) workaround involving the download button calling both the callback updating the stylesheet and the download callback, and seetting a sleep in the latter to wait for the former to finish, but this laeves the the download-stylesheeet in app. I thought I could then have the download-callback have a second output calling the styleesheeet-callback again so as to restore that to the app-stylesheet, but this gets the app stuck: I guess it doesnt like this kind of circular calls…

Is there a better approach? Any workaround would bee appreciate as well!

What about two buttons: first one to change the stylesheet and second one to download? the download button will be disabled until you click on the stylesheet once. You will essentially need two callback: first one outputs to download button’s “disabled” prop and also updates the stylesheet, second one performs download.

Hi All,
For those that are new to Dash Cytoscape, I created an intro video tutorial that will help you get started.

1 Like

Thanks, I managed to solve it with a time.sleep workaround.

NEW QUESTION: I have added a slider to show the evolution of my cyto network over time. Nodes and edges are weighted. The size of nodes and edges is sort of automatically rescaled (very small actually) as I move the slider on. I would like to NOT have any rescale as in this way I can show how much the node size increases with time. Responsive option is turned to False already, but this does not seem to help.

Any help super appreciated!!!

I’m not really sure without code to reproduce, but I would recommend setting the edge thickness as well as the node position explicitly so that they are not handled by a layout algorithm. Both are shown in the cytoscape editor which is described in the repo readme.