cytoscape / py4cytoscape

Python library for calling Cytoscape Automation via CyREST
https://Py4Cytoscape.readthedocs.io
Other
69 stars 15 forks source link

How to set the label rotation bypass and if that can be copied to another network? #111

Closed gmhhope closed 1 year ago

gmhhope commented 1 year ago

Hi Barry,

Sorry for bothering you these days. Could you provide me solutions to set the label rotation bypass? Additionally, if I have premade the rotation bypass, is there a way I can retrieve them using py4cytoscape and then copied those properties (the rotation levels) to another network?

For example, I created a new network and used layout_copycat and set the style with the older one but it cannot inherit the node position (possibly any bypass properties)? In other words, I definitely had hard time to understand how the bypass properties related to the style. Will they get documented in the particular style or they remained separate properties isolated from a particular style?

I looked forward to any of your suggestions! Thanks for being so helpful these couples of days/weeks.

Thanks, Minghao Gong

gmhhope commented 1 year ago

The bypass is standalone properties which are isolated from style.

p4c.get_node_property(visual_property='NODE_LABEL_ROTATION') can retrieve all label rotations. And I can apply back by p4c.set_node_property_bypass()

However, I did get a warning by doing the following:

p4c.set_node_property_bypass(list(PID2rot.keys()),
                             list(PID2rot.values()), 
                             visual_property='NODE_LABEL_ROTATION',
                             network = 'networkOfInterest')

Warning: setting unknown node bypass property "NODE_LABEL_ROTATION"
gmhhope commented 1 year ago

This is consistent with here:

p4c.clear_network_property_bypass(visual_property='NODE_LABEL_POSITION') p4c.clear_network_property_bypass(visual_property='NODE_LABEL_ROTATION')

CyError: In cyrest_delete(): Bypass Visual Property does not exist: NODE_LABEL_POSITION

But the guideline said: look at the visual_property (str) – Name of a visual property. See get_visual_property_names, which I check the property and it does have "NODE_LABEL_ROTATION", "NODE_LABEL_POSITION". This becomes very confusing.

The error seems to come from source

    # If the property is verifiable, verify the values and adjust as appropriate
    if visual_property in NODE_COLOR_PROPERTIES:
        new_values = verify_hex_colors(new_values)
    elif visual_property in NODE_DIMENSION_PROPERTIES.keys():
        new_values = verify_dimensions(NODE_DIMENSION_PROPERTIES[visual_property], new_values)
    elif visual_property in NODE_OPACITY_PROPERTIES:
        new_values = verify_opacities(new_values)
    elif visual_property in NODE_SHAPE_PROPERTIES:
        new_values = verify_node_shapes(new_values, styles.get_node_shapes(base_url=base_url))
    elif visual_property in NODE_VISIBLE_PROPERTIES:
        new_values = verify_bools(new_values)
    elif visual_property in NODE_LABEL_PROPERTIES | NODE_TOOLTIP_PROPERTIES | NODE_FONT_FACE_PROPERTIES:
        new_values = verify_strs(new_values)
    else:
        show_error(f'Warning: setting unknown node bypass property "{visual_property}"')

The property somehow cannot verified? It doesn't make sense for bypass as it can be set in the GUI

gmhhope commented 1 year ago
NODE_FONT_FACE_PROPERTIES = {'NODE_LABEL_FONT_FACE'}
NODE_LABEL_PROPERTIES = {'NODE_LABEL'}

Does it mean this feature (NODE_LABEL_POSITION and NODE_LABEL_ROTATION) not yet supported in py4cytoscape?

https://github.com/cytoscape/py4cytoscape/blob/645042fe4bd63e1ef5e9620fb4c9578b4bef63f7/py4cytoscape/style_visual_props.py#L29

bdemchak commented 1 year ago

Hi --

Getting the warning you're asking about doesn't mean that a property isn't supported ... it just means that there isn't a validation for the argument. So, the argument you supply will be used without checking it first.

Regarding the grouping of style values, bypasses and defaults, it's not so arbitrary as it might seem. Taking a look at the py4cytoscape documentation, see the grouping of all of the style-related functions:

image

This roughly tracks what the GUI Style Mapping panels are doing:

image

The Default setting is the style value if there is no mapping or default style value.

The Mapping setting determines the style value based on a node or edge property.

The Bypass is pretty important to you because it applies a property to a particular node or edge instead of all nodes or edges, regardless of the Default or Mapping settings. You've been using it to set the node location, which is appropriate because each node has its own location.

Good to review the Styles documentation for the GUI, especially the How Mappings Section.

