Module lang_main.render.cytoscape

Functions

def analyse_network(property_degree_weighted: str = 'degree_weighted',
network_name: str = 'token_graph') ‑> None
Expand source code
def analyse_network(
    property_degree_weighted: str = PROPERTY_NAME_DEGREE_WEIGHTED,
    network_name: str = CYTO_BASE_NETWORK_NAME,
) -> None:
    node_table = p4c.get_table_columns(table='node', network=network_name)
    net_analyse_possible: bool = True
    if len(node_table) < 4:  # pragma: no cover
        net_analyse_possible = False

    if net_analyse_possible:
        p4c.analyze_network(directed=False)
        node_table = p4c.get_table_columns(table='node', network=network_name)
        node_table['stress_norm'] = node_table['Stress'] / node_table['Stress'].max()
        node_table[CYTO_SELECTION_PROPERTY] = (
            node_table[property_degree_weighted]
            * node_table['BetweennessCentrality']
            * node_table['stress_norm']
        )
    else:  # pragma: no cover
        node_table[CYTO_SELECTION_PROPERTY] = 1

    p4c.load_table_data(node_table, data_key_column='name', network=network_name)
def apply_style_to_network(style_name: str = 'lang_main',
pth_to_stylesheet: pathlib.Path = WindowsPath('A:/Arbeitsaufgaben/lang-main/src/lang_main/cytoscape_config/lang_main.xml'),
network_name: str = 'token_graph',
node_size_property: str = 'node_selection',
min_node_size: int = 15,
max_node_size: int = 40,
sandbox_name: str = 'lang_main') ‑> None
Expand source code
def apply_style_to_network(
    style_name: str = CYTO_STYLESHEET_NAME,
    pth_to_stylesheet: Path = CYTO_PATH_STYLESHEET,
    network_name: str = CYTO_BASE_NETWORK_NAME,
    node_size_property: str = CYTO_SELECTION_PROPERTY,
    min_node_size: int = 15,
    max_node_size: int = 40,
    sandbox_name: str = CYTO_SANDBOX_NAME,
) -> None:
    """Cytoscape: apply a chosen Cytoscape style to the defined network

    Parameters
    ----------
    style_name : str, optional
        Cytoscape name of the style which should be applied,
        by default CYTO_STYLESHEET_NAME
    pth_to_stylesheet : Path, optional
        path where the stylesheet definition in Cytoscape's XML format can
        be found,
        by default CYTO_PATH_STYLESHEET
    network_name : str, optional
        network to apply the style on, by default CYTO_BASE_NETWORK_NAME

    Raises
    ------
    FileNotFoundError
        if provided stylesheet can not be found under the provided path
    """
    logger.debug('Applying style to network...')
    styles_avail = cast(list[str], p4c.get_visual_style_names())
    logger.debug('Available styles: %s', styles_avail)
    if style_name not in styles_avail:
        if not pth_to_stylesheet.exists():
            # existence for standard path verified at import, but not for other
            # provided paths
            raise FileNotFoundError(
                f'Visual stylesheet for Cytoscape not found under: >>{pth_to_stylesheet}<<'
            )
        # send to sandbox
        sandbox_filename = pth_to_stylesheet.name
        p4c.sandbox_send_to(
            source_file=pth_to_stylesheet,
            dest_file=sandbox_filename,
            overwrite=True,
            sandbox_name=sandbox_name,
        )
        # load stylesheet
        p4c.import_visual_styles(sandbox_filename)

    p4c.set_visual_style(style_name, network=network_name)
    # node size mapping, only if needed property is available
    scheme = p4c.scheme_c_number_continuous(
        start_value=min_node_size, end_value=max_node_size
    )
    node_size_map = p4c.gen_node_size_map(
        node_size_property,
        number_scheme=scheme,
        mapping_type='c',
        style_name=style_name,
        default_number=min_node_size,
    )
    p4c.set_node_size_mapping(**node_size_map)
    fit_content(network_name=network_name)
    logger.debug('Style application to network successful.')

