cytoscape / py4cytoscape

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

Embed image in nodes automation by py4cytoscape #120

Closed gmhhope closed 5 months ago

gmhhope commented 1 year ago

Hey @bdemchak

Any easy and quick way to embed image automatically by providing path in local directory?

Thanks, Minghao Gong

bdemchak commented 1 year ago

Have you considered add_annotation_image()?

This corresponds to the Annotation tab on the far left of the Cytoscape window, and is activated when you hit the image button.

I'm not sure exactly what you're trying to accomplish, but that's what jumps to mind.

Or are you trying to use an image to represent a node? If so, you might consider a visual style? Doing that in py4cytoscape isn't supported by explicit calls but should be possible via generic style functions.

Does this help?

gmhhope commented 1 year ago

Thanks very much for helping me!

Or are you trying to use an image to represent a node? If so, you might consider a visual style? Doing that in py4cytoscape isn't supported by explicit calls but should be possible via generic style functions.

I am currently trying to do it manually using the following way: Style>Image/Chart1>Open Image manager>add the image>then imbed per node using bypass. But it is not fun at all considering this won't be my last version.

I looked through the customize options. But there seems no such an option? Screenshot 2023-09-21 at 2 15 44 PM

Thanks, Minghao Gong

bdemchak commented 1 year ago

I see ... thanks.

The visual property that you'd need to set would be NODE_CUSTOMGRAPHICS_1, and the value would be something like:

file:/C:/Users/CyDeveloper/Desktop/New%20Bitmap%20Image.jpg,bitmap image

Not so obvious. So, to nail this down, I'll pose the question to the developers to see exactly what value should be set.

(optional question) I think I can set chart type as a bypass in the Cytoscape GUI. I first select the node, then I use the Style tab to click Bypass for the Image/Chart 1 property, and then choose the Charts tab and then configure the chart. It seems like the followon question would be how to set the bypass via py4cytoscape by using a call something like set_node_custom_bar_chart() ... is that what you're thinking?

gmhhope commented 1 year ago

/### NODE_CUSTOMGRAPHICS_1

I see ... thanks.

The visual property that you'd need to set would be NODE_CUSTOMGRAPHICS_1, and the value would be something like:

file:/C:/Users/CyDeveloper/Desktop/New%20Bitmap%20Image.jpg,bitmap image

Not so obvious. So, to nail this down, I'll pose the question to the developers to see exactly what value should be set.

Thanks, that is exactly I am trying to find. I am also reading the automation>command API:

Based on the node list properties: http://localhost:1234/v1/commands/node/list properties

{
  "data": [
    "Image/Chart 9",
    "Label Font Size",
    "Custom Paint 8",
    "Image/Chart Size 3",
    "Size",
    "Visible",
    "(Compound Node)",
    "Custom Paint 4",
    "(Compound Node)",
    "Image/Chart Size 8",
    "Transparency",
    "Image/Chart 1",
    "Image/Chart Position 5",
    "Image/Chart 4",
    "Border Line Type",
    "Z Location",
    "Visual Property",
    "Image/Chart Position 1",
    "Image/Chart Size 7",
    "Label Position",
    "Custom Paint 9",
    "Custom Paint 7",
    "Image/Chart 7",
    "Custom Paint 1",
    "Label Width",
    "Image/Chart Size 1",
    "Image/Chart Size 6",
    "Width",
    "Image/Chart 5",
    "Network Image Visible",
    "Label Rotation",
    "Label Color",
    "Border Transparency",
    "Custom Paint 5",
    "Paint",
    "Image/Chart Size 9",
    "Label",
    "Image/Chart Size 5",
    "Image/Chart 6",
    "Shape",
    "Image/Chart Position 2",
    "X Location",
    "Label Transparency",
    "Image/Chart Position 9",
    "Image/Chart 8",
    "Image/Chart Size 2",
    "Tooltip",
    "Border Paint",
    "Selected",
    "Image/Chart 3",
    "Image/Chart 2",
    "Border Width",
    "Image/Chart Position 8",
    "Custom Paint 3",
    "Image/Chart Position 3",
    "Selected Paint",
    "Height",
    "Label Font Face",
    "Image/Chart Size 4",
    "Image/Chart Position 7",
    "Custom Paint 2",
    "Image/Chart Position 4",
    "Custom Paint 6",
    "Image/Chart Position 6",
    "Y Location",
    "Depth",
    "Fill Color"
  ],
  "errors": []
}

I actually don't see NODE_CUSTOMGRAPHICS_1, am I looking into a wrong place?

Okay I found it by get_visual_property_names

p4c.get_visual_property_names()

