Cytoscape结合Networkx生成有向图

需求

搜索水质监测自动站上游及下游的其他自动站,以有向图的形式展示在web端,最终效果图如下
在这里插入图片描述

代码

1、使用Python的networkx包进行有向图的构建
2、使用Cytoscape前端js库绘制有向图

安装依赖

pip install networkx==2.5 -i https://pypi.tuna.tsinghua.edu.cn/simple

后端代码

import json
from functools import reduce

import networkx as nx
from networkx.readwrite import json_graph


def list_dict_duplicate_removal(data_list):
    return reduce(lambda x, y: x if y in x else x + [y], [[], ] + data_list)


class Graph(object):
    def __init__(self, node=147):
        self.dict_node = {96: "剔除敏感数据", 97: "剔除敏感数据", 98: "剔除敏感数据", 99: "剔除敏感数据", 100: "剔除敏感数据", 102: "剔除敏感数据",
                          103: "剔除敏感数据", 104: "剔除敏感数据", 105: "剔除敏感数据", 106: "剔除敏感数据", 107: "剔除敏感数据",
                          108: "剔除敏感数据", 109: "剔除敏感数据", 110: "剔除敏感数据", 111: "剔除敏感数据", 112: "剔除敏感数据", 113: "剔除敏感数据",
                          114: "剔除敏感数据", 115: "剔除敏感数据", 116: "剔除敏感数据", 117: "剔除敏感数据", 118: "剔除敏感数据", 119: "剔除敏感数据",
                          120: "剔除敏感数据", 121: "剔除敏感数据", 122: "剔除敏感数据", 123: "剔除敏感数据", 124: "剔除敏感数据", 125: "剔除敏感数据",
                          126: "剔除敏感数据", 127: "剔除敏感数据", 128: "剔除敏感数据", 129: "剔除敏感数据", 130: "剔除敏感数据", 131: "剔除敏感数据",
                          132: "剔除敏感数据", 133: "剔除敏感数据", 134: "剔除敏感数据", 135: "剔除敏感数据", 136: "剔除敏感数据", 137: "剔除敏感数据", 143: "剔除敏感数据",
                          144: "剔除敏感数据", 145: "剔除敏感数据", 146: "剔除敏感数据", 147: "剔除敏感数据", 148: "剔除敏感数据", 149: "剔除敏感数据", 150: "剔除敏感数据",
                          151: "剔除敏感数据", 152: "剔除敏感数据", 153: "剔除敏感数据", 154: "剔除敏感数据", 155: "剔除敏感数据", 156: "剔除敏感数据", 157: "剔除敏感数据",
                          158: "剔除敏感数据", 159: "剔除敏感数据", 160: "剔除敏感数据", 161: "剔除敏感数据", 162: "剔除敏感数据", 163: "剔除敏感数据",
                          164: "剔除敏感数据", 165: "剔除敏感数据", 166: "剔除敏感数据", 167: "剔除敏感数据", 168: "剔除敏感数据", 169: "剔除敏感数据", 170: "剔除敏感数据",
                          171: "剔除敏感数据", 172: "剔除敏感数据", 173: "剔除敏感数据", 175: "剔除敏感数据", 176: "剔除敏感数据", 177: "剔除敏感数据",
                          178: "剔除敏感数据", 179: "剔除敏感数据", 180: "剔除敏感数据", 181: "剔除敏感数据", 183: "剔除敏感数据", 184: "剔除敏感数据"}

        self.relationship = [
            (131, 132), (132, 133), (132, 134), (134, 147), (147, 180), (180, 179), (179, 170), (179, 123),
            (179, 128), (179, 169), (170, 124), (123, 124), (124, 184), (184, 168), (128, 126), (169, 126),
            (126, 127), (143, 144), (144, 145), (145, 146), (146, 147), (99, 152), (152, 151), (153, 150),
            (150, 149), (149, 151), (151, 118), (151, 117), (118, 116), (117, 115), (116, 112), (115, 112),
            (112, 119), (119, 125), (171, 115), (178, 171), (108, 178), (100, 108), (155, 100), (156, 155),
            (155, 154), (119, 122), (108, 148), (108, 104), (104, 107), (108, 111), (111, 103), (97, 98),
            (98, 96), (96, 176), (176, 114), (114, 113), (113, 130), (130, 129), (98, 158), (102, 109),
            (109, 110), (110, 103), (102, 105), (105, 106), (106, 173), (173, 183), (183, 121), (121, 136),
            (136, 122), (173, 172), (172, 177), (177, 175), (175, 120), (165, 163), (163, 160), (160, 161),
            (161, 157), (157, 135), (157, 137), (162, 167), (167, 159), (181, 164), (164, 157), (125, 126),
            (166, 167), (155, 98), (159, 163)
        ]

        self.start_node = [131, 143, 99, 153, 156, 97, 102, 165, 162, 166, 181]  # 上游

        self.node = node

    def search(self):
        G = nx.DiGraph()  # 创建空的简单有向图
        G.add_nodes_from(list(self.dict_node.keys()))
        G.add_edges_from(self.relationship)

        nodes, edges = [], []
        for node in self.start_node:  # 遍历入河自动站
            river = nx.dfs_successors(G, node)  # 从上到下查找自动站
            if self.node in river:  # 判断要查找得自动站是否在该河流上
                GG = nx.Graph(river)
                for n in GG:
                    GG.nodes[n]["name"] = self.dict_node[n]
                item_dict = json_graph.cytoscape_data(GG)
                nodes.extend(item_dict['elements']['nodes'])
                edges.extend(item_dict['elements']['edges'])
        return {'elements': {'nodes': list_dict_duplicate_removal(nodes), 'edges': list_dict_duplicate_removal(edges)}}