Cytoscape: apply a chosen Cytoscape style to the defined network

Parameters

style_name : str, optional
Cytoscape name of the style which should be applied, by default CYTO_STYLESHEET_NAME
pth_to_stylesheet : Path, optional
path where the stylesheet definition in Cytoscape's XML format can be found, by default CYTO_PATH_STYLESHEET
network_name : str, optional
network to apply the style on, by default CYTO_BASE_NETWORK_NAME

Raises

FileNotFoundError
if provided stylesheet can not be found under the provided path
def build_subnetworks(nodes_to_analyse: Iterable[int],
network_name: str = 'token_graph',
export_image: bool = True,
target_folder: pathlib.Path = WindowsPath('A:/Arbeitsaufgaben/lang-data/out')) ‑> None
Expand source code
def build_subnetworks(
    nodes_to_analyse: Iterable[CytoNodeID],
    network_name: str = CYTO_BASE_NETWORK_NAME,
    export_image: bool = True,
    target_folder: Path = SAVE_PATH_FOLDER,
) -> None:
    """Cytoscape: iteratively build subnetworks from a collection of nodes
    and their respective neighbouring nodes

    Parameters
    ----------
    nodes_to_analyse : Iterable[CytoNodeID]
        collection of nodes to make subnetworks from, for each node a dedicated
        subnetwork will be generated
    network_name : str, optional
        network which contains the provided nodes,
        by default CYTO_BASE_NETWORK_NAME
    export_image : bool, optional
        trigger image export of newly generated subnetworks, by default True
    """
    logger.debug('Generating all subnetworks for node selection...')
    for idx, node in enumerate(nodes_to_analyse):
        select_neighbours_of_node(node=node, network_name=network_name)
        make_subnetwork(
            index=idx,
            network_name=network_name,
            export_image=export_image,
            target_folder=target_folder,
        )
    logger.debug('Generation of all subnetworks for node selection successful.')

Cytoscape: iteratively build subnetworks from a collection of nodes and their respective neighbouring nodes

Parameters

nodes_to_analyse : Iterable[CytoNodeID]
collection of nodes to make subnetworks from, for each node a dedicated subnetwork will be generated
network_name : str, optional
network which contains the provided nodes, by default CYTO_BASE_NETWORK_NAME
export_image : bool, optional
trigger image export of newly generated subnetworks, by default True
def change_default_layout() ‑> None
Expand source code
def change_default_layout() -> None:
    """Cytoscape: resets the default layout to `grid` to accelerate the import process
    (grid layout one of the fastest)

    Raises
    ------
    RequestException
        API endpoint not reachable or CyREST operation not successful
    """
    body: dict[str, str] = {'value': 'grid', 'key': 'layout.default'}
    try:
        p4c.cyrest_put('properties/cytoscape3.props/layout.default', body=body)
    except RequestException as error:
        logger.error('[CytoAPIConnection] Property change of default layout not successful.')
        raise error

Cytoscape: resets the default layout to grid to accelerate the import process (grid layout one of the fastest)

Raises