[...
 'NODE_CUSTOMGRAPHICS_1',
 'NODE_CUSTOMGRAPHICS_2',
 'NODE_CUSTOMGRAPHICS_3',
 'NODE_CUSTOMGRAPHICS_4',
 'NODE_CUSTOMGRAPHICS_5',
 'NODE_CUSTOMGRAPHICS_6',
 'NODE_CUSTOMGRAPHICS_7',
 'NODE_CUSTOMGRAPHICS_8',
 'NODE_CUSTOMGRAPHICS_9',
 'NODE_CUSTOMGRAPHICS_POSITION_1',
 'NODE_CUSTOMGRAPHICS_POSITION_2',
 'NODE_CUSTOMGRAPHICS_POSITION_3',
 'NODE_CUSTOMGRAPHICS_POSITION_4',
 'NODE_CUSTOMGRAPHICS_POSITION_5',
 'NODE_CUSTOMGRAPHICS_POSITION_6',
 'NODE_CUSTOMGRAPHICS_POSITION_7',
 'NODE_CUSTOMGRAPHICS_POSITION_8',
 'NODE_CUSTOMGRAPHICS_POSITION_9',
 'NODE_CUSTOMGRAPHICS_SIZE_1',
 'NODE_CUSTOMGRAPHICS_SIZE_2',
 'NODE_CUSTOMGRAPHICS_SIZE_3',
 'NODE_CUSTOMGRAPHICS_SIZE_4',
 'NODE_CUSTOMGRAPHICS_SIZE_5',
 'NODE_CUSTOMGRAPHICS_SIZE_6',
 'NODE_CUSTOMGRAPHICS_SIZE_7',
 'NODE_CUSTOMGRAPHICS_SIZE_8',
 'NODE_CUSTOMGRAPHICS_SIZE_9',
 'NODE_CUSTOMPAINT_1',
 'NODE_CUSTOMPAINT_2',
 'NODE_CUSTOMPAINT_3',
 'NODE_CUSTOMPAINT_4',
 'NODE_CUSTOMPAINT_5',
 'NODE_CUSTOMPAINT_6',
 'NODE_CUSTOMPAINT_7',
 'NODE_CUSTOMPAINT_8',
 'NODE_CUSTOMPAINT_9',
...]

Not so obvious. So, to nail this down, I'll pose the question to the developers to see exactly what value should be set.

Thanks very much for it! This will save my life!

NODECUSTOMGRAPHICS# help me set the size

p4c.set_node_property_bypass(node_names = ['m_31'],
                             new_values = [300],
                             visual_property = 'NODE_CUSTOMGRAPHICS_SIZE_1')

But if there is a way I can just set size based on the original size then it will be great! But it helps already.

set_node_custom_bar_chart_by_pass ?

It seems like the followon question would be how to set the bypass via py4cytoscape by using a call something like set_node_custom_bar_chart() ... is that what you're thinking?

Exactly this is what I am wondering. lol

Thanks again!

Best, Minghao

bdemchak commented 1 year ago

OK ... custom graphics (as either graphs or static images) are an odd thing in Cytoscape. Clearly, this all works in the GUI. But getting defaults and bypasses working in CyREST/py4cytoscape/RCy3 is another matter. I have submitted questions, but there aren't any immediate answers. I'm also having trouble getting them to work myself from either Swagger or py4cytoscape.

I think we have to wait until the developers can engage this, and even then, with no certain result.

Sorry not to have more definite information.

bdemchak commented 1 year ago

Hi --

I have answers regarding static images ...

In Cytoscape, a static image must be registered in the ImageManager before it can be used in a NODE_CUSTOMGRAPHICS_1 style. Unfortunately, there aren't any REST calls that allow access to the ImageManager, so calls would need to be added.

I'm happy to request new calls, and they may be feasible. Supposing I were to do that, can you give me any idea of how many unique images would suit your application? I suspect that there are some ImageManager assumptions about the count of images in existing Cytoscape, supposing that they'll be entered via the GUI and would naturally be limited to only a few. Good to know these requirements and limits ahead of time.

The functions I would ask for would be Add, Delete, List, and Clear.

As for your question about a Pythonic way of loading tables, I think you must be asking about load_table_data_from_file(). You raise a decent point. I think you might get that functionality by using load_table_data() after loading a dataframe from a JSON file. No?? See here.

gmhhope commented 1 year ago

Hi Barry,

Thanks very much for replying back to me. Yes, if I can do python call to image for nodes that will be great. Then at least I don't need to do bypass to put new graph in each node.

