plotting.py 13.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
import matplotlib
import matplotlib.pyplot as plt
import matplotlib.colors as mc
import networkx as nx
import numpy as np
import utils
import random
import time
import readline, sys

class PlotUI:

13
14
15
16
17
18
19
20
21
22
23
24
   nodesizes  = {'main'        : 700,
                 'mainpath'    : 800,
                 'mainstart'   : 800,
                 'mainstop'    : 800,
                 'mainopath'   : 700,
                 'mainupath'   : 800,
                 'normal'      : 350,
                 'normalstart' : 425,
                 'normalstop'  : 425,
                 'normalpath'  : 425,
                 'normalopath' : 350,
                 'normalupath' : 425}
25
26
27
28
29
30
31
32
33
34
35
36

   nodecolors  = {'main'       : '#cccccc',
                 'mainpath'    : '#77aaff',
                 'mainstart'   : '#44dd44',
                 'mainstop'    : '#dd7777',
                 'mainopath'   : '#cccc99',
                 'mainupath'   : '#4477cc',
                 'normal'      : '#dddddd',
                 'normalstart' : '#44dd44',
                 'normalstop'  : '#dd7777',
                 'normalpath'  : '#77aaff',
                 'normalopath' : '#cccc99',
37
                 'normalupath' : '#4477cc'}
38
39
40
41
42
43
44

   edgewidths = {'main'          : 4,
                 'mainpath'      : 5,
                 'mainaltpath'   : 5,
                 'mainopath'     : 4,
                 'mainupath'     : 5,
                 'mainoaltpath'  : 4,
45
                 'mainualtpath'  : 5,
46
47
48
49
50
51
52
                 'normal'        : 1,
                 'normalpath'    : 2.5,
                 'normalaltpath' : 2.5,
                 'normalopath'   : 2,
                 'normalupath'   : 2.5,
                 'normaloaltpath': 2,
                 'normalualtpath': 2.5,
Morten Knutsen's avatar
Morten Knutsen committed
53
                100000000        : 15,
54
55
56
                 10000000        : 10,
                  2488000        : 6,
                  1000000        : 3,
Morten Knutsen's avatar
Morten Knutsen committed
57
58
59
60
                   155000        : 1.75,
                   100000        : 1.5,
                    34010        : 1.0,
                    34000        : 1.9,
61
                     1984        : 0.75}
62
63
64

   edgecolors = {'main'           : '#bbbbbb',
                 'mainpath'       : '#77aaff',
65
                 'mainaltpath'    : '#77aaff',
66
67
68
                 'mainopath'      : '#aaaa77',
                 'mainupath'      : '#4477cc',
                 'mainoaltpath'   : '#aaaa77',
69
                 'mainualtpath'   : '#2255aa',
70
71
                 'normal'         : '#dddddd',
                 'normalpath'     : '#77aaff',
72
                 'normalaltpath'  : '#77aaff',
73
74
75
                 'normalopath'    : '#aaaa77',
                 'normalupath'    : '#4477cc',
                 'normaloaltpath' : '#bbbb88',
76
                 'normalualtpath' : '#2255aa'}
77
78
79
80
81
82
83

   edgestyles = {'main'           : 'solid',
                 'mainpath'       : 'solid',
                 'mainaltpath'    : 'dotted',
                 'mainopath'      : 'solid',
                 'mainupath'      : 'solid',
                 'mainoaltpath'   : 'dotted',
84
                 'mainualtpath'   : 'dotted',
85
86
87
88
89
90
                 'normal'         : 'solid',
                 'normalpath'     : 'solid',
                 'normalaltpath'  : 'dotted',
                 'normalopath'    : 'solid',
                 'normalupath'    : 'solid',
                 'normaloaltpath' : 'dotted',
91
                 'normalualtpath' : 'dotted'}
92
93
94
95
96
97
98
99
100


   areacolors = [(0.65,0.5,0,1), (0.5,0.75,0.35,1), (0.28,0.8,0.68,1),
                 (0.7,0.5,0.95,1), (0.35,0.5,0.7,1), (0.7,0.9,0.35,1),
                 (0.6,0.8,0.2,1), (0.9,0.7,0.6,1), (0.4,0.5,0.4,1),
                 (0.8,0.5,0.8,1), (0.45,0.65,0.55,1), (0.75,0.75,0.9,1),
                 (0.3,0.4,0.8,1), (0.1,0.9,0.85,1), (0.35,0.83,0.68,1),
                 (0.3,0.83,0.69,1), (0.95,0.95,0.8,1), (0.14,0.78,0.87,1),
                 (0.74,0.23,0.95,1)]
101

102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
   def __init__(self, command):

      self.has_plotted = False
      self.command = command
      self.plottednodes = {}

   def picktest(self, event):
      #print "Picker fired, details:"

      #print " Index: %s"      % (event.ind)
      #print " (x,y): (%s,%s)" % (event.mouseevent.xdata,
      #                           event.mouseevent.ydata)
      #print "button: %s"      % (event.mouseevent.button)

      if not self.command: return

      if not event.artist in self.plottednodes: return
119

