tvaLib
vis.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 # tvaLib Copyright (c) 2012-2016 Paul G. St-Aubin
3 # Ecole Polytechnique de Montreal, McGill University
4 # Python 2.7; (dt) Spyder Windows 10 64-bit; ipython Ubuntu 15.04 64-bit
5 
9 import os, sys
10 import math as m
11 from copy import deepcopy
12 from random import random as random
13 from random import choice as random_choice
14 from inspect import getfile as inspect_getfile
15 from inspect import currentframe as inspect_currentframe
16 from datetime import timedelta
17 
18 try: import numpy as np
19 except ImportError: raise Exception, [0101, 'Numpy is not installed.']
20 try:
21  import matplotlib as mpl
22  import matplotlib.pyplot as plt
23  import matplotlib.pylab as plb
24  import matplotlib.image as mpimg
25  from mpl_toolkits.mplot3d import Axes3D
26 except ImportError: raise Exception, [106, 'Matplotlib could not be found/imported.']
27 
28 if __name__ == '__main__':
29  print('Visualisation library loaded directly.')
30  sys.path.insert(0,os.path.dirname(os.path.dirname(os.path.abspath(inspect_getfile(inspect_currentframe())))))
31 import include.local as tvaLocal
32 import lib.tools as tvaLib
33 
34 
35 
36 
39 def show():
40  ''' This is a matplotlib shorcut. '''
41  plt.show()
42 
43 
44 def plotSettings(style='', size=16, weight='normal', family='Arial', tickLabelSize=None, tickLength=4, verbose=0):
45  ''' Set matplotlib plotting settings.
46 
47  For styles, see:
48  https://tonysyu.github.io/raw_content/matplotlib-style-gallery/gallery.html
49  Recommend using "bmh"
50  '''
51 
52 
53  if(style): plt.style.use(style)
54 
55  if(not tickLabelSize):
56  tickLabelSize = int(round(size*0.8))
57 
58  if(family): font = {'family' : family, 'weight' : weight, 'size' : size}
59  else: font = {'family' : family, 'weight' : weight, 'size' : size}
60 
61  mpl.rc('xtick', labelsize=tickLabelSize)
62  mpl.rc('xtick.major', size=tickLength)
63  mpl.rc('ytick', labelsize=tickLabelSize)
64  mpl.rc('ytick.major', size=tickLength)
65  mpl.rc('font', **font)
66  if(verbose < 2 and mpl.__version__ == '1.3.1'):
67  mpl.rc('figure', max_open_warning=100)
68  return {'style':style, 'size':size, 'weight':weight, 'family':family, 'tickLabelSize':tickLabelSize}
69 
70 
71 def close(fig='all'):
72  plt.close(fig)
73  return True
74 
75 
76 
77 def Save(figures, results_path='', fig_dpi=300, fig_format='png', fig_lan_suffix='', supressClose=False, fig_resize=None, fig_bg_colour='', verbose=0):
78  ''' Save list of figures. '''
79  if(results_path and not os.path.exists(results_path)): os.makedirs(results_path)
80  if(not isinstance(figures, list)): figures = [figures]
81  if(type(fig_lan_suffix) == str):
82  if(fig_lan_suffix): fig_lan_suffix = '_'+fig_lan_suffix
83  else: fig_lan_suffix = ''
84 
85  for figure in figures:
86  if(type(figure) == plt.Figure):
87  #Determine figure format
88  try: f_format = figure.forceFormat
89  except: f_format = fig_format
90  #Determine dpi
91  try: f_dpi = figure.forceDPI
92  except: f_dpi = fig_dpi
93  #Resize if necessary
94  if(fig_resize):
95  try: figure.set_size_inches(fig_resize[0],fig_resize[1])
96  except: tvaLib.printWarning('Incorrect figure resize specification. It should be in inches and look like: [newX.float,newY.float]', indent=4)
97 
98  try:
99  if(figure.make3D_movie):
100  for ii in xrange(0,360,5):
101  figure.pass_ax.view_init(elev=15., azim=ii)
102  if(fig_bg_colour): figure.savefig(os.path.join(results_path, tvaLib.Parse.clean_file_name(figure.get_label())+'_movie'%ii+'.png'), dpi=f_dpi, format='png', facecolor=fig_bg_colour, bbox_inches='tight')
103  else: figure.savefig(os.path.join(results_path, tvaLib.Parse.clean_file_name(figure.get_label())+'_movie'%ii+'.png'), dpi=f_dpi, format='png', transparent=True, bbox_inches='tight')
104  continue
105  except: pass
106 
107  #Save figure
108  try:
109  if(fig_bg_colour): figure.savefig(os.path.join(results_path, tvaLib.Parse.clean_file_name(figure.get_label())+fig_lan_suffix+'.'+f_format), dpi=f_dpi, format=f_format, facecolor=fig_bg_colour, bbox_inches='tight')
110  else: figure.savefig(os.path.join(results_path, tvaLib.Parse.clean_file_name(figure.get_label())+fig_lan_suffix+'.'+f_format), dpi=f_dpi, format=f_format, transparent=True, bbox_inches='tight')
111  except IOError: tvaLib.printWarning('Figure "'+tvaLib.Parse.clean_file_name(figure.get_label())+'" could not be saved because it is locked down by another process and will be skipped.', indent=4)
112  except Exception:
113  if(verbose >= 2): tvaLib.grabError()
114  tvaLib.printWarning('There was a problem saving the figure "'+figure.get_label()+'" (use verbose>=2 to print traceback).', indent=4)
115  if(not supressClose): plt.close(figure)
116  return True
117 
118 def plots(X, Y, legend_labels=None, colours=['b','r','g','orange','k','m','y'], linewidths=[1], linestyles=['-'], markers = [''], x_bounds=None, y_bounds=None, x_label='', y_label='', local=None, fig_name='Generic plots', figsize=[15.0,12.0]):
119  ''' Plot generic data series.
120 
121  Input:
122  ======
123  X is an array of X coordinates
124  Y is an array of Y coordinates
125 
126  X and Y can also be passed as a list of multiple series to plot [[Y1,Y2,...],[Y1,Y2,...],...]
127  '''
128  fig = plt.figure(fig_name, figsize=(figsize[0], figsize[1]))
129  if(not local): local = tvaLocal.Local()
130  if(len(X) != len(Y)): return False
131 
132  # Enable multiplotting
133  if(type(X[0]) is not list): X = [X]
134  if(type(Y[0]) is not list): Y = [Y]
135 
136 
137  rects=[]
138  for x,y,Ix in zip(X,Y,range(len(X))):
139  if(Ix >= len(colours)): colour = (random(),random(),random())
140  else: colour = colours[Ix]
141  if(Ix >= len(linestyles)): linestyle = random_choice(['-', '-', '--', ':','-.'])
142  else: linestyle = linestyles[Ix]
143  if(Ix >= len(markers)): marker = random_choice(['', '', 'o', 'x', 'D'])
144  else: marker = markers[Ix]
145  if(Ix >= len(linewidths)): linewidth = 1
146  else: linewidth = linewidths[Ix]
147  try: rects.append(plt.plot(x, y, linewidth=linewidth, color=colour, linestyle=linestyle, marker=marker, label=legend_labels[Ix]))
148  except: plt.plot(x, y, linewidth=linewidth, color=colour, linestyle=linestyle, marker=marker)
149 
150 
151  ax = plb.gca()
152  if(x_bounds and type(x_bounds) == list): ax.set_xlim(x_bounds)
153  if(y_bounds and type(y_bounds) == list): ax.set_ylim(y_bounds)
154  if(x_label): ax.set_xlabel(x_label)
155  if(y_label): ax.set_ylabel(y_label)
156 
157 
158  ax.legend(handles=[x[0] for x in rects], loc='lower right', prop={'size':16})
159 
160  return fig
161 
162 
163 
164 def Histo(data, enableBars=True, dist_type='freq', enableHalfStepOffset=True, halfStepSign=1, legendLabels='', linewidth=2, spacing_modifier=1, x_bounds=None, y_bounds=None, x_label='', y_label='', force_one_label_per_bar=False, local=None, fig_name='Generic histogram', figsize=[15.0,12.0]):
165  ''' Plot generic histogram.
166 
167  Input:
168  ======
169  data: a histo type object returned by np.histogram(), i.e.
170  (array(frequencies), array(bins)). Optionally, multiple histos
171  can be passed as a list.
172 
173  enableBars==True: Plots data as a bar graph if true (disabled for CDFs)
174  spacing_modifier: This agjusts the spacing between bar groups. set to one to have one bar length between groups, or 0 to remove
175 
176  dist_type=='freq': Plot as a frequency
177  dist_type=='pdf': Plot as a probability distribution function
178  '''
179  fig = plt.figure(fig_name, figsize=(figsize[0], figsize[1]))
180  if(not local): local = tvaLocal.Local()
181 
182  # Enable multiplotting
183  if(type(data) is not list): data = [data]
184 
185 
186  rects = []
187  i = 0
188  for histo in data:
189  if(not histo): continue
190  colour=(i/float(len(data)),0,1-i/float(len(data)))
191 
192  # Handle data aggregation
193  histo = [x for x in histo]
194  if(dist_type!='freq' and (sum(histo[0]) < 0.98 or sum(histo[0]) > 1.02)): histo[0] = [x/float(sum(histo[0])) for x in histo[0]]
195  if(dist_type=='cdf'): histo[0] = list(tvaLib.Math.running_sum(histo[0]))
196 
197  # Plotting
198  try:
199  if(enableBars and dist_type!='cdf'):
200  if(type(data) is list and len(data) >= 2): width = (histo[1][2]-histo[1][0])/2.0/float(len(data)+spacing_modifier)
201  else: width = (histo[1][2]-histo[1][0])/2.0
202  if(enableHalfStepOffset): halfStepOffset = halfStepSign*(histo[1][2]-histo[1][0])/4.0
203  else: halfStepOffset = 0
204  rects.append(plt.bar([x+width*i+halfStepOffset for x in histo[1][0:-1]], histo[0], width=width, color=colour))
205  else:
206  rects.append(plt.plot(histo[1][0:-1], histo[0], zorder=20, color=colour, linewidth=linewidth))
207  except: pass
208  i += 1
209 
210 
211  ax = plb.gca()
212  if(x_bounds and type(x_bounds) == list): ax.set_xlim(x_bounds)
213  if(y_bounds and type(y_bounds) == list): ax.set_ylim(y_bounds)
214  if(x_label): ax.set_xlabel(x_label)
215  if(y_label): ax.set_ylabel(y_label)
216  else:
217  if(dist_type=='freq'): ax.set_ylabel(local['vis_hist_frequency'])
218  elif(dist_type=='cdf'): ax.set_ylabel(local['vis_hist_y_cdf'])
219  else: ax.set_ylabel(local['vis_hist_y_pdf'])
220  if(force_one_label_per_bar): ax.set_xticks(histo[1][0:-1])
221 
222  #Legend
223  if(legendLabels):
224  if(type(legendLabels) is not list): legendLabels = [legendLabels]
225  if(dist_type=='cdf'): ax.legend([x[0] for x in rects], legendLabels, loc=4)
226  else: ax.legend([x[0] for x in rects], legendLabels)
227 
228  return fig
229 
230 
231 def plotWithArrows(x, y, aspace=5, color='b', alpha=1.0, zorder=1, **kwargs):
232  ''' Plot spline with arrow heads
233  https://stackoverflow.com/questions/8247973/how-do-i-specify-an-arrow-like-linestyle-in-matplotlib
234  '''
235 
236  # r is the distance spanned between pairs of points
237  r = [0]
238  for i in range(1,len(x)):
239  dx = x[i]-x[i-1]
240  dy = y[i]-y[i-1]
241  r.append(np.sqrt(dx*dx+dy*dy))
242  r = np.array(r)
243 
244  # rtot is a cumulative sum of r, it's used to save time
245  rtot = []
246  for i in range(len(r)): rtot.append(r[0:i].sum())
247  rtot.append(r.sum())
248 
249  arrowData = [] # will hold tuples of x,y,theta for each arrow
250  arrowPos = 0 # current point on walk along data
251  rcount = 1
252  while arrowPos < r.sum():
253  x1,x2 = x[rcount-1],x[rcount]
254  y1,y2 = y[rcount-1],y[rcount]
255  da = arrowPos-rtot[rcount]
256  theta = np.arctan2((x2-x1),(y2-y1))
257  ax = np.sin(theta)*da+x1
258  ay = np.cos(theta)*da+y1
259  arrowData.append((ax,ay,theta))
260  arrowPos+=aspace
261  while arrowPos > rtot[rcount+1]:
262  rcount+=1
263  if(arrowPos > rtot[-1]):
264  break
265 
266  arrows = []
267  # could be done in above block if you want
268  for ax,ay,theta in arrowData:
269  # use aspace as a guide for size and length of things
270  # scaling factors were chosen by experimenting a bit
271  arrows.append(plt.arrow(ax,ay, np.sin(theta)*aspace/10.0,np.cos(theta)*aspace/10.0, head_width=aspace/10.0, color=color, alpha=alpha, zorder=zorder))
272  plot = plt.plot(x,y, color=color, alpha=alpha, zorder=zorder, **kwargs)
273  return plot, arrows
274 
275 
276 def BoxPlotSeries(data, x_label='', y_label='', x_tick_labels=None, y_bounds=None, y_logScale=False, orderByMedian=False, colour=None, sperator_position=None, local=None, fig_name='Generic boxplot', figsize=[15.0,12.0], verbose=0):
277  ''' Plot generic Boxplot series. Useful for generating quartiles by
278  sequence or site.
279 
280  Input:
281  ======
282  data: a list of data arrays.
283  orderByMedian: 'ascending' (default) | 'descending'
284  x_tick_labels: should be same 0-order dimension as data
285  colour: should be same 0-order dimension as data
286  sperator_position: should be an integer index (starting at 0) AFTER which to add a vertical separator, or none to disable
287  '''
288 
289  fig = plt.figure(fig_name, figsize=(figsize[0], figsize[1]))
290  if(not local): local = tvaLocal.Local()
291  if(len(data) != len(x_tick_labels) or len(data) == 0): return False
292  if(colour and len(data) != len(colour)): return False
293 
294  # Enable multiplotting
295  if(type(data[0]) is not list): data = [data]
296 
297 
298  if(orderByMedian):
299  medians=[]
300  for dat in data:
301  medians.append(sorted(dat)[len(dat)/2])
302 
303  if(orderByMedian=='descending'):
304  data = [x for (y,x) in sorted(zip(medians,data),reverse=True)]
305  x_tick_labels = [x for (y,x) in sorted(zip(medians,x_tick_labels),reverse=True)]
306  if(colour):
307  colour = [x for (y,x) in sorted(zip(medians,colour),reverse=True)]
308  else:
309  data = [x for (y,x) in sorted(zip(medians,data))]
310  x_tick_labels = [x for (y,x) in sorted(zip(medians,x_tick_labels))]
311  if(colour):
312  colour = [x for (y,x) in sorted(zip(medians,colour))]
313 
314 
315  bp = plb.boxplot(data, patch_artist=True)
316 
317 
318  if(colour):
319  for Ix in range(len(data)):
320  bp['boxes'][Ix].set(color=colour[Ix], linewidth=1)
321  bp['whiskers'][Ix*2].set(color=colour[Ix], linewidth=1)
322  bp['whiskers'][Ix*2+1].set(color=colour[Ix], linewidth=1)
323  bp['caps'][Ix*2].set(color=colour[Ix], linewidth=1)
324  bp['caps'][Ix*2+1].set(color=colour[Ix], linewidth=1)
325  if(colour[Ix]=='r'): bp['medians'][Ix].set(color='k', linewidth=1)
326 
327 
328  if(sperator_position):
329  plt.axvline(x=sperator_position+1.5, linewidth=2, color='k')
330 
331 
332  if(verbose >= 4):
333  print 'BoxPlot data for '+fig_name
334  print 'Label,25%,Median,75%'
335  for i in range(len(data)):
336  try: print str(x_tick_labels[i])+','+str(min(bp['boxes'][i].get_ydata()))+','+str(bp['medians'][i].get_ydata()[0])+','+str(max(bp['boxes'][i].get_ydata()))
337  except: print str(x_tick_labels[i])+','
338 
339 
340  ax = plb.gca()
341  if(x_label): ax.set_xlabel(x_label)
342  if(y_label): ax.set_ylabel(y_label)
343  if(y_bounds and type(y_bounds) == list): ax.set_ylim(y_bounds)
344  if(y_logScale): ax.set_yscale('log')
345  if(x_tick_labels and type(x_tick_labels) == list):
346  plt.xticks(range(1,len(data)+1), x_tick_labels, rotation=70, ha='right')
347  if(len(data) > 5):
348  for tick in ax.xaxis.get_major_ticks():
349  tick.label.set_fontsize(int(tick.label.get_fontsize()/2.0))
350  return fig
351 
352 
353 def Scatter(pointList, alignments=False, mask=False, labels=False, local=None, fig_name='Generic scatter', verbose=0, figsize=[15.0,12.0]):
354  ''' Generic point cloud with alignment and BB. '''
355  fig = plt.figure(fig_name, figsize=(figsize[0], figsize[1]))
356  if(not local): local = tvaLocal.Local()
357 
358 
359  plotBB(mask, labels=labels, boxLabel=local['vis_mask'])
360 
361 
362  X = []
363  Y = []
364  for row in pointList:
365  X.append(row[0])
366  Y.append(row[1])
367  plb.scatter(X, Y, s=80, marker=(5,0), c='r')
368 
369  plotAlign(alignments, labels=labels)
370  return fig
371 
372 
373 def Map(pointList, colour='hot', xy_bounds=None, gridsize=[60,60], mincnt=1, sm_scale=None, alignments=False, mask=False, labels=False, local=None, fig_name='Generic Map', verbose=0, figsize=[15.0,12.0], full_plot=True):
374  ''' Generic map with alignment and BB
376  Input:
377  ======
378  colour: http://wiki.scipy.org/Cookbook/Matplotlib/Show_colormaps
379  gridsize: Must be a two-item list, preferably square
380  mincnt: Bins with fewer than this many points will not be plotted
381  sm_scale: If this is an int or float, bounds the upper maximum of the colour map; if this is a two-item list, bounds the lower and upper maximum of the colour map respectively
382  full_plot: Set to false if calling from another vis function
383  '''
384  if(not local): local = tvaLocal.Local()
385  if(len(pointList[0]) == 0 or len(pointList[1]) == 0): return False
386 
387  if(full_plot):
388  fig = plt.figure(fig_name, figsize=(figsize[0], figsize[1]))
389 
390 
391  plotBB(mask, labels=labels, boxLabel=local['vis_mask'])
392 
393 
394  if(sm_scale):
395  if(type(sm_scale) == list and len(sm_scale) == 2): scale_norm = plt.Normalize(sm_scale[0],sm_scale[1])
396  else: scale_norm = plt.Normalize(0,sm_scale)
397  else: scale_norm = None
398 
399  # Plot hexbin
400  hexBinMap = plt.hexbin(pointList[0], pointList[1], gridsize=gridsize, cmap=plt.get_cmap(colour), mincnt=mincnt, norm=scale_norm)
401  hexBinMap.set_zorder(5)
402  cb = plt.colorbar()
403  cb.set_label(local['vis_map_density'])
404 
405  if(full_plot):
406 
407  plotAlign(alignments, labels=labels)
408 
409 
410  ax = plb.gca()
411  plt.axis('equal')
412  if(xy_bounds):
413  ax.set_xlim([xy_bounds[0].lower,xy_bounds[0].upper])
414  ax.set_ylim([xy_bounds[1].lower,xy_bounds[1].upper])
415  return fig
416  else:
417  return True
418 
419 
420 def plotBB(bounding_boxes, labels=False, legacyLabels=False, boxLabel=None, outlineOnly=False, alpha=1.00, zorder=1, zone_bgcolour='0.66', plotSettings=None, **kwargs):
421  ''' Plot bounding_boxes. If outlineOnly is set to an int, will use as line
422  thickness (defaults to 2). '''
423  if(not bounding_boxes or len(bounding_boxes) == 0): return False
424  if(type(outlineOnly) is int): linewidth = outlineOnly
425  else: linewidth = 2
426  for bounding_box in bounding_boxes:
427  if(outlineOnly): plt.plot([x[0] for x in bounding_box]+[bounding_box[0][0]], [y[1] for y in bounding_box]+[bounding_box[0][1]], color='k', linewidth=linewidth, zorder=zorder)
428  else: plt.fill([x[0] for x in bounding_box], [y[1] for y in bounding_box], zone_bgcolour, alpha=alpha, zorder=zorder)
429  if(boxLabel and labels):
430  if(legacyLabels):
431  plt.annotate(boxLabel, xy = (bounding_boxes[0][0][0], bounding_boxes[0][0][1]), xytext = (-20, 20), textcoords = 'offset points', ha = 'right', va = 'bottom', bbox = dict(boxstyle = 'Square,pad=0.5', fc = 'white', alpha = 0.5), arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'))
432  else:
433  for bIx in range(len(bounding_boxes)):
434  if(len(bounding_boxes[bIx])>=3): label_vertices = [0,int(len(bounding_boxes[bIx])/2.0)]
435  else: label_vertices = [0]
436  for lpIx in label_vertices:
437  # The angle needs to be set to negative to compensate for flipping on the vertical (y) axis)
438  try: angle = -m.degrees(m.atan((bounding_boxes[bIx][lpIx+1][1]-bounding_boxes[bIx][lpIx][1])/(bounding_boxes[bIx][lpIx+1][0]-bounding_boxes[bIx][lpIx][0])))
439  except: angle = -90.0
440  # Determine offset
441  if(20 < angle+90 and angle+90 < 60): offset = (5*(1-(angle+90.0)/180.0)+5, 5-5*(1-(angle+90.0)/180.0))
442  else: offset = (-5*(1-(angle+90.0)/180.0)-10, 5+10*(1-(angle+90.0)/180.0))
443  # Choose location
444  location = ((bounding_boxes[bIx][lpIx+1][0]+bounding_boxes[bIx][lpIx][0])/2.0, (bounding_boxes[bIx][lpIx+1][1]+bounding_boxes[bIx][lpIx][1])/2.0)
445  if(plotSettings): plt.annotate(boxLabel, xy = location, rotation=angle, xytext=offset, textcoords='offset points', ha='center', va='center', color=zone_bgcolour, zorder=zorder+1, bbox=dict(facecolor='#000000', alpha=0.5, boxstyle='Square,pad=0.1'), size=plotSettings['size']*0.5)
446  else: plt.annotate(boxLabel, xy = location, rotation=angle, xytext=offset, textcoords='offset points', ha='center', va='center', color=zone_bgcolour, zorder=zorder+1, bbox=dict(facecolor='#000000', alpha=0.5, boxstyle='Square,pad=0.1'))
447 
448  return True
449 
450 def plotSDR(SDR, local=None, outlineOnly=False, alpha=1.00, zorder=1, sdr_bgcolour='0.66', **kwargs):
451  ''' Plot bounding_boxes. If outlineOnly is set to an int, will use as line
452  thickness (defaults to 2). '''
453  if(not local): local = tvaLocal.Local()
454  if(not SDR or len(SDR) == 0): return False
455  if(type(outlineOnly) is int): linewidth = outlineOnly
456  else: linewidth = 2
457  for SDRpoly in SDR:
458  if(outlineOnly): plt.plot([x[0] for x in SDRpoly]+[SDRpoly[0][0]], [y[1] for y in SDRpoly]+[SDRpoly[0][1]], color='k', linewidth=linewidth, zorder=zorder)
459  else: plt.fill([x[0] for x in SDRpoly], [y[1] for y in SDRpoly], sdr_bgcolour, alpha=alpha, zorder=zorder)
460  return True
461 
462 def plotVL(virtual_loops, labels=False, colour='#D63E33'):
463  ''' Plot bounding_boxes. '''
464  if(not virtual_loops or len(virtual_loops.coordinates) == 0):
465  return False
466  fig = plt.gcf()
467  for i in range(len(virtual_loops.coordinates)):
468  circle = plt.Circle((virtual_loops.coordinates[i].x, virtual_loops.coordinates[i].y), radius=virtual_loops.radius, color=colour, alpha=0.7, zorder=1000)
469  fig.gca().add_artist(circle)
470  #if(labels):
471  plt.annotate('# '+str(i)+' ['+str(round(virtual_loops.coordinates[i].x,2))+', '+str(round(virtual_loops.coordinates[i].y,2))+']', xy = (virtual_loops.coordinates[i].x, virtual_loops.coordinates[i].y), xytext = (-20, 20), textcoords = 'offset points', ha = 'right', va = 'bottom', bbox = dict(boxstyle = 'Square,pad=0.5', fc = 'white', alpha = 0.5), arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'))
472  return True
473 
474 
475 def plotAlign(alignments, custom_colours=None, draw_connectors=True, draw_corridors=True, labels=False, legacyLabels=False, distanceBetweenLabels=20.0, highContrastLabels=False, lineAlpha=1.0, annotateAlpha=0.2, corridorAlpha=0.5, zorder=20, plotSettings=None):
476  ''' Plot alignments. '''
477  if(not alignments or len(alignments) == 0): return False
478 
479  for lane in range(len(alignments)):
480  try:
481  if(hasattr(alignments[lane], 'hasAlignBB') and alignments[lane].hasAlignBB()):
482  x = alignments[lane].getXCoordinatesBB()
483  y = alignments[lane].getYCoordinatesBB()
484  s = alignments[lane].getSCoordinatesBB()
485  else:
486  x = alignments[lane].getXCoordinates()
487  y = alignments[lane].getYCoordinates()
488  s = alignments[lane].getSCoordinates()
489  except:
490  x = alignments[lane].getXCoordinates()
491  y = alignments[lane].getYCoordinates()
492  legacyLabels = True
493 
494  if(lane in alignments.sidewalks): plt.plot(x, y, color='#377220', lw=3, zorder=zorder, alpha=lineAlpha)
495  elif(lane in alignments.bikepaths): plotWithArrows(x, y, color='#700f92', lw=3, zorder=zorder, alpha=lineAlpha)
496  else: plotWithArrows(x, y, color='m', lw=3, zorder=zorder, alpha=lineAlpha)
497  if(labels):
498  if(legacyLabels): plt.annotate(alignments[lane].getPrintShortName(), xy = (x[0], y[0]), xytext = (-20, 20), textcoords = 'offset points', ha = 'right', va = 'bottom', bbox = dict(boxstyle = 'Square,pad=0.5', fc = 'white', alpha = 0.5), arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'))
499  else:
500  lastDistance = 0
501  for segment in range(len(alignments[lane])-1):
502  lastDistance += s[segment+1] - s[segment]
503  if(lastDistance > distanceBetweenLabels):
504  lastDistance = 0
505 
506  no_labels = max(1,int((s[segment+1] - s[segment])/distanceBetweenLabels))
507  for lIdx in range(no_labels):
508  # The angle needs to be set to negative to compensate for flipping on the vertical (y) axis)
509  try: angle = -m.degrees(m.atan((y[segment+1]-y[segment])/(x[segment+1]-x[segment])))
510  except: angle = -90.0
511  # Choose location
512  location = (x[segment]+(x[segment+1]-x[segment])*(lIdx+1)/float(no_labels+1), y[segment]+(y[segment+1]-y[segment])*(lIdx+1)/float(no_labels+1))
513  # Determine offset
514  if(20 < angle+90 and angle+90 < 60): offset = (5*(1-(angle+90.0)/180.0)+5, 5-5*(1-(angle+90.0)/180.0))
515  else: offset = (-5*(1-(angle+90.0)/180.0)-10, 5+10*(1-(angle+90.0)/180.0))
516  # Set colour
517  if(custom_colours): colour = custom_colours[lane]
518  elif(highContrastLabels): colour = '#FFFFFF'
519  elif(lane in alignments.sidewalks): colour = '#377220'
520  elif(lane in alignments.bikepaths): colour = '#700f92'
521  else: colour = 'm'
522  if(plotSettings):
523  if(highContrastLabels): plt.annotate(alignments[lane].getPrintName(), xy = location, rotation=angle, xytext=offset, textcoords='offset points', ha='center', va='center', color=colour, zorder=zorder+1, bbox=dict(facecolor='#000000', alpha=0.5, boxstyle='Square,pad=0.1'), size=plotSettings['size']*0.5)
524  else: plt.annotate(alignments[lane].getPrintName(), xy = location, rotation=angle, xytext=offset, textcoords='offset points', ha='center', va='center', color=colour, zorder=zorder+1, alpha=annotateAlpha, size=plotSettings['size']*0.5)
525  else:
526  if(highContrastLabels): plt.annotate(alignments[lane].getPrintName(), xy = location, rotation=angle, xytext=offset, textcoords='offset points', ha='center', va='center', color=colour, zorder=zorder+1, bbox=dict(facecolor='#000000', alpha=0.5, boxstyle='Square,pad=0.1'))
527  else: plt.annotate(alignments[lane].getPrintName(), xy = location, rotation=angle, xytext=offset, textcoords='offset points', ha='center', va='center', color=colour, zorder=zorder+1, alpha=annotateAlpha)
528 
529  if(draw_connectors):
530  for link in alignments.getLinks():
531  plb.plot([link[2], link[6]], [link[3], link[7]], 'c', lw=4, alpha=lineAlpha)
532  if(draw_corridors):
533  for corridorSet in alignments.getCorridors():
534  if(alignments[corridorSet[0]].hasAlignBB() and alignments[corridorSet[1]].hasAlignBB()):
535  X2 = alignments[corridorSet[1]].getXCoordinatesBB()
536  X2.reverse()
537  Y2 = alignments[corridorSet[1]].getYCoordinatesBB()
538  Y2.reverse()
539  plt.fill(alignments[corridorSet[0]].getXCoordinatesBB()+X2, alignments[corridorSet[0]].getYCoordinatesBB()+Y2, 'c', alpha=corridorAlpha, zorder=zorder-1)
540  else:
541  X2 = alignments[corridorSet[1]].getXCoordinates()
542  X2.reverse()
543  Y2 = alignments[corridorSet[1]].getYCoordinates()
544  Y2.reverse()
545  plt.fill(alignments[corridorSet[0]].getXCoordinates()+X2, alignments[corridorSet[0]].getYCoordinates()+Y2, 'c', alpha=corridorAlpha, zorder=zorder-1)
546 
547  return True
548 
549 def plotSatellite(sateliteImage, sateliteResolution, color=False, zorder=0, origin=[0,0], zoomTo=False):
550  ''' Plot satellite image '''
551  if(not sateliteImage or not sateliteResolution): return False
552  try: img = mpimg.imread(sateliteImage)
553  except: return False
554  x = int(img.shape[1]*sateliteResolution)
555  y = int(img.shape[0]*sateliteResolution)
556  if(not color):
557  img = img[:,:,0]
558  plt.imshow(img, extent=(origin[0],x,origin[1],y), origin='lower', cmap="Greys_r", zorder=zorder)
559  else:
560  plt.imshow(img, extent=(origin[0],x,origin[1],y), origin='lower', zorder=zorder)
561  if(zoomTo):
562  ax = plb.gca()
563  ax.set_xlim([0,x])
564  ax.set_ylim([0,y])
565  ax.set_autoscale_on(False)
566  return True
567 
568 def plotImageWorldSpace(imagePath, scale=1.0, zorder=0, origin=[0,0]):
569  ''' Plot image to world space (scaled to metres). '''
570  if(not imagePath): return False
571  try: img = mpimg.imread(imagePath)
572  except: return False
573  x = int(img.shape[1]*scale)
574  y = int(img.shape[0]*scale)
575  plt.imshow(img, extent=(origin[0],x+origin[0],origin[1],y+origin[1]), origin='lower', zorder=zorder)
576  return True
577 
578 def annotate(text, x=None, y=None, target='bottom-right'):
579  ''' Plot generic text annotation, where x and y denote a fraction of the
580  figure if less than 0. '''
581  #Pull current axes information
582  ax = plb.gca()
583  if(target=='top-right'):
584  if(not x): x_ = (ax.get_xlim()[1]-ax.get_xlim()[0])*0.95 + ax.get_xlim()[0]
585  elif(x < 1 and y < 1): x_ = (ax.get_xlim()[1]-ax.get_xlim()[0])*x + ax.get_xlim()[0]
586  else: x_ = x
587  if(not y): y_ = (ax.get_ylim()[1]-ax.get_ylim()[0])*0.95 + ax.get_ylim()[0]
588  elif(x < 1 and y < 1): y_ = (ax.get_ylim()[1]-ax.get_ylim()[0])*y + ax.get_ylim()[0]
589  else: y_ = y
590  ha='right'
591  va='bottom'
592  else:
593  if(not x): x_ = (ax.get_xlim()[1]-ax.get_xlim()[0])*0.95 + ax.get_xlim()[0]
594  elif(x < 1 and y < 1): x_ = (ax.get_xlim()[1]-ax.get_xlim()[0])*x + ax.get_xlim()[0]
595  else: x_ = x
596  if(not y): y_ = (ax.get_ylim()[1]-ax.get_ylim()[0])*0.05 + ax.get_ylim()[0]
597  elif(x < 1 and y < 1): y_ = (ax.get_ylim()[1]-ax.get_ylim()[0])*y + ax.get_ylim()[0]
598  else: y_ = y
599  ha='right'
600  va='bottom'
601  plt.annotate(text, xy=(x_,y_), textcoords='offset points', ha=ha, va=va, bbox=dict(boxstyle='Square,pad=0.5', fc='white', alpha=0.5))
602 
603  return True
604 
605 def scatterInBins(lists, bins):
606  ''' Randomly scatter columns of data according to a set of bins. (Effectivly blurs mid-point values of a binning operation). Order is maintained.
607 
608  Example:
609  ========
610  >>> scatterInBins([1.5,2.5,0.5,2.5,3], [0,1,2,3])
611  [1.9358528821939882, 2.8487475428825326, 0.25158512665668165, 2.512719161810347, 3]
612  '''
613  if(type(lists) != list): return False
614  bins.sort()
615  return_list = []
616 
617  for i in lists:
618  for bin in range(len(bins)):
619  if(i < bins[bin]):
620  return_list.append(random()*(bins[bin]-bins[bin-1])+bins[bin-1])
621  break
622  elif(bin >= len(bins)-1):
623  return_list.append(i)
624  break
625  return return_list
626 
627 def pointList2DHisto(data, bins=[60,60]):
628  ''' Condense a large list of points into a 2D histogram. Currently only supports 2D data but a third dimension can be used as weight.
629 
630  Input:
631  ======
632  data is a list of points with up to three coordinates, or otherwise a list of coordinate columns (each row is a point)
633 
634  Output:
635  =======
636  A 2D np.array object or False on fail
637  return[0] is the joint data, as a 2D np.array
638  return[1] is the x-axis bin values as a 1D np.array
639  return[2] is the y-axis bin values as a 1D np.array
640  '''
641  if(type(data) != list): return False
642  if(len(data) == 2): dimension = 2
643  elif(len(data) == 3): dimension = 3
644  else:
645  data = tvaLib.pointList2ColumnList(data)
646  if(len(data) == 2): dimension = 2
647  elif(len(data) == 3): dimension = 3
648  else: return False
649 
650  if(dimension == 2): return np.histogram2d(data[0], data[1], bins=bins)
651  elif(len(data) == 3): return np.histogram2d(data[0], data[1], weights=data[2], bins=bins)
652  else: return False
653 
654 class basicPlot():
655  def __init__(self, fig_rows=1, fig_columns=1, local=None, sharex=False, sharey=False, fig_name='Basic Figure', verbose=0, figsize=[15.0,12.0], **kwargs):
656  if(not local): self.local = tvaLocal.Local()
657  else: self.local = local
658  self.verbose = verbose
659  self.fig, self.axes = plt.subplots(fig_rows, fig_columns, sharex=sharex, sharey=sharey, num=fig_name, figsize=(figsize[0], figsize[1]))
661  def setAxes(self, x_lavbel=['x'], y_lavbel=['y']):
662  cIx = 0
663  for index, ax in np.ndenumerate(self.axes):
664  ax.set_xlabel(x_lavbel[cIx])
665  ax.set_ylabel(y_lavbel[cIx])
666  if(len(x_lavbel) > cIx+1 and len(y_lavbel) > cIx+1): cIx += 1
667 
668  def compileFigure(self): pass
669 
670  def get(self):
671  self.compileFigure()
672  self.setAxes()
673  return self.fig
674 
675 
676 class overheadPlot(basicPlot):
677  def __init__(self, alignments=None, bounding_box=None, xy_bounds=None, sateliteImage=None, sateliteResolution=None, draw_connectors=True, **kwargs):
678  basicPlot.__init__(self, **kwargs)
679  self.xy_bounds = xy_bounds
680  self.alignments = alignments
681  self.bounding_box=None,
682 
683  if(plotSatellite(sateliteImage, sateliteResolution, color=True)):
684  self.fig.forceDPI = 150
685  self.fig.forceFormat = 'jpg'
686  draw_connectors = False #Disable for satellite images or else image is too busy
687  plotBB(bounding_box)
688  plotAlign(alignments, draw_connectors=draw_connectors)
689 
690 
691  def setAxes(self):
692  self.axes.set_xlabel(self.local['vis_gen_x_coords_m'])
693  self.axes.set_ylabel(self.local['vis_gen_y_coords_m'])
694  self.axes.set_aspect('equal')
695  if(self.xy_bounds):
696  self.axes.set_xlim([self.xy_bounds[0].lower,self.xy_bounds[0].upper])
697  self.axes.set_ylim([self.xy_bounds[1].lower,self.xy_bounds[1].upper])
698  self.axes.set_ylim(self.axes.get_ylim()[::-1]) #Reversal is done here, in case xy_bounds is not set
699 
700 
701 
702 
703 
706 class trajSample(overheadPlot):
707  def __init__(self, objects, fig_name='Sample Trajectory', **kwargs):
708  ''' Plot individual trajectories highlighting individual frame stops. '''
709  overheadPlot.__init__(self, fig_name=fig_name, **kwargs)
710  self.addTraj(objects, **kwargs)
711 
712  def addTraj(self, objects, traj_colour='b', linestyle='-', markerstyle='o', linewidth=2, **kwargs):
713  if(type(objects) is not list): objects = [objects]
714  for obj in objects:
715  if(traj_colour == 'random'): traj_colour_actual = random(),random(),random()
716  else: traj_colour_actual = traj_colour
717  self.axes.plot(obj.getXCoordinates(), obj.getYCoordinates(), color=traj_colour_actual, linestyle=linestyle, marker=markerstyle, linewidth=linewidth)
718 
719 
720 
721 def traj2D(objects, draw_max_traj=200, xy_bounds=None, alignments=None, draw_connectors=True, mask=None, zone=None, SDR=None, virtual_loops=None, sateliteImage=None, sateliteResolution=None, labels=False, labels_overlap=True, timeStampLabels=False, objects_uncon=None, velocity_vector=False, local=None, constantFramerate=15.0, mps_kmh=3.6, traj_colour='b', traj_colour_alternate='', sm_scale=50, cm_colour='hot', alignAlpha=1.0, fig_name='Vehicle Trajectories', figsize=[15.0,12.0], plotSettings=None, **kwargs):
722  ''' Plot all trajectories in 2 dimensions (X, Y).
724  Input:
725  ======
726  objects: An ordinary list of moving objects.
727  objects_uncon: An ordinary list of moving objects, plotted behind, in
728  gray (useful to highlight objects outside of the
729  analysis zone).
730  traj_colour: Colour each (primary) trajectory this coulour, following
731  matplotlib conventions. However, some special parameters
732  may be passed instead:
733  'speed': Trajectories will be colour coded according to their
734  speed using standard speed colour scale.
735  'random': Trajectories will be colour coded randomly. This might be
736  useful in distinguishing individual tracks.
737  'class': Trajectories will be colour coded according to their
738  road user classification.
739 
740  **Kwargs:
741  -plotBB and plotSDR passthrough
742  -Additional objects datasets can be passed as kwargs and plotted
743  with random alternative colours.
744  '''
745 
746  from moving import MovingObject
747 
748  fig = plt.figure(fig_name, figsize=(figsize[0], figsize[1]))
749  if(not local): local = tvaLocal.Local()
750  class_colours = ['#ff0000','#0000ff','#00cc00','#996633','#cc0099','#cccc00','#000066',]
751 
752  #Suggest plotting a maximum of two or three trajectories with the following options enabled.
753  config_spec_debug = False
754  config_spec_debug_lane_labels = False
755  config_spec_timestamp = True
756 
757 
758  if(not xy_bounds and not objects and not kwargs): zoomToSatelite = True
759  else: zoomToSatelite = False
760  if(plotSatellite(sateliteImage, sateliteResolution, color=True, zoomTo=zoomToSatelite)):
761  fig.forceDPI = 150
762  fig.forceFormat = 'jpg'
763  draw_connectors = False #Disable for satellite images or else image is too busy
764  outlineOnly = True
765  else: outlineOnly = False
766 
767 
768  plotBB(mask, labels=labels, boxLabel=local['vis_mask'], outlineOnly=outlineOnly, zone_bgcolour='0.90', plotSettings=plotSettings, **kwargs)
769  plotBB(zone, labels=labels, boxLabel=local['vis_analysis_area'], zone_bgcolour='green', alpha=0.5, plotSettings=plotSettings, **kwargs)
770  plotSDR(SDR, zone_bgcolour='0.20', **kwargs)
771  plotVL(virtual_loops, labels=labels)
772 
773 
774  if(objects_uncon):
775  if(not draw_max_traj): draw_max_traj_actual = max(len(objects_uncon), 1)
776  else: draw_max_traj_actual = max(min(len(objects_uncon), draw_max_traj),1)
777 
778  for i in range(0,len(objects_uncon),len(objects_uncon)/draw_max_traj_actual):
779  plt.plot(objects_uncon[i].getXCoordinates(), objects_uncon[i].getYCoordinates(),'0.80')
780 
781 
782  if(traj_colour != 'random' and len(objects) == 2):
783  start_ = max(objects[0].timeInterval.first,objects[1].timeInterval.first)
784  end = min(objects[0].timeInterval.last,objects[1].timeInterval.last)
785  if(start_ <= end):
786  difBefore = objects[0].timeInterval.first-objects[1].timeInterval.first
787  label_vector_range=tvaLib.Geo.rotateVector(330.0, [1,0], inputRadians=False)
788  label_vect_rotation = 15
789  label_vect_length = 175.0
790  label_vect_growth = -7
791  for commonPointIx in range(end-start_):
792  if(difBefore > 0):
793  p0 = commonPointIx
794  p1 = commonPointIx+difBefore
795  else:
796  p0 = commonPointIx-difBefore
797  p1 = commonPointIx
798 
799  #plt.scatter([objects[0].getXCoordinates()[p0],objects[1].getXCoordinates()[p1]], [objects[0].getYCoordinates()[p0],objects[1].getYCoordinates()[p1]], color='k', marker='x')
800 
801  if(commonPointIx % 8 == 0):
802  plt.plot([objects[0].getXCoordinates()[p0],objects[1].getXCoordinates()[p1]], [objects[0].getYCoordinates()[p0],objects[1].getYCoordinates()[p1]], color='0.75')
803  if(labels):
804  deltaD = m.sqrt((objects[0].getXCoordinates()[p0]-objects[1].getXCoordinates()[p1])**2+(objects[0].getYCoordinates()[p0]-objects[1].getYCoordinates()[p1])**2)
805  deltaV = m.sqrt((objects[0].velocities.getXCoordinates()[p0]-objects[1].velocities.getXCoordinates()[p1])**2+(objects[0].velocities.getYCoordinates()[p0]-objects[1].velocities.getYCoordinates()[p1])**2)
806  plt.annotate('$\Delta$v = '+str(round(deltaV*constantFramerate,2))+'m/s\nd = '+str(round(deltaD,2))+'m\nt = '+str(round(float(commonPointIx+start_)/constantFramerate,2))+'s', xy = (objects[0].getXCoordinates()[p1], objects[0].getYCoordinates()[p1]), xytext = (label_vector_range[0]*label_vect_length, label_vector_range[1]*label_vect_length), textcoords = 'offset points', ha = 'right', va = 'bottom', bbox = dict(boxstyle = 'Square,pad=0.10', fc = 'white', alpha = 0.5), arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'), size=16)
807  label_vector_range=tvaLib.Geo.rotateVector(label_vect_rotation, label_vector_range, inputRadians=False)
808  label_vect_length+=label_vect_growth
809 
810 
811 
812  objects_sets = [objects]
813  if(kwargs): import moving as TrafIntMoving
814  for kwarg in kwargs:
815  if(type(kwargs[kwarg]) == list and len(kwargs[kwarg]) > 0 and (isinstance(kwargs[kwarg][0], MovingObject) or isinstance(kwargs[kwarg][0], TrafIntMoving.BBAnnotation))): objects_sets.append(kwargs[kwarg])
816 
817 
818  ann=[]
819  for objects,j in zip(objects_sets,range(len(objects_sets))):
820  if(len(objects) == 0): continue
821  if(j != 0 and traj_colour != 'speed'):
822  if(traj_colour_alternate): traj_colour = traj_colour_alternate
823  else: traj_colour = random(),random(),random()
824  if(not draw_max_traj): draw_max_traj_actual = max(len(objects),1)
825  else: draw_max_traj_actual = max(min(len(objects), draw_max_traj),1)
826  for i in range(0,len(objects), len(objects)/draw_max_traj_actual):
827  if(traj_colour == 'random'): traj_colour_actual = random(),random(),random()
828  elif(traj_colour == 'speed'): traj_colour_actual = plt.get_cmap(cm_colour)(sum(objects[i].getSpeeds())*mps_kmh*constantFramerate/float(len(objects[i].getSpeeds())*sm_scale))
829  elif(traj_colour == 'class'): traj_colour_actual = class_colours[objects[i].getUserType()]
830  else: traj_colour_actual = traj_colour
831  plt.plot(objects[i].getXCoordinates(), objects[i].getYCoordinates(), color=traj_colour_actual)
832 
833 
834  if(labels):
835  if(plotSettings): ann.append(plt.annotate(objects[i].num, xy=(objects[i].getXCoordinates()[1], objects[i].getYCoordinates()[1]), size=plotSettings['size']*0.5))
836  else: ann.append(plt.annotate(objects[i].num, xy=(objects[i].getXCoordinates()[1], objects[i].getYCoordinates()[1])))
837  yoffset=-2
838  if(timeStampLabels): plt.annotate('t='+str(objects[i].getFirstInstant()), xy=(objects[i].getXCoordinates()[1], objects[i].getYCoordinates()[1]+yoffset), size=12)
839  if(velocity_vector):
840  for point in range(len(objects[i].getXCoordinates())):
841  plt.annotate(' ', xy = (objects[i].getXCoordinates()[point], objects[i].getYCoordinates()[point]), xytext = (objects[i].getXCoordinates()[point]+objects[i].velocities.getXCoordinates()[point], objects[i].getYCoordinates()[point]+objects[i].velocities.getYCoordinates()[point]), arrowprops = dict(arrowstyle = '<-', connectionstyle = 'arc3,rad=0'))
842  #Spec debug level
843  if(config_spec_debug):
844  if(config_spec_debug_lane_labels):
845  for point in range(len(objects[i].getXCoordinates())):
846  plt.annotate(objects[i].curvilinearPositions.getLanes()[point], xy = (objects[i].getXCoordinates()[point], objects[i].getYCoordinates()[point]), xytext = (-10, 10), textcoords = 'offset points', ha = 'right', va = 'bottom')
847  if(config_spec_timestamp):
848  skip = 0
849  for point in range(len(objects[i].getXCoordinates())):
850  if(skip < 5):
851  skip = skip + 1
852  continue
853  else:
854  skip = 0
855  plt.text(objects[i].getXCoordinates()[point], objects[i].getYCoordinates()[point], objects[i].getFirstInstant()+point, color='#FF0000')
856 
857 
858 
859  if(not labels_overlap):
860  mask_ = np.zeros(fig.canvas.get_width_height(), bool)
861  fig.canvas.draw()
862  for a in ann:
863  bbox = a.get_window_extent()
864  x0 = int(bbox.x0)
865  x1 = int(m.ceil(bbox.x1))
866  y0 = int(bbox.y0)
867  y1 = int(m.ceil(bbox.y1))
868 
869  s = np.s_[x0:x1+1, y0:y1+1]
870  if(np.any(mask_[s])): a.set_visible(False)
871  else: mask_[s] = True
872 
873 
874 
875  plotAlign(alignments, draw_connectors=draw_connectors, lineAlpha=alignAlpha, labels=labels, plotSettings=plotSettings)
876 
877 
878  if(traj_colour == 'class'):
879  #Create custom artists
880  dummy_class_colour_prototypes = []
881  for cIx in range(len(local['userTypeNames'])):
882  dummy_class_colour_prototypes.append(plt.Line2D((objects[0].getXCoordinates()[0],objects[0].getYCoordinates()[0]),(objects[0].getXCoordinates()[0],objects[0].getYCoordinates()[0]), color=class_colours[cIx], linewidth=2))
883  plt.legend(dummy_class_colour_prototypes,local['userTypeNames'])
884 
885 
886 
887 
888  ax = plb.gca()
889  if(not zoomToSatelite): plt.axis('equal')
890  if(xy_bounds):
891  ax.set_xlim([xy_bounds[0].lower,xy_bounds[0].upper])
892  ax.set_ylim([xy_bounds[1].lower,xy_bounds[1].upper])
893  ax.set_ylim(ax.get_ylim()[::-1])
894  ax.set_xlabel(local['vis_gen_x_coords_m'])
895  ax.set_ylabel(local['vis_gen_y_coords_m'])
896 
897 
898  fig.tight_layout()
899 
900  return fig
901 
902 
903 def traj2DHighlightAlignments(objects, xy_bounds, alignments, marker_size=0.4, labels=True, local=None, fig_name='Trajectory Lane Highlight', figsize=[15.0,12.0], plotSettings=None, **kwargs):
904  ''' Plot trajectories highlighting which alignment it is associate with '''
905  fig = plt.figure(fig_name, figsize=(figsize[0], figsize[1]))
906  if(not local): local = tvaLocal.Local()
907 
908 
909  colours=['#ff7133','#d3cc18','#33a1ff','#ff0000','#33ff59','#ea14ed','#49a353',
910  '#603c2c','#4018d3','#050906','#7b7b7b','#fb1a8e','#c39d71','#71c3c2',
911  '#f1f33c','#266719','#4b6d87','#9f82cf','#f05ec9','#c3350f']
912 
913  for lane in range(len(alignments)):
914  plt.scatter(tvaLib.flatten_list([[obj.getXCoordinates()[pIx] for pIx in range(len(obj.getXCoordinates())) if obj.curvilinearPositions.getLanes()[pIx] == lane] for obj in objects]), tvaLib.flatten_list([[obj.getYCoordinates()[pIx] for pIx in range(len(obj.getYCoordinates())) if obj.curvilinearPositions.getLanes()[pIx] == lane] for obj in objects]), color=colours[lane], s=marker_size)
915 
916  '''for obj in objects:
917  for pIx in range(len(obj.getXCoordinates())-1):
918  try: plt.plot([obj.getXCoordinates()[pIx],obj.getXCoordinates()[pIx+1]], [obj.getYCoordinates()[pIx],obj.getYCoordinates()[pIx+1]], color=colours[obj.curvilinearPositions.getLanes()[pIx]])
919  except IndexError:
920  tvaLib.printWarning('There are too many alignments to draw this site\'s highlight map', local['gen_warning'])
921  return None'''
922 
923 
924  plotAlign(alignments, custom_colours=colours, labels=labels, highContrastLabels=True, plotSettings=plotSettings)
925 
926 
927  ax = plb.gca()
928  plt.axis('equal')
929  if(xy_bounds):
930  ax.set_xlim([xy_bounds[0].lower,xy_bounds[0].upper])
931  ax.set_ylim([xy_bounds[1].lower,xy_bounds[1].upper])
932  ax.set_ylim(ax.get_ylim()[::-1])
933  ax.set_xlabel(local['vis_gen_x_coords_m'])
934  ax.set_ylabel(local['vis_gen_y_coords_m'])
935 
936 
937  fig.tight_layout()
938 
939  return fig
940 
941 
942 def visTrajImageSpace(objects=None, image='', homography=None, labels=False, start=0, draw_max_traj=200, mask=None, local=None, fig_name='Vehicle Trajectories in Image Space', traj_colour='b', alpha=1.0, figsize=[15.0,12.0], **kwargs):
943  ''' Plot all trajectories in projected imagespace.
945  Additional objects datasets can be passed as kwargs and plotted with random alternative colours
946  '''
947  fig = plt.figure(fig_name, figsize=(figsize[0], figsize[1]))
948  if(not local): local = tvaLocal.Local()
949 
950 
951  if(objects):
952  for i in range(len(objects)):
953  if(not hasattr(objects[i], 'projectedPositions')):
954  if(homography is None): return None
955  objects[i].projectedPositions = tvaLib.Obj.trajectoryProject(objects[i], homography)
956  if(mask):
957  mask_ = deepcopy(mask)
958  for mIx in range(len(mask_)):
959  for pIx in range(len(mask_[mIx])):
960  x,y = tvaLib.Obj.homographyProject(homography, [[mask_[mIx][pIx][0]],[mask_[mIx][pIx][1]]])
961  mask_[mIx][pIx].x = x[0]
962  mask_[mIx][pIx].y = y[0]
963 
964 
965  if(image):
966  img = mpimg.imread(image)
967  plt.imshow(img, extent=(0,img.shape[1],0,img.shape[0]), origin='lower')
968  alpha = 0.5
969 
970 
971  if(mask): plotBB(mask_, labels=labels, boxLabel=local['vis_mask'], alpha=alpha, **kwargs)
972 
973 
974  if(objects):
975  if(not draw_max_traj): draw_max_traj_actual = max(len(objects),1)
976  else: draw_max_traj_actual = max(min(len(objects),(start+draw_max_traj)),1)
977  for i in range(len(objects))[start:draw_max_traj_actual]:
978  plt.plot(objects[i].projectedPositions.getXCoordinates(), objects[i].projectedPositions.getYCoordinates(), traj_colour)
979 
980 
981  ax = plb.gca()
982  ax.set_ylim(ax.get_ylim()[::-1])
983 
984  return fig
985 
986 
987 def traj3D(objects, start=0, draw_max_traj=200, draw_connectors=True, xy_bounds=None, alignments=None, mask=None, labels=False, timeStampLabels=False, local=None, fig_name='Vehicle Trajectories 3D', traj_colour='b', figsize=[15.0,12.0]):
988  ''' Plot all trajectories in 3 dimensions (X, Y, t). '''
989  fig = plt.figure(fig_name, figsize=(figsize[0], figsize[1]))
990  ax = Axes3D(plt.gcf())
991  if(not local): local = tvaLocal.Local()
992 
993 
994  plotBB(mask, labels=labels, boxLabel=local['vis_mask'])
995 
996 
997  for i in range(len(objects))[start:min(len(objects),(start+draw_max_traj))]:
998  if(traj_colour == 'random'): traj_colour_actual = random(),random(),random()
999  else: traj_colour_actual = traj_colour
1000  ax.plot(objects[i].getXCoordinates(), objects[i].getYCoordinates(), range(objects[i].getTimeInterval().first,objects[i].getTimeInterval().last+1), color=traj_colour_actual)
1001 
1002 
1003  if(labels):
1004  plt.annotate(objects[i].num, xy=(objects[i].getXCoordinates()[1], objects[i].getYCoordinates()[1]))
1005  yoffset=-2
1006  if(timeStampLabels):
1007  plt.annotate('t='+str(objects[i].getFirstInstant()), xy=(objects[i].getXCoordinates()[1], objects[i].getYCoordinates()[1]+yoffset), size=12)
1008 
1009 
1010  plotAlign(alignments, draw_connectors=draw_connectors, labels=labels)
1011 
1012 
1013 
1014  ax = plb.gca()
1015  plt.axis('equal')
1016  if(xy_bounds):
1017  ax.set_xlim([xy_bounds[0].lower,xy_bounds[0].upper])
1018  ax.set_ylim([xy_bounds[1].lower,xy_bounds[1].upper])
1019  ax.set_ylim(ax.get_ylim()[::-1])
1020  ax.set_xlabel(local['vis_gen_x_coords_m'])
1021  ax.set_ylabel(local['vis_gen_y_coords_m'])
1022 
1023  return fig, ax
1024 
1025 
1026 def plotGeometry(alignments, sateliteImage, sateliteResolution, xy_bounds=None, draw_connectors=True, mask=None, zone=None, virtual_loops=None, labels=False, local=None, fig_name='Geometry', figsize=[15.0,12.0], plotSettings=None, **kwargs):
1027  ''' Plot geometry
1028  '''
1029  fig = plt.figure(fig_name, figsize=(figsize[0], figsize[1]))
1030  if(not local): local = tvaLocal.Local()
1031 
1032 
1033  if(not xy_bounds): zoomToSatelite = True
1034  else: zoomToSatelite = False
1035  if(plotSatellite(sateliteImage, sateliteResolution, color=True, zoomTo=zoomToSatelite)):
1036  fig.forceDPI = 150
1037  fig.forceFormat = 'jpg'
1038  draw_connectors = False #Disable for satellite images or else image is too busy
1039  outlineOnly = True
1040  else: outlineOnly = False
1041 
1042 
1043  plotBB(mask, labels=labels, boxLabel=local['vis_mask'], outlineOnly=outlineOnly, zone_bgcolour='0.90', plotSettings=plotSettings, **kwargs)
1044  plotBB(zone, labels=labels, boxLabel=local['vis_analysis_area'], zone_bgcolour='green', alpha=0.5, plotSettings=plotSettings, **kwargs)
1045  plotVL(virtual_loops, labels=labels)
1046 
1047 
1048  plotAlign(alignments, draw_connectors=draw_connectors, labels=labels, highContrastLabels=True, plotSettings=plotSettings)
1049 
1050 
1051  ax = plb.gca()
1052  if(not zoomToSatelite): plt.axis('equal')
1053  if(xy_bounds):
1054  ax.set_xlim([xy_bounds[0].lower,xy_bounds[0].upper])
1055  ax.set_ylim([xy_bounds[1].lower,xy_bounds[1].upper])
1056  ax.set_ylim(ax.get_ylim()[::-1])
1057  ax.set_xlabel(local['vis_gen_x_coords_m'])
1058  ax.set_ylabel(local['vis_gen_y_coords_m'])
1059 
1060 
1061  fig.tight_layout()
1062 
1063  return fig
1064 
1065 
1066 
1067 
1070 def hourlyFlows(flows_curve_list, speed_data=None, speed_data_stds=None, sm_scale=None, local=None, tickFrequency=4, fig_name='Hourly flows', figsize=[15.0,12.0]):
1071  ''' Plot hourly flows. flows_curves can be of size 24 or 96
1073  Input:
1074  ======
1075  flows_curve_list: A list of 24-hour-point flows (a list of lists of flows)
1076  '''
1077 
1078  fig = plt.figure(fig_name, figsize=(figsize[0], figsize[1]))
1079  if(not local): local = tvaLocal.Local()
1080 
1081 
1082  if(type(sm_scale) == list and len(sm_scale) == 2): sm_scale = sm_scale[1]
1083  else: sm_scale = 50
1084  if(len(flows_curve_list[0]) == 96): period = 96
1085  else: period = 24
1086 
1087 
1088  ax = plb.gca()
1089  for flows_curve in flows_curve_list:
1090  ax.plot(range(period), flows_curve, linewidth=2, color='b')
1091 
1092 
1093  if(speed_data):
1094  ax2 = ax.twinx()
1095  for speed_curve in speed_data:
1096  ax2.plot(range(period), speed_curve, linewidth=2, color='k')
1097  if(speed_data_stds):
1098  for speed_curve,speed_stds in zip(speed_data,speed_data_stds):
1099  ax2.plot(range(period), [speed+speed_std if speed else None for speed,speed_std in zip(speed_curve,speed_stds)], linewidth=1, color='k', linestyle='--')
1100  ax2.plot(range(period), [speed-speed_std if speed else None for speed,speed_std in zip(speed_curve,speed_stds)], linewidth=1, color='k', linestyle='--')
1101 
1102  ax.set_xlim([0,period])
1103  ax.set_ylim([0,max([max(y) for y in flows_curve_list])])
1104  ax2.set_ylim([0,sm_scale])
1105  for tl in ax.get_yticklabels():
1106  tl.set_color('b')
1107  for tl in ax2.get_yticklabels():
1108  tl.set_color('k')
1109  ax.xaxis.set_ticks(np.arange(0, period, period/24.0*tickFrequency))
1110  ax.set_xticklabels([str(int(tick/float(period)*24))+':'+"%02d" % (int(tick/float(period)*24%1.0*60)) for tick in np.arange(0, period, period/24.0*tickFrequency)])
1111  for x in np.arange(0, period, period/24.0*tickFrequency):
1112  plt.plot((x, x), (0, max([max(y) for y in flows_curve_list])), color='#CCCCCC')
1113  ax.set_ylabel(local['vis_flow_rate'])
1114  ax2.set_ylabel(local['vis_speed_cm_label_kmh'])
1115 
1116  return fig
1117 
1118 def microTrafficIntensity(objects, startTime, endTime, framerate, local=None, window_s=20.0, maxBins=1000, fig_name='Traffic Intensity', figsize=[15.0,12.0], plotSettings=None, **kwargs):
1119  ''' Plot Traffic Intensity
1121  Input:
1122  ======
1123  objects: Object space, or a list of objects
1124  startTime: A datetime object representing the start time of the first object
1125  endTime: A datetime object representing the end time of the last object
1126  '''
1127 
1128  fig = plt.figure(fig_name, figsize=(figsize[0], figsize[1]))
1129  if(not local): local = tvaLocal.Local()
1130 
1131  timeDelta = endTime-startTime
1132 
1133  numBins = int(timeDelta.total_seconds()/float(window_s))
1134  if(numBins > maxBins):
1135  numBins = maxBins
1136  window_s = timeDelta.total_seconds()/maxBins
1137  bins = [[0 for x in range(numBins)] for l in local['userTypeNames']]
1138 
1139 
1140  if(hasattr(objects, 'iterateSequences')):
1141  objectStartTimeReference = min([y.getStartTime() for y in tvaLib.flatten_list([x.metadatas for x in objects])])
1142 
1143 
1144  for b in range(numBins):
1145  binFrameStart = b*window_s*framerate
1146  binFrameEnd = (b+1)*window_s*framerate - 1
1147 
1148  if(hasattr(objects, 'iterateSequences')):
1149  for metadata,objs in objects.iterateSequences():
1150  frameOffset = (metadata.getStartTime()-objectStartTimeReference).total_seconds()*framerate
1151  for obj in objs:
1152  if(obj.getFirstInstant()+frameOffset >= binFrameStart):
1153  if(obj.getFirstInstant()+frameOffset < binFrameEnd): bins[obj.getUserType()][b] += 1
1154  elif(obj.getLastInstant()+frameOffset >= binFrameStart): bins[obj.getUserType()][b] += 1
1155  else:
1156  for obj in objects:
1157  if(obj.getFirstInstant() >= binFrameStart):
1158  if(obj.getFirstInstant() < binFrameEnd): bins[obj.getUserType()][b] += 1
1159  elif(obj.getLastInstant() >= binFrameStart): bins[obj.getUserType()][b] += 1
1160 
1161 
1162  artists = []
1163  for cIx in range(len(local['userTypeNames'])):
1164  artists.append(plt.bar(range(numBins), bins[cIx], width=1.0, bottom=[sum(x[:cIx]) for x in zip(*bins)]))
1165 
1166 
1167  ax = plb.gca()
1168  plt.legend([artist[0] for artist in artists], local['userTypeNames'])
1169  ticklabel_interval = 10
1170  ax.set_xticklabels([startTime+timedelta(seconds=int(b*window_s)) for b in range(0, numBins, ticklabel_interval)], rotation=45)
1171  ax.set_ylabel(local['vis_traf_intensity_y'].format(round(window_s,2)))
1172 
1173  return fig
1174 
1175 class visualiseOD(overheadPlot):
1176  def __init__(self, ODM, fig_name='OD Visualisation', **kwargs):
1177  overheadPlot.__init__(self, fig_name=fig_name, **kwargs)
1178  self.addODM(ODM, **kwargs)
1179 
1180  def addODM(self, ODM, linescaler=2, arrowscaler=4, **kwargs):
1181  if(ODM):
1182  maxFlow = float(max([max(x) for x in ODM]))
1183  for oIx in range(len(ODM)):
1184  for dIx in range(len(ODM[oIx])):
1185  if(ODM[oIx][dIx]):
1186  scale=ODM[oIx][dIx]/maxFlow
1187  self.axes.arrow(self.alignments[oIx][0][0], self.alignments[oIx][0][1], self.alignments[dIx][-1][0]-self.alignments[oIx][0][0], self.alignments[dIx][-1][1]-self.alignments[oIx][0][1], width=scale*linescaler, head_width=scale*arrowscaler, head_length=scale*arrowscaler, color='b')
1188  self.axes.text((self.alignments[dIx][-1][0]+self.alignments[oIx][0][0])/2, (self.alignments[dIx][-1][1]+self.alignments[oIx][0][1])/2, str(ODM[oIx][dIx]), fontsize=15, color='k', va='center', ha='center')
1189  self.axes.text((self.alignments[dIx][-1][0]+self.alignments[oIx][0][0])/2, (self.alignments[dIx][-1][1]+self.alignments[oIx][0][1])/2, str(ODM[oIx][dIx]), fontsize=12, color='w', va='center', ha='center')
1190 
1191 
1192 
1193 
1194 
1197 def speedMap(objects, ptype='heat', sm_scale=None, colour='hot', xy_bounds=None, gridsize=[60,60], arrowGridReductionFactor=0.3, mincnt=10, virtualLoops=False, zone=False, alignments=False, local=None, fig_name='Speed Heat Map', figsize=[15.0,12.0], constantFramerate=15.0, mps_kmh=3.6, duration=0):
1198  ''' Plot speed heat/vector/stream map
1200  Input:
1201  ======
1202  objects: can be passed as an ordinary list or as a nested camera/sequence ObjectSpace type
1203  ptype: [option]
1204  'heat' (default)
1205  'vector'
1206  'stream'
1207  constantFramerate: pass this if objects isn't an objectSpace type
1208  duration: pass this if objects isn't an objectSpace type (in seconds)
1209  colour: http://wiki.scipy.org/Cookbook/Matplotlib/Show_colormaps
1210  gridsize: must be a two-item list, preferably square
1211  arrowGridReductionFactor: if ptype is vector, the gridsize will be multiplied by this factor
1212  mincnt: bins with fewer than this many points will not be plotted
1213  sm_scale: if this is an int or float, bounds the upper maximum of the colour map; if this is a two-item list, bounds the lower and upper maximum of the colour map respectively
1214  '''
1215  fig = plt.figure(fig_name, figsize=(figsize[0], figsize[1]))
1216  if(not local): local = tvaLocal.Local()
1217  plot_success = False
1218 
1219 
1221  if(sm_scale and type(sm_scale) == list and len(sm_scale) == 2):
1222  scale_norm = plt.Normalize(sm_scale[0],sm_scale[1])
1223  sm_scale = sm_scale[1]
1224  elif(sm_scale and (type(sm_scale) is float or type(sm_scale) is int)):
1225  scale_norm = plt.Normalize(0,sm_scale)
1226  else:
1227  sm_scale = max([max(obj.getSpeeds()) for obj in objects])*float(mps_kmh)*float(constantFramerate)
1228  scale_norm = plt.Normalize(0,sm_scale)
1229  # Bounds
1230  if(xy_bounds is None and zone): xy_bounds = [tvaLib.Constructors.SuperBound([min(zone[0].getXCoordinates()),max(zone[0].getXCoordinates())]), tvaLib.Constructors.SuperBound([min(zone[0].getYCoordinates()),max(zone[0].getYCoordinates())])]
1231 
1232 
1233  if(ptype=='heat' or ptype=='vector'):
1234  posX = []
1235  posY = []
1236  speeds = []
1237  if(type(objects) is list):
1238  speed_conv = float(mps_kmh)*float(constantFramerate)
1239  for obj in objects:
1240  posX += obj.getXCoordinates()
1241  posY += obj.getYCoordinates()
1242  speeds += list(obj.getSpeeds()*speed_conv)
1243  else:
1244  for cam_objs in objects:
1245  for seq_objs, camera in zip(cam_objs, objects.metadatas):
1246  speed_conv = float(camera.camera.frameRate)*float(mps_kmh)
1247  duration += camera.getDuration()
1248  for obj in seq_objs:
1249  posX += obj.getXCoordinates()
1250  posY += obj.getYCoordinates()
1251  speeds += list(obj.getSpeeds()*speed_conv)
1252 
1253 
1254  if(ptype=='vector' or ptype=='stream'):
1255  #Find grid bounds
1256  if(type(objects) is list):
1257  x_min = min([min(obj.getXCoordinates()) for obj in objects])
1258  x_max = max([max(obj.getXCoordinates()) for obj in objects])
1259  y_min = min([min(obj.getYCoordinates()) for obj in objects])
1260  y_max = max([max(obj.getYCoordinates()) for obj in objects])
1261  else:
1262  x_min = min([min(obj.getXCoordinates()) for obj in objects.getAll()])
1263  x_max = max([max(obj.getXCoordinates()) for obj in objects.getAll()])
1264  y_min = min([min(obj.getYCoordinates()) for obj in objects.getAll()])
1265  y_max = max([max(obj.getYCoordinates()) for obj in objects.getAll()])
1266  #Split coordinates into grid system (enforce square bins)
1267  if(ptype=='vector'): gridsize_ = min([int(grid*arrowGridReductionFactor) for grid in gridsize])
1268  else: gridsize_ = min(gridsize)
1269  bin_length = max((x_max-x_min)/gridsize_,(y_max-y_min)/gridsize_)
1270  sideLength = bin_length*float(gridsize_)
1271  PX_t = [x+bin_length/2.0 for x in list(np.arange(x_min,x_min+sideLength,bin_length))[:int(gridsize_)]][:-1]
1272  PY_t = [y+bin_length/2.0 for y in list(np.arange(y_min,y_min+sideLength,bin_length))[:int(gridsize_)]][:-1]
1273  #For each object sort speed values into appropriate bin
1274  speedCacheX=[[[] for j in PY_t] for i in PX_t]
1275  speedCacheY=[[[] for j in PY_t] for i in PX_t]
1276  if(type(objects) is list):
1277  speed_conv = float(mps_kmh)*float(constantFramerate)
1278  for obj in objects:
1279  for point in range(len(obj.getXCoordinates())):
1280  x_bin = min(range(len(PX_t)), key=lambda i: abs(PX_t[i]-obj.getXCoordinates()[point]))
1281  y_bin = min(range(len(PY_t)), key=lambda i: abs(PY_t[i]-obj.getYCoordinates()[point]))
1282  speedCacheX[x_bin][y_bin].append(obj.velocities.getXCoordinates()[point]*speed_conv)
1283  speedCacheY[x_bin][y_bin].append(obj.velocities.getYCoordinates()[point]*speed_conv)
1284  else:
1285  for cam_objs in objects:
1286  for seq_objs, camera in zip(cam_objs, objects.metadatas):
1287  speed_conv = float(camera.camera.frameRate)*float(mps_kmh)
1288  duration += camera.getDuration()
1289  for obj in objects:
1290  for point in range(len(obj.getXCoordinates())):
1291  x_bin = min(range(len(PX_t)), key=lambda i: abs(PX_t[i]-obj.getXCoordinates()[point]))
1292  y_bin = min(range(len(PY_t)), key=lambda i: abs(PY_t[i]-obj.getYCoordinates()[point]))
1293  speedCacheX[x_bin][y_bin].append(obj.velocities.getXCoordinates()[point]*speed_conv)
1294  speedCacheY[x_bin][y_bin].append(obj.velocities.getYCoordinates()[point]*speed_conv)
1295  #Compile average speeds
1296  vectorField = {'PX':[],'PY':[],'VX':[],'VY':[],'S':[]}
1297  for x_bin in range(len(PX_t)):
1298  for y_bin in range(len(PY_t)):
1299  if(len(speedCacheX[x_bin][y_bin]) >= mincnt and len(speedCacheY[x_bin][y_bin]) >= mincnt):
1300  vectorField['PX'].append(PX_t[x_bin])
1301  vectorField['PY'].append(PY_t[y_bin])
1302  vectorField['VX'].append(sum(speedCacheX[x_bin][y_bin])/float(len(speedCacheX[x_bin][y_bin])))
1303  vectorField['VY'].append(sum(speedCacheY[x_bin][y_bin])/float(-1*len(speedCacheY[x_bin][y_bin])))
1304  vectorField['S'].append(m.sqrt(vectorField['VX'][-1]**2+vectorField['VX'][-1]**2))
1305  elif(ptype=='stream'):
1306  vectorField['PX'].append(PX_t[x_bin])
1307  vectorField['PY'].append(PY_t[y_bin])
1308  vectorField['VX'].append(0)
1309  vectorField['VY'].append(0)
1310  vectorField['S'].append(0)
1311 
1312 
1313  if(ptype=='heat' or ptype=='vector'):
1314  plt.hexbin(posX, posY, norm=scale_norm, C=speeds, gridsize=gridsize, cmap=plt.get_cmap(colour), mincnt=mincnt)
1315  cb = plt.colorbar()
1316  cb.set_label(local['vis_speed_cm_label_kmh'])
1317  plot_success = True
1318 
1319 
1320  if(ptype=='vector'):
1321  plt.quiver(vectorField['PX'], vectorField['PY'], vectorField['VX'], vectorField['VY'], units='width', width=0.005)
1322  #plt.quiverkey(Q, 0.9, 0.95, 2, r'$2 \frac{m}{s}$', labelpos='E', coordinates='figure', fontproperties={'weight': 'bold'})
1323  plot_success = True
1324 
1325 
1326  if(ptype=='stream'):
1327  if(not hasattr(plt, 'streamplot')):
1328  tvaLib.printWarning('The module streamplot is not available in the currently installed version of matplotlib (needed for figure "'+fig_name+'").')
1329  plot_success = False
1330  else:
1331  X = np.asarray(tvaLib.wrapList2SquareMatrix(vectorField['PX']))
1332  Y = np.asarray(tvaLib.wrapList2SquareMatrix(vectorField['PY']))
1333  U = np.asarray(tvaLib.wrapList2SquareMatrix(vectorField['VX']))
1334  V = np.asarray(tvaLib.wrapList2SquareMatrix([x*-1.0 for x in vectorField['VY']]))
1335  S = np.asarray(tvaLib.wrapList2SquareMatrix(vectorField['S']))
1336  S2 = np.asarray(tvaLib.wrapList2SquareMatrix([x / sm_scale for x in vectorField['S']]))
1337  try:
1338  plt.streamplot(X.transpose(), Y.transpose(), U.transpose(), V.transpose(), color=S.transpose(), density=4, linewidth=S2.transpose(), arrowsize=3, norm=scale_norm, cmap=plt.get_cmap(colour))
1339  cb = plt.colorbar()
1340  cb.set_label(local['vis_speed_cm_label_kmh'])
1341  plot_success = True
1342  except: plot_success = False
1343 
1344 
1345  if(virtualLoops and hasattr(alignments, 'size')):
1346  virtualLoops_halflength = len(virtualLoops)/2
1347  for lane in range(len(alignments)):
1348  if(duration):
1349  in_flow = str(int(round(float(virtualLoops[lane])/duration*3600)))+' '+local['gen_hourly_veh_units']
1350  out_flow = str(int(round(float(virtualLoops[lane+virtualLoops_halflength])/duration*3600)))+' '+local['gen_hourly_veh_units']
1351  else:
1352  in_flow = str(virtualLoops[lane])+' '+local['vis_speed_veh']
1353  out_flow = str(virtualLoops[lane+virtualLoops_halflength])+' '+local['vis_speed_veh']
1354  if(alignments[lane].hasAlignBB()):
1355  plt.annotate(local['vis_speed_flow']+in_flow, xy = (alignments[lane].getXCoordinatesBB()[0], alignments[lane].getYCoordinatesBB()[0]), xytext = (-20, 20), textcoords = 'offset points', ha = 'right', va = 'bottom', bbox = dict(boxstyle = 'Square,pad=0.5', fc = 'white', alpha = 0.5), arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'))
1356  plt.annotate(local['vis_speed_flow']+out_flow, xy = (alignments[lane].getXCoordinatesBB()[-1], alignments[lane].getYCoordinatesBB()[-1]), xytext = (-20, 20), textcoords = 'offset points', ha = 'right', va = 'bottom', bbox = dict(boxstyle = 'Square,pad=0.5', fc = 'white', alpha = 0.5), arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'))
1357  else:
1358  plt.annotate(local['vis_speed_flow']+in_flow, xy = (alignments[lane].getXCoordinates()[0], alignments[lane].getYCoordinates()[0]), xytext = (-20, 20), textcoords = 'offset points', ha = 'right', va = 'bottom', bbox = dict(boxstyle = 'Square,pad=0.5', fc = 'white', alpha = 0.5), arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'))
1359  plt.annotate(local['vis_speed_flow']+out_flow, xy = (alignments[lane].getXCoordinates()[-1], alignments[lane].getYCoordinates()[-1]), xytext = (-20, 20), textcoords = 'offset points', ha = 'right', va = 'bottom', bbox = dict(boxstyle = 'Square,pad=0.5', fc = 'white', alpha = 0.5), arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'))
1360 
1361 
1362  ax = plb.gca()
1363  plt.axis('equal')
1364  if(xy_bounds):
1365  ax.set_xlim([xy_bounds[0].lower,xy_bounds[0].upper])
1366  ax.set_ylim([xy_bounds[1].lower,xy_bounds[1].upper])
1367  ax.set_ylim(ax.get_ylim()[::-1])
1368  ax.set_xlabel(local['vis_gen_x_coords_m'])
1369  ax.set_ylabel(local['vis_gen_y_coords_m'])
1370 
1371  if(plot_success): return fig
1372  else: return False
1373 
1374 
1375 def speedHist(speed_histos, labels='', plotPDF=True, sm_scale=80, enableBars=True, color='k', linestyle='', linewidth=5, minObservations=10, local=None, fig_name='Speed Distribution', figsize=[15.0,12.0]):
1376  ''' Plot speed histogram.
1378  Input:
1379  ======
1380  If plotPDF is set to true, will plot PDF values, otherwise will plot
1381  frequency (counts).
1382  '''
1383  if(not local): local = tvaLocal.Local()
1384 
1385  if(type(speed_histos[0][0]) is not list): speed_histos = [speed_histos]
1386  if(type(labels) is not list): labels = [labels]
1387  labels = [labels[x] for x in range(len(speed_histos)) if sum(speed_histos[x][1]) > minObservations]
1388  speed_histos = [speed_histos[x] for x in range(len(speed_histos)) if sum(speed_histos[x][1]) > minObservations]
1389  if(not speed_histos): return False
1390 
1391  if(len(speed_histos) <= 2): rows=1; cols=len(speed_histos)
1392  elif(3 <= len(speed_histos) and len(speed_histos) <= 4): rows=2; cols=3
1393  elif(5 <= len(speed_histos) and len(speed_histos) <= 6): rows=2; cols=3
1394  elif(7 <= len(speed_histos) and len(speed_histos) <= 8): rows=2; cols=4
1395  elif(len(speed_histos) == 9): rows=3; cols=3
1396  elif(10 <= len(speed_histos) and len(speed_histos) <= 12): rows=3; cols=4
1397  else: rows=int(m.ceil(m.sqrt(len(speed_histos)))); cols=int(m.ceil(m.sqrt(len(speed_histos))))
1398  fig, axes = plt.subplots(rows, cols, num=fig_name, figsize=(figsize[0], figsize[1]), sharex=True, sharey=True)
1399  if(type(axes) != np.ndarray): axes = np.array(axes)
1400 
1401 
1402  if(plotPDF): y_index = 2
1403  else: y_index = 1
1404 
1405 
1406  axIx = 0
1407  for speed_histo,label in zip(speed_histos,labels):
1408  if(enableBars):
1409  width = (speed_histo[0][1]-speed_histo[0][0])
1410  bar_x_offset = [x-width/2.0 for x in speed_histo[0][1:]]
1411  axes.item(axIx).bar(bar_x_offset, speed_histo[y_index][:], width=width)
1412  axes.item(axIx).plot(speed_histo[0][1:], speed_histo[y_index][:], color=color, linestyle=linestyle, linewidth=linewidth, zorder=20)
1413  if(len(speed_histos) > 1): axes.item(axIx).set_xlabel(label)
1414  axIx += 1
1415 
1416 
1417  axes.item(0).set_xlim([0,sm_scale])
1418  axes.item(0).set_ylim([0,max([max(speed_histo[y_index]) for speed_histo in speed_histos])])
1419  fig.text(0.5, 0.04, local['gen_speed'], ha='center', va='center')
1420  if(plotPDF): fig.text(0.06, 0.5, local['vis_hist_y_pdf'].format(round(speed_histo[0][1]-speed_histo[0][0],3)), ha='center', va='center', rotation='vertical')
1421  else: fig.text(0.06, 0.5, local['vis_hist_y_fre'], ha='center', va='center', rotation='vertical')
1422 
1423  return fig
1424 
1425 class SpeedHistograms(basicPlot):
1426  def __init__(self, alpha=1, **kwargs):
1427  basicPlot.__init__(self, **kwargs)
1428  self.alpha = alpha
1429 
1430  def addHistogram(self, objects, fps):
1431  ''' TODO: '''
1432  if(objects):
1433  for object_ in objects:
1434  point_list = userPair.getPointList()
1435  if(point_list):
1436  point_list = sorted(point_list, key=lambda x: x[4])
1437  # Select offset style
1438  #ti = 0 # first indicator
1439  min_ttc = min([x[0] for x in point_list])
1440  ti = [x for x,y in zip(range(len(point_list)),point_list) if y[0] == min_ttc][0]# minimum TTC
1441  # ti +TTC_ti -intercept
1442  offset = point_list[ti][4]/float(fps)+point_list[ti][0]/float(fps)-self.expectationIntercept
1443  for t,ttc in zip([x[4]/float(fps)-offset for x in point_list], [x[0]/float(fps) for x in point_list]):
1444  t = round(t, 1)
1445  try: self.avgVal[t] += ttc
1446  except: self.avgVal[t] = ttc
1447  try: self.avgValWeight[t] += 1
1448  except: self.avgValWeight[t] = 1
1449  self.axes.plot([x[4]/float(fps)-offset for x in point_list], [x[0]/float(fps) for x in point_list], color='b', alpha=self.alpha)
1450 
1451 
1452  def setAxes(self):
1453  self.axes.set_xlabel(self.local['vis_timeseries_x'])
1454  self.axes.set_ylabel(self.local['vis_cp_hist_x_v2'])
1455  self.axes.set_xlim(0, self.expectationIntercept*1.3)
1456  self.axes.set_ylim(0, self.expectationIntercept*1.3)
1457 
1458  def get(self):
1459  self.axes.legend()
1460  return basicPlot.get(self)
1461 
1462 
1465 def interactionMap(pointColumnList, ptype='hexbin', colour='hot', weightedDensity=False, xy_bounds=None, z_bounds=None, gridsize=[60,60], minGridSize=1.0, mincnt=1, alignments=False, mask=False, zone=False, labels=False, local=None, zlabel='', fig_name='CP Map', indent=4, verbose=0, figsize=[15.0,12.0], plotSettings=None, **kwargs):
1466  ''' Plot CP heatmap
1468  Generally makes use of matplotlib's hexbin. If the number of points is too great, the data will be condensed with condensePointList() and matplotlib's pcolor will be used instead.
1469 
1470  Input:
1471  ======
1472  pointColumnList: A list of coordinate columns (each row is a point)
1473  mode: 'hexbin' for a hexbin plot, 'imshow' for an imshow plot (defaults to hexbin)
1474  colour: http://wiki.scipy.org/Cookbook/Matplotlib/Show_colormaps
1475  gridsize: Must be a two-item list, preferably square, indicating the size of the hex grid
1476  minGridSize: Minimum size of each hex (in metres)
1477  mincnt: Bins with fewer than this many points will not be plotted
1478  zticks:
1479  '''
1480  fig = plt.figure(fig_name, figsize=(figsize[0], figsize[1]))
1481  if(not local): local = tvaLocal.Local()
1482 
1483 
1484  if(not pointColumnList or type(pointColumnList) != list or len(pointColumnList) == 0 or len(pointColumnList[0]) == 0):
1485  if(verbose >= 2): tvaLib.printWarning('Empty dataset passed in interactionMap "'+fig_name+'".', indent=indent)
1486  return False
1487  if(verbose >= 2): print(''.rjust(indent,' ')+'Conflict points loaded in CP mapping function: '+str(len(pointColumnList[1])))
1488 
1489 
1490  plotBB(mask, labels=labels, boxLabel=local['vis_mask'], outlineOnly=False, zone_bgcolour='0.90', plotSettings=plotSettings, **kwargs)
1491  plotBB(zone, labels=labels, boxLabel=local['vis_analysis_area'], zone_bgcolour='green', alpha=0.5, plotSettings=plotSettings, **kwargs)
1492 
1493 
1495  if(ptype == 'imshow'):
1496  #Experimental
1497  if(weightedDensity): pointColumnList_ = pointList2DHisto([pointColumnList[1], pointColumnList[2], pointColumnList[3]], bins=[60,60])
1498  else: pointColumnList_ = pointList2DHisto([pointColumnList[1], pointColumnList[2]], bins=[30,30])
1499 
1500  #Adjust transparency of colour map
1501  cm = plt.get_cmap(colour)
1502  #cm._init()
1503  #cm._lut[:-3,-1] = np.abs(np.linspace(-1.0, 1.0, cm.N))
1504  #Plot
1505  #import pdb; pdb.set_trace()
1506  extent = [pointColumnList_[1][0],pointColumnList_[1][-1],pointColumnList_[2][0],pointColumnList_[2][-1]]
1507  Map = plt.imshow(np.transpose(pointColumnList_[0]), interpolation='None', cmap=cm, extent=(extent[0], extent[1], extent[2], extent[3]), origin='lower')
1508  else: #(hexbin)
1509 
1510  extent = [max(pointColumnList[1])-min(pointColumnList[1]), max(pointColumnList[2])-min(pointColumnList[2])]
1511  if(extent[0] < gridsize[0]*minGridSize or extent[1] < gridsize[1]*minGridSize): gridsize = [int(extent[0]/minGridSize)+(extent[0] % minGridSize > 0), int(extent[1]/minGridSize)+(extent[1] % minGridSize > 0)]
1512 
1513  if(weightedDensity):
1514  if(z_bounds):
1515  if(type(z_bounds) == list and len(z_bounds) == 2): Map = plt.hexbin(pointColumnList[1], pointColumnList[2], C=pointColumnList[3], gridsize=gridsize, cmap=plt.get_cmap(colour), vmin=z_bounds[0], vmax=z_bounds[1])
1516  else: Map = plt.hexbin(pointColumnList[1], pointColumnList[2], C=pointColumnList[3], gridsize=gridsize, cmap=plt.get_cmap(colour), vmax=z_bounds)
1517  else:
1518  Map = plt.hexbin(pointColumnList[1], pointColumnList[2], C=pointColumnList[3], gridsize=gridsize, cmap=plt.get_cmap(colour))
1519  else:
1520  Map = plt.hexbin(pointColumnList[1], pointColumnList[2], gridsize=gridsize, cmap=plt.get_cmap(colour), mincnt=mincnt)
1521  Map.set_zorder(5)
1522  cb = plt.colorbar()
1523  if(zlabel): cb.set_label(zlabel)
1524  else: cb.set_label(local['vis_cp_label'])
1525 
1526 
1527  plotAlign(alignments, draw_corridors=False, labels=labels, lineAlpha=0.2, annotateAlpha=0.2, plotSettings=plotSettings)
1528 
1529 
1530  ax = plb.gca()
1531  plt.axis('equal')
1532  if(xy_bounds):
1533  ax.set_xlim([xy_bounds[0].lower,xy_bounds[0].upper])
1534  ax.set_ylim([xy_bounds[1].lower,xy_bounds[1].upper])
1535  ax.set_ylim(ax.get_ylim()[::-1])
1536  ax.set_xlabel(local['vis_gen_x_coords_m'])
1537  ax.set_ylabel(local['vis_gen_y_coords_m'])
1538 
1539  return fig
1540 
1541 
1542 def interactionTTCHist(ttc_histos, fps=15.0, timehorizon=5.0, enableBars=True, linewidth=5, dist_type='pdf', labels=False, label_ratio='', local=None, fig_name='TTC pdf', verbose=0, figsize=[15.0,12.0]):
1543  ''' Plot TTC distribution.
1545  Input:
1546  ======
1547  Expects ttc_histos to be in the following format:
1548  [[[TTC values (X), Frequencies (Y)], 'Name'], ...]
1549  ttc_histos can be passed as pdfs, cdfs, or frequencies
1550 
1551  timehorizon: Max TTC value to consider, in seconds
1552  legend_location: "4" for bottom right, defaults to top right
1553  '''
1554 
1555  fig = plt.figure(fig_name, figsize=(figsize[0], figsize[1]))
1556  if(not local): local = tvaLocal.Local()
1557  if(not ttc_histos or not isinstance(ttc_histos, list) or len(ttc_histos) <= 0 or not isinstance(ttc_histos[0], list) or len(ttc_histos[0]) <= 0 or not ttc_histos[0][0]):
1558  if(verbose): tvaLib.printWarning('Empty or incorrect dataset passed in interactionTTCHist "'+fig_name+'".', indent=4)
1559  return False
1560 
1561 
1563  if(len(ttc_histos) == 1 and enableBars):
1564  plt.bar([x/float(fps) for x in ttc_histos[0][0][0][:-1]], ttc_histos[0][0][1][:], width=(ttc_histos[0][0][0][1]-ttc_histos[0][0][0][0])/float(fps), label=ttc_histos[0][1])
1565  #Plot line graphs
1566  max_y = 0
1567  for ttc_histo in ttc_histos:
1568  plt.plot([x/float(fps) for x in ttc_histo[0][0][:-1]], ttc_histo[0][1][:], label=ttc_histo[1], linewidth=linewidth)
1569  try:
1570  if(max(ttc_histo[0][1]) > max_y): max_y = max(ttc_histo[0][1])
1571  except ValueError: max_y = 1
1572 
1573 
1574  if(labels):
1575  if(dist_type=='cdf'): plt.legend(loc=4)
1576  else: plt.legend()
1577  #plt.annotate(label_ratio, xytext=(float(timehorizon)*0.95, max_y*0.05), textcoords='offset points', ha='right', va='bottom', bbox=dict(boxstyle='Square,pad=0.5', fc='white', alpha=0.5))
1578 
1579 
1580  plt.axis([0,timehorizon,0,max_y])
1581  ax = plb.gca()
1582  ax.set_xlabel(local['vis_cp_hist_x'])
1583  if(dist_type=='cdf'): ax.set_ylabel(local['vis_hist_y_cdf'])
1584  else:
1585  try: ax.set_ylabel(local['vis_hist_y_pdf'].format(round((ttc_histos[0][0][1][1]-ttc_histos[0][0][1][0])/float(fps),3)))
1586  except IndexError: ax.set_ylabel(local['vis_hist_y_pdf'].format(0.00))
1587 
1588  return fig
1589 
1591  def __init__(self, userPairs, fps, alpha=0.1, fig_name='TTC timeseries', **kwargs):
1592  basicPlot.__init__(self, fig_name=fig_name, **kwargs)
1593  self.alpha = alpha
1594  self.avgVal = {}
1595  self.avgValWeight = {}
1597  self.addTimeseries(userPairs, fps)
1599 
1600  def addTimeseries(self, userPairs, fps):
1601  if(userPairs):
1602  for userPair in userPairs:
1603  point_list = userPair.getPointList()
1604  if(point_list):
1605  point_list = sorted(point_list, key=lambda x: x[4])
1606  # Select offset style
1607  #ti = 0 # first indicator
1608  min_ttc = min([x[0] for x in point_list])
1609  ti = [x for x,y in zip(range(len(point_list)),point_list) if y[0] == min_ttc][0]# minimum TTC
1610  # ti +TTC_ti -intercept
1611  offset = point_list[ti][4]/float(fps)+point_list[ti][0]/float(fps)-self.expectationIntercept
1612  for t,ttc in zip([x[4]/float(fps)-offset for x in point_list], [x[0]/float(fps) for x in point_list]):
1613  t = round(t, 1)
1614  try: self.avgVal[t] += ttc
1615  except: self.avgVal[t] = ttc
1616  try: self.avgValWeight[t] += 1
1617  except: self.avgValWeight[t] = 1
1618  self.axes.plot([x[4]/float(fps)-offset for x in point_list], [x[0]/float(fps) for x in point_list], color='b', alpha=self.alpha)
1619 
1620  def computeAverage(self):
1621  try: maxSampleSize = max(self.avgValWeight.values())
1622  except ValueError: return False
1623  x = sorted(self.avgVal.keys())
1624  y = [self.avgVal[t]/float(self.avgValWeight[t]) if (self.avgValWeight[t] > maxSampleSize*0.05) else None for t in x]
1625  self.axes.plot(x, y, linewidth=3, color='k', zorder=9000, label=self.local['gen_average'])
1626 
1627  def plotExpectation(self):
1628  self.axes.plot([0,self.expectationIntercept], [self.expectationIntercept,0], c='k', linewidth=2, alpha=0.5, linestyle='dashed', label=self.local['vis_expected_evolution'])
1630  def setAxes(self):
1631  self.axes.set_xlabel(self.local['vis_timeseries_x'])
1632  self.axes.set_ylabel(self.local['vis_cp_hist_x_v2'])
1633  self.axes.set_xlim(0, self.expectationIntercept*1.3)
1634  self.axes.set_ylim(0, self.expectationIntercept*1.3)
1635 
1636  def get(self):
1637  self.plotExpectation()
1639  self.axes.legend()
1640  return basicPlot.get(self)
1641 
1642 
1643 
1646 '''
1647 class VisAlignData(basicPlot):
1648  def __init__(self, sl, slsd, hl_offset=False, min_obs=10, **kwargs):
1649  basicPlot.__init__(self, fig_rows=len(sl) **kwargs)
1650 
1651  twinIxRecords=[]
1652  for align in range(len(sl)):
1653  #Get mean number of observations
1654  mean_obs = np.mean(slsd[align][0])
1655  if(mean_obs < min_obs): continue
1656  #Get un-nan bounds
1657  for point in range(len(sl[align][2])):
1658  if(not m.isnan(sl[align][2][point])):
1659  x_min_1 = point
1660  break
1661  for point in range(len(slsd[align][0])):
1662  if(slsd[align][0][point] > (mean_obs/3)):
1663  x_min_2 = point
1664  break
1665  x_min=max(x_min_1,x_min_2)
1666 
1667  for point in range(len(sl[align][2])):
1668  i_point = len(sl[align][2]) - point - 1
1669  if(not m.isnan(sl[align][2][i_point])):
1670  x_max_1 = i_point
1671  break
1672  for point in range(len(slsd[align][0])):
1673  i_point = len(slsd[align][0]) - point - 1
1674  if(slsd[align][0][i_point] > (mean_obs/3)):
1675  x_max_2 = i_point
1676  break
1677  x_max=min(x_max_1,x_max_2)
1678 
1679  try: x_min
1680  except NameError:
1681  tvaLib.printWarning('No trajectories found while attempting to plot alignment {0}'.format(align), indent=4)
1682  x_min = 0
1683  try: x_max
1684  except NameError:
1685  tvaLib.printWarning('No trajectories found while attempting to plot alignment {0}'.format(align), indent=4)
1686  x_max = 0
1687 
1688  ## Plot Stuff
1689  try: ax = fig.add_subplot(len(sl),1,1+align, sharey=ax)
1690  except UnboundLocalError: ax = fig.add_subplot(len(sl),1,1+align)
1691  plt.annotate(local['gen_alignment']+' '+str(align), xy=(0.5, 0.2), xycoords='axes fraction', xytext=(0.80, 0.90), textcoords='axes fraction', bbox = dict(boxstyle = 'Square,pad=0.5', fc = 'white', alpha = 0.9), fontsize=20)
1692  plt.xlabel('Alignment distance (in metres)')
1693 
1694  ## First axis
1695  plt.plot(sl[align][1][x_min:x_max], sl[align][2][x_min:x_max],'r',linewidth=2) plt.annotate(u'\u039C Speed', family='cambria', xy=(sl[align][1][5+x_min], sl[align][2][5+x_min]), xytext = (-20,20), textcoords = 'offset points', ha = 'right', va = 'bottom', bbox = dict(boxstyle = 'Square,pad=0.5', fc = 'white', alpha = 0.5), arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'))
1696  std_up = [sum(pair) for pair in zip(sl[align][2][x_min:x_max], sl[align][3][x_min:x_max])]
1697  std_down = [pair[0]-pair[1] for pair in zip(sl[align][2][x_min:x_max], sl[align][3][x_min:x_max])]
1698  if(not std_up or not std_down): continue
1699  plt.plot(sl[align][1][x_min:x_max], std_up,'b--')
1700  plt.annotate(u'+1 \u03C3', family='cambria', xy=(sl[align][1][5+x_min], std_up[5]), xytext = (-20,20), textcoords = 'offset points', ha = 'right', va = 'bottom', bbox = dict(boxstyle = 'Square,pad=0.5', fc = 'white', alpha = 0.5), arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'))
1701  plt.plot(sl[align][1][x_min:x_max], std_down,'b--')
1702  plt.annotate(u'-1 \u03C3', family='cambria', xy=(sl[align][1][5+x_min], std_down[5]), xytext = (-20,20), textcoords = 'offset points', ha = 'right', va = 'bottom', bbox = dict(boxstyle = 'Square,pad=0.5', fc = 'white', alpha = 0.5), arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'))
1703  plt.ylabel(local['gen_speed'])
1704  x_lim = plb.gca().get_xlim()
1705 
1706 
1707  ax2 = ax.twinx()
1708  ax2.plot(slsd[align][1][x_min:x_max],slsd[align][0][x_min:x_max],'k',linewidth=3)
1709  ax2.annotate('Observations', xy=(slsd[align][1][x_max-10], slsd[align][0][x_max-10]), xytext = (20,20), textcoords = 'offset points', ha = 'left', va = 'bottom', bbox = dict(boxstyle = 'Square,pad=0.5', fc = 'white', alpha = 0.5), arrowprops = dict(arrowstyle = '->', connectionstyle = 'arc3,rad=0'))
1710  ax2.set_ylabel('Observations')
1711  ax2.set_ylim(max(min((max(slsd[align][0][x_min:x_max])/2),min(slsd[align][0][x_min:x_max]))-10,0), max(slsd[align][0][x_min:x_max])+10)
1712 
1713 
1714  if(hl_offset != False):
1715  X = []
1716  Y = []
1717  for point in hl_offset[align]:
1718  X.append(point[0])
1719  Y.append(point[1])
1720  ay2 = plt.twiny()
1721  #Recalculate axis alignment (e.g. equivalent xmin, xmax)
1722  ay2.set_xlim(x_lim[0], x_lim[1])
1723  ay2.set_xticks(X)
1724  ay2.set_xticklabels(Y)
1725  ay2.set_xlabel('Merge region (normalised)')
1726  twinIxRecords.append(ax2)
1727 
1728 '''
1729 
1730 
1731 def visAlignData(sl, slsd, hl_offset=False, local=None, min_obs=10, fig_name='Alignment data', figsize=[15.0,12.0], plotSettings=None):
1732  ''' Plot alignment speed and observation data
1733 
1734  Greek letter documentation at: http://matplotlib.sourceforge.net/users/mathtext.html
1735  '''
1736  ## Verify and prepare data
1737  aligns = {}
1738  for align in range(len(sl)):
1739  #Get mean number of observations
1740  mean_obs = np.mean(slsd[align][0])
1741  if(mean_obs < min_obs): continue
1742  #Get un-nan bounds
1743  for point in range(len(sl[align][2])):
1744  if(not m.isnan(sl[align][2][point])):
1745  x_min_1 = point
1746  break
1747  for point in range(len(slsd[align][0])):
1748  if(slsd[align][0][point] > (mean_obs/3)):
1749  x_min_2 = point
1750  break
1751  x_min=max(x_min_1,x_min_2)
1752 
1753  for point in range(len(sl[align][2])):
1754  i_point = len(sl[align][2]) - point - 1
1755  if(not m.isnan(sl[align][2][i_point])):
1756  x_max_1 = i_point
1757  break
1758  for point in range(len(slsd[align][0])):
1759  i_point = len(slsd[align][0]) - point - 1
1760  if(slsd[align][0][i_point] > (mean_obs/3)):
1761  x_max_2 = i_point
1762  break
1763  x_max=min(x_max_1,x_max_2)
1764 
1765  try: x_min
1766  except NameError:
1767  tvaLib.printWarning('No trajectories found while attempting to plot alignment {0}'.format(align), indent=4)
1768  x_min = 0
1769  try: x_max
1770  except NameError:
1771  tvaLib.printWarning('No trajectories found while attempting to plot alignment {0}'.format(align), indent=4)
1772  x_max = 0
1773 
1774  aligns[align] = [x_min,x_max]
1775 
1776  if(len(aligns)==0): return False
1777  fig, axes = plt.subplots(nrows=len(aligns), ncols=1, num=fig_name, sharex=True, figsize=(figsize[0], figsize[1]))
1778  if(type(axes) is not list and type(axes) is not np.ndarray): axes = [axes]
1779  if(not local): local = tvaLocal.Local()
1780  labelsPlotted=False
1781 
1782  for align,axis in zip(aligns,axes):
1783  x_min = aligns[align][0]
1784  x_max = aligns[align][1]
1785  ## First axis
1786  axis.plot(sl[align][1][x_min:x_max], sl[align][2][x_min:x_max], 'r', linewidth=2, label=r"$\mu$ "+local['gen_speed_'])
1787  y_max = max(sl[align][2][x_min:x_max])
1788  std_up = [sum(pair) for pair in zip(sl[align][2][x_min:x_max], sl[align][3][x_min:x_max])]
1789  std_down = [pair[0]-pair[1] for pair in zip(sl[align][2][x_min:x_max], sl[align][3][x_min:x_max])]
1790  if(std_up and std_down):
1791  axis.plot(sl[align][1][x_min:x_max], std_up, 'b--', label=r"$+1 \sigma$")
1792  axis.plot(sl[align][1][x_min:x_max], std_down, 'b--', label=r"$-1 \sigma$")
1793  y_max = max(std_up)
1794  axis.set_ylim(0, y_max)
1795 
1796 
1797  ## Second axis
1798  ax2 = axis.twinx()
1799  axis.plot(slsd[align][1][x_min], slsd[align][0][x_min], 'k', linewidth=3, label=local['gen_observations']) ## This is a dummy plot to add label to legend
1800  ax2.plot(slsd[align][1][x_min:x_max], slsd[align][0][x_min:x_max], 'k', linewidth=3, label=local['gen_observations'])
1801  ax2.set_ylim(max(min((max(slsd[align][0][x_min:x_max])/2),min(slsd[align][0][x_min:x_max]))-10,0), max(slsd[align][0][x_min:x_max])+10)
1802 
1803  ## Add feature offset ticker
1804  if(hl_offset != False):
1805  X = []
1806  Y = []
1807  for point in hl_offset[align]:
1808  X.append(point[0])
1809  Y.append(point[1])
1810  ay2 = plt.twiny()
1811  #Recalculate axis alignment (e.g. equivalent xmin, xmax)
1812  ay2.set_xticks(X)
1813  ay2.set_xticklabels(Y)
1814  ay2.set_xlabel('Merge region (normalised)')
1815 
1816 
1817  ## Set title
1818  axis.set_title(local['gen_alignment']+' '+str(align+1), size=plotSettings['size']*0.66)
1819  if(not labelsPlotted):
1820  axis.legend(prop={'size':plotSettings['size']*0.66})
1821  labelsPlotted=True
1822 
1823 
1824  ## Set Axis labels
1825  fig.text(0.5, 0.04, local['vis_align_x_label'], ha='center', va='center')
1826  fig.text(0.06, 0.5, local['gen_speed'], ha='center', va='center', rotation='vertical')
1827  fig.text(0.96, 0.5, local['gen_observations'], ha='center', va='center', rotation='vertical')
1828 
1829  return fig
1830 
1831 ##################
1832 ## Analysis
1833 ##################
1834 class Analysis():
1835  def __init__(self):
1836  return
1838  @staticmethod
1839  def plotTODSamplingDistribution(site_analyses, saIxs=None, local=None, fig_name='TOD Sampling', verbose=0, figsize=[15.0,12.0], **kwargs):
1840  ''' Plot the distribution of seqeuences by time of day, showing daily sampling
1841 
1842  Note that the sample is approximate. Each hour is counted once if at least one sequence starts in that hour
1843 
1844  Input:
1845  ======
1846 
1847 
1848  '''
1849  fig, ax = plt.subplots(num=fig_name, figsize=(figsize[0], figsize[1]))
1850 
1851  ## Aggregate data
1852  hourBins = [0 for x in range(24)]
1853  for saIx in saIxs:
1854  for x in site_analyses[saIx].getCamSeqs_Hourly():
1855  hourBins[x] += 1
1856 
1857  ## Plot data
1858  plt.plot(range(24), hourBins)
1859 
1860  ## Labels
1861  ax.set_xlabel(local['vis_tod'])
1862  ax.set_ylabel(local['gen_sequences'])
1863 
1864  return fig
1865 
1866 
1867 
1868  @staticmethod
1869  def plotIndicatorCounts_worker(data, ax=None, fig_name='Indicator counts', verbose=0, figsize=[15.0,12.0]):
1870  ''' Plot indicator counts
1871 
1872  Input:
1873  ======
1874  data: a list of three values: ind below threshold, indicators, user pairs
1875  '''
1876  rects1 = ax.bar(0, data[0], color='r')
1877  rects2 = ax.bar(0, data[1], color='b')
1878  rects3 = ax.bar(0, data[2], color='g')
1879  return True
1880 
1881  @staticmethod
1882  def plotIndicatorCounts(data, local=None, fig_name='Indicator counts', verbose=0, figsize=[15.0,12.0], **kwargs):
1883  ''' Plot indicator counts
1884 
1885  Input:
1886  ======
1887  data: a list of three values: ind below threshold, indicators, user pairs
1888  '''
1889  fig, ax = plt.subplots(num=fig_name, figsize=(figsize[0], figsize[1]))
1890  if(not local): local = tvaLocal.Local()
1891 
1892  Analysis.plotIndicatorCounts_worker(data, ax=ax, fig_name=fig_name, verbose=verbose, **kwargs)
1893 
1894 
1895  ax.set_xlabel(local['vis_cp_hist_x'])
1896  ax.set_ylabel(local['vis_hist_y_cdf'])
1897 
1898  return fig
1899 
1900 
1901  @staticmethod
1902  def plotMethodGrid(datas, prototype, workerArgs=None, set_ylim=None, local=None, fig_name='Grid', verbose=0, fontsize=16, figsize=[15.0,12.0], **kwargs):
1903  ''' Plot graphs ina a grid based on calculation method. '''
1904  if(len(datas) != 12): return False
1905  fig, ((ax11, ax12, ax13, ax14), (ax21, ax22, ax23, ax24), (ax31, ax32, ax33, ax34)) = plt.subplots(3, 4, sharex=True, sharey=True, num=fig_name, figsize=(figsize[0], figsize[1]))
1906  if(not local): local = tvaLocal.Local()
1907 
1908  for data, ax in zip(datas, [ax11, ax12, ax13, ax14, ax21, ax22, ax23, ax24, ax31, ax32, ax33, ax34]):
1909  if(workerArgs): workerArg = workerArgs[datas.index(data)]
1910  else: workerArg = {}
1911  prototype(data, ax=ax, verbose=verbose, **workerArg.update(kwargs))
1912 
1913 
1914  ax31.set_xlabel(local['int_all_instants'], fontsize=int(round(fontsize*0.75,0)))
1915  ax32.set_xlabel(local['int_unique_min'], fontsize=int(round(fontsize*0.75,0)))
1916  ax33.set_xlabel(local['int_unique_15th'], fontsize=int(round(fontsize*0.75,0)))
1917  ax34.set_xlabel(local['int_unique_max_prob'], fontsize=int(round(fontsize*0.75,0)))
1918 
1919  ax11.set_ylabel(local['int_const_vel'], fontsize=int(round(fontsize*0.75,0)))
1920  ax21.set_ylabel(local['int_norm_adapt'], fontsize=int(round(fontsize*0.75,0)))
1921  ax31.set_ylabel(local['int_motion_pattern'], fontsize=int(round(fontsize*0.75,0)))
1922 
1923  fig.text(0.5, 0.00, local['vis_cp_hist_x'], ha='center', va='center')
1924  fig.text(0.06, 0.5, local['vis_hist_y_cdf'], ha='center', va='center', rotation='vertical')
1925 
1926 
1927  if(set_ylim): ax11.set_ylim(set_ylim)
1928  return fig
1929 
1930 
1931 
1932  @staticmethod
1933  def plotTTCdistros_worker(data, ax=None, klusters=None, klusterColors=['r',(0.105,0.867,0.617),(0.91796875,0.0859375,0.9453125),(0.875,0.12109375,0.03515625),(0.73828125,0.53515625,0.1640625),(0.588,0.380,0),'y'], klusterLinestyles=['-', '-', '--', ':','-.','-'], klusterMarkers = ['', 'o', '', '','','x'], method=0, plotMedian=False, dist_type='pdf', timehorizon=10.0, set_ylim=None, labelSampleSize=False, labelSize=10, shadeBySampleSize=True, dumpMedianData=False, fig_name='TTC Frequency', verbose=0, figsize=[15.0,12.0]):
1934  ''' Plot TTC distros for all sites
1935 
1936  Input:
1937  ======
1938  data: analysis.Frequency -type object, e.g. in the form [[[xBins],[yFreqs]],...]
1939  where xBin is one larger than it's corresponding yFreq
1940  method=0: automatic
1941  =1: plot all sites in red
1942  =2: plot 25th and 75th quartile
1943  klusters: optional list, same size as data of cluster groups for each data
1944  type='pdf': probability distribution
1945  ='cdf': cumulative distribution
1946  shadeBySampleSize: If set to True, and method=1 will shade individual sites by sample size
1947  '''
1948 
1949  try:
1950  if(True not in [datum.getPDF() != False for datum in data]): return False, False, False
1951  except: return False, False, False
1952  if(not ax): return False, False, False
1953  if(klusters==None): klusters = [0 for x in data]
1954 
1955 
1956  if(method==0):
1957  if(len(data) < 10): method = 1
1958  else: method = 2
1959 
1960  for kluster in [x for x in list(set(klusters)) if x is not None]:
1961  kluster_depth=0
1962  # Determine max sample size if necessary
1963  if(method==1 and shadeBySampleSize): largestSampleSize = max([datum.depth for datum in [data[i] for i, x in enumerate(klusters) if x==kluster]])
1965  for datum in [data[i] for i, x in enumerate(klusters) if x==kluster]:
1966  if(not datum.getPDF()): continue
1967  #Determine bin range
1968  x_range = [(x+y)/2.0 for x,y in zip(datum.binStops[:-1],datum.binStops[1:])]
1969  #Get raw freq data for mean/std.dev calculation
1970  try: ydata = [x+[y] for x, y in zip(ydata, datum.getFreq())]
1971  except:
1972  ydata = [[] for x in x_range]
1973  ydata = [x+[y] for x, y in zip(ydata, datum.getFreq())]
1974 
1975  #Plot each site in red
1976  if(method==1):
1977  if(shadeBySampleSize): intensity = datum.depth/float(largestSampleSize)
1978  else: intensity = 1
1979  if(dist_type=='cdf'):
1980  ax.plot(x_range, datum.getCDF(), color=klusterColors[kluster], alpha=intensity, linestyle=klusterLinestyles[kluster], marker=klusterMarkers[kluster], linewidth=1)
1981  if(labelSampleSize): ax.text(x_range[datum.getCDF().index(min(datum.getCDF(), key=lambda x:abs(x-0.5)))], min(datum.getCDF(), key=lambda x:abs(x-0.5)), str(datum.depth), color=klusterColors[kluster], alpha=intensity, size=labelSize, horizontalalignment='left', verticalalignment='top')
1982  else:
1983  ax.plot(x_range, datum.getPDF(), color=klusterColors[kluster], alpha=intensity, linestyle=klusterLinestyles[kluster], marker=klusterMarkers[kluster], linewidth=1)
1984  if(labelSampleSize): ax.text(x_range[datum.getPDF().index(max(datum.getPDF()))], max(datum.getPDF()), str(datum.depth), color=klusterColors[kluster], alpha=intensity, size=labelSize)
1985  kluster_depth += datum.depth
1986  try:
1987  mean, median, percent_low, percent_high, stddev = tvaLib.Math.pdfStatsOnBinnedFreqData(ydata)
1988 
1989  if(method==2):
1990  ax.fill_between(x_range, percent_low, percent_high, facecolor='red', alpha=0.2)
1991  #plt.plot(x_range, [x+y for x, y in zip(mean, stddev)], 'red', linewidth=1)
1992  #plt.plot(x_range, [x-y for x, y in zip(mean, stddev)], 'red', linewidth=1)
1994 
1995  if(len([x for x in list(set(klusters)) if x is not None]) <= 1): colour = 'k'
1996  else: colour = klusterColors[kluster]
1997 
1998  if(dist_type=='cdf'):
1999  ax.plot(x_range, tvaLib.Math.pdfToCDF(mean), color=colour, linestyle=klusterLinestyles[kluster], marker=klusterMarkers[kluster], linewidth=3)
2000  if(plotMedian): ax.plot(x_range, tvaLib.Math.pdfToCDF(median), color=colour, linestyle=klusterLinestyles[kluster], marker=klusterMarkers[kluster], linewidth=2)
2001  if(labelSampleSize): ax.text(x_range[tvaLib.Math.pdfToCDF(mean).index(min(tvaLib.Math.pdfToCDF(mean), key=lambda x:abs(x-0.5)))], min(tvaLib.Math.pdfToCDF(mean), key=lambda x:abs(x-0.5)), str(kluster_depth), color=colour, size=labelSize, horizontalalignment='left', verticalalignment='top')
2002  else:
2003  ax.plot(x_range, mean, color=colour, linestyle=klusterLinestyles[kluster], marker=klusterMarkers[kluster], linewidth=3)
2004  if(plotMedian): ax.plot(x_range, median, color=colour, linestyle=klusterLinestyles[kluster], marker=klusterMarkers[kluster], linewidth=2)
2005  if(labelSampleSize): ax.text(x_range[mean.index(max(mean))], max(mean), str(kluster_depth), color=colour, size=labelSize)
2006  if(dumpMedianData):
2007  with open(fig_name+'.txt', 'w') as f:
2008  f.write(str(x_range))
2009  f.write(str(median))
2010  except: pass
2011 
2012 
2013 
2014  ax.set_xlim([0.0,timehorizon])
2015  if(dist_type=='cdf'): ax.set_ylim([0.0,1.0])
2016  elif(set_ylim): ax.set_ylim(set_ylim)
2017 
2018  return round(x_range[1]-x_range[0],3), x_range, mean
2019 
2020  @staticmethod
2021  def plotTTCdistros(data, local=None, dist_type='pdf', set_ylim=None, fig_name='TTC Frequency', verbose=0, figsize=[15.0,12.0], **kwargs):
2022  ''' Plot TTC distros for all sites
2023 
2024  Input:
2025  ======
2026  data = [[[xBins],[yFreqs]],...] where xBin is one larger than it's corresponding yFreq
2027  method = 0: automatic
2028  1: plot all sites in red
2029  2: plot 25th and 75th quartile
2030 
2031  type = 'pdf'|'cdf'
2032  '''
2033  fig, ax = plt.subplots(num=fig_name, figsize=(figsize[0], figsize[1]))
2034  if(not local): local = tvaLocal.Local()
2035 
2036  try: binsize, x_range, mean = Analysis.plotTTCdistros_worker(data, ax=ax, dist_type=dist_type, fig_name=fig_name, verbose=verbose, **kwargs)
2037  except:
2038  tvaLib.printWarning('TTC distribution plotting worker failed in figure "'+fig_name+'".', local['gen_warning'])
2039  return False, False, False
2040 
2041 
2042  ax.set_xlabel(local['vis_cp_hist_x'])
2043  if(dist_type=='cdf'): ax.set_ylabel(local['vis_hist_y_cdf'])
2044  else: ax.set_ylabel(local['vis_hist_y_pdf'].format(binsize))
2045 
2046  return fig, x_range, mean
2047 
2048 
2049  @staticmethod
2050  def plotTTCdistros_grid(datas, klusters, local=None, dist_type='pdf', set_ylim=[0.0,0.2], fig_name='TTC Frequency', verbose=0, fontsize=16, figsize=[15.0,12.0], **kwargs):
2051  ''' Plot TTC distros for all sites. This version differs from
2052  plotTTCdistros() in that it takes 12 input distributions.
2053  TODO: refactor with plotMethodGrid ()
2054  '''
2055  if(len(datas) != 12): return False
2056  fig, ((ax11, ax12, ax13, ax14), (ax21, ax22, ax23, ax24), (ax31, ax32, ax33, ax34)) = plt.subplots(3, 4, sharex=True, sharey=True, num=fig_name, figsize=(figsize[0], figsize[1]))
2057  if(not local): local = tvaLocal.Local()
2058 
2059  for data, kluster_s, ax in zip(datas, klusters, [ax11, ax12, ax13, ax14, ax21, ax22, ax23, ax24, ax31, ax32, ax33, ax34]):
2060  binsize, _, _ = Analysis.plotTTCdistros_worker(data, ax=ax, klusters=kluster_s, dist_type=dist_type, verbose=verbose, **kwargs)
2061 
2062 
2063  ax31.set_xlabel(local['int_all_instants'], fontsize=int(round(fontsize*0.75,0)))
2064  ax32.set_xlabel(local['int_unique_min'], fontsize=int(round(fontsize*0.75,0)))
2065  ax33.set_xlabel(local['int_unique_15th'], fontsize=int(round(fontsize*0.75,0)))
2066  ax34.set_xlabel(local['int_unique_max_prob'], fontsize=int(round(fontsize*0.75,0)))
2067 
2068  ax11.set_ylabel(local['int_const_vel'], fontsize=int(round(fontsize*0.75,0)))
2069  ax21.set_ylabel(local['int_norm_adapt'], fontsize=int(round(fontsize*0.75,0)))
2070  ax31.set_ylabel(local['int_motion_pattern'], fontsize=int(round(fontsize*0.75,0)))
2071 
2072  fig.text(0.5, 0.00, local['vis_cp_hist_x'], ha='center', va='center')
2073  if(dist_type=='cdf'): fig.text(0.06, 0.5, local['vis_hist_y_cdf'], ha='center', va='center', rotation='vertical')
2074  else: fig.text(0.06, 0.5, local['vis_hist_y_pdf'].format(binsize), ha='center', va='center', rotation='vertical')
2075 
2076 
2077  if(dist_type=='pdf' and set_ylim): ax11.set_ylim(set_ylim)
2078 
2079  return fig
2080 
2081  @staticmethod
2082  def siteTTC(data, labels=None, colours=['r','b','c','m','k','g'], linestyles=['-.','--','-','-','-','-'], timehorizon=10.0, local=None, fig_name='TTC Frequency', verbose=0, figsize=[15.0,12.0]):
2083  ''' Plot TTC cdfs for one site at a time. '''
2084  fig, ax = plt.subplots(num=fig_name, figsize=(figsize[0], figsize[1]))
2085  if(not local): local = tvaLocal.Local()
2086 
2087  rects = []
2088  for datum in data:
2089  for dat in datum:
2090  try:
2091  xrange = [(x+y)/2.0 for x,y in zip(dat[-1].binStops[:-1],dat[-1].binStops[1:])]
2092  if(labels): label = labels[data.index(datum)][0]+' '+labels[data.index(datum)][1][datum.index(dat)]
2093  else: label = ''
2094  rects.append( ax.plot(xrange, dat[-1].getCDF(), label=label, color=colours[data.index(datum)], linestyle=linestyles[datum.index(dat)], linewidth=1))
2095  except:
2096  pass
2097 
2098 
2099  ax.set_xlim([0.0,timehorizon])
2100  ax.set_ylim([0.0,1.0])
2101 
2102 
2103  ax.set_xlabel(local['vis_cp_hist_x'])
2104  ax.set_ylabel(local['vis_hist_y_cdf'])
2105  handles, labels = ax.get_legend_handles_labels()
2106  ax.legend(handles, labels, loc='lower right', prop={'size':16})
2107 
2108 
2109  return fig
2110 
2111 
2114 class DrawOther():
2115  def __init__(self):
2116  return
2118  @staticmethod
2119  def DMPExperimental(predictionParameters, objects, site_analysis, config, fig_dpi=100, fig_format='png', dmp_plot_depth_frames=80, indent=8, plotSettings=None, verbose=0):
2120  ''' EXPERIMENTAL VISUALISATION '''
2121 
2122  sampleSizes = predictionParameters.getSampleSizes()
2123 
2124 
2125  max_value, max_index = max((x, (i, j, k))
2126  for i, row in enumerate(sampleSizes)
2127  for j, row2 in enumerate(row)
2128  for k, x in enumerate(row2))
2129 
2130 
2131  histo1 = np.histogram(tvaLib.flatten_list(sampleSizes), bins=range(1,50))
2132  histo2 = np.histogram(tvaLib.flatten_list(sampleSizes), bins=range(1,15))
2133  empty = len(filter(None, tvaLib.flatten_list(sampleSizes)))
2134  top = deepcopy(tvaLib.flatten_list(sampleSizes))
2135  top.sort(reverse=True)
2136 
2137  fig = plt.figure('DMP initial conditions sample size distribution', figsize=(config.figsize[0], config.figsize[1]))
2138  ax1 = fig.add_subplot(221)
2139  ax1.bar(histo2[1][1:-1],histo2[0][1:], 1, color=(0.449, 0.449, 0.449), linewidth=0)
2140  ax1.set_ylabel('Initial conditions frequency')
2141  ax1.set_xlabel('Sample size')
2142  annotate('Empty initial conditions: '+str(empty), x=0.85, y=0.85, target='top-right')
2143  ax2 = fig.add_subplot(222)
2144  ax2.bar(histo1[1][1:-1],histo1[0][1:], 1, color=(0.449, 0.449, 0.449), linewidth=0)
2145  ax2.set_xlabel('Sample size')
2146  annotate('Empty initial conditions: '+str(empty), x=0.85, y=0.85, target='top-right')
2147  ax3 = fig.add_subplot(212)
2148  ax3.bar(range(200),top[0:200], 1, color=(0.449, 0.449, 0.449), linewidth=0)
2149  ax3.set_ylabel('Sample size')
2150  ax3.set_xlabel('Initial condition ordered by sample size')
2151  plt.tight_layout()
2152  Save(fig, site_analysis.getFullResultsFolder(config.output_folder, customSubPath='DMP'), fig_dpi=fig_dpi, fig_format=fig_format, verbose=verbose)
2153  plt.close(fig)
2154 
2155 
2156  nonZeroCellCount = predictionParameters.getNonZeroCellCount()
2157  print(''.rjust(indent,' ')+'Non-zero cells: '+str(nonZeroCellCount))
2158  print(''.rjust(indent,' ')+'DMP total cell size: '+str(predictionParameters.getSize()))
2159  print(''.rjust(indent,' ')+'Non-zero ratio: '+str(nonZeroCellCount/float(predictionParameters.getSize())))
2160 
2161  figures = []
2162  dmp_lane_i = max_index[0]
2163  dmp_curvy_i = max_index[1]
2164  dmp_speed_i = max_index[2]
2165  dmp_curvy_x_list = []
2166  dmp_curvy_y_list = []
2167 
2168  for align in range(len(site_analysis.site.alignments)):
2169  for point in predictionParameters.curvy[align][:]:
2170  [x,y] = tvaLib.Geo.getXYfromSY(point, site_analysis.site.alignments[align])
2171  dmp_curvy_x_list.append(x)
2172  dmp_curvy_y_list.append(y)
2173  dmp_total_greatest_count = 0
2174  for dmp_dt_i in range(1,dmp_plot_depth_frames):
2175  try: temp = predictionParameters.getLargestValAt(dmp_lane_i, dmp_curvy_i, dmp_speed_i, dmp_dt_i)
2176  except: #Prevent depth from exceeding available timehorzion
2177  dmp_plot_depth_frames = dmp_dt_i-1
2178  break
2179  if(temp > dmp_total_greatest_count): dmp_total_greatest_count = temp
2180  dmp_curvy_l = predictionParameters.curvy[dmp_lane_i][dmp_curvy_i]
2181  dmp_curvy_h = predictionParameters.curvy[dmp_lane_i][dmp_curvy_i+1]
2182  [dmp_curvy_x1, dmp_curvy_y1] = tvaLib.Geo.getXYfromSY(dmp_curvy_l, site_analysis.site.alignments[dmp_lane_i])
2183  [dmp_curvy_x2, dmp_curvy_y2] = tvaLib.Geo.getXYfromSY(dmp_curvy_h, site_analysis.site.alignments[dmp_lane_i])
2184 
2185 
2187 
2188  maxSum = 2000
2189  a = 0
2190  b = 0
2191  x_debug2 = []
2192  #percentiles = tvaLib.Math.getPercintileBinsFromList(histoDump, 50, includeLeftEdge=True, sampleSize=10000)
2193  for i in predictionParameters:
2194  i_sum = i.getMat().sum()
2195  if(i_sum > 0):
2196  x_debug2.append(i_sum)
2197  a += 1
2198  b += 1
2199 
2200  histo = np.histogram(x_debug2, bins=100)
2201  if(verbose): print histo, a, b
2202  Histo(histo, x_bounds=[0,maxSum])
2203 
2204 
2205  '''
2206  ######
2207  obj1 = 4
2208  to = 10
2209  timeHorizon = 50
2210  dmp_3d_data = [[],[],[],[]]
2211  #import pdb; pdb.set_trace()
2212  dmp_userType_i2 = predictionParameters.userType.findIDofLowerRangeFromValue(objects[obj1].getUserType())
2213  for dmp_dt_i in range(1, timeHorizon):
2214  dmp_lane_i2 = predictionParameters.lane.findIDofLowerRangeFromValue(objects[obj1].curvilinearPositions.getLanes()[to+dmp_dt_i])
2215  dmp_curvy_i2 = predictionParameters.curvy[dmp_lane_i2].findIDofLowerRangeFromValue(objects[obj1].curvilinearPositions.getXCoordinates()[to+dmp_dt_i])
2216  dmp_speed_i2 = predictionParameters.speed.findIDofLowerRangeFromValue(objects[obj1].getSpeeds()[to+dmp_dt_i])
2217  data = predictionParameters.getMatrixData(dmp_lane_i2, dmp_curvy_i2, dmp_speed_i2, dmp_userType_i2, dmp_dt_i, normalise=True)
2218  if(not data): break
2219  for x in range(len(data)):
2220  for y in range(len(data[x])):
2221  dmp_3d_data[0].append(x)
2222  dmp_3d_data[1].append(y)
2223  dmp_3d_data[2].append(dmp_dt_i)
2224  dmp_3d_data[3].append(data[x][y])
2225  figures.append(DrawOther.DMP3D(dmp_3d_data, plotcurvy=[[dmp_curvy_x1,dmp_curvy_x2],[dmp_curvy_y1,dmp_curvy_y2]], plotcurvyall=[dmp_curvy_x_list,dmp_curvy_y_list], text='something', xy_bounds=site_analysis.xy_bounds, alignments=site.alignments, bounding_boxes=site_analysis.zone, fig_name='Motion Pattern Map for object #'+str(obj1)))
2226  plt.show()'''
2227 
2228 
2229  for dmp_dt_i in range(1,dmp_plot_depth_frames):
2230  # Flush figure buffer
2231  if(dmp_dt_i % 5 == 0):
2232  Save(figures, site_analysis.getFullResultsFolder(config.output_folder, customSubPath='DMP'), fig_dpi=fig_dpi, verbose=verbose)
2233  figures = []
2234  dmp_data = predictionParameters.getMatrixData(dmp_lane_i, dmp_curvy_i, dmp_speed_i, dmp_dt_i, normalise=True); dmp_sm_scale = [0,0.030]
2235  #dmp_data = predictionParameters.getPointData(dmp_lane_i, dmp_curvy_i, dmp_speed_i, dmp_dt_i, format='columns'); dmp_sm_scale = [0,50]
2236  dmp_sample_size = predictionParameters.getSampleSizeAt(dmp_lane_i, dmp_curvy_i, dmp_speed_i, dmp_dt_i)
2237  dmp_greatest_density = predictionParameters.getLargestValAt(dmp_lane_i, dmp_curvy_i, dmp_speed_i, dmp_dt_i)
2238  dmp_an_text='sample size = {0}\ngreatest density = {1}\nlane = {2}\nS = [{3:.2f},{4:.2f}[ m\nspeed = [{5:.1f},{6:.1f}[ km/h\ndeltaTime = {7} frames'.format(dmp_sample_size, dmp_greatest_density, int(predictionParameters.lane[dmp_lane_i]+1), dmp_curvy_l, dmp_curvy_h, predictionParameters.speed[dmp_speed_i], predictionParameters.speed[dmp_speed_i+1], int(predictionParameters.deltatime[dmp_dt_i]))
2239  figures.append(DrawOther.DMP(dmp_data, plotcurvy=[[dmp_curvy_x1,dmp_curvy_x2],[dmp_curvy_y1,dmp_curvy_y2]], plotcurvyall=[dmp_curvy_x_list,dmp_curvy_y_list], text=dmp_an_text, sm_scale=dmp_sm_scale, extent=predictionParameters.getSpatialBounds(), interpolation='nearest', xy_bounds=site_analysis.xy_bounds, alignments=site_analysis.site.alignments, fig_name='DMP_deltatime_'+"%02d" % (int(predictionParameters.deltatime[dmp_dt_i])), plotSettings=plotSettings))
2240 
2241 
2242 
2243  Save(figures, site_analysis.getFullResultsFolder(config.output_folder, customSubPath='DMP'), fig_dpi=fig_dpi, verbose=verbose)
2244 
2245  return True
2246 
2247 
2248  @staticmethod
2249  def viewInteractionAsDMP(userPairs, predictionParameters, site_analysis, config, fig_dpi=100, fig_format='png', dmp_plot_depth_frames=80, indent=8, plotSettings=None, verbose=0):
2250  ''' Plot a single interaction sequence as a series of DMP calculations '''
2251  import pdb; pdb.set_trace()
2252  figures = []
2253  for dmp_dt_i in range(1,dmp_plot_depth_frames):
2254  # Flush figure buffer
2255  if(dmp_dt_i % 5 == 0):
2256  Save(figures, site_analysis.getFullResultsFolder(config.output_folder, customSubPath='DMP'), fig_dpi=fig_dpi, verbose=verbose)
2257  figures = []
2258  dmp_data = predictionParameters.getMatrixData(dmp_lane_i, dmp_curvy_i, dmp_speed_i, dmp_dt_i, normalise=True); dmp_sm_scale = [0,0.030]
2259  #dmp_data = predictionParameters.getPointData(dmp_lane_i, dmp_curvy_i, dmp_speed_i, dmp_dt_i, format='columns'); dmp_sm_scale = [0,50]
2260  dmp_sample_size = predictionParameters.getSampleSizeAt(dmp_lane_i, dmp_curvy_i, dmp_speed_i, dmp_dt_i)
2261  dmp_greatest_density = predictionParameters.getLargestValAt(dmp_lane_i, dmp_curvy_i, dmp_speed_i, dmp_dt_i)
2262  dmp_an_text='sample size = {0}\ngreatest density = {1}\nlane = {2}\nS = [{3:.2f},{4:.2f}[ m\nspeed = [{5:.1f},{6:.1f}[ km/h\ndeltaTime = {7} frames'.format(dmp_sample_size, dmp_greatest_density, int(predictionParameters.lane[dmp_lane_i]+1), dmp_curvy_l, dmp_curvy_h, predictionParameters.speed[dmp_speed_i], predictionParameters.speed[dmp_speed_i+1], int(predictionParameters.deltatime[dmp_dt_i]))
2263  figures.append(DrawOther.DMP(dmp_data, plotcurvy=[[dmp_curvy_x1,dmp_curvy_x2],[dmp_curvy_y1,dmp_curvy_y2]], plotcurvyall=[dmp_curvy_x_list,dmp_curvy_y_list], text=dmp_an_text, sm_scale=dmp_sm_scale, extent=predictionParameters.getSpatialBounds(), interpolation='nearest', xy_bounds=site_analysis.xy_bounds, alignments=site_analysis.site.alignments, fig_name='DMP_deltatime_'+"%02d" % (int(predictionParameters.deltatime[dmp_dt_i])), plotSettings=plotSettings))
2264  return True
2265 
2266 
2267 
2268 
2269  @staticmethod
2270  def DMP(data, plotcurvy=None, plotcurvyall=None, text='', extent=[0,1,0,1], mask=None, sm_scale=[0,50], colour='bone', interpolation='bilinear', xy_bounds=None, alignments=None, bounding_boxes=None, labels=True, local=None, verbose=0, fig_name='Motion Pattern Map', figsize=[15.0,12.0], plotSettings=None):
2271  ''' Plot 2D map (X,Y) of motion pattern array
2272 
2273  The plotting format is dependant on the type of data:
2274  - Plot a hexbin if data is a 2-column-by-n-row matrix of points (x,y)
2275  - Plot an imshow if data is a n*m matrix
2276  '''
2277  fig = plt.figure(fig_name, figsize=(figsize[0], figsize[1]))
2278  ax = fig.add_subplot(111, axisbg='black')
2279  if(not local): local = tvaLocal.Local()
2280 
2281 
2282 
2283  from matplotlib.patches import Rectangle
2284  try: ax.add_patch(Rectangle((xy_bounds[0].lower-100, xy_bounds[1].lower-100), 1000, 1000, facecolor='black', zorder=-20))
2285  except: pass
2286 
2287 
2288  plotBB(mask, labels=labels, boxLabel=local['vis_mask'])
2289 
2290 
2291  if(type(data) == list and len(data) == 2 and type(data[0]) == list):
2292  Map(data, colour=colour, xy_bounds=xy_bounds, gridsize=[10,10], mincnt=2, sm_scale=sm_scale, full_plot=False)
2293  else:
2294  #Adjust transparency of colour map
2295  cm = plt.get_cmap(colour)
2296  #cm._init()
2297  #cm._lut[:-3,-1] = np.abs(np.linspace(-1.0, 1.0, cm.N))
2298  #Plot
2299  plt.imshow(np.transpose(data), interpolation=interpolation, cmap=cm, vmin=sm_scale[0], vmax=sm_scale[1], extent=(extent[0], extent[1], extent[2], extent[3]), origin='lower')
2300  cb = plt.colorbar()
2301  cb.set_label(local['vis_map_density'])
2302 
2303 
2304 
2305  plotAlign(alignments, labels=labels, plotSettings=plotSettings)
2306 
2307 
2308  plt.axis('equal')
2309  if(xy_bounds):
2310  ax.set_xlim([xy_bounds[0].lower,xy_bounds[0].upper])
2311  ax.set_ylim([xy_bounds[1].lower,xy_bounds[1].upper])
2312  ax.set_ylim(ax.get_ylim()[::-1])
2313 
2314 
2315  if(plotcurvy): plt.plot(plotcurvy[0], plotcurvy[1], color='c', linestyle='-', marker='', linewidth=4, zorder=20)
2316  if(plotcurvyall): plt.plot(plotcurvyall[0], plotcurvyall[1], color='r', linestyle='', marker='o', linewidth=4, zorder=22) if(plotcurvy): plt.plot(plotcurvy[0], plotcurvy[1], color='c', linestyle='', marker='o', linewidth=4, zorder=23)
2317  if(text): plt.annotate(text, xy=(0.95, 0.05), xycoords='axes fraction', xytext=(0.95, 0.05), textcoords='axes fraction', ha='right', va='bottom', bbox=dict(boxstyle='Square,pad=0.5', fc='white'), size=plotSettings['size']*0.5)
2318 
2319  return fig
2320 
2321 
2322  @staticmethod
2323  def DMP3D(data, plotcurvy=None, plotcurvyall=None, text='', colour='winter', marker='o', xy_bounds=None, alignments=None, bounding_boxes=None, labels=True, local=None, verbose=0, fig_name='3D Motion Pattern Map', figsize=[15.0,12.0]):
2324  ''' Plot a 3D map (x,y,t) of motion pattern memory
2325 
2326  The plotting format is dependant on the type of data:
2327  - Plot a scatter if data is a 4-column-by-n-row matrix of points (x,y,t,value)
2328  '''
2329 
2330  fig = plt.figure(fig_name, figsize=(figsize[0], figsize[1]))
2331  ax = fig.add_subplot(111, projection='3d')
2332  if(not local): local = tvaLocal.Local()
2333 
2334 
2336 
2337 
2338  if(type(data) == list and len(data) == 4):
2339  cm = plt.get_cmap(colour)
2340  # Find max density
2341  max_density = 0
2342  for i in data[3]:
2343  if(max_density < i):
2344  max_density = i
2345  if(max_density == 0):
2346  return False
2347  for i in range(len(data[3])):
2348  #Filter empty values
2349  if(data[3][i] and data[3][i]/max_density > 0.2):
2350  alpha = data[3][i]/max_density
2351  traj_colour_actual = alpha,0,0
2352  p = ax.scatter(data[0][i], data[1][i], data[2][i], c=data[3][i], cmap=cm, marker=marker, color=traj_colour_actual, alpha=alpha)
2353  cb = fig.colorbar(p)
2354  cb.set_clim(0.1, max_density)
2355  else:
2356  return False
2357 
2358 
2359  plotAlign(alignments, labels=labels)
2360 
2361 
2362  ax = plb.gca()
2363  plt.axis('equal')
2364  if(xy_bounds):
2365  ax.set_xlim([xy_bounds[0].lower,xy_bounds[0].upper])
2366  ax.set_ylim([xy_bounds[1].lower,xy_bounds[1].upper])
2367  ax.set_ylim(ax.get_ylim()[::-1])
2368  ax.set_xlabel(local['vis_gen_x_coords_m'])
2369  ax.set_ylabel(local['vis_gen_y_coords_m'])
2370  ax.set_zlabel(local['vis_gen_z_coords_m'])
2371  cb.set_label(local['vis_map_density'])
2372 
2373 
2374  if(plotcurvy): plt.plot(plotcurvy[0], plotcurvy[1], color='r', linestyle='-', marker='', linewidth=4, zorder=20) if(plotcurvyall): plt.plot(plotcurvyall[0], plotcurvyall[1], color='r', linestyle='', marker='o', linewidth=4, zorder=22)
2375  if(text): annotate(text, 120, 120)
2376 
2377  return fig
2378 
2379 if __name__ == '__main__':
2380  plots([[0,1],[0,1],[0,1]], [[0,1],[1,0],[0.5,0.5]], legend_labels=['QC','SE'])
2381  plt.show()
2382  pass
def DMP3D(data, plotcurvy=None, plotcurvyall=None, text='', colour='winter', marker='o', xy_bounds=None, alignments=None, bounding_boxes=None, labels=True, local=None, verbose=0, fig_name='3D Motion Pattern Map', figsize=[15.0)
Definition: vis.py:2327
def plotTTCdistros(data, local=None, dist_type='pdf', set_ylim=None, fig_name='TTC Frequency', verbose=0, figsize=[15.0, kwargs)
Axes.
Definition: vis.py:2024
def __init__(self)
Definition: vis.py:1838
def setAxes(self)
Definition: vis.py:1454
def speedMap(objects, ptype='heat', sm_scale=None, colour='hot', xy_bounds=None, gridsize=[60, arrowGridReductionFactor=0.3, mincnt=10, virtualLoops=False, zone=False, alignments=False, local=None, fig_name='Speed Heat Map', figsize=[15.0, constantFramerate=15.0, mps_kmh=3.6, duration=0)
Speed.
Definition: vis.py:1199
def addODM(self, ODM, linescaler=2, arrowscaler=4, kwargs)
Definition: vis.py:1182
def plotBB(bounding_boxes, labels=False, legacyLabels=False, boxLabel=None, outlineOnly=False, alpha=1.00, zorder=1, zone_bgcolour='0.66', plotSettings=None, kwargs)
Definition: vis.py:422
def show()
Visualisation library.
Definition: vis.py:39
def setAxes(self)
Definition: vis.py:693
def plotVL(virtual_loops, labels=False, colour='#D63E33')
Definition: vis.py:464
def plotAlign(alignments, custom_colours=None, draw_connectors=True, draw_corridors=True, labels=False, legacyLabels=False, distanceBetweenLabels=20.0, highContrastLabels=False, lineAlpha=1.0, annotateAlpha=0.2, corridorAlpha=0.5, zorder=20, plotSettings=None)
Definition: vis.py:477
def DMP(data, plotcurvy=None, plotcurvyall=None, text='', extent=[0, mask=None, sm_scale=[0, colour='bone', interpolation='bilinear', xy_bounds=None, alignments=None, bounding_boxes=None, labels=True, local=None, verbose=0, fig_name='Motion Pattern Map', figsize=[15.0, plotSettings=None)
Definition: vis.py:2273
def plotImageWorldSpace(imagePath, scale=1.0, zorder=0, origin=[0)
Definition: vis.py:570
def plotSettings(style='', size=16, weight='normal', family='Arial', tickLabelSize=None, tickLength=4, verbose=0)
Definition: vis.py:44
def plotGeometry(alignments, sateliteImage, sateliteResolution, xy_bounds=None, draw_connectors=True, mask=None, zone=None, virtual_loops=None, labels=False, local=None, fig_name='Geometry', figsize=[15.0, plotSettings=None, kwargs)
Definition: vis.py:1028
def compileFigure(self)
Definition: vis.py:670
def annotate(text, x=None, y=None, target='bottom-right')
Definition: vis.py:580
def Save(figures, results_path='', fig_dpi=300, fig_format='png', fig_lan_suffix='', supressClose=False, fig_resize=None, fig_bg_colour='', verbose=0)
Definition: vis.py:77
def plots(X, Y, legend_labels=None, colours=['b', r, g, orange, k, m, y, linewidths=[1], linestyles=['-'], markers=[''], x_bounds=None, y_bounds=None, x_label='', y_label='', local=None, fig_name='Generic plots', figsize=[15.0)
Definition: vis.py:118
Trajectory.
Definition: vis.py:708
def microTrafficIntensity(objects, startTime, endTime, framerate, local=None, window_s=20.0, maxBins=1000, fig_name='Traffic Intensity', figsize=[15.0, plotSettings=None, kwargs)
Definition: vis.py:1120
def __init__(self, alignments=None, bounding_box=None, xy_bounds=None, sateliteImage=None, sateliteResolution=None, draw_connectors=True, kwargs)
Definition: vis.py:679
def siteTTC(data, labels=None, colours=['r', b, c, m, k, g, linestyles=['-.', timehorizon=10.0, local=None, fig_name='TTC Frequency', verbose=0, figsize=[15.0)
Definition: vis.py:2085
def visTrajImageSpace(objects=None, image='', homography=None, labels=False, start=0, draw_max_traj=200, mask=None, local=None, fig_name='Vehicle Trajectories in Image Space', traj_colour='b', alpha=1.0, figsize=[15.0, kwargs)
Definition: vis.py:944
def Scatter(pointList, alignments=False, mask=False, labels=False, local=None, fig_name='Generic scatter', verbose=0, figsize=[15.0)
Definition: vis.py:354
def close(fig='all')
Definition: vis.py:71
def Histo(data, enableBars=True, dist_type='freq', enableHalfStepOffset=True, halfStepSign=1, legendLabels='', linewidth=2, spacing_modifier=1, x_bounds=None, y_bounds=None, x_label='', y_label='', force_one_label_per_bar=False, local=None, fig_name='Generic histogram', figsize=[15.0)
Definition: vis.py:164
def setAxes(self, x_lavbel=['x'], y_lavbel=['y'])
Definition: vis.py:663
def viewInteractionAsDMP(userPairs, predictionParameters, site_analysis, config, fig_dpi=100, fig_format='png', dmp_plot_depth_frames=80, indent=8, plotSettings=None, verbose=0)
Definition: vis.py:2252
def addTimeseries(self, userPairs, fps)
Definition: vis.py:1602
def addTraj(self, objects, traj_colour='b', linestyle='-', markerstyle='o', linewidth=2, kwargs)
Definition: vis.py:714
def scatterInBins(lists, bins)
Definition: vis.py:607
def pointList2DHisto(data, bins=[60)
Definition: vis.py:629
def DMPExperimental(predictionParameters, objects, site_analysis, config, fig_dpi=100, fig_format='png', dmp_plot_depth_frames=80, indent=8, plotSettings=None, verbose=0)
Definition: vis.py:2122
def plotWithArrows(x, y, aspace=5, color='b', alpha=1.0, zorder=1, kwargs)
Definition: vis.py:231
def plotSDR(SDR, local=None, outlineOnly=False, alpha=1.00, zorder=1, sdr_bgcolour='0.66', kwargs)
Definition: vis.py:452
def plotMethodGrid(datas, prototype, workerArgs=None, set_ylim=None, local=None, fig_name='Grid', verbose=0, fontsize=16, figsize=[15.0, kwargs)
Definition: vis.py:1905
def plotTTCdistros_worker(data, ax=None, klusters=None, klusterColors=['r')
Definition: vis.py:1936
def interactionMap(pointColumnList, ptype='hexbin', colour='hot', weightedDensity=False, xy_bounds=None, z_bounds=None, gridsize=[60, minGridSize=1.0, mincnt=1, alignments=False, mask=False, zone=False, labels=False, local=None, zlabel='', fig_name='CP Map', indent=4, verbose=0, figsize=[15.0, plotSettings=None, kwargs)
Interactions.
Definition: vis.py:1467
def traj2DHighlightAlignments(objects, xy_bounds, alignments, marker_size=0.4, labels=True, local=None, fig_name='Trajectory Lane Highlight', figsize=[15.0, plotSettings=None, kwargs)
Definition: vis.py:905
def plotSatellite(sateliteImage, sateliteResolution, color=False, zorder=0, origin=[0, zoomTo=False)
Definition: vis.py:551
def traj3D(objects, start=0, draw_max_traj=200, draw_connectors=True, xy_bounds=None, alignments=None, mask=None, labels=False, timeStampLabels=False, local=None, fig_name='Vehicle Trajectories 3D', traj_colour='b', figsize=[15.0)
Definition: vis.py:989
def __init__(self, fig_rows=1, fig_columns=1, local=None, sharex=False, sharey=False, fig_name='Basic Figure', verbose=0, figsize=[15.0, kwargs)
Definition: vis.py:657
def speedHist(speed_histos, labels='', plotPDF=True, sm_scale=80, enableBars=True, color='k', linestyle='', linewidth=5, minObservations=10, local=None, fig_name='Speed Distribution', figsize=[15.0)
Definition: vis.py:1377
def addHistogram(self, objects, fps)
Definition: vis.py:1432
Other.
Definition: vis.py:2117
def traj2D(objects, draw_max_traj=200, xy_bounds=None, alignments=None, draw_connectors=True, mask=None, zone=None, SDR=None, virtual_loops=None, sateliteImage=None, sateliteResolution=None, labels=False, labels_overlap=True, timeStampLabels=False, objects_uncon=None, velocity_vector=False, local=None, constantFramerate=15.0, mps_kmh=3.6, traj_colour='b', traj_colour_alternate='', sm_scale=50, cm_colour='hot', alignAlpha=1.0, fig_name='Vehicle Trajectories', figsize=[15.0, plotSettings=None, kwargs)
Definition: vis.py:723
def plotIndicatorCounts(data, local=None, fig_name='Indicator counts', verbose=0, figsize=[15.0, kwargs)
Definition: vis.py:1885
def interactionTTCHist(ttc_histos, fps=15.0, timehorizon=5.0, enableBars=True, linewidth=5, dist_type='pdf', labels=False, label_ratio='', local=None, fig_name='TTC pdf', verbose=0, figsize=[15.0)
Definition: vis.py:1544
def plotTTCdistros_grid(datas, klusters, local=None, dist_type='pdf', set_ylim=[0.0, fig_name='TTC Frequency', verbose=0, fontsize=16, figsize=[15.0, kwargs)
Definition: vis.py:2053
def BoxPlotSeries(data, x_label='', y_label='', x_tick_labels=None, y_bounds=None, y_logScale=False, orderByMedian=False, colour=None, sperator_position=None, local=None, fig_name='Generic boxplot', figsize=[15.0, verbose=0)
Definition: vis.py:276
def hourlyFlows(flows_curve_list, speed_data=None, speed_data_stds=None, sm_scale=None, local=None, tickFrequency=4, fig_name='Hourly flows', figsize=[15.0)
Flows.
Definition: vis.py:1072
def get(self)
Definition: vis.py:672
def Map(pointList, colour='hot', xy_bounds=None, gridsize=[60, mincnt=1, sm_scale=None, alignments=False, mask=False, labels=False, local=None, fig_name='Generic Map', verbose=0, figsize=[15.0, full_plot=True)
Definition: vis.py:375