RequestException
API endpoint not reachable or CyREST operation not successful
def export_network_to_image(filename: str,
target_folder: pathlib.Path = WindowsPath('A:/Arbeitsaufgaben/lang-data/out'),
filetype: Literal['JPEG', 'PDF', 'PNG', 'PS', 'SVG'] = 'SVG',
network_name: str = 'token_graph',
pdf_export_page_size: Literal['A0', 'A1', 'A2', 'A3', 'A4', 'A5', 'Auto', 'Legal', 'Letter', 'Tabloid'] = 'A4',
sandbox_name: str = 'lang_main') ‑> None
Expand source code
def export_network_to_image(
    filename: str,
    target_folder: Path = SAVE_PATH_FOLDER,
    filetype: CytoExportFileTypes = 'SVG',
    network_name: str = CYTO_BASE_NETWORK_NAME,
    pdf_export_page_size: CytoExportPageSizes = 'A4',
    sandbox_name: str = CYTO_SANDBOX_NAME,
) -> None:
    """Cytoscape: export current selected view as image

    Parameters
    ----------
    filename : str
        export filename
    filetype : CytoExportFileTypes, optional
        export filetype supported by Cytoscape, by default 'SVG'
    network_name : str, optional
        network to export, by default CYTO_BASE_NETWORK_NAME
    pdf_export_page_size : CytoExportPageSizes, optional
        page size which should be used for PDF exports supported by Cytoscape,
        by default 'A4'
    """
    logger.debug('Exporting image to file...')
    if not target_folder.exists():  # pragma: no cover
        target_folder.mkdir(parents=True)
    dst_file_pth = (target_folder / filename).with_suffix(f'.{filetype.lower()}')

    text_as_font = True
    if filetype == 'SVG':
        text_as_font = False

    # close non-necessary windows and fit graph in frame before image display
    fit_content(network_name=network_name)
    # image is generated in sandbox directory and transferred to target destination
    # (preparation for remote instances of Cytoscape)
    p4c.export_image(
        filename=filename,
        type=filetype,
        network=network_name,
        overwrite_file=True,
        all_graphics_details=True,
        export_text_as_font=text_as_font,
        page_size=pdf_export_page_size,
    )
    logger.debug('Exported image to sandbox.')
    logger.debug('Transferring image from sandbox to target destination...')
    sandbox_filename = f'{filename}.{filetype.lower()}'
    p4c.sandbox_get_from(
        source_file=sandbox_filename,
        dest_file=str(dst_file_pth),
        overwrite=True,
        sandbox_name=sandbox_name,
    )
    logger.debug('Transfer of image from sandbox to target destination successful.')

Cytoscape: export current selected view as image

Parameters

filename : str
export filename
filetype : CytoExportFileTypes, optional
export filetype supported by Cytoscape, by default 'SVG'
network_name : str, optional
network to export, by default CYTO_BASE_NETWORK_NAME
pdf_export_page_size : CytoExportPageSizes, optional
page size which should be used for PDF exports supported by Cytoscape, by default 'A4'
def fit_content(zoom_factor: float = 0.96, network_name: str = 'token_graph') ‑> None
Expand source code
def fit_content(
    zoom_factor: float = CYTO_NETWORK_ZOOM_FACTOR,
    network_name: str = CYTO_BASE_NETWORK_NAME,
) -> None:
    p4c.hide_all_panels()
    p4c.fit_content(selected_only=False, network=network_name)
    zoom_current = p4c.get_network_zoom(network=network_name)
    zoom_new = zoom_current * zoom_factor
    p4c.set_network_zoom_bypass(zoom_new, bypass=False, network=network_name)
def get_subgraph_node_selection(network_name: str = 'token_graph', num_subgraphs: int = 5) ‑> list[int]
Expand source code
def get_subgraph_node_selection(
    network_name: str = CYTO_BASE_NETWORK_NAME,
    num_subgraphs: int = CYTO_NUMBER_SUBGRAPHS,
) -> list[CytoNodeID]:
    """Cytoscape: obtain the relevant nodes for iterative subgraph generation

    Parameters
    ----------
    network_name : str, optional
        network to retrieve the nodes from, by default CYTO_BASE_NETWORK_NAME
    property_degree_weighted : str, optional
        property name which contains the weighted degree,
        by default PROPERTY_NAME_DEGREE_WEIGHTED
    num_subgraphs : int, optional
        number of relevant nodes which form the basis to generate subgraphs from,
        by default CYTO_NUMBER_SUBGRAPHS

    Returns
    -------
    list[CytoNodeID]
        list containing all relevant Cytoscape nodes
    """
    logger.debug('Selecting nodes for subgraph generation...')
    node_table = p4c.get_table_columns(table='node', network=network_name)
    node_table = node_table.sort_values(by=CYTO_SELECTION_PROPERTY, ascending=False)
    p4c.load_table_data(node_table, data_key_column='name', network=network_name)
    node_table_choice = node_table.iloc[:num_subgraphs]
    logger.debug('Selection of nodes for subgraph generation successful.')

    return node_table_choice['SUID'].to_list()