120
121
122
123
124
125
126
127
128
129
130
      nodes = self.plottednodes[event.artist]

      for i in event.ind:
         self.command.fromui(nodes[i])

   def savefig(self, fname, load=False):

      f = plt.gcf()
      f.set_figwidth(8)
      f.set_figheight(13)
      plt.subplot(111)
Morten Knutsen's avatar
Morten Knutsen committed
131
132
133
134
135
      plt.axis("off")
      if load:
         plt.savefig(fname, facecolor='#000000', dpi=72)
      else:
         plt.savefig(fname, dpi=72)
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154

      return

   def clear(self):
      plt.clf()

   def plot(self, graph, data, opacity=1, areagroups=False, anycast=False,
            edge_cmap=False, edge_capa=False):
      ax = plt.gca()

      interactive = matplotlib.is_interactive()
      ci = 0

      for (nodes, type) in data['nodegroups']:

         nodecolors = PlotUI.nodecolors[type]
         nodealpha = self._get_alpha(type, opacity)

         if edge_cmap:
Morten Knutsen's avatar
Morten Knutsen committed
155
            nodecolors = '#444488'
156
            nodealpha = 0.9
157

158
159
160
161
162
163
164
165
166
167
168
         if areagroups:

            areas = [data['areagroups'][nodes[i]] for i in range(len(nodes))]

            for a in areas:
               if not a in PlotUI.nodecolors:
                  if ci < len(PlotUI.areacolors):
                     PlotUI.nodecolors[a] = PlotUI.areacolors[ci]
                     ci += 1
                  else:
                     PlotUI.nodecolors[a] = random.choice(PlotUI.areacolors)
169

170
171
172
173
174
            nodecolors = [PlotUI.nodecolors[data['areagroups'][nodes[i]]]
                          for i in range(len(nodes))]

         elif anycast:

175
            ci = 0
176
            for group in data['acnodes'] + ['multi']:
177
178
179
180
181
               if ci < len(PlotUI.areacolors):
                  PlotUI.nodecolors[group] = PlotUI.areacolors[ci]
                  ci += 1
               else:
                  PlotUI.nodecolors[group] = random.choice(PlotUI.areacolors)
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213

            nodecolors = []
            for i in range(len(nodes)):
               current_node = nodes[i]
               current_group = data['acgroups'][current_node]
               if len(current_group) > 1:
                  color = PlotUI.nodecolors['multi']
                  color = (color[0], color[1], color[2], 0.3)
                  nodecolors.append(color)
               else:
                  color = PlotUI.nodecolors[current_group[0]]
                  color = (color[0], color[1], color[2], 0.3)
                  if current_node in data['acnodes']:
                     color = (color[0], color[1], color[2], 1)
                  nodecolors.append(color)

         nodec = nx.draw_networkx_nodes(graph, pos=data['pos'],
                                nodelist=nodes,
                                node_size=PlotUI.nodesizes[type],
                                node_color=nodecolors,
                                alpha = nodealpha,
                                hold=True)


         self.plottednodes[nodec] = nodes
         nodec.set_picker(True)
         #self.nodec.set_urls(nodes)


      for (edges, type) in data['edgegroups']:

         edgecolors = PlotUI.edgecolors[type]
214

215
216
217
218
         #print "colors:", edgecolors

         if nx.__version__ > "0.36":
            edgecolors = [PlotUI.edgecolors[type]] * len(edges)
219

220
221
222
223
224
225
         ealpha = self._get_alpha(type, opacity)
         if anycast:
            ealpha = 0.5

         if edge_cmap != False:
            assert edge_capa != False
226
227
228
229
230
231
232
233
234
235
            ccm = {
               'red'  :  ((0., 0., 0.), (0.005, 0.0, 0.0),
                          (0.01, 0.2, 0.2), (0.1, 0., 0.),
                          (0.6, 1, 1),
                          (0.7, 0.75, 0.75), (0.8, 0.9, 0.9),
                          (1., 1., 1.)),
               'green':  ((0., 0., 0.), (0.01, 0., 0.),
                          (0.05, 0.3, 0.3), (0.1, 0.75, 0.75),
                          (0.3, 1., 1.),
                          (0.6, 0.75, 0.75), (1., 0., 0.)),
Morten Knutsen's avatar
Morten Knutsen committed
236
237
               'blue' :  ((0., 0.45, 0.45), (0.005, 0.55, 0.55),
                          (0.05, 0.8, 0.8), (0.10, 1., 1.),
238
239
240
                          (0.25, 0., 0.), (1., 0., 0.))
               }
            my_cmap = mc.LinearSegmentedColormap('my_colormap', ccm, 1024)
241
242
            ealpha = 0.7
            f = plt.gcf()
Morten Knutsen's avatar
Morten Knutsen committed
243
            f.set_facecolor('#000000')
244
245
246
            edgecolors = [max(edge_cmap[(edges[i][0], edges[i][1])],
                              edge_cmap[(edges[i][1], edges[i][0])])
                          for i in range(len(edges))]
247
248
249
250
            try:
               edgewidths = [PlotUI.edgewidths[edge_capa[(edges[i][0], edges[i][1])]]
                             for i in range(len(edges))]
            except KeyError:
251
               print("Error: Unknown or missing capacity information provided to plot command")
252
253
               return

254
255
256
257
            self.edgec = nx.draw_networkx_edges(graph, pos=data['pos'],
                                edgelist=edges,
                                width=edgewidths,
                                edge_color=edgecolors,
258
259
260
                                edge_cmap=my_cmap,
                                edge_vmin=0.005,
                                edge_vmax=1.0,
261
262
263
264
265
266
267
268
269
270
271
272
                                style=PlotUI.edgestyles[type],
                                alpha=ealpha,
                                arrows=False,
                                hold=True)
         else:
            self.edgec = nx.draw_networkx_edges(graph, pos=data['pos'],
                                edgelist=edges,
                                width=PlotUI.edgewidths[type],
                                edge_color=edgecolors,
                                style=PlotUI.edgestyles[type],
                                alpha=ealpha,
                                arrows=False,
273
                                hold=True)
274
275
276

      if 'labels' in data:
         color = 'k'
277
         fsize = 7.5
278
         if edge_cmap:
Morten Knutsen's avatar
Morten Knutsen committed
279
            color = '#bbbbbb'
280
            fsize = 8.5
281

282
283
         self.nlabelc = nx.draw_networkx_labels(graph, pos=data['pos'],
                                 labels=data['labels'],
Morten Knutsen's avatar
Morten Knutsen committed
284
                                 font_size=fsize,
285
286
287
                                 font_color=color,
                                 alpha=1,
                                 hold=True)
288

289
290
291
292
      if 'edgelabels' in data and not edge_cmap:
         self.elabelc = self._plot_edge_labels(graph,
                                               data['edgelabels'],
                                               pos=data['pos'])
293
      plt.axis("off")
294
295
296
297
298
299
      plt.subplots_adjust(0,0,1,1)
      ax.set_xbound(-10, 210)
      ax.set_ybound(0, 200)
      plt.xlim(-10, 210)
      plt.ylim(0,200)

300

301
302
303
304
      f = plt.gcf()
      if not edge_cmap:
         f.set_facecolor('w')
      else:
Morten Knutsen's avatar
Morten Knutsen committed
305
         cb = plt.colorbar(self.edgec, shrink=0.15,
306
307
                           fraction=0.10, pad=0)
         for t in cb.ax.get_yticklabels():
Morten Knutsen's avatar
Morten Knutsen committed
308
            t.set_color('#bbbbbb')
309
310
311

         cb.set_label("Link utilization", color='#bbbbbb')
      fm = plt.get_current_fig_manager()
312
313

      if (not self.has_plotted) and interactive:
314
         f.set_figheight(13)
315
316
317
         f.set_size_inches(8,13)
         if matplotlib.get_backend() == 'TkAgg':
            maxh = fm.window.winfo_screenheight() - 60
318
            fm.window.minsize(600,maxh)
319
320
321
      if interactive:
         fm.set_window_title("PyMetric - " + data['title'])
         f.canvas.mpl_connect('pick_event', self.picktest)
322
      plt.draw()
323
324
325
326
327
328
329
330
331
      self.has_plotted = True

   def _get_alpha(self, type, opacity):
      if not (type.endswith('path') \
                 or type.endswith('start') \
                 or type.endswith('stop')):
         return opacity
      else:
         return 1
332

333
334
335
336
   def _plot_edge_labels(self, G, edgelabels, pos):
      from math import sqrt

      lpos = []
337
      for (u,v,w) in G.edges(data=True):
338
339
340

         (x1, y1) = pos[u]
         (x2, y2) = pos[v]
341

342
343
         x_diff = (x2 - x1)
         y_diff = (y2 - y1)
344

345
346
347
348
349
         d = sqrt( x_diff**2 + y_diff**2 )

         x = (x1+x2) / 2
         y = (y1+y2) / 2

Morten Knutsen's avatar
Morten Knutsen committed
350
         if d < 70 and G[v][u]['weight'] == w['weight']:
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
            pass

         else:
            wy = (9.0/d)*y_diff
            wx = (9.0/d)*x_diff

            if abs(wy) > 7:
               if wy < 0:
                  wy = -7
               else:
                  wy = 7
            if abs(wx) > 10:
               if wx < 0:
                  wx = -10
               else:
                  wx = 10
367

368
369
370
371
372
373
374
375
            if x_diff == 0:
               y = y1 + wy
            elif y_diff == 0:
               x = x1 + wx
            else:
               x = x1 + wx
               y = y1 + wy

376

377
378
379


         lpos.append((x,y))
380

381
382
      ax = plt.gca()
      text_items = {}
383

384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
      for (i, label, bold) in edgelabels:
         label = str(label)
         (x,y) = lpos[i]
         fw = 'normal'
         fs = 8
         if bold:
            fs = 10.5
            fw = 'bold'

         color = '#662222'

         t = ax.text(x, y,
                     label,
                     size=fs,
                     color=color,
                     family="sans-serif",
                     weight=fw,
                     horizontalalignment='center',
                     verticalalignment='center',
                     transform = ax.transData)
         text_items[i] = t

      return text_items