I think there might be at least 20 images I need to imbed. So far, they work manually. Thus, I am not aware of the limits of images allowed in GUI. But, I think this will be something very interesting to use in long run (e.g., some metabolic flux figures, which will be much better if I can imbed bar charts in the flux (e.g., TCA) that I generated externally.

And thanks for the answer regarding load_table_data_from_file(). The problem I had before is that JSON allows some field that will be missing and when converting to table, they will turn to np.nan, which is not handled right in the cytoscape table. I found that if there is np.nan, then cytoscape seems considering the column to be character type rather than float type. I can assign some float values to replace np.nan, but this can be painful.

Thanks, Minghao Gong

gmhhope commented 1 year ago

I may misunderstand what you just told me:

I understands that there might be a missing call to import external figures to ImageManager. But do you mean that if I already have the figures in the ImageManager, there is already REST call to load figure to a specific node?

If so, please let me know as assigning figures to nodes is basically the rate-limiting step for my process.

Thanks, Minghao Gong

gmhhope commented 11 months ago

Hi Barry,

How is this feature going now? Just want to check in if there are updates.

Best, MInghao Gong

bdemchak commented 11 months ago

Hi, Minghao Gong --

This is a difficult issue, and I haven't gotten a good answer from the developers yet.

For the sake of keeping track of information, suppose that there is an image loaded into the ImageManager (regardless of how it was loaded, which is another story). Setting the image for a node (e.g., 2301863) would be done by a call that looks like this:

p4c.set_node_property_bypass(2301863, "org.cytoscape.ding.customgraphics.bitmap.URLImageCustomGraphics,32,file:/C:/Users/CyDeveloper/CytoscapeConfiguration/3/karaf_data/tmp/32.png,bitmap image", 'NODE_CUSTOMGRAPHICS_1')

It's unclear how the "32" and the "32.png" figure into this. And it's unclear how the image gets loaded into ImageManager.

That's what I'm tracking down.

Stay tuned ...

carissableker commented 7 months ago

Hi,

In case the following is helpful for anyone. Here's a function I use to add png's per node.:

https://github.com/NIB-SI/skm-tools/blob/d29f104e03f88fb38737e924e3a430c68e848963/skm_tools/cytoscape_utils.py#L366C1-L396C1


import pandas as pd
import py4cytoscape as p4c

def add_custom_png(network, create_png, style=None):
    '''
    network : int
        Cytoscape suid, where to apply the layout
    create_png: function
        function that creates a png per node and returns png file path

    '''

    nodes = p4c.get_all_nodes(network=network)

    node_pngs = {}
    for node in nodes:
        node_png_fname = create_png(node)
        if node_png_fname:
            node_pngs[node] = {'fig_location':f"file:{str(node_png_fname.absolute())}"}

    table = pd.DataFrame.from_dict(node_pngs, orient='index')

    if style is None:
        style = p4c.styles.get_current_style(network=network)

    p4c.load_table_data(table, network=network)
    p4c.style_dependencies.sync_node_custom_graphics_size(False, style_name=style)

    style_mapping = p4c.style_mappings.map_visual_property(
        visual_prop="NODE_CUSTOMGRAPHICS_1",
        table_column="fig_location",
        mapping_type="p",
    )
    p4c.style_mappings.update_style_mapping(style, style_mapping)

For example here: skm-tools/case-study-2-CKN-network-analysis.ipynb (very last section), I create heatmaps for each node and load it next the node.

image

The style (e.g. png size and location relative to the node) is specific to my use-case, but it's easily adjusted.

gmhhope commented 7 months ago

that is wonderful. Could it be vector-based fight like avg?

Thanks, Minghao

On Sat, Apr 6, 2024 at 5:52 PM Carissa Bleker @.***> wrote:

Hi,

In case the following is helpful for anyone. Here's a function I use to add png's per node.:

https://github.com/NIB-SI/skm-tools/blob/d29f104e03f88fb38737e924e3a430c68e848963/skm_tools/cytoscape_utils.py#L366C1-L396C1

import pandas as pdimport py4cytoscape as p4c def add_custom_png(network, create_png, style=None): ''' network : int Cytoscape suid, where to apply the layout create_png: function function that creates a png per node and returns png file path '''

nodes = p4c.get_all_nodes(network=network)

node_pngs = {}
for node in nodes:
    node_png_fname = create_png(node)
    if node_png_fname:
        node_pngs[node] = {'fig_location':f"file:{str(node_png_fname.absolute())}"}

table = pd.DataFrame.from_dict(node_pngs, orient='index')

if style is None:
    style = p4c.styles.get_current_style(network=network)

p4c.load_table_data(table, network=network)
p4c.style_dependencies.sync_node_custom_graphics_size(False, style_name=style)

style_mapping = p4c.style_mappings.map_visual_property(
    visual_prop="NODE_CUSTOMGRAPHICS_1",
    table_column="fig_location",
    mapping_type="p",
)
p4c.style_mappings.update_style_mapping(style, style_mapping)

For example here: skm-tools/case-study-2-CKN-network-analysis.ipynb https://github.com/NIB-SI/skm-tools/blob/main/publication/case-study-2/case-study-2-CKN-network-analysis.ipynb (very last section), I create heatmaps for each node and load it next the node.

image.png (view on web) https://github.com/cytoscape/py4cytoscape/assets/26261557/b849c436-4cdf-490a-b915-974934e26390

The style (e.g. png size and location relative to the node) is specific to my use-case, but it's easily adjusted.

— Reply to this email directly, view it on GitHub https://github.com/cytoscape/py4cytoscape/issues/120#issuecomment-2041214631, or unsubscribe https://github.com/notifications/unsubscribe-auth/ADDBUIOBAWL36GK2ZX3ZA2TY4BVDBAVCNFSM6AAAAAA5B4UBOWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDANBRGIYTINRTGE . You are receiving this because you authored the thread.Message ID: @.***>

carissableker commented 7 months ago

I haven't tried it, but that should be possible, since Cytoscape does support SVG images as annotations.

bdemchak commented 7 months ago

Very nice work!