Cytoscape: obtain the relevant nodes for iterative subgraph generation

Parameters

network_name : str, optional
network to retrieve the nodes from, by default CYTO_BASE_NETWORK_NAME
property_degree_weighted : str, optional
property name which contains the weighted degree, by default PROPERTY_NAME_DEGREE_WEIGHTED
num_subgraphs : int, optional
number of relevant nodes which form the basis to generate subgraphs from, by default CYTO_NUMBER_SUBGRAPHS

Returns

list[CytoNodeID]
list containing all relevant Cytoscape nodes
def import_to_cytoscape(graph: networkx.classes.digraph.DiGraph | networkx.classes.graph.Graph,
network_name: str = 'token_graph',
sandbox_name: str = 'lang_main',
reinitialise_sandbox: bool = True) ‑> None
Expand source code
def import_to_cytoscape(
    graph: DiGraph | Graph,
    network_name: str = CYTO_BASE_NETWORK_NAME,
    sandbox_name: str = CYTO_SANDBOX_NAME,
    reinitialise_sandbox: bool = True,
) -> None:
    """Cytoscape: import NetworkX graph as new network collection

    Parameters
    ----------
    graph : DiGraph | Graph
        NetworkX graph object
    """
    logger.debug('Checking Cytoscape connection...')
    verify_connection()
    logger.debug('Checking graph size for rendering...')
    verify_graph_render_size(graph)
    logger.debug('Setting default layout to improve import speed...')
    change_default_layout()
    logger.debug('Setting Cytoscape sandbox...')
    p4c.sandbox_set(
        sandbox_name=sandbox_name,
        reinitialize=reinitialise_sandbox,
        copy_samples=False,
    )
    logger.debug('Importing to and analysing network in Cytoscape...')
    p4c.delete_all_networks()
    p4c.create_network_from_networkx(
        graph,
        title=network_name,
        collection=CYTO_COLLECTION_NAME,
    )
    analyse_network(network_name=network_name)
    logger.debug('Import and analysis of network to Cytoscape successful.')

Cytoscape: import NetworkX graph as new network collection

Parameters

graph : DiGraph | Graph
NetworkX graph object
def layout_network(layout_name: Literal['attribute-circle', 'attribute-grid', 'attributes-layout', 'circular', 'cose', 'degree-circle', 'force-directed', 'force-directed-cl', 'fruchterman-rheingold', 'grid', 'hierarchical', 'isom', 'kamada-kawai', 'stacked-node-layout'] = 'force-directed',
layout_properties: dict[str, float | bool] = {'numIterations': 1000, 'defaultSpringCoefficient': 0.0001, 'defaultSpringLength': 45, 'defaultNodeMass': 11, 'isDeterministic': True, 'singlePartition': False},
network_name: str = 'token_graph') ‑> None
Expand source code
def layout_network(
    layout_name: CytoLayouts = CYTO_LAYOUT_NAME,
    layout_properties: CytoLayoutProperties = CYTO_LAYOUT_PROPERTIES,
    network_name: str = CYTO_BASE_NETWORK_NAME,
) -> None:
    """Cytoscape: apply a supported layout algorithm to currently selected
    network

    Parameters
    ----------
    layout_name : CytoLayouts, optional
        layout algorithm supported by Cytoscape (name of the CyREST API, does not
        necessarily match the name in the Cytoscape UI),
        by default CYTO_LAYOUT_NAME
    layout_properties : CytoLayoutProperties, optional
        configuration of parameters for the given layout algorithm,
        by default CYTO_LAYOUT_PROPERTIES
    network_name : str, optional
        network to apply the layout algorithm on, by default CYTO_BASE_NETWORK_NAME
    """
    logger.debug('Applying layout to network...')
    p4c.set_layout_properties(layout_name, layout_properties)
    p4c.layout_network(layout_name=layout_name, network=network_name)
    fit_content(network_name=network_name)
    logger.debug('Layout application to network successful.')

