3

I have a Networkx graph like the following image (image source)

enter image description here

I perform edge attacks and observe the change in values at the node of the resulting subgraph.

Example, If I attack edge (a,2): edge (a, 2) and (2, 1) will be removed. To explain a bit, when edge (a, 2) is attacked the node 2 will have a degree < 2. So the edge that's connected to node 2 is also removed.

enter image description here

The above attack results in a subgraph

enter image description here

Each time an edge is attacked, the value of the terminal node labelled e observed over time changes. Let's say I perform 5 (attack = 5) attacks, I have a time x attack matrix (time=25, attack=5) that stores the time-series data of node e.

I would like to ask for suggestions on how to visualize the effect of these attacks on the value of node e changing over time. EDIT:

What information do you want to be able to see or identify from your visualizations?

I want to see the attack on which edge has the maximum effect on the time course value observed at e. We could imagine this to be a transportation network and the values at node reflect the amount of a product that has reached the location/node. From the source node b, the goods are transported to target node e. The observation made is the change in node values after an edge is attacked and no observation of the edge value is available.

Please find the code that is used to attack edges

import networkx as nx
import matplotlib.pyplot as plt


def attack(G):
    print(G.edges())

    for i, edge in enumerate(G.edges()):
        no_attack = [(6, 9), (3, 16)]
        if edge not in no_attack:
            data = {}
            print(f'attacking edge {edge}')

            H = G.copy()

            # attack an edge
            H.remove_edges_from(ebunch=[edge])

            n = len(G.nodes)
            retain_node_ids = [9, 3]
            H.add_edges_from([(u, v) for u in retain_node_ids for v in (n+1, n+2)])

            # remove nodes with degree < 2
            H = nx.k_core(H, k=2)
            H.remove_nodes_from([n + 1, n + 2])
            # graph_utils_py.draw_graph3d(H, fig=2, show=True)

            # H = nx.convert_node_labels_to_integers(H, first_label=1, ordering='default', label_attribute=None)

            # delete connected nodes and edges
            diff_nodes = set(G.nodes()).difference(H.nodes())
            diff_edges = {e for e in G.edges() for n in diff_nodes if n in e}

            print(f"deleting connected nodes {diff_nodes} ...")
            print(f"deleting connected edges {diff_edges} ...")

            data['diff_nodes'] = list(diff_nodes)
            data['diff_edges'] = list(diff_edges)
            data['edge'] = edge


if __name__ == '__main__':
    n = 20
    G = nx.gnm_random_graph(n=20, m=30, seed=1)
    # nx.draw(G, with_labels=True)
    # plt.show()

    retain_node_ids = [11, 4]
    G.add_edges_from([(u, v) for u in retain_node_ids for v in (n, n + 1)])

    G = nx.k_core(G, k=2)
    G.remove_nodes_from([n, n + 1])
    # nx.draw(G, with_labels=True)
    # plt.show()

    G = nx.convert_node_labels_to_integers(G, first_label=1, ordering='default', label_attribute=None)
    nx.draw(G, with_labels=True)
    plt.show()

    attack(G)

EDIT2: The answer posted below suggests visualizing the edge attacks by varying the opacity and setting different color schemes. Unfortunately, this doesn't help. One has to create a different image for each attack. I am still looking for other suggestions.

EDIT3: Clarifying a bit more on what exactly I want to visualize to keep things simple.

I'm looking for an interactive graph like the following.

enter image description here

One could click the edge that is attacked and the LHS plot will display the observation made at the target node. The dashed lines are the edges that are affected (stored in variable diff_edges in the code) as a result of an attack on a given edge (stored in variable edge).

If there are overlaps in the edges that are affected after attacking a link, we could display it as multiple lines with the corresponding color mappings. An interactive graph will help the user pick and choose the edge attacks to compare the observation at node e. The edges that are attacked can be displayed by varying the opacity/ line style/ color. enter image description here

EDIT4: The answer posted below helps. But there is a problem when the impacted edges overlap.

Example, attack(H, (6, 4), color='red') attack(H, (5, 4), color='yellow')

gives

enter image description here

The colors overlap and it's hard to visualize. If we can draw the impacted edges next to each other, without overlapping, as shown in the image posted above in edit3 that will be good.

