How to have and declare/define array of tuple[ string , seq[ array[2,string] ] ]
Illustration is
var
a : seq[tuple[ string , seq[array[ 2, string]] ] ]
a[0] = [ "foo", [ ["hello", "foo"], ["foo", "bar" ] ] ]
a[1] = [ "bar", [ ["hello", "world"], ["hello", bar"] ] ]
a[2] = [ "hello", [ ["foo","bar"], ["hello","world"], ["bar", "baz"] ] ]
.
.
.
a[n] =
Tried rather long in this variations, e.g.
a = newSeqOfCap[ (string, newSeqOfCap[ array[ 2, string]](40) ) ](9)
all just end with no avail
Please guide the correct way. Thanks in advance for sincere help
You need to use newSeq, not newSeqOfCap. The latter only allocates the space for the sequence, not actually put anything in there for you to modify.
var a = newSeq[(string, seq[array[2, string]])](n)
a[0] = ("foo", #[["hello", "foo"], ["foo", "bar"]])
a[1] = ("bar", #[["hello", "world"], ["hello", "bar"]])
a[2] = ("hello", #[["foo", "bar"], ["hello", "world"], ["bar", "baz"]])
.
.
.
a[n] = ...
I have a Networkx graph like the following image (image source)
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.
The above attack results in a subgraph
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.
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.
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
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.
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()
I hope you will find what you want in this answer.
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
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
I have a matrix that I want to split up into two. The two new are sort of tangled together, but I do have a "start" and "stop" array indicating what rows belong to each new matrix.
I have given a small example below including my own solution which I do not find satisfying.
Is there a smarter way of splitting the matrix?
Note that there is a certain periodicity in this example, which in not the case in the real matrix.
import numpy as np
np.random.seed(1)
a = np.random.normal(size=[20,2])
print(a)
b_start = np.array([0, 5, 10, 15])
b_stop = np.array([2, 7, 12, 17])
c_start = np.array([2, 7, 12, 17])
c_stop = np.array([5, 10, 15, 20])
b = a[b_start[0]:b_stop[0], :]
c = a[c_start[0]:c_stop[0], :]
for i in range(1, len(b_start)):
b = np.append(b, a[b_start[i]:b_stop[i], :], axis=0)
c = np.append(c, a[c_start[i]:c_stop[i], :], axis=0)
print(b)
print(c)
You can use fancy indexing functionality of numpy.
index_b = np.array([np.arange(b_start[i], b_stop[i]) for i in range(b_start.size)])
index_c = np.array([np.arange(c_start[i], c_stop[i]) for i in range(c_start.size)])
b = a[index_b].reshape(-1, a.shape[1])
c = a[index_c].reshape(-1, a.shape[1])
This will give you the same output.
Test run:
import numpy as np
np.random.seed(1)
a = np.random.normal(size=[20,2])
print(a)
b_start = np.array([0, 5, 10, 15])
b_stop = np.array([2, 7, 12, 17])
c_start = np.array([2, 7, 12, 17])
c_stop = np.array([5, 10, 15, 20])
index_b = np.array([np.arange(b_start[i], b_stop[i]) for i in range(b_start.size)])
index_c = np.array([np.arange(c_start[i], c_stop[i]) for i in range(c_start.size)])
b = a[index_b].reshape(-1, a.shape[1])
c = a[index_c].reshape(-1, a.shape[1])
print(b)
print(c)
Output:
[[ 1.62434536 -0.61175641]
[-0.52817175 -1.07296862]
[ 1.46210794 -2.06014071]
[-0.3224172 -0.38405435]
[-1.10061918 1.14472371]
[ 0.90159072 0.50249434]
[-0.69166075 -0.39675353]
[-0.6871727 -0.84520564]]
[[ 0.86540763 -2.3015387 ]
[ 1.74481176 -0.7612069 ]
[ 0.3190391 -0.24937038]
[ 1.13376944 -1.09989127]
[-0.17242821 -0.87785842]
[ 0.04221375 0.58281521]
[ 0.90085595 -0.68372786]
[-0.12289023 -0.93576943]
[-0.26788808 0.53035547]
[-0.67124613 -0.0126646 ]
[-1.11731035 0.2344157 ]
[ 1.65980218 0.74204416]]
I did 100 runs of two approaches, running time is:
0.008551359176635742#python for loop
0.0034341812133789062#fancy indexing
And 10000 runs:
0.18994426727294922#python for loop
0.26583170890808105#fancy indexing
Congratulations on using np.append correctly. A lot of posters have problems with it.
But it is faster to collect values in a list, and do one concatenate. np.append makes a whole new array each time; list append just adds a pointer to the list in-place.
b = []
c = []
for i in range(1, len(b_start)):
b.append(a[b_start[i]:b_stop[i], :])
c.append(a[c_start[i]:c_stop[i], :])
b = np.concatenate(b, axis=0)
c = np.concatenate(c, axis=0)
or even
b = np.concatenate([a[i:j,:] for i,j in zip(b_start, b_stop)], axis=0)
The other answer does
idx = np.hstack([np.arange(i,j) for i,j in zip(b_start, b_stop)])
a[idx,:]
Based on previous SO questions I expect the two approaches to have about the same speed.
I have a map where a key holds multiple values
datamap = [ 'Antenna Software':[ 'Salarpuria', 'Cessna', 'Vrindavan Tech', 'Alpha Center' ],
'Ellucian':[ 'Malvern', 'Ellucian House', 'Residency Road'] ]
here i need to alphabetically sort the values
datamap = [ 'Antenna Software':[ 'Alpha Center', 'Cessna', 'Salarpuria', 'Vrindavan Tech' ],
'Ellucian':[ 'Ellucian House', 'Malvern', 'Residency Road' ] ]
how to do it in groovy way?
You should be able to do:
def sortedMap = datamap.sort().collectEntries { k, v ->
[ k, v.sort( false ) ]
}
If you're not bothered about sorting the keys of the map, you can get rid of the initial sort():
def sortedMap = datamap.collectEntries { k, v ->
[ k, v.sort( false ) ]
}
Explanation of sort( false ):
By default, the sort method in Groovy changes the original list, so:
// Given a List
def a = [ 3, 1, 2 ]
// We can sort it
def b = a.sort()
// And the result is sorted
assert b == [ 1, 2, 3 ]
// BUT the original list has changed too!
assert a != [ 3, 1, 2 ] && a == [ 1, 2, 3 ]
So if you pass false to sort, it leaves the original list alone, and just returns the sorted list:
// Given a List
def a = [ 3, 1, 2 ]
// We can sort it (passing false)
def b = a.sort( false )
// And the result is sorted
assert b == [ 1, 2, 3 ]
// AND the original list has remained the same
assert a == [ 3, 1, 2 ]