Cytoscape: apply a supported layout algorithm to currently selected network

Parameters

layout_name : CytoLayouts, optional
layout algorithm supported by Cytoscape (name of the CyREST API, does not necessarily match the name in the Cytoscape UI), by default CYTO_LAYOUT_NAME
layout_properties : CytoLayoutProperties, optional
configuration of parameters for the given layout algorithm, by default CYTO_LAYOUT_PROPERTIES
network_name : str, optional
network to apply the layout algorithm on, by default CYTO_BASE_NETWORK_NAME
def make_subnetwork(index: int,
network_name: str = 'token_graph',
export_image: bool = True,
target_folder: pathlib.Path = WindowsPath('A:/Arbeitsaufgaben/lang-data/out')) ‑> None
Expand source code
def make_subnetwork(
    index: int,
    network_name: str = CYTO_BASE_NETWORK_NAME,
    export_image: bool = True,
    target_folder: Path = SAVE_PATH_FOLDER,
) -> None:
    """Cytoscape: generate a new subnetwork based on the currently
    selected nodes and edges

    Parameters
    ----------
    index : int
        id-like property to identify the subnetwork relative to its parent
    network_name : str, optional
        network to generate subnetwork from, by default CYTO_BASE_NETWORK_NAME
    export_image : bool, optional
        trigger image export of newly generated subnetwork, by default True
    """
    logger.debug('Generating subnetwork with index %d...', index)
    subnetwork_name = network_name + f'_sub_{index+1}'
    p4c.create_subnetwork(
        nodes='selected',
        edges='selected',
        subnetwork_name=subnetwork_name,
        network=network_name,
    )
    p4c.set_current_network(subnetwork_name)

    if export_image:
        time.sleep(1)
        export_network_to_image(
            filename=subnetwork_name,
            target_folder=target_folder,
            network_name=subnetwork_name,
        )

    logger.debug('Generation of subnetwork with index %d successful.', index)

Cytoscape: generate a new subnetwork based on the currently selected nodes and edges

Parameters

index : int
id-like property to identify the subnetwork relative to its parent
network_name : str, optional
network to generate subnetwork from, by default CYTO_BASE_NETWORK_NAME
export_image : bool, optional
trigger image export of newly generated subnetwork, by default True
def reset_current_network_to_base() ‑> None
Expand source code
def reset_current_network_to_base() -> None:
    """resets to currently selected network in Cytoscape back to the base one"""
    p4c.set_current_network(CYTO_BASE_NETWORK_NAME)

resets to currently selected network in Cytoscape back to the base one

def select_neighbours_of_node(node: int, neighbour_iter_depth: int = 2, network_name: str = 'token_graph') ‑> None
Expand source code
def select_neighbours_of_node(
    node: CytoNodeID,
    neighbour_iter_depth: int = CYTO_ITER_NEIGHBOUR_DEPTH,
    network_name: str = CYTO_BASE_NETWORK_NAME,
) -> None:
    """Cytoscape: iterative selection of a node's neighbouring nodes and
    their connecting edges

    Parameters
    ----------
    node : CytoNodeID
        node which neighbours should be selected
    neighbour_iter_depth : int, optional
        indicates how many levels of neighbours should be choosen, e.g. 1 --> only
        first-level neighbours are considered which are directly connected to the node,
        2 --> all nodes with iteration depth of 1 are chosen and additionally their
        direct neighbours,
        by default CYTO_ITER_NEIGHBOUR_DEPTH
    network_name : str, optional
        network to perform action on, by default CYTO_BASE_NETWORK_NAME
    """
    logger.debug('Selecting node neighbours for %s...', node)
    p4c.clear_selection(network=network_name)
    p4c.select_nodes(node, network=network_name)

    for _ in range(neighbour_iter_depth):
        _ = p4c.select_first_neighbors(network=network_name)

    _ = p4c.select_edges_connecting_selected_nodes()
    logger.debug('Selection of node neighbours for %s successful.', node)

Cytoscape: iterative selection of a node's neighbouring nodes and their connecting edges

Parameters

node : CytoNodeID
node which neighbours should be selected
neighbour_iter_depth : int, optional
indicates how many levels of neighbours should be choosen, e.g. 1 –> only first-level neighbours are considered which are directly connected to the node, 2 –> all nodes with iteration depth of 1 are chosen and additionally their direct neighbours, by default CYTO_ITER_NEIGHBOUR_DEPTH
network_name : str, optional
network to perform action on, by default CYTO_BASE_NETWORK_NAME
def verify_connection() ‑> None
Expand source code
def verify_connection() -> None:
    """Cytoscape: checks if CyREST and Cytoscape versions are compatible nad
    if Cytoscape API endpoint is reachable

    Raises
    ------
    CyError
        incompatible CyREST or Cytoscape versions
    RequestException
        API endpoint not reachable
    """
    try:
        p4c.cytoscape_ping()
    except CyError as error:  # pragma: no cover
        logger.error('[CyError] CyREST or Cytoscape version not supported.')
        raise error
    except RequestException as error:
        logger.error('[CytoAPIConnection] Connection to CyREST API failed.')
        raise error

Cytoscape: checks if CyREST and Cytoscape versions are compatible nad if Cytoscape API endpoint is reachable

Raises

CyError
incompatible CyREST or Cytoscape versions
RequestException
API endpoint not reachable
def verify_graph_render_size(graph: networkx.classes.digraph.DiGraph | networkx.classes.graph.Graph,
max_node_count: int | None = 500,
max_edge_count: int | None = 800) ‑> None
Expand source code
def verify_graph_render_size(
    graph: Graph | DiGraph,
    max_node_count: int | None = CYTO_MAX_NODE_COUNT,
    max_edge_count: int | None = CYTO_MAX_EDGE_COUNT,
) -> None:
    """verify that the graph size can still be handled within an acceptable time
    frame for rendering in Cytoscape

    Parameters
    ----------
    graph : Graph | DiGraph
        graph to verify
    max_node_count : int | None, optional
        maximum allowed number of nodes, by default CYTO_MAX_NODE_COUNT
    max_edge_count : int | None, optional
        maximum allowed number of edges, by default CYTO_MAX_EDGE_COUNT

    Raises
    ------
    GraphRenderError
        if any of the provided limits is exceeded
    """
    num_nodes = len(graph.nodes)
    num_edges = len(graph.edges)
    if max_node_count is not None and num_nodes > max_node_count:
        raise GraphRenderError(
            f'Maximum number of nodes for rendering exceeded. '
            f'Limit {max_node_count}, Counted: {num_nodes}'
        )

    if max_edge_count is not None and num_edges > max_edge_count:
        raise GraphRenderError(
            f'Maximum number of edges for rendering exceeded. '
            f'Limit {max_edge_count}, Counted: {num_edges}'
        )

verify that the graph size can still be handled within an acceptable time frame for rendering in Cytoscape

Parameters

graph : Graph | DiGraph
graph to verify
max_node_count : int | None, optional
maximum allowed number of nodes, by default CYTO_MAX_NODE_COUNT
max_edge_count : int | None, optional
maximum allowed number of edges, by default CYTO_MAX_EDGE_COUNT

Raises

GraphRenderError
if any of the provided limits is exceeded
def verify_table_property(property: str,
table_type: Literal['node', 'edge', 'network'] = 'node',
network_name: str = 'token_graph') ‑> bool
Expand source code
def verify_table_property(
    property: str,
    table_type: Literal['node', 'edge', 'network'] = 'node',
    network_name: str = CYTO_BASE_NETWORK_NAME,
) -> bool:
    table = p4c.get_table_columns(table=table_type, network=network_name)
    logger.debug('Table >>%s<< wiht columns: %s', table, table.columns)

    return property in table.columns