For reusing style Default or Mapping settings, you can define a style and name it (e.g., Test1) using either the GUI ("Create New Style" under the settings menu in the Style panel or via py4cytoscape's Style Management functions ... and apply an existing style to a new network.

For reusing the bypass values, it's a little tricker. You're already using set_node_property_bypass() (or a variation) on a node-by-node basis. So, how to perform the equivalent of get_node_property_bypass(), which isn't provided in py4cytoscape?

To know this, you might understand that py4cytoscape is a front end to Cytoscape's CyREST interface. set_node_property_bypass() resolves to the CyREST PUT /v1/networks/{networkId}/views/{viewId}/{objectType}/{objectId} function. You can see this by visiting the Help | Automation | CyREST API menu, which puts up a Swagger page. This function is in the Network View section.

If you get that far, you might notice a corresponding GET function. So, you can build your own get_node_property_bypass() by using the set_node_property_bypass() function to inform how you might call the corresponding GET function. You can learn more about this in the Concepts documentation section.

Feel free to ask questions. Frankly, I think get_node_property_bypass() might be a good addition to the py4cytoscape/RCy3 API, but that won't happen quickly.

@AlexanderPico @yihangx

gmhhope commented 1 year ago

I have been working around this issue by just not going for circular visualization. Now I just would like to change all the default node label postion. But figure out there isn't such function? The closest one is set_node_custom_position, which seems not changing the labeling position but probably the customized graph position relative to the node.

Could you help with that? I think I am closed to finish using this tool for my figure : ) Thanks always for all the help @bdemchak

Best, MG

bdemchak commented 1 year ago

Hi --

Please note that py4cytoscape 1.8 was released today, and it addresses some of the points you've raised. For new functions, I'm talking with the RCy3 people ... they're not in 1.8.

For information on 1.8, please see https://py4cytoscape.readthedocs.io/en/latest/release_log.html#py4cytoscape-1-8-0

bdemchak commented 1 year ago

Regarding the default node label position, can you send me a screenshot showing a poorly positioned label and indicating where you'd like the label to be instead?? Thanks!

gmhhope commented 1 year ago

Sorry for the late comment.

Screenshot 2023-07-23 at 2 37 37 PM

Just position like this. I meant I can easily do it in GUI. But I just cannot figure out how to do it in the python pkg.

Thanks, Minghao

bdemchak commented 1 year ago

No problem... happy for the reply ... how would you do this with the GUI?

On Sun, Jul 23, 2023, 11:38 AM Minghao Gong @.***> wrote:

Sorry for the late comment. [image: Screenshot 2023-07-23 at 2 37 37 PM] https://urldefense.com/v3/__https://user-images.githubusercontent.com/12982817/255425461-ec0a4b05-c0f8-4093-a0b0-9f6e1f2e19b8.png__;!!Mih3wA!B6sA6xDxnGSigQtq3eWPQhWmH7kpw-vbKBtNZ-9Ssoa8jzpHxKvB6qqIyhBGKQV1-WRHneJ6jEtGfrPncrLD-EviMQ$

Just position like this. I meant I can easily do it in GUI. But I just cannot figure out how to do it in the python pkg.

Thanks, Minghao

— Reply to this email directly, view it on GitHub https://urldefense.com/v3/__https://github.com/cytoscape/py4cytoscape/issues/111*issuecomment-1646927038__;Iw!!Mih3wA!B6sA6xDxnGSigQtq3eWPQhWmH7kpw-vbKBtNZ-9Ssoa8jzpHxKvB6qqIyhBGKQV1-WRHneJ6jEtGfrPncrIKQcuetw$, or unsubscribe https://urldefense.com/v3/__https://github.com/notifications/unsubscribe-auth/AA4GLXXKNFQONBBNGYY3E3DXRVVTFANCNFSM6AAAAAA2NBZEFM__;!!Mih3wA!B6sA6xDxnGSigQtq3eWPQhWmH7kpw-vbKBtNZ-9Ssoa8jzpHxKvB6qqIyhBGKQV1-WRHneJ6jEtGfrPncrLk4iudrg$ . You are receiving this because you were mentioned.Message ID: @.***>

gmhhope commented 1 year ago

Here it is: see the label position screenshot: Screenshot 2023-07-23 at 2 54 40 PM

bdemchak commented 1 year ago

Hi --

This was a wonderful question, and it caused me to do a little work because property values aren't documented anywhere.

The short answer:

p4c.set_visual_property_default({'visualProperty': 'NODE_LABEL_POSITION', 'value':'N,S,c,10.00,20.00'}, 'default')

So, the NODE_LABEL_POSITION property is a list of values that correspond to the dialog box fields. The field values appear to be Node Anchor Points, Label Anchor Points, Text Justification, X Offset, Y Offset.

So, 'N,S,c,10.00,20.00' would be North, South, Center Justified, X Offset 10, Y Offset 20.

How did I figure this out?? I used the Cytoscape GUI to dump the visual style to styles.xml ... the menu item is File | Export | Styles to File..., and I chose the name of the style being used for my network.

From there, I looked into styles.xml and found the NODE_LABEL_POSITION property:

<visualProperty default="N,S,c,10.00,20.00" name="NODE_LABEL_POSITION"/>

From there, the format of the property can be deduced.

Does this make sense to you, or should I go into more depth?

Note that you can set the default value (and other style information) by using the GUI and the dialog you showed me. Once you do that, you can save the whole style to styles.xml. You can use py4cytoscape to load the style:

p4c.import_visual_styles()

Note that set_visual_property_default() generates the same warning message as I fixed for the bypass properties. I didn't realize this check was also made for default properties. I have removed the warning and checked the fix into the 1.9.0 branch in case you'd like to use it.

@AlexanderPico @yihangx

gmhhope commented 1 year ago

Hey Barry,

I don't mean to reply late. I was in a conference for a talk and then so many works afterwards.

Thanks very much for this wonderful answer. I am coming back to this project and I just have another question that I will post in a separate issue.

Thanks again for the detailed answer!

Best, Minghao Gong

gmhhope commented 1 year ago

Hi Barry,

I have to reopen this as I still want to figure out how to clear the bypass of node label...

Trying to reset the wrongly assigned rotation/label. See the following screenshot:

Screenshot 2023-08-30 at 6 17 12 PM

Here is my command:

node_names = list(p4c.get_table_columns(columns='name')['name'])
p4c.clear_node_property_bypass(node_names = node_names,visual_property='NODE_LABEL_POSITION')

But this gives me an error:

In cyrest_delete(): Bypass Visual Property does not exist: NODE_LABEL_POSITION
---------------------------------------------------------------------------
HTTPError                                 Traceback (most recent call last)
File ~/mambaforge/envs/yoda/lib/python3.11/site-packages/py4cytoscape/commands.py:109, in cyrest_delete(operation, parameters, base_url, require_json)
    108 r = _do_request('DELETE', url, params=parameters, base_url=base_url)
--> 109 r.raise_for_status()
    110 try:

File ~/mambaforge/envs/yoda/lib/python3.11/site-packages/requests/models.py:1021, in Response.raise_for_status(self)
   1020 if http_error_msg:
-> 1021     raise HTTPError(http_error_msg, response=self)

HTTPError: 404 Client Error: Not Found for url: http://127.0.0.1:1234/v1/networks/2221/views/2673/nodes/2306/NODE_LABEL_POSITION/bypass

During handling of the above exception, another exception occurred:

CyError                                   Traceback (most recent call last)
Cell In[299], line 2
      1 node_names = list(p4c.get_table_columns(columns='name')['name'])
----> 2 p4c.clear_node_property_bypass(node_names = node_names,visual_property='NODE_LABEL_POSITION')

File ~/mambaforge/envs/yoda/lib/python3.11/site-packages/py4cytoscape/py4cytoscape_logger.py:133, in cy_log.<locals>.wrapper_log(*args, **kwargs)
    131     return log_return(func, value)
    132 except Exception as e:
--> 133     log_exception(func, e)
    134 finally:
    135     log_finally()

File ~/mambaforge/envs/yoda/lib/python3.11/site-packages/py4cytoscape/py4cytoscape_logger.py:130, in cy_log.<locals>.wrapper_log(*args, **kwargs)
    128 log_incoming(func, *args, **kwargs)
    129 try:
--> 130     value = func(*args, **kwargs) # Call function being logged
    131     return log_return(func, value)
    132 except Exception as e:

File ~/mambaforge/envs/yoda/lib/python3.11/site-packages/py4cytoscape/style_bypasses.py:219, in clear_node_property_bypass(node_names, visual_property, network, base_url)
    217 else:
    218     for suid in node_suids:
--> 219         res = commands.cyrest_delete(f'networks/{net_suid}/views/{view_suid}/nodes/{suid}/{visual_property}/bypass',
    220                                      base_url=base_url)
    222 return res

File ~/mambaforge/envs/yoda/lib/python3.11/site-packages/py4cytoscape/py4cytoscape_logger.py:133, in cy_log.<locals>.wrapper_log(*args, **kwargs)
    131     return log_return(func, value)
    132 except Exception as e:
--> 133     log_exception(func, e)
    134 finally:
    135     log_finally()

File ~/mambaforge/envs/yoda/lib/python3.11/site-packages/py4cytoscape/py4cytoscape_logger.py:130, in cy_log.<locals>.wrapper_log(*args, **kwargs)
    128 log_incoming(func, *args, **kwargs)
    129 try:
--> 130     value = func(*args, **kwargs) # Call function being logged
    131     return log_return(func, value)
    132 except Exception as e:

File ~/mambaforge/envs/yoda/lib/python3.11/site-packages/py4cytoscape/commands.py:118, in cyrest_delete(operation, parameters, base_url, require_json)
    116             return r.text
    117 except requests.exceptions.RequestException as e:
--> 118     _handle_error(e)

File ~/mambaforge/envs/yoda/lib/python3.11/site-packages/py4cytoscape/commands.py:683, in _handle_error(e, force_cy_error)
    681     else:
    682         show_error(f'In {caller}: {e}\n{content}')
--> 683 raise e

CyError: In cyrest_delete(): Bypass Visual Property does not exist: NODE_LABEL_POSITION

I just have some crunching time and cannot plunge myself to look for answers from what you told me about all the other alternatives.

Hope you can help!

Best, Minghao