Natasha
  • 1,111
  • 5
  • 28
  • 66
  • Any suggestions? – Natasha Sep 04 '20 at 02:27
  • What information do you want to be able to see or identify from your visualizations? Can you elaborate on how the edge value changes? – templatetypedef Sep 05 '20 at 05:14
  • @templatetypedef Could you please have a look at the edit? – Natasha Sep 05 '20 at 05:21
  • @templatetypedef Please find the code updated in the original post for attacking edges – Natasha Sep 05 '20 at 06:36
  • @templatetypedef Any suggestions? – Natasha Sep 06 '20 at 01:49
  • So you want to visualize some sort of traffic from node `b` to `e` and the effect of an edge removal on it? – Azim Mazinani Sep 07 '20 at 09:01
  • @Azim Mazinani Yes, you are right – Natasha Sep 08 '20 at 00:54
  • Why not add a networkx arrows to the a -> b edges of interest? Perhaps even highlighting node and edges to be modified due to node attack red. – pygeek Sep 08 '20 at 14:17
  • @Natasha what are the values that you want to evaluate? I suppose you feed the graph with some input through node `b` and get some output result from node `e`, if so, it's important to know what happens to the input in each step before giving some answer. – Azim Mazinani Sep 11 '20 at 11:40
  • Hello @AzimMazinani We could use a numpy array with random values for both input `b` and output `e` . Please note: The input array (1D array of len(time)) which is a function of time, for node `b`, will remain the same for all attacks. For the same input, we observe the variation in output over time for each attack. Please let me know if this is not clear. Thanks a lot for the respone – Natasha Sep 11 '20 at 12:13
  • Cool. What I don't understand is that what happens to the input in each node. Let's say the random array is sent to `a` and is multiplied by some weight and then it broadcasts a copy to `2`, `1` and `c`, then they are multiplied by each node's weight, next they are sent to `d` and d gets their mean value and multiplies it by its weight by which eventually you have the output in `e`. do you want to show this process in one shot which is not a good idea or in multiple shots/plots? – Azim Mazinani Sep 11 '20 at 12:51
  • @AzimMazinani I don't want to observe what happens in the intermediate nodes. We could simply assume that the random array that we consider for the target node is the output of all the processes that you just mentioned :) I just want to see 1. which edge is attacked (stored in variable `edge` in the code posted above) 2. the edges that are removed as a result of the edge attack (stored in variable `diff_edges`). 3. how the result at the target node varies over time for each attack. I would prefer to have 2 plots: one for visualizing the edge attacks, the other for visualizing the output at e. – Natasha Sep 11 '20 at 13:32
  • @AzimMazinani For visualizing the edge attacks, I would prefer to visualize the attacks as a function of positions. i.e the source node can be some sort of an origin and the position of each edge attack could be obtained by computing the distance between the source node and the midpoint of the edge that is attacked. This will help in understanding attack at which position will have a major effect on output observed at e. Please let me know if you have other ideas. – Natasha Sep 11 '20 at 13:46
  • sorry @Natasha unfortunately it's still not clear to me at least :) maybe you can draw what you want to demonstrate and put it here. – Azim Mazinani Sep 12 '20 at 13:49
  • @AzimMazinani Please check my edit . I hope it's a bit clear now. – Natasha Sep 12 '20 at 15:11
  • @Natasha now it's a lot more clear! I've posted my answer. – Azim Mazinani Sep 12 '20 at 17:11

3 Answers3

1

You can first remove the attacked edge and see if it makes another neighboring node decommissioned (impacted edge), then after finding the right edges you draw them with a color specific to that attack. Here I drew the main attack in solid style and the impacted one in dashed style.

import matplotlib.pyplot as plt
import networkx as nx


H = nx.gnm_random_graph(n=8, m=9, seed=5)  # generate a random graph
H.add_edges_from([('In', 1), (5, 'Out')])  # adding input/output nodes
pos = nx.spring_layout(H, iterations=400)  # find good positions for nodes

edges = []
impacted_edges = []


def attack(G, edge, color):
    G.remove_edge(*edge)  # first remove the edge

    # check if another could be also impacted
    if G.degree[edge[0]] == 1:
        neighbor = [n for n in G.neighbors(edge[0])][0]
        impacted_edge = (edge[0], neighbor, color)

    elif G.degree[edge[1]] == 1:
        neighbor = [n for n in G.neighbors(edge[1])][0]
        impacted_edge = (edge[1], neighbor, color)

    else:
        impacted_edge = None

    if impacted_edge:
        impacted_edges.append(impacted_edge)

    edges.append((edge[0], edge[1], color))
    nx.draw_networkx_edges(
        H,
        edgelist=[edge],
        pos=pos,
        edge_color=color,
        style='solid',
        label=f'Attack {edge[0]}-{edge[1]}',
        width=4
    )
    G.add_edge(*edge)

# attack some edges
attack(H, (6, 4), color='red')
attack(H, (3, 6), color='blue')
attack(H, (1, 2), color='green')
attack(H, (5, 4), color='purple')

ax = plt.gca()
for edge in impacted_edges:
    ax.annotate('',
                xy=pos[edge[0]],
                xytext=pos[edge[1]],
                zorder=1,
                arrowprops=dict(
                    color=edge[2],
                    arrowstyle='-',
                    connectionstyle='arc3,rad=0.2',
                    lw=4,
                    linestyle='--'
                )
                )

H.remove_edges_from([(e[0], e[1]) for e in impacted_edges])
H.remove_edges_from([(e[0], e[1]) for e in edges])

nx.draw(H, pos, node_size=700, with_labels=True, node_color='gray', edge_color='gray')

plt.legend()
plt.show()

enter image description here

I hope you will find what you want in this answer.

Azim Mazinani
  • 705
  • 6
  • 11
  • Thank you. The next step would be to combine the nx graph with the data points for visualization. Please have a look at my edit – Natasha Sep 13 '20 at 02:47
  • 1
    You're welcome. Check the corrections. You can use [this](https://stackoverflow.com/questions/42818361/how-to-make-two-plots-side-by-side-using-python/42818547) in order to plot it next to your data points. – Azim Mazinani Sep 13 '20 at 14:20
  • Thanks a lot for the update. I honestly didn't have a clear picture when I posted this question. Thanks to your comments, it helped me a lot. I just see one problem with the current implementation, if the is an instance in which one has to plot two impacted edges (e.g 4-5 there is one colored in red, if another dashed line has to be added in yellow) the dashed lines may overlap – Natasha Sep 13 '20 at 14:48
  • 1
    Sure. In that case you can change the `connectionstyle='arc3,rad=0.2'` parameter to a greater or smaller `rad` (let's say 0.3) for one of the overlapped lines. – Azim Mazinani Sep 13 '20 at 15:02
0

Solution

Prior to deleting the node add arrows to the edges pointing towards node e, node and edges to be removed in green, then red, and repeat. Alphas can also be incorporated to represent min-max distances and how they change as the graph is modified.

References

NetworkX directed graph example: https://networkx.github.io/documentation/stable/auto_examples/drawing/plot_directed.html

NetworkX draw_networkx_edges arguments (includes arrow, color and alpha): https://networkx.github.io/documentation/stable/reference/generated/networkx.drawing.nx_pylab.draw_networkx_edges.html

pygeek
  • 7,356
  • 1
  • 20
  • 41
  • Unfortunately this will not be an easy option. If there are 50 edges in a graph one has to create 50 images with different alphas or a different color coding for the edges that are attacked – Natasha Sep 09 '20 at 02:33
  • @natasha what medium do you intend to publish to? – pygeek Sep 09 '20 at 04:15
  • I'd like to add these to the manuscript that I am writing. – Natasha Sep 09 '20 at 05:12
0

Would a Sankey Chart help?

A sankey diagram is a visualization used to depict a flow from one set of values to another. The snippet below is from Google charts, just as an example of how the graph flow visualization looks.

<html>
<body>
 <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>

<div id="sankey_multiple" style="width: 900px; height: 300px;"></div>

<script type="text/javascript">
  google.charts.load("current", {packages:["sankey"]});
  google.charts.setOnLoadCallback(drawChart);
   function drawChart() {
    var data = new google.visualization.DataTable();
    data.addColumn('string', 'From');
    data.addColumn('string', 'To');
    data.addColumn('number', 'Weight');
    data.addRows([
       [ 'Brazil', 'Portugal', 5 ],
       [ 'Brazil', 'France', 1 ],
       [ 'Brazil', 'Spain', 1 ],
       [ 'Brazil', 'England', 1 ],
       [ 'Canada', 'Portugal', 1 ],
       [ 'Canada', 'France', 5 ],
       [ 'Canada', 'England', 1 ],
       [ 'Mexico', 'Portugal', 1 ],
       [ 'Mexico', 'France', 1 ],
       [ 'Mexico', 'Spain', 5 ],
       [ 'Mexico', 'England', 1 ],
       [ 'USA', 'Portugal', 1 ],
       [ 'USA', 'France', 1 ],
       [ 'USA', 'Spain', 1 ],
       [ 'USA', 'England', 5 ],
       [ 'Portugal', 'Angola', 2 ],
       [ 'Portugal', 'Senegal', 1 ],
       [ 'Portugal', 'Morocco', 1 ],
       [ 'Portugal', 'South Africa', 3 ],
       [ 'France', 'Angola', 1 ],
       [ 'France', 'Senegal', 3 ],
       [ 'France', 'Mali', 3 ],
       [ 'France', 'Morocco', 3 ],
       [ 'France', 'South Africa', 1 ],
       [ 'Spain', 'Senegal', 1 ],
       [ 'Spain', 'Morocco', 3 ],
       [ 'Spain', 'South Africa', 1 ],
       [ 'England', 'Angola', 1 ],
       [ 'England', 'Senegal', 1 ],
       [ 'England', 'Morocco', 2 ],
       [ 'England', 'South Africa', 7 ],
       [ 'South Africa', 'China', 5 ],
       [ 'South Africa', 'India', 1 ],
       [ 'South Africa', 'Japan', 3 ],
       [ 'Angola', 'China', 5 ],
       [ 'Angola', 'India', 1 ],
       [ 'Angola', 'Japan', 3 ],
       [ 'Senegal', 'China', 5 ],
       [ 'Senegal', 'India', 1 ],
       [ 'Senegal', 'Japan', 3 ],
       [ 'Mali', 'China', 5 ],
       [ 'Mali', 'India', 1 ],
       [ 'Mali', 'Japan', 3 ],
       [ 'Morocco', 'China', 5 ],
       [ 'Morocco', 'India', 1 ],
       [ 'Morocco', 'Japan', 3 ]
    ]);

    // Set chart options
    var options = {
      width: 600,
    };

    // Instantiate and draw our chart, passing in some options.
    var chart = new google.visualization.Sankey(document.getElementById('sankey_multiple'));
    chart.draw(data, options);
   }
</script>
</body>
</html>

If you are looking for a python library, check out Sankey diagrams in Plotly

vvg
  • 1,010
  • 7
  • 25