if __name__ == "main":
    print(json.dumps(Graph(147).search()))

前端

忘了从哪里扒的代码了,稍作修改了一下,使用ajax同步获取后端的接口数据

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        #cy {
            width: 100%;
            height: 100%;
            position: absolute;
            left: 0;
            top: 0;
        }
    </style>
</head>

<body>
    <div id="cy"></div>
    <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
    <script src="https://cdn.bootcdn.net/ajax/libs/cytoscape/3.16.3/cytoscape.min.js"></script>
    <script>
        var waterName = "剔除敏感数据";
        $.ajax({
            cache: false,
            type: "GET",
            url: "http://127.0.0.1:6070/water/water_prediction/nearby_unit",
            dataType: 'json',
            data: {
                "waterName": waterName
            },
            async: false,
            success: function (data) {
                if (data.code == 1) {
                    // 此处请求回来的数据其中 elements 字段为, 该数据通过python networkx包json_graph.cytoscape_data生成的图json数据
                    // {"edges":[{"data":{"source":102,"target":109}},{"data":{"source":102,"target":105}},{"data":{"source":109,"target":110}},{"data":{"source":110,"target":103}},{"data":{"source":105,"target":106}},{"data":{"source":106,"target":173}},{"data":{"source":173,"target":183}},{"data":{"source":173,"target":172}},{"data":{"source":183,"target":121}},{"data":{"source":121,"target":136}},{"data":{"source":136,"target":122}},{"data":{"source":172,"target":177}},{"data":{"source":177,"target":175}},{"data":{"source":175,"target":120}}],"nodes":[{"data":{"id":"102","name":"\u00\u67\u6c34\u93","value":102}},{"data":{"id":"109","name":"\05\cb3\uf8","value":109}},{"data":{"id":"110","name":"\ub1\u58def","value":110}},{"data":{"id":"105","name":"\u6c99\9d","value":105}},{"data":{"id":"106","name":"\u0\ub\u\u6","value":106}},{"data":{"id":"173","name":"\u4\u61","value":173}},{"data":{"id":"183","name":"\u5927\u59","value":183}},{"data":{"id":"121","name":"\u59","value":121}},{"data":{"id":"136","name":"\u4e3","value":136}},{"data":{"id":"172","name":"\u73","value":172}},{"data":{"id":"177","name":"\u01\90f\u89\u5c\u8","value":177}},{"data":{"id":"175","name":"\u6\u25\u6c\634\u9","value":175}},{"data":{"id":"103","name":"\u93\u7c\596\27\7","value":103}},{"data":{"id":"122","name":"\u7\u3\u7\uf8","value":122}},{"data":{"id":"120","name":"\u5\u98\u7c","value":120}}]}
                    elements = data.resData.elements;
                } else if (data.code == 0) {
                    alert(data.msg);
                }
            },
            error: function () {
                elements =  {"edges":[{"data":{"source":102,"target":109}},{"data":{"source":102,"target":105}},{"data":{"source":109,"target":110}},{"data":{"source":110,"target":103}},{"data":{"source":105,"target":106}},{"data":{"source":106,"target":173}},{"data":{"source":173,"target":183}},{"data":{"source":173,"target":172}},{"data":{"source":183,"target":121}},{"data":{"source":121,"target":136}},{"data":{"source":136,"target":122}},{"data":{"source":172,"target":177}},{"data":{"source":177,"target":175}},{"data":{"source":175,"target":120}}],"nodes":[{"data":{"id":"102","name":"\u00\u67\u6c34\u93","value":102}},{"data":{"id":"109","name":"\05\cb3\uf8","value":109}},{"data":{"id":"110","name":"\ub1\u58def","value":110}},{"data":{"id":"105","name":"\u6c99\9d","value":105}},{"data":{"id":"106","name":"\u0\ub\u\u6","value":106}},{"data":{"id":"173","name":"\u4\u61","value":173}},{"data":{"id":"183","name":"\u5927\u59","value":183}},{"data":{"id":"121","name":"\u59","value":121}},{"data":{"id":"136","name":"\u4e3","value":136}},{"data":{"id":"172","name":"\u73","value":172}},{"data":{"id":"177","name":"\u01\90f\u89\u5c\u8","value":177}},{"data":{"id":"175","name":"\u6\u25\u6c\634\u9","value":175}},{"data":{"id":"103","name":"\u93\u7c\596\27\7","value":103}},{"data":{"id":"122","name":"\u7\u3\u7\uf8","value":122}},{"data":{"id":"120","name":"\u5\u98\u7c","value":120}}]}
            }
        });
        var cy = cytoscape({
            container: document.getElementById('cy'),
            boxSelectionEnabled: true,
            autounselectify: true,
            motionBlur: !1,
            maxZoom: 2.5,
            minZoom: .4,
            wheelSensitivity: .1,//滑动滚轮一次缩放大小
            textureOnViewport: !1,
            style: [{
                selector: 'node',
                style: {
                    "text-valign": 'center',
                    "width": 60,
                    "height": 60,
                    "background-color": '#2196F4',
                    "color": '#fff',
                    "border-color": '#2196F4',
                    "border-width": 1,
                    "text-wrap": "wrap",
                    "font-size": 10,
                    "font-family": "microsoft yahei",
                    "overlay-color": "#fff",
                    "overlay-opacity": 0,
                    "background-opacity": 1,
                    "shape": "ellipse",
                    "z-index-compare": "manual",
                    "z-index": 20,
                    "padding": 3,
                    "text-max-width": 60,
                    "text-margin-y": 4,
                    "label": function (a) {
                        a = a.data("name");
                        var b = a.length;
                        return 5 >= b ? a : 5 <= b && 9 >= b ? a.substring(0, b - 5) + "\n" + a.substring(
                            b - 5, b) : 9 <= b && 13 >= b ? a.substring(0, 4) + "\n" + a.substring(
                                4, 9) + "\n" + a.substring(9, 13) : a.substring(0, 4) + "\n" + a.substring(
                                    4, 9) + "\n" + a.substring(9, 12) + ".."
                    },
                }
            },
            {
                selector: 'edge',
                style: {
                    // 添加箭头
                    "line-style": "solid",
                    "curve-style": "bezier",
                    "control-point-step-size": 20,
                    "target-arrow-shape": "triangle",
                    "target-arrow-color": '#DCDCDC',
                    "arrow-scale": .5,
                    "line-color": '#DCDCDC',
                    "label": "流向",
                    "text-opacity": .8,
                    "font-size": 10,
                    "background-color": "#333",
                    "width": 1,
                    "overlay-color": "#fff",
                    "overlay-opacity": 0,
                    "font-family": "microsoft yahei"
                }
            },
            {
                selector: ':selected',
                style: {
                    "border-width": 3,
                    "border-color": '#333',
                    "background-color": 'black',
                    "line-color": 'black',
                    "target-arrow-color": 'black',
                    "source-arrow-color": 'black'
                }
            },
            {
                selector: ".nodeHover", //节点变暗,有悬停效果
                style: {
                    "shape": "ellipse",
                    "background-opacity": .8
                }
            },
            {
                selector: ".nodeActive",
                style: {
                    "border-color": '#4EA2F0',
                    "border-width": 10,
                    "border-opacity": .5
                }
            },
            {
                selector: ".edgeShow",
                style: {
                    "color": "#999",
                    "text-opacity": 1,
                    "font-weight": 400,
                    "label": "流向",
                    "font-size": 10,
                    "arrow-scale": .8,
                    "width": 1.5,
                    "source-text-margin-y": 20,
                    "target-text-margin-y": 20,
                },
            },
            {
                selector: ".edgeActive",
                style: {
                    "arrow-scale": .8,
                    "width": 1.5,
                    "color": "#330",
                    "text-opacity": 1,
                    "font-size": 10,
                    "text-background-color": "#fff",
                    "text-background-opacity": .8,
                    "text-background-padding": 0,
                    "source-text-margin-y": 20,
                    "target-text-margin-y": 20,
                    "z-index-compare": "manual",
                    "z-index": 1,
                    "line-color": "#4EA2F0",
                    "target-arrow-color": "#4EA2F0",
                    "label": "流向"
                }
            },
            {
                selector: ".dull",
                style: {
                    "z-index": 1,
                    "opacity": .2
                }
            }
            ],
            elements: elements,
            layout: {
                name: 'cose',//用哪种方式排列,可选:breadthfirst(广度优先)、cose(缝制,乱交)、preset(预设)、circle(圆形)、grid(矩形)
                idealEdgeLength: 60,
                nodeOverlap: 20,
                refresh: 20,
                fit: true,
                padding: 30,
                randomize: false,
                componentSpacing: 20,
                nodeRepulsion: 400,
                edgeElasticity: 10,
                nestingFactor: 5,
                animate: true,//出来动画
                gravity: 80,
                numIter: 1000,
                initialTemp: 200,
                coolingFactor: 0.95,
                minTemp: 1.0
            }
        })
        cy.collection("edge").addClass("edgeShow");
        cy.on("mouseover", "node", function (a) {
            $('#cy').css('cursor', 'move');
            let c = a.target;
            c.addClass("nodeHover");
            cy.collection("edge").removeClass("edgeActive");
            c.neighborhood("edge").addClass("edgeActive");
        })
        cy.on("mouseout", "node", function (a) {
            $('#cy').css('cursor', 'default');
            let c = a.target;
            c.removeClass("nodeHover");
            cy.collection("edge").removeClass("edgeActive");
        })
        cy.on("click", "node", function (a) {
            let c = a.target;
            c.removeClass("nodeActive");
            cy.collection("edge").removeClass("edgeActive");
        })
        cy.on("vmousedown", "node", function (a) { //监听鼠标左键按下
            let c = a.target;
            cy.collection("edge").addClass('dull');
            cy.collection("node").addClass('dull');
            c.removeClass("dull");
            c.neighborhood("edge").removeClass("dull");
            c.neighborhood("edge").addClass("edgeActive");
            c.neighborhood("edge").connectedNodes().removeClass("dull"); //当前节点的邻域边的边缘节点!
        })
        cy.on("tapend", "node", function (a) { //监听鼠标左键释放
            let c = a.target;
            cy.collection("edge").removeClass('dull');
            cy.collection("node").removeClass('dull');
            c.neighborhood("edge").removeClass("edgeActive");
            c.neighborhood("node").removeClass("nodeActive");
        })

        //线
        cy.on("mouseover", "edge", function (a) {
            let c = a.target;
            cy.collection("edge").removeClass("edgeActive");
            c.addClass("edgeActive")
        })
        cy.on("mouseout", "edge", function (a) {
            let c = a.target;
            c.removeClass("edgeActive")
        })
    </script>
</body>

</html>
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Cytoscape的Biological General Network (BiNGO)是用于生物学数据的功能注释和富集分析的插件。它可以帮助研究人员理解基因和蛋白质的功能以及其在细胞生物学过程中的作用。 如果在使用Cytoscape的BiNGO时没有生成图形,可能有以下几个原因: 1. 数据格式不符合要求:BiNGO要求输入节点和边的数据必须符合特定的格式要求。如果输入的网络数据格式不正确,BiNGO将无法正确解析并生成相关图形。 解决方法:可以检查输入的数据是否符合BiNGO的格式要求,例如节点和边的命名是否正确,是否缺少必要的数据等。可以参考Cytoscape和BiNGO的官方文档以获取正确的数据格式要求。 2. 数据过于庞大:如果输入的网络数据非常庞大,可能会导致BiNGO无法在合理的时间内生成图形。这可能是由于计算资源不足或不够强大。 解决方法:可以尝试在更高性能的计算机上运行BiNGO,或者在运行BiNGO之前对数据进行筛选和简化,以减少计算的复杂性。 3. 插件安装错误或版本不兼容:如果BiNGO插件的安装过程出错或与Cytoscape的版本不兼容,可能会导致无法生成图形。 解决方法:可以尝试重新安装BiNGO插件,并确保已安装的插件版本与Cytoscape的版本相匹配。 总之,如果Cytoscape的BiNGO插件无法生成图形,可以检查输入数据的格式是否正确,考虑数据的大小和计算资源,以及插件的安装情况和版本兼容性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值