1   
   2   
   3   
   4   
   5   
   6   
   7   
   8   
   9   
  10   
  11   
  12   
  13   
  14   
  15   
  16   
  17  """ 
  18  This module is intended to store generic, reusable, sub-classable plot classes 
  19  to minimize formulaic copying and pasting. 
  20  """ 
  21   
  22  from __future__ import division 
  23   
  24  __author__ = "Nickolas Fotopoulos <nvf@gravity.phys.uwm.edu>" 
  25   
  26  import itertools 
  27  from mpl_toolkits.mplot3d import Axes3D 
  28  from mpl_toolkits.axes_grid import make_axes_locatable 
  29  from mpl_toolkits.basemap import Basemap 
  30   
  31  import numpy 
  32  import pylab 
  33  import re 
  34  import copy 
  35  import ConfigParser 
  36   
  37  from glue import iterutils 
  38  from glue import segments 
  39   
  40  from pylal import viz 
  41   
  42   
  43  pylab.rc("lines", markersize=12) 
  44  pylab.rc("text", usetex=True) 
  48      """ 
  49      Convert a floating point number to a latex representation.  In particular, 
  50      scientific notation is handled gracefully: e -> 10^ 
  51      """ 
  52      base_str = format % x 
  53      if "e" not in base_str: 
  54          return base_str 
  55      mantissa, exponent = base_str.split("e") 
  56      exponent = exponent.lstrip("0+") 
  57      if mantissa == "1": 
  58          return r"10^{%s}" % exponent 
  59      else: 
  60          return r"%s\times 10^{%s}" % (mantissa, exponent) 
   61   
  66      """ 
  67      A very default meta-class to almost any plot you might want to make. 
  68      It provides basic initialization, a savefig method, and a close method. 
  69      It is up to developers to subclass BasicPlot and fill in the add_content() 
  70      and finalize() methods. 
  71      """ 
  72 -    def __init__(self, xlabel="", ylabel="", title="", subtitle="", **kwargs): 
   73          """ 
  74          Basic plot initialization.  A subclass can override __init__ and call 
  75          this one (plotutils.BasicPlot.__init__(self, *args, **kwargs)) and 
  76          then initialize variables to hold data to plot and labels. 
  77          """ 
  78          self.fig = pylab.figure(**kwargs) 
  79          self.ax = self.fig.add_subplot(111) 
  80   
  81          self.ax.set_xlabel(xlabel) 
  82          self.ax.set_ylabel(ylabel) 
  83          if subtitle: 
  84              self.ax.set_title(title, x=0.5, y=1.03) 
  85              self.ax.text(0.5, 1.035, subtitle, horizontalalignment='center', 
  86                           transform=self.ax.transAxes, verticalalignment='top') 
  87          else: 
  88              self.ax.set_title(title) 
  89          self.ax.grid(True) 
   90   
  91 -    def add_content(self, data, label="_nolabel_"): 
   92          """ 
  93          Stub.  Replace with a method that appends values or lists of values 
  94          to self.data_sets and appends labels to self.data_labels.  Feel free 
  95          to accept complicated inputs, but try to store only the raw numbers 
  96          that will enter the plot. 
  97          """ 
  98          raise NotImplementedError 
   99   
 101          """ 
 102          Stub.  Replace with a function that creates and makes your plot 
 103          pretty.  Do not do I/O here. 
 104          """ 
 105          raise NotImplementedError 
  106   
 107 -    def savefig(self, *args, **kwargs): 
  108          self.fig.savefig(*args, **kwargs) 
  109   
 111          """ 
 112          Close the plot and release its memory. 
 113          """ 
 114          pylab.close(self.fig) 
  115   
 117          """ 
 118          Create a legend if there are any non-trivial labels. 
 119          """ 
 120   
 121           
 122          alpha      = kwargs.pop("alpha", None) 
 123          linewidth  = kwargs.pop("linewidth", None) 
 124          markersize = kwargs.pop("markersize", None) 
 125   
 126           
 127          for plot_kwargs in self.kwarg_sets: 
 128              if "label" in plot_kwargs and \ 
 129                  not plot_kwargs["label"].startswith("_"): 
 130                   
 131                  self.ax.legend(*args, **kwargs) 
 132                   
 133                  leg   = self.ax.get_legend() 
 134                  frame = leg.get_frame() 
 135                  if alpha: 
 136                      frame.set_alpha(alpha) 
 137                  if linewidth: 
 138                      for l in leg.get_lines(): 
 139                          l.set_linewidth(linewidth) 
 140                  return 
   141   
 146      """ 
 147      An infinite iterator of some default colors. 
 148      """ 
 149      return itertools.cycle(('b', 'g', 'r', 'c', 'm', 'y', 'k')) 
  150   
 152      """ 
 153      An infinite iterator of some default symbols. 
 154      """ 
 155      return itertools.cycle(('x', '^', 'D', 'H', 'o', '1', '+')) 
  156   
 158      """ 
 159      Given a some nested sequences (e.g. list of lists), determine the largest 
 160      and smallest values over the data sets and determine a common binning. 
 161      """ 
 162      max_stat = max(list(iterutils.flatten(data_sets)) + [-numpy.inf]) 
 163      min_stat = min(list(iterutils.flatten(data_sets)) + [numpy.inf]) 
 164      if numpy.isinf(-max_stat): 
 165          max_stat = default_max 
 166      if numpy.isinf(min_stat): 
 167          min_stat = default_min 
 168      return min_stat, max_stat 
  169   
 171      """ 
 172      Decorator to make a method complain if called more than once. 
 173      """ 
 174      def _new(self, *args, **kwargs): 
 175          attr = "_" + f.__name__ + "_already_called" 
 176          if hasattr(self, attr) and getattr(self, attr): 
 177              raise ValueError, f.__name__ + " can only be called once" 
 178          setattr(self, attr, True) 
 179          return f(self, *args, **kwargs) 
  180      _new.__doc__ == f.__doc__ 
 181      _new.__name__ = f.__name__ 
 182      return _new 
 183   
 184  _dq_params = {"text.usetex": True,   "text.verticalalignment": "center", 
 185                "lines.linewidth": 2,  "xtick.labelsize": 16, 
 186                "ytick.labelsize": 16, "axes.titlesize": 22, 
 187                "axes.labelsize": 16,  "axes.linewidth": 1, 
 188                "grid.linewidth": 1,   "legend.fontsize": 16, 
 189                "legend.loc": "best",  "figure.figsize": [12,6], 
 190                "figure.dpi": 80,      "image.origin": 'lower', 
 191                "axes.grid": True,     "axes.axisbelow": False} 
 194      """ 
 195      Update pylab plot parameters, defaulting to parameters for DQ-style trigger 
 196      plots. 
 197      """ 
 198   
 199       
 200      pylab.rcParams.update(params) 
  201   
 203      """ 
 204      Format the string columnName (e.g. xml table column) into latex format for 
 205      an axis label. Formats known acronyms, greek letters, units, subscripts, and 
 206      some miscellaneous entries. 
 207   
 208      Examples: 
 209   
 210      >>> display_name('snr') 
 211      'SNR' 
 212      >>> display_name('bank_chisq_dof') 
 213      'Bank $\\chi^2$ DOF' 
 214      >>> display_name('hoft') 
 215      '$h(t)$' 
 216   
 217      Arguments: 
 218   
 219        columnName : str 
 220          string to format 
 221      """ 
 222   
 223       
 224      acro    = ['snr', 'ra','dof', 'id', 'ms', 'far'] 
 225       
 226      greek   = ['alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta', 'eta',\ 
 227                 'theta', 'iota', 'kappa', 'lamda', 'mu', 'nu', 'xi',\ 
 228                 'pi', 'rho', 'sigma', 'tau', 'upsilon', 'phi', 'chi', 'psi',\ 
 229                 'omega'] 
 230       
 231      unit    = {'ns':'ns', 'hz':'Hz'} 
 232       
 233      sub     = ['flow', 'fhigh', 'hrss', 'mtotal', 'mchirp'] 
 234       
 235      misc    = {'hoft': '$h(t)$'} 
 236   
 237      if len(columnName)==1: 
 238          return columnName 
 239   
 240       
 241      words = [] 
 242      for w in re.split('\s', columnName): 
 243          if w[:-1].isupper(): words.append(w) 
 244          else:           words.extend(re.split('_', w)) 
 245   
 246       
 247      for i,w in enumerate(words): 
 248          if w.startswith('\\'): 
 249              pass 
 250          wl = w.lower() 
 251           
 252          if wl in misc.keys(): 
 253              words[i] = misc[wl] 
 254           
 255          elif wl in acro: 
 256              words[i] = w.upper() 
 257           
 258          elif wl in unit: 
 259              words[i] = '(%s)' % unit[wl] 
 260           
 261          elif wl in sub: 
 262              words[i] = '%s$_{\mbox{\\small %s}}$' % (w[0], w[1:]) 
 263           
 264          elif wl in greek: 
 265              words[i] = '$\%s$' % w 
 266           
 267          elif re.match('(%s)' % '|'.join(greek), w): 
 268              if w[-1].isdigit(): 
 269                  words[i] = '$\%s_{%s}$''' %tuple(re.findall(r"[a-zA-Z]+|\d+",w)) 
 270              elif wl.endswith('sq'): 
 271                  words[i] = '$\%s^2$' % w[:-2] 
 272           
 273          else: 
 274              if w[:-1].isupper(): 
 275                  words[i] = w 
 276              else: 
 277                  words[i] = w.title() 
 278               
 279              words[i] = re.sub('(?<!\\\\)_', '\_', words[i]) 
 280   
 281      return ' '.join(words) 
  282   
 283 -def add_colorbar(ax, mappable=None, visible=True, log=False, clim=None,\ 
 284                   label=None, **kwargs): 
  285      """ 
 286      Adds a figure colorbar to the given Axes object ax, based on the values 
 287      found in the mappable object. If visible=True, returns the Colorbar object,  
 288      otherwise, no return. 
 289   
 290      Arguments: 
 291   
 292          ax : matplotlib.axes.AxesSubplot 
 293              axes object beside which to draw colorbar 
 294   
 295      Keyword arguments: 
 296   
 297          mappable : [ matplotlib.image.Image | matplotlib.contour.ContourSet... ] 
 298              image object from which to map colorbar values 
 299          visible : [ True | False] 
 300              add colorbar to figure, or simply resposition ax as if to draw one 
 301          log : [ True | False ] 
 302              use logarithmic scale for colorbar 
 303          clim : tuple 
 304              (vmin, vmax) pair for limits of colorbar 
 305          label : str 
 306              label string for colorbar 
 307   
 308      All other keyword arguments will be passed to pylab.colorbar. Logarithmic 
 309      colorbars can be created by plotting log10 of the data and setting log=True. 
 310      """ 
 311   
 312      div = make_axes_locatable(ax) 
 313      cax = div.new_horizontal("3%", pad="1%") 
 314      if not visible: 
 315          return 
 316      else: 
 317          div._fig.add_axes(cax) 
 318       
 319       
 320      if pylab.rcParams['text.usetex']: 
 321          kwargs.setdefault('format',\ 
 322              pylab.matplotlib.ticker.FuncFormatter(lambda x,pos: "$%s$"\ 
 323                                                    % float_to_latex(x))) 
 324   
 325       
 326      if not clim: 
 327          cmin = min([c.get_array().min() for c in ax.collections+ax.images]) 
 328          cmax = max([c.get_array().max() for c in ax.collections+ax.images]) 
 329          clim = [cmin, cmax] 
 330      if log: 
 331          kwargs.setdefault("ticks", numpy.logspace(numpy.log10(clim[0]),\ 
 332                                                    numpy.log10(clim[1]), num=9,\ 
 333                                                    endpoint=True)) 
 334      else: 
 335          kwargs.setdefault("ticks", numpy.linspace(clim[0], clim[1], num=9,\ 
 336                                                    endpoint=True)) 
 337   
 338       
 339      if not mappable: 
 340          if len(ax.collections+ax.images) == 0: 
 341              norm = log and pylab.matplotlib.colors.LogNorm() or none 
 342              mappable = ax.scatter([1], [1], c=[clim[0]], vmin=clim[0],\ 
 343                                     vmax=clim[1], visible=False, norm=norm) 
 344          else: 
 345              minindex = numpy.asarray([c.get_array().min() for c in\ 
 346                                        ax.collections+ax.images]).argmin() 
 347              mappable = (ax.collections+ax.images)[minindex] 
 348   
 349       
 350      if mappable.get_array() is None: 
 351          norm = log and pylab.matplotlib.colors.LogNorm() or none 
 352          mappable = ax.scatter([1], [1], c=[clim[0]], vmin=clim[0],\ 
 353                                 vmax=clim[1], visible=False, norm=norm) 
 354       
 355       
 356      colorbar = ax.figure.colorbar(mappable, cax=cax, **kwargs) 
 357      if clim: colorbar.set_clim(clim) 
 358      if label: colorbar.set_label(label) 
 359      colorbar.draw_all() 
 360   
 361      return colorbar 
  362   
 364      """ 
 365      Parser ConfigParser.ConfigParser section for plotting parameters. Returns 
 366      a dict that can be passed to any plotutils.plot_xxx function in **kwargs 
 367      form. Set ycolumn to 'hist' or 'rate' to generate those types of plots. 
 368   
 369      Arguments: 
 370   
 371          cp : ConfigParser.ConfigParser 
 372              INI file object from which to read 
 373          section : str 
 374              section name to read for options 
 375   
 376      Basic parseable options: 
 377   
 378          xcolumn : str 
 379              parameter to plot on x-axis     
 380          ycolumn : str 
 381              parameter to plot on y-axis     
 382          zcolumn : str 
 383              parameter to plot on z-axis     
 384          rank-by : str 
 385              parameter by which to rank elements 
 386          xlim : list 
 387              [xmin, xmax] pair for x-axis limits 
 388          ylim : list 
 389              [ymin, ymax] pair for y-axis limits 
 390          zlim : list 
 391              [zmin, zmax] pair for z-axis limits 
 392          clim : list 
 393              [cmin, cmax] pair for colorbar limits 
 394          logx : [ True | False ] 
 395              plot x-axis in log scale 
 396          logy : [ True | False ] 
 397              plot y-axis in log scale 
 398          logz : [ True | False ] 
 399              plot z-axis in log scale 
 400   
 401      Trigger plot options: 
 402   
 403          detchar-style : [ True | False ] 
 404              use S6-style plotting: low snr triggers small with no edges 
 405          detchar-style-theshold : float 
 406              z-column threshold at below which to apply detchar-style 
 407   
 408      Trigger rate plot options: 
 409   
 410          bins : str 
 411              semi-colon-separated list of comma-separated bins for rate plot 
 412   
 413      Histogram options: 
 414   
 415          cumulative : [ True | False ] 
 416              plot cumulative counts in histogram 
 417          rate : [ True | False ] 
 418              plot histogram counts as rate 
 419          num-bins : int 
 420              number of bins for histogram 
 421          fill : [ True | False ] 
 422              plot solid colour underneath histogram curve 
 423          color-bins : str 
 424              semi-colon-separated list of comma-separated bins for colorbar 
 425              histogram 
 426   
 427      Data plot options: 
 428   
 429          zero-indicator : [ True | False ] 
 430              draw vertical dashed red line at t=0 
 431   
 432      Other options: 
 433   
 434          greyscale : [ True | False ] 
 435              save plot in black-and-white 
 436          bbox-inches : 'tight' 
 437              save figure with tight bounding box around Axes 
 438          calendar-time : [ True | False ] 
 439              plot time axis with date and time instead of time from zero. 
 440      """ 
 441      params = dict() 
 442   
 443       
 444      pairs    = ['xlim', 'ylim', 'zlim', 'colorlim'] 
 445      pairlist = ['bins', 'color-bins'] 
 446      booleans = ['logx', 'logy', 'logz', 'cumulative', 'rate', 'detchar-style',\ 
 447                  'greyscale', 'zero-indicator', 'normalized', 'fill',\ 
 448                  'calendar-time', 'bar'] 
 449      floats   = ['detchar-style-threshold', 'dcthreshold'] 
 450      ints     = ['num-bins'] 
 451   
 452       
 453      for key,val in cp.items(section, raw=True): 
 454          if val == None: continue 
 455           
 456          val = val.rstrip('"').strip('"') 
 457           
 458          hkey = re.sub('_', '-', key) 
 459          ukey = re.sub('-', '_', key) 
 460           
 461          if hkey in pairs: 
 462              params[ukey] = map(float, val.split(',')) 
 463           
 464          elif hkey in pairlist: 
 465              params[ukey] = map(lambda p: map(float,p.split(',')),val.split(';')) 
 466           
 467          elif hkey in booleans: 
 468              params[ukey] = cp.getboolean(section, key) 
 469           
 470          elif hkey in floats: 
 471              params[ukey] = float(val) 
 472           
 473          elif hkey in ints: 
 474              params[ukey] = int(val) 
 475           
 476          else: 
 477              params[ukey] = str(val) 
 478   
 479      return params 
  480   
 499   
 501      """ 
 502      Work out renormalisation for the time axis, makes the label more 
 503      appropriate. Returns unit (in seconds) and string descriptor. 
 504   
 505      Example: 
 506   
 507      >>> time_axis_unit(100) 
 508      (1, 'seconds') 
 509   
 510      >>> time_axis_unit(604800) 
 511      (86400, 'days') 
 512   
 513      Arguments: 
 514   
 515          duration : float 
 516              plot duration to normalise 
 517      """ 
 518      if (duration) < 1000: 
 519          return 1,"seconds" 
 520      elif (duration) < 20000: 
 521          return 60,"minutes" 
 522      elif (duration) >= 20000 and (duration) < 604800: 
 523          return 3600,"hours" 
 524      elif (duration) < 8640000: 
 525          return 86400,"days" 
 526      else: 
 527          return 2592000,"months" 
  528   
 530      """ 
 531      Quick utility to set better formatting for ticks on a time axis. 
 532      """ 
 533      xticks = ax.get_xticks() 
 534      if len(xticks)>1 and xticks[1]-xticks[0]==5: 
 535          ax.xaxis.set_major_locator(pylab.matplotlib.ticker.MultipleLocator(base=2)) 
 536      return 
  537   
 539      """ 
 540      Labels first minor tick in the case that there is only a single major 
 541      tick label visible. 
 542      """ 
 543   
 544      def even(x, pos): 
 545          if int(str(int(x*10**8))[0]) % 2: 
 546              return "" 
 547          elif pylab.rcParams["text.usetex"]: 
 548              return "$%s$" % float_to_latex(x) 
 549          else: 
 550              return str(int(x)) 
  551   
 552       
 553      if x: 
 554          ticks = list(ax.get_xticks()) 
 555          xlim  = ax.get_xlim() 
 556          for i,tick in enumerate(ticks[::-1]): 
 557              if not xlim[0] <= tick <= xlim[1]: 
 558                  ticks.pop(-1) 
 559          if len(ticks) <= 1: 
 560              ax.xaxis.set_minor_formatter(pylab.FuncFormatter(even)) 
 561   
 562       
 563      if y: 
 564          ticks = list(ax.get_yticks()) 
 565          ylim  = ax.get_ylim() 
 566          for i,tick in enumerate(ticks[::-1]): 
 567              if not ylim[0] <= tick <= ylim[1]: 
 568                  ticks.pop(-1) 
 569          if len(ticks)<=1: 
 570              ax.yaxis.set_minor_formatter(pylab.FuncFormatter(even)) 
 571   
 572      return 
 573   
 578      """ 
 579      Exactly what you get by calling pylab.plot(), but with the handy extras 
 580      of the BasicPlot class. 
 581      """ 
 583          BasicPlot.__init__(self, *args, **kwargs) 
 584          self.x_data_sets = [] 
 585          self.y_data_sets = [] 
 586          self.kwarg_sets = [] 
  587   
 588 -    def add_content(self, x_data, y_data, **kwargs): 
  589          self.x_data_sets.append(x_data) 
 590          self.y_data_sets.append(y_data) 
 591          self.kwarg_sets.append(kwargs) 
  592   
 593      @method_callable_once 
 595           
 596          for x_vals, y_vals, plot_kwargs in \ 
 597              itertools.izip(self.x_data_sets, self.y_data_sets, self.kwarg_sets): 
 598              self.ax.plot(x_vals, y_vals, **plot_kwargs) 
 599   
 600           
 601          self.add_legend_if_labels_exist(loc=loc, alpha=alpha) 
 602   
 603           
 604          del self.x_data_sets 
 605          del self.y_data_sets 
 606          del self.kwarg_sets 
   607   
 609      """ 
 610      A simple vertical bar plot.  Bars are centered on the x values and have 
 611      height equal to the y values. 
 612      """ 
 614          BasicPlot.__init__(self, *args, **kwargs) 
 615          self.x_data_sets = [] 
 616          self.y_data_sets = [] 
 617          self.kwarg_sets = [] 
  618   
 619 -    def add_content(self, x_data, y_data, **kwargs): 
  620          self.x_data_sets.append(x_data) 
 621          self.y_data_sets.append(y_data) 
 622          self.kwarg_sets.append(kwargs) 
  623   
 624      @method_callable_once 
 625 -    def finalize(self, loc=0, orientation="vertical", alpha=0.8): 
  626           
 627          for x_vals, y_vals, plot_kwargs, c in \ 
 628              itertools.izip(self.x_data_sets, self.y_data_sets, 
 629                             self.kwarg_sets, default_colors()): 
 630              plot_kwargs.setdefault("align", "center") 
 631              plot_kwargs.setdefault("color", c) 
 632               
 633               
 634               
 635               
 636              plot_kwargs.setdefault("orientation", orientation) 
 637              self.ax.bar(x_vals, y_vals, **plot_kwargs) 
 638   
 639           
 640          self.add_legend_if_labels_exist(loc=loc, alpha=alpha) 
 641   
 642           
 643          del self.x_data_sets 
 644          del self.y_data_sets 
 645          del self.kwarg_sets 
   646   
 648      """ 
 649      Histogram data sets with a common binning, then make a vertical bar plot. 
 650      """ 
 652          BasicPlot.__init__(self, *args, **kwargs) 
 653          self.data_sets = [] 
 654          self.kwarg_sets = [] 
  655   
 656 -    def add_content(self, data, **kwargs): 
  657          self.data_sets.append(data) 
 658          self.kwarg_sets.append(kwargs) 
  659   
 660      @method_callable_once 
 661 -    def finalize(self, loc=0, alpha=0.8, num_bins=20, normed=False,\ 
 662                   logx=False, logy=False): 
  663           
 664          min_stat, max_stat = determine_common_bin_limits(self.data_sets) 
 665          if logx: 
 666              bins = numpy.logspace(numpy.log10(min_stat), numpy.log10(max_stat),\ 
 667                                    num_bins + 1, endpoint=True) 
 668          else: 
 669              bins = numpy.linspace(min_stat, max_stat, num_bins+1, endpoint=True) 
 670   
 671           
 672          if logx: 
 673              width = list(numpy.diff(bins)) 
 674          else: 
 675              width = (1 - 0.1 * len(self.data_sets)) * (bins[1] - bins[0]) 
 676   
 677           
 678          for i, (data_set, plot_kwargs, c) in \ 
 679              enumerate(itertools.izip(self.data_sets, self.kwarg_sets,\ 
 680                                       default_colors())): 
 681               
 682              plot_kwargs.setdefault("alpha", 0.6) 
 683              plot_kwargs.setdefault("width", width) 
 684              plot_kwargs.setdefault("color", c) 
 685   
 686               
 687              y, x = numpy.histogram(data_set, bins=bins, normed=normed) 
 688              x = x[:-1] 
 689   
 690               
 691              if logy: 
 692                  y = numpy.ma.masked_where(y==0, y, copy=False) 
 693   
 694               
 695              plot_item = self.ax.bar(x, y, **plot_kwargs) 
 696   
 697           
 698          self.add_legend_if_labels_exist(loc=loc, alpha=alpha) 
 699   
 700          if logx: 
 701              self.ax.set_xscale("log") 
 702          if logy: 
 703              self.ax.set_yscale("log") 
 704   
 705           
 706          del self.data_sets 
 707          del self.kwarg_sets 
   708   
 710      """ 
 711      Make a bar plot in which the width and placement of the bars are set 
 712      by the given bins. 
 713      """ 
 715          BasicPlot.__init__(self, *args, **kwargs) 
 716          self.bin_sets = [] 
 717          self.value_sets = [] 
 718          self.kwarg_sets = [] 
  719   
 720 -    def add_content(self, bins, values, **kwargs): 
  721          if len(bins) != len(values): 
 722              raise ValueError, "length of bins and values do not match" 
 723   
 724          self.bin_sets.append(bins) 
 725          self.value_sets.append(values) 
 726          self.kwarg_sets.append(kwargs) 
  727   
 728      @method_callable_once 
 729 -    def finalize(self, orientation="vertical"): 
  730          for bins, values, plot_kwargs in itertools.izip(self.bin_sets, 
 731              self.value_sets, self.kwarg_sets): 
 732              x_vals = bins.centres() 
 733   
 734               
 735              label = "_nolegend_" 
 736              if "label" in plot_kwargs: 
 737                  label = plot_kwargs["label"] 
 738                  del plot_kwargs["label"] 
 739   
 740               
 741              plot_kwargs.setdefault("align", "center") 
 742   
 743              if orientation == "vertical": 
 744                  plot_kwargs.setdefault("width", bins.upper() - bins.lower()) 
 745                  patches = self.ax.bar(x_vals, values, **plot_kwargs) 
 746              elif orientation == "horizontal": 
 747                  plot_kwargs.setdefault("height", bins.upper() - bins.lower()) 
 748                  patches = self.ax.barh(x_vals, values, **plot_kwargs) 
 749              else: 
 750                  raise ValueError, orientation + " must be 'vertical' " \ 
 751                      "or 'horizontal'" 
 752   
 753               
 754              if len(patches) > 0: 
 755                  patches[0].set_label(label) 
 756   
 757          pylab.axis('tight') 
 758   
 759           
 760          self.add_legend_if_labels_exist() 
 761   
 762           
 763          del self.bin_sets 
 764          del self.value_sets 
 765          del self.kwarg_sets 
   766   
 768      """ 
 769      Cumulative histogram of foreground that also has a shaded region, 
 770      determined by the mean and standard deviation of the background 
 771      population coincidence statistics. 
 772      """ 
 774          BasicPlot.__init__(self, *args, **kwargs) 
 775          self.fg_data_sets = [] 
 776          self.fg_kwarg_sets = [] 
 777          self.bg_data_sets = [] 
 778          self.bg_kwargs = {} 
  779   
 780 -    def add_content(self, fg_data_set, **kwargs): 
  781          self.fg_data_sets.append(fg_data_set) 
 782          self.fg_kwarg_sets.append(kwargs) 
  783   
 785          self.bg_data_sets.extend(bg_data_sets) 
 786          self.bg_kwargs = kwargs 
  787   
 788      @method_callable_once 
 789 -    def finalize(self, num_bins=20, normalization=1): 
  790          epsilon = 1e-8 
 791   
 792           
 793          min_stat, max_stat = determine_common_bin_limits(\ 
 794              self.fg_data_sets + self.bg_data_sets) 
 795          bins = numpy.linspace(min_stat, max_stat, num_bins + 1, endpoint=True) 
 796          bins_bg = numpy.append(bins, float('Inf')) 
 797          dx = bins[1] - bins[0] 
 798   
 799           
 800          for data_set, plot_kwargs in \ 
 801              itertools.izip(self.fg_data_sets, self.fg_kwarg_sets): 
 802               
 803              y, x = numpy.histogram(data_set, bins=bins) 
 804              y = y[::-1].cumsum()[::-1] 
 805              x = x[:-1] 
 806   
 807               
 808              y = numpy.array(y, dtype=numpy.float32) 
 809              y[y <= epsilon] = epsilon 
 810              self.ax.plot(x + dx/2, y*normalization, **plot_kwargs) 
 811   
 812           
 813          if len(self.bg_data_sets) > 0: 
 814               
 815              hist_sum = numpy.zeros(len(bins), dtype=float) 
 816              sq_hist_sum = numpy.zeros(len(bins), dtype=float) 
 817              for instance in self.bg_data_sets: 
 818                   
 819                  y, x = numpy.histogram(instance, bins=bins_bg) 
 820                  x = numpy.delete(x, -1) 
 821                  y = y[::-1].cumsum()[::-1] 
 822                  hist_sum += y 
 823                  sq_hist_sum += y*y 
 824   
 825               
 826              N = len(self.bg_data_sets) 
 827              means = hist_sum / N 
 828              stds = numpy.sqrt((sq_hist_sum - hist_sum*means) / (N - 1)) 
 829   
 830               
 831              means[means <= epsilon] = epsilon 
 832              self.ax.plot(x + dx/2, means*normalization, 'r+', **self.bg_kwargs) 
 833   
 834               
 835              if "label" in self.bg_kwargs: 
 836                  self.bg_kwargs["label"] = r"$\mu_\mathrm{%s}$" \ 
 837                      % self.bg_kwargs["label"] 
 838              self.bg_kwargs.setdefault("alpha", 0.3) 
 839              self.bg_kwargs.setdefault("facecolor", "y") 
 840              upper = means + stds 
 841              lower = means - stds 
 842              lower[lower <= epsilon] = epsilon 
 843              tmp_x, tmp_y = viz.makesteps(bins, upper, lower) 
 844              self.ax.fill(tmp_x, tmp_y*normalization, **self.bg_kwargs) 
 845   
 846           
 847          self.ax.set_yscale("log") 
 848   
 849           
 850          self.ax.set_xlim((0.9 * min_stat, 1.1 * max_stat)) 
 851          possible_ymins = [0.6] 
 852          if len(self.bg_data_sets) > 0: 
 853              possible_ymins.append(0.6 / N) 
 854          else: 
 855              possible_ymins.append(0.6 * normalization) 
 856          self.ax.set_ylim(min(possible_ymins)) 
 857   
 858           
 859          self.kwarg_sets = self.fg_kwarg_sets 
 860          self.add_legend_if_labels_exist() 
 861   
 862           
 863          del self.kwarg_sets 
 864          del self.fg_data_sets 
 865          del self.fg_kwarg_sets 
 866          del self.bg_data_sets 
 867          del self.bg_kwargs 
   868   
 871      """ 
 872      The equivalent of pylab.imshow(), but with the BasicPlot niceties and 
 873      some defaults that are more in tune with what a scientist wants -- 
 874      origin="lower", requiring x and y bins so that we can label axes 
 875      correctly, and a colorbar. 
 876      """ 
 878          colorlabel = kwargs.pop("colorlabel", None) 
 879          BasicPlot.__init__(self, *args, **kwargs) 
 880          self.image_sets  = [] 
 881          self.x_bins_sets = [] 
 882          self.y_bins_sets = [] 
 883          self.kwarg_sets  = [] 
 884          self.colorlabel  = colorlabel 
  885   
 886 -    def add_content(self, image, x_bins, y_bins, **kwargs): 
  887          """ 
 888          Add a given image to this plot. 
 889   
 890          @param image: two-dimensional numpy array to plot 
 891          @param x_bins: pylal.rate.Bins instance describing the x binning 
 892          @param y_bins: pylal.rate.Bins instance describing the y binning 
 893          """ 
 894          if image.ndim != 2: 
 895              raise ValueError, "require 2-D array" 
 896          self.image_sets.append(image) 
 897          self.x_bins_sets.append(x_bins) 
 898          self.y_bins_sets.append(y_bins) 
 899          self.kwarg_sets.append(kwargs) 
  900   
 901      @method_callable_once 
 902 -    def finalize(self, colorbar=True, logcolor=False, minorticks=False,\ 
 903                   clim=None): 
  904          from lal import rate 
 905   
 906          logx = False 
 907          logy = False 
 908   
 909          for image,x_bins,y_bins,plot_kwargs in\ 
 910              itertools.izip(self.image_sets, self.x_bins_sets, self.y_bins_sets,\ 
 911                             self.kwarg_sets): 
 912              extent = [x_bins.lower()[0], x_bins.upper()[-1], 
 913                        y_bins.lower()[0], y_bins.upper()[-1]] 
 914              plot_kwargs.setdefault("origin", "lower") 
 915              plot_kwargs.setdefault("interpolation", "nearest") 
 916              if logcolor and clim: 
 917                  plot_kwargs.setdefault(\ 
 918                      "norm", pylab.matplotlib.colors.LogNorm(vmin=clim[0],\ 
 919                                                              vmax=clim[1])) 
 920              elif logcolor: 
 921                  plot_kwargs.setdefault("norm",\ 
 922                                         pylab.matplotlib.colors.LogNorm()) 
 923              elif clim: 
 924                  plot_kwargs.setdefault(\ 
 925                      "norm", pylab.matplotlib.colors.Normalize(vmin=clim[0],\ 
 926                                                                vmax=clim[1])) 
 927              if colorbar: 
 928                  plot_kwargs.setdefault("cmap", \ 
 929                       pylab.matplotlib.colors.LinearSegmentedColormap("clrs",\ 
 930                                         pylab.matplotlib.cm.jet._segmentdata)) 
 931   
 932              im = self.ax.imshow(image, extent=extent, **plot_kwargs) 
 933   
 934               
 935               
 936              if isinstance(x_bins, rate.LogarithmicBins): 
 937                  logx = True 
 938              if logx and not isinstance(x_bins, rate.LogarithmicBins): 
 939                  raise ValueError("Cannot process both linear and logarithmic "+\ 
 940                                   "Images on the same Axis.") 
 941              if isinstance(y_bins, rate.LogarithmicBins): 
 942                  logy = True 
 943              if logy and not isinstance(y_bins, rate.LogarithmicBins): 
 944                  raise ValueError("Cannot process both linear and logarithmic "+\ 
 945                                   "Images on the same Axis.") 
 946   
 947          pylab.axis('tight') 
 948   
 949          if colorbar: 
 950              add_colorbar(self.ax, log=logcolor, clim=clim,\ 
 951                           label=self.colorlabel) 
 952   
 953          if logx: 
 954              xticks, xlabels, xminorticks = log_transform(self.ax.get_xlim()) 
 955              self.ax.set_xticks(xticks) 
 956              self.ax.set_xticklabels(xlabels) 
 957              if minorticks: self.ax.set_xticks(xminorticks, minor=True) 
 958          if logy: 
 959              yticks, ylabels, yminorticks = log_transform(self.ax.get_ylim()) 
 960              self.ax.set_yticks(yticks) 
 961              self.ax.set_yticklabels(ylabels) 
 962              if minorticks: self.ax.set_yticks(yminorticks, minor=True) 
   963   
 965      """ 
 966      Given a list of vertices (passed by x-coords and y-coords), fill the 
 967      regions (by default with successively darker gray shades). 
 968      """ 
 970          BasicPlot.__init__(self, *args, **kwargs) 
 971          self.x_coord_sets = [] 
 972          self.y_coord_sets = [] 
 973          self.kwarg_sets = [] 
 974          self.shades = [] 
  975   
 976 -    def add_content(self, x_coords, y_coords, shade=None, **kwargs): 
  977          if len(x_coords) != len(y_coords): 
 978              raise ValueError, "x and y coords have different length" 
 979          if iterutils.any(s is None for s in self.shades) and shade is not None \ 
 980          or iterutils.any(s is not None for s in self.shades) and shade is None: 
 981              raise ValueError, "cannot mix explicit and automatic shading" 
 982   
 983          self.x_coord_sets.append(x_coords) 
 984          self.y_coord_sets.append(y_coords) 
 985          self.kwarg_sets.append(kwargs) 
 986          self.shades.append(shade) 
  987   
 988      @method_callable_once 
 990           
 991          if iterutils.any(s is None for s in self.shades): 
 992              n = len(self.shades) 
 993              grays = numpy.linspace(0, 1, n, endpoint=False)[::-1] 
 994              self.shades = numpy.vstack((grays, grays, grays)).T 
 995   
 996           
 997          for x, y, s, plot_kwargs in zip(self.x_coord_sets, self.y_coord_sets, 
 998                                self.shades, self.kwarg_sets): 
 999              self.ax.fill(x, y, facecolor=s, **plot_kwargs) 
1000   
1001           
1002          self.add_legend_if_labels_exist(loc=0) 
  1003   
1005      """ 
1006      Given a time- or frequency-series, plot it across six horizontal axes, 
1007      stacked on top of one another.  This is good for representing a 
1008      high-resolution one-dimensional data set.  To support missing data, 
1009      we require x and y coordinates for each data set. 
1010      """ 
1011 -    def __init__(self, xlabel="", ylabel="", title=""): 
 1012          self.fig = pylab.figure(figsize=(5.54, 7.5)) 
1013          self.title = title 
1014   
1015           
1016          self.xlabel = xlabel 
1017          self.ylabel = ylabel 
1018   
1019          self.x_coord_sets = [] 
1020          self.y_coord_sets = [] 
1021          self.kwarg_sets = [] 
 1022   
1023 -    def add_content(self, x_coords, y_coords, **kwargs): 
 1024          if len(x_coords) != len(y_coords): 
1025              raise ValueError, "x and y coords have different length" 
1026          if len(self.kwarg_sets) and \ 
1027              (iterutils.any("color" in kw for kw in self.kwarg_sets) 
1028               ^ ("color" in kwargs)): 
1029              raise ValueError, "cannot mix explicit and automatic coloring" 
1030   
1031          self.x_coord_sets.append(x_coords) 
1032          self.y_coord_sets.append(y_coords) 
1033          self.kwarg_sets.append(kwargs) 
 1034   
1035      @method_callable_once 
1037          for kw, c in zip(self.kwarg_sets, default_colors()): 
1038              kw.setdefault("color", c) 
1039   
1040          min_x, max_x = determine_common_bin_limits(self.x_coord_sets) 
1041   
1042          numaxes = 6   
1043          ticks_per_axis = 6  
1044          fperaxis = (max_x - min_x) / numaxes 
1045          freq_boundaries = numpy.linspace(min_x, max_x, numaxes + 1) 
1046          freq_ranges = zip(freq_boundaries[:-1], freq_boundaries[1:]) 
1047   
1048           
1049           
1050          tickspacing = int(numpy.ceil(fperaxis / ticks_per_axis / 10)) * 10 
1051          if abs(fperaxis / tickspacing - ticks_per_axis) > 2: 
1052              tickspacing = int(numpy.ceil(fperaxis / ticks_per_axis)) 
1053   
1054           
1055          for j, freq_range in enumerate(freq_ranges): 
1056               
1057              ax = self.fig.add_axes([.12, .84-.155*j, .86, 0.124]) 
1058   
1059              for x_coords, y_coords, kwarg_set in zip(self.x_coord_sets, 
1060                  self.y_coord_sets, self.kwarg_sets): 
1061                   
1062                  ind = (x_coords >= freq_range[0]) & (x_coords < freq_range[1]) 
1063                  x = x_coords[ind] 
1064                  y = y_coords[ind] 
1065   
1066                   
1067                  ax.plot(x, y, **kwarg_set) 
1068   
1069                   
1070                  ax.set_xlim(freq_range) 
1071   
1072                  mintick = int(numpy.ceil(freq_range[0] / tickspacing)) \ 
1073                      * tickspacing 
1074                  maxtick = int(numpy.floor(freq_range[1] / tickspacing)) \ 
1075                      * tickspacing 
1076                  ax.set_xticks(xrange(mintick, maxtick+1, tickspacing)) 
1077   
1078                  ax.set_ylabel(self.ylabel) 
1079                  ax.set_yscale(yscale) 
1080                  ax.grid(True) 
1081   
1082           
1083          ax.set_xlabel(self.xlabel) 
1084   
1085           
1086          self.fig.axes[0].set_title(self.title) 
1087   
1088           
1089          y_lims = [ax.get_ylim() for ax in self.fig.axes] 
1090          new_y_lims = determine_common_bin_limits(y_lims) 
1091          for ax in self.fig.axes: 
1092              ax.set_ylim(new_y_lims) 
  1093   
1095      """ 
1096      Plot the receiver operating characteristic (ROC) based on the foreground 
1097      and background values from given techniques.  For example, to compare 
1098      SNR vs IFAR, do something like: 
1099   
1100      plot = ROCPlot("FAP", "EFF", "ROC IFAR vs SNR") 
1101      plot.add_content(ifar_bg, ifar_fg, label="IFAR") 
1102      plot.add_content(snr_bg, snr_fg, label="SNR") 
1103      plot.finalize() 
1104      """ 
1106          BasicPlot.__init__(self, *args, **kwargs) 
1107          self.bg_sets = [] 
1108          self.fg_sets = [] 
1109          self.eff_weight_sets = [] 
1110          self.kwarg_sets = [] 
 1111   
1112 -    def add_content(self, bg, fg, eff_weight=None, **kwargs): 
 1113          """ 
1114          Enter a particular technique's background, foreground, and efficiency 
1115          weights.  These should be one-dimensional arrays with the values of 
1116          of your statistics for backgrounds and foregrounds.  Eff_weight 
1117          are weights on the efficiency, useful if, say, you have a different 
1118          prior than your injection set reflects. 
1119          """ 
1120          if eff_weight is not None and len(fg) != len(eff_weight): 
1121              raise ValueError, "efficiency weights and foreground values "\ 
1122                  "must be the same length" 
1123          self.bg_sets.append(bg) 
1124          self.fg_sets.append(fg) 
1125          self.eff_weight_sets.append(eff_weight) 
1126          self.kwarg_sets.append(kwargs) 
 1127   
1128      @method_callable_once 
1130          for bg, fg, weights, kwargs in itertools.izip(self.bg_sets, 
1131              self.fg_sets, self.eff_weight_sets, self.kwarg_sets): 
1132               
1133              bg = numpy.array(bg)   
1134              bg.sort() 
1135              fg = numpy.array(fg)   
1136              if weights is not None: 
1137                  weights = numpy.array(weights)[fg.argsort()] 
1138              fg.sort() 
1139   
1140               
1141              FAP = 1 - numpy.arange(len(bg), dtype=float) / len(bg) 
1142              if weights is not None: 
1143                  EFF = weights[::-1].cumsum()[::-1] 
1144              else: 
1145                  EFF = 1 - numpy.arange(len(fg), dtype=float) / len(fg) 
1146   
1147               
1148               
1149              EFF_ind = numpy.array([fg.searchsorted(x) for x in bg]) 
1150              fg_too_loud = EFF_ind == len(fg) 
1151              EFF_ind[fg_too_loud] = 0   
1152              EFF_by_FAP = EFF[EFF_ind] 
1153              EFF_by_FAP[fg_too_loud] = 0. 
1154   
1155               
1156              self.ax.plot(FAP, EFF_by_FAP, **kwargs) 
1157   
1158           
1159          self.ax.grid(True) 
1160          self.ax.set_xlim((0, 1)) 
1161          self.ax.set_ylim((0, 1)) 
1162   
1163           
1164          fig_side = min(self.fig.get_size_inches()) 
1165          self.fig.set_size_inches(fig_side, fig_side) 
1166   
1167           
1168          self.add_legend_if_labels_exist(loc=loc) 
1169   
1170           
1171          del self.fg_sets 
1172          del self.bg_sets 
1173          del self.eff_weight_sets 
1174          del self.kwarg_sets 
  1175   
1177      """ 
1178      Plot the global rank versus the self rank, like a Q-Q plot, i.e. 
1179      differences between the probability distribution of a 
1180      statistical population to a test population. 
1181      """ 
1183          BasicPlot.__init__(self, *args, **kwargs) 
1184          self.fg_data = [] 
1185          self.bg_data = [] 
1186          self.fg_kwargs = [] 
1187          self.bg_kwargs = [] 
1188          self.kwargs = None 
 1189   
1190 -    def add_content(self, *args): 
 1191          raise NotImplementedError, "A function 'add_content' is not "\ 
1192                "implemented for QQPlot. "\ 
1193                "Please use the functions 'add_fg' and 'add_bg'." 
 1194   
1196          """ 
1197          Calculates the sorted quantiles to be plotted. 
1198          """ 
1199          from scipy import stats 
1200   
1201          N_FG = len(fg) 
1202          N_BG = len(bg) 
1203          N_tot = N_BG + N_FG 
1204   
1205           
1206          bg_self_quantile = stats.rankdata(bg).astype(float) / N_BG 
1207          fg_self_quantile = stats.rankdata(fg).astype(float) / N_FG 
1208   
1209          popAB = numpy.concatenate((fg, bg)) 
1210          popAB_ranked = stats.rankdata(popAB).astype(float) 
1211          fg_global_quantile = popAB_ranked[:N_FG] / N_tot 
1212          bg_global_quantile = popAB_ranked[N_FG:] / N_tot 
1213   
1214          fg_self_quantile.sort() 
1215          bg_self_quantile.sort() 
1216          fg_global_quantile.sort() 
1217          bg_global_quantile.sort() 
1218   
1219          return fg_self_quantile, bg_self_quantile, fg_global_quantile, bg_global_quantile 
 1220   
1221 -    def add_fg(self, data, **kwargs): 
 1222          """ 
1223          Add the foreground data and the kwargs to a list for the 
1224          """ 
1225          self.fg_data.append(data) 
1226          self.fg_kwargs.append(kwargs) 
 1227   
1228 -    def add_bg(self, data, **kwargs): 
 1229          """ 
1230          Add the foreground data and the kwargs to a list for the 
1231          """ 
1232          self.bg_data.append(data) 
1233          self.bg_kwargs.append(kwargs) 
 1234   
1235      @method_callable_once 
1237   
1238          if len(self.fg_data)!=len(self.bg_data): 
1239              raise ValueError, "You have to add the same number of foreground data"\ 
1240                    " as background data. But you have specified %d sets of foreground data but %d"\ 
1241                    " sets of background data. " % ( len(self.fg_data), len(self.bg_data)) 
1242   
1243          for fg, bg, fg_kwargs, bg_kwargs in itertools.izip(self.fg_data, self.bg_data, \ 
1244                                                             self.fg_kwargs, self.bg_kwargs): 
1245   
1246              fg_self, bg_self, fg_global, bg_global = \ 
1247                       self._compute_quantiles(fg, bg) 
1248   
1249              self.ax.plot(bg_self, bg_global, **bg_kwargs) 
1250              self.ax.plot(fg_self, fg_global, **fg_kwargs) 
1251   
1252           
1253          self.ax.grid(True) 
1254   
1255           
1256          self.ax.legend(loc=4) 
1257   
1258           
1259          del self.fg_data 
1260          del self.bg_data 
1261          del self.fg_kwargs 
1262          del self.bg_kwargs 
1263          del self.kwargs 
  1264   
1266      """ 
1267      Class to create a clickable map html page. 
1268      """ 
1270          BasicPlot.__init__(self, *args, **kwargs) 
1271          self.x_data_sets = [] 
1272          self.y_data_sets = [] 
1273          self.link_list = [] 
1274          self.kwarg_sets = [] 
1275   
1276          self.click_size = 5 
1277   
1278          self.click_x = [] 
1279          self.click_y = [] 
1280          self.click_link = [] 
 1281   
1283          """ 
1284          Sets the size of the area around a point that can be clicked at. 
1285          """ 
1286          self.click_size = size 
 1287   
1288 -    def add_content(self, x_data, y_data, link, **kwargs): 
 1289          self.x_data_sets.append(x_data) 
1290          self.y_data_sets.append(y_data) 
1291          self.link_list.append(link) 
1292          self.kwarg_sets.append(kwargs) 
 1293   
1294   
1295      @method_callable_once 
1297   
1298           
1299          for x_vals, y_vals, plot_kwargs in \ 
1300              itertools.izip(self.x_data_sets, self.y_data_sets, self.kwarg_sets): 
1301              self.ax.plot(x_vals, y_vals, **plot_kwargs) 
1302   
1303           
1304          self.add_legend_if_labels_exist(loc=loc) 
 1305   
1306   
1308          """ 
1309          Calculate the rescaling to map the point coordinates 
1310          to the actual coordinates on the image. 
1311          """ 
1312   
1313           
1314          if dpi is None: 
1315              dpi = pylab.rcParams['savefig.dpi'] 
1316          self.ax.get_figure().set_dpi(dpi) 
1317   
1318           
1319          _, _, width, height = self.fig.bbox.extents 
1320   
1321           
1322          self.click_x = [] 
1323          self.click_y = [] 
1324          self.click_link = [] 
1325          for xvec, yvec, link in \ 
1326                  itertools.izip(self.x_data_sets, self.y_data_sets, self.link_list): 
1327               
1328              if link is None: 
1329                  continue 
1330   
1331              for point in zip(xvec, yvec): 
1332   
1333                   
1334                  pixel = self.ax.transData.transform(point) 
1335   
1336                   
1337                   
1338                  self.click_x.append(pixel[0]) 
1339                  self.click_y.append(height - pixel[1]) 
1340                  self.click_link.append(link) 
 1341   
1342   
1344          """ 
1345          Create the html file with the name of the plot 
1346          as the only additional input information needed. 
1347          If the actual plot is saved with a different 
1348          dpi than the standard one, it must be specified here!! 
1349          """ 
1350   
1351           
1352          self.rescale(dpi) 
1353   
1354           
1355          _, _, width, height = self.fig.bbox.extents 
1356   
1357           
1358          page = '' 
1359          page += '<IMG src="%s" width=%dpx '\ 
1360              'usemap="#map">' % ( plotname, width) 
1361          page +=  '<MAP name="map"> <P>' 
1362          n=0 
1363          for px, py, link in zip( self.click_x, self.click_y, self.click_link): 
1364              n+=1 
1365              page +=  '<area href="%s" shape="circle" '\ 
1366                  'coords="%d, %d, 5"> Point%d</a>' %\ 
1367                  ( link, px, py, n) 
1368          page += '</P></MAP></OBJECT><br>' 
1369          page += "<hr/>" 
1370   
1371           
1372           
1373          return page 
  1374   
1375   
1376   
1377  plot3D_head = """ 
1378    <style type="text/css"> 
1379      .rotationViewer { 
1380        position:relative; 
1381        width:640px; 
1382        height:378px; 
1383        border-style:solid; 
1384        border-width:1px; 
1385        margin:auto; 
1386        margin-bottom:10px; 
1387        cursor:pointer; 
1388      } 
1389      .rotationViewer img { 
1390        position:absolute; 
1391        visibility:hidden; 
1392        left:0; 
1393        top:0; 
1394        width:100%; 
1395        height:100%; 
1396      } 
1397    </style> 
1398  """ 
1399   
1400  plot3D_body = """ 
1401  <script type="text/javascript" src="PATHTOUIZE/Uize.js"></script> 
1402   
1403  <div class="main"> 
1404    <div id="page_rotationViewer" class="rotationViewer insetBorderColor"></div> 
1405  </div> 
1406   
1407  <!-- JavaScript code to make the static bar HTML "come alive" --> 
1408  <!-- Based on http://www.uize.com/examples/3d-rotation-viewer.html --> 
1409  <script type="text/javascript"> 
1410   
1411  Uize.module ({ 
1412    required:[ 
1413      'UizeDotCom.Page.Example.library', 
1414      'UizeDotCom.Page.Example', 
1415      'Uize.Widget.Drag', 
1416      'Uize.Fade.xFactory', 
1417      'Uize.Curve.Rubber', 
1418      'Uize.Curve.Mod' 
1419    ], 
1420    builder:function () { 
1421      /*** create the example page widget ***/ 
1422        var page = window.page = Uize.Widget.Page  ({evaluator:function (code) {eval (code)}}); 
1423   
1424      /*** configuration variables ***/ 
1425        var 
1426          totalFrames = TOTALFRAMES, 
1427          frameUrlTemplate = 'URLTEMPLATE' 
1428        ; 
1429   
1430      /*** state variables ***/ 
1431        var 
1432          rotation = 0, 
1433          lastFrameNo = -1, 
1434          dragStartRotation 
1435        ; 
1436   
1437      /*** create the Uize.Widget.Drag instance ***/ 
1438        var rotationViewer = page.addChild ( 
1439          'rotationViewer', 
1440          Uize.Widget.Drag, 
1441          { 
1442            cancelFade:{duration:5000,curve:Uize.Curve.Rubber.easeOutBounce ()}, 
1443            releaseTravel:function (speed) { 
1444              var 
1445                deceleration = 5000, // measured in pixels/s/s 
1446                duration = speed / deceleration 
1447              ; 
1448              return { 
1449                duration:duration, 
1450                distance:Math.round (speed * duration / 2), 
1451                curve:function (_value) {return 1 - (_value = 1 - _value) * _value} 
1452              }; 
1453            }, 
1454            html:function (input) { 
1455              var 
1456                htmlChunks = [], 
1457                frameNodeIdPrefix = input.idPrefix + '-frame' 
1458              ; 
1459              for (var frameNo = 0; ++frameNo <= totalFrames;) { 
1460                htmlChunks.push ( 
1461                  '<img' + 
1462                    ' id="' + frameNodeIdPrefix + frameNo + '"' + 
1463                    ' src="' + Uize.substituteInto (frameUrlTemplate,{frame:(frameNo < 10 ? '0' : '') + frameNo}) +'"' + 
1464                  '/>' 
1465                ); 
1466              } 
1467              return htmlChunks.join (''); 
1468            }, 
1469            built:false 
1470          } 
1471        ); 
1472   
1473      /*** wire up the drag widget with events for updating rotation degree ***/ 
1474        function updateRotation (newRotation) { 
1475          rotation = ((newRotation % 360) + 360) % 360; 
1476          var frameNo = 1 + Math.round (rotation / 360 * (totalFrames - 1)); 
1477          if (frameNo != lastFrameNo) { 
1478            rotationViewer.showNode ('frame'+ lastFrameNo,false); 
1479            rotationViewer.showNode ('frame'+ (lastFrameNo = frameNo)); 
1480          } 
1481        } 
1482        rotationViewer.wire ({ 
1483          'Drag Start':function () {dragStartRotation = rotation}, 
1484          'Drag Update':function (e) {updateRotation (dragStartRotation - e.source.eventDeltaPos [0] / 2.5)} 
1485        }); 
1486   
1487      /*** function for animating spin ***/ 
1488        function spin (degrees,duration,curve) { 
1489          Uize.Fade.fade (updateRotation,rotation,rotation + degrees,duration,{quantization:1,curve:curve}); 
1490        } 
1491   
1492      /*** initialization ***/ 
1493        Uize.Node.wire (window,'load',function () {spin (360,2700,Uize.Curve.easeInOutPow (4))}); 
1494   
1495      /*** wire up the page widget ***/ 
1496        page.wireUi (); 
1497    } 
1498  }); 
1499   
1500  </script> 
1501  """ 
1502   
1503   
1504 -class Plot3D(BasicPlot): 
 1505      """ 
1506      Exactly what you get by calling pylab.plot(), but with the handy extras 
1507      of the BasicPlot class. 
1508      """ 
1510   
1511   
1512          BasicPlot.__init__(self) 
1513          self.x_data_sets = [] 
1514          self.y_data_sets = [] 
1515          self.z_data_sets = [] 
1516          self.kwarg_sets = [] 
1517   
1518           
1519          self.ax =  Axes3D(self.fig) 
1520   
1521           
1522          self.ax.set_xlabel(args[0]) 
1523          self.ax.set_ylabel(args[1]) 
1524          self.ax.set_zlabel(args[2]) 
1525          self.ax.set_title(args[3]) 
1526   
1527          self.ax.grid(True) 
 1528   
1529 -    def add_content(self, x_data, y_data, z_data, **kwargs): 
 1530          self.x_data_sets.append(x_data) 
1531          self.y_data_sets.append(y_data) 
1532          self.z_data_sets.append(z_data) 
1533          self.kwarg_sets.append(kwargs) 
 1534   
1535   
1536      @method_callable_once 
1537 -    def finalize(self, plot_basename, n=50, dpi=50, loc=0, plot_dir = '.',\ 
1538                       js_dir = 'https://ldas-jobs.phys.uwm.edu/~dietz/js'): 
 1539   
1540           
1541          if n>100: 
1542              raise ValueError("The 3D code cannot handle more than 100 frames currently.") 
1543   
1544          fig = pylab.figure() 
1545          ax = Axes3D(fig) 
1546   
1547           
1548          for x_vals, y_vals, z_vals, plot_kwargs in \ 
1549              itertools.izip(self.x_data_sets, self.y_data_sets, \ 
1550                             self.z_data_sets, self.kwarg_sets): 
1551              self.ax.scatter(x_vals, y_vals, z_vals, **plot_kwargs) 
1552   
1553           
1554          self.add_legend_if_labels_exist(loc=loc) 
1555   
1556           
1557          dphi = 360.0/float(n) 
1558          for i, angle in enumerate(numpy.arange(0.0, 360.0, dphi)): 
1559   
1560               
1561              self.ax.view_init(30.0, angle) 
1562   
1563               
1564              picname = '%s/%s-%02d'%(plot_dir, plot_basename, i) 
1565              self.savefig(picname+'.png',dpi=dpi) 
1566   
1567   
1568           
1569          del self.x_data_sets 
1570          del self.y_data_sets 
1571          del self.z_data_sets 
1572          del self.kwarg_sets 
1573   
1574   
1575           
1576          plot_template = '%s/%s-[#frame].png'%(plot_dir, plot_basename) 
1577          body = plot3D_body.replace('TOTALFRAMES',str(n)) 
1578          body = body.replace('URLTEMPLATE', plot_template) 
1579          body = body.replace('PATHTOUIZE', js_dir) 
1580   
1581           
1582          return plot3D_head, body 
  1583   
1585      """ 
1586      Exactly what you get from calling pylab.scatter(), but with the handy extras 
1587      of the BasicPlot class. 
1588      """ 
1589   
1590      @method_callable_once 
1592           
1593          for x_vals, y_vals, plot_kwargs, color in \ 
1594              itertools.izip(self.x_data_sets, self.y_data_sets, self.kwarg_sets,\ 
1595                             default_colors()): 
1596              plot_kwargs.setdefault("c", color) 
1597              if (len(x_vals) and 
1598                  (isinstance(y_vals, numpy.ma.MaskedArray) and y_vals.count() or 
1599                   True)): 
1600                  self.ax.scatter(x_vals, y_vals, **plot_kwargs) 
1601              else: 
1602                  plot_kwargs["visible"] = False 
1603                  self.ax.scatter([1], [1], **plot_kwargs) 
1604   
1605           
1606          self.add_legend_if_labels_exist(loc=loc, alpha=0.8) 
1607   
1608           
1609          del self.x_data_sets 
1610          del self.y_data_sets 
1611          del self.kwarg_sets 
  1612   
1614      """ 
1615      Exactly what you get from calling pylab.scatter() when you want a colorbar, 
1616      but with the handy extras of the BasicPlot class. 
1617      """ 
1618   
1619 -    def __init__(self, xlabel="", ylabel="", clabel="", title="", subtitle=""): 
 1620          BasicPlot.__init__(self, xlabel=xlabel, ylabel=ylabel, title=title,\ 
1621                             subtitle=subtitle) 
1622          self.clabel      = clabel 
1623          self.x_data_sets = [] 
1624          self.y_data_sets = [] 
1625          self.c_data_sets = [] 
1626          self.kwarg_sets  = [] 
 1627   
1628 -    def add_content(self, x_data, y_data, c_data, **kwargs): 
 1629          self.x_data_sets.append(x_data) 
1630          self.y_data_sets.append(y_data) 
1631          self.c_data_sets.append(c_data) 
1632          self.kwarg_sets.append(kwargs) 
 1633   
1634 -    def finalize(self, loc=0, colorbar=True, logcolor=False, clim=None,\ 
1635                   alpha=0.8): 
 1636           
1637          p = None 
1638          for x_vals, y_vals, c_vals, plot_kwargs in\ 
1639              itertools.izip(self.x_data_sets, self.y_data_sets, self.c_data_sets, 
1640                             self.kwarg_sets): 
1641              if len(x_vals): 
1642                  zipped = zip(x_vals, y_vals, c_vals) 
1643                  zipped.sort(key=lambda (x,y,c): c) 
1644                  x_vals, y_vals, c_vals = map(numpy.asarray, zip(*zipped)) 
1645              if logcolor: 
1646                  plot_kwargs.setdefault("norm",pylab.matplotlib.colors.LogNorm()) 
1647              try: 
1648                  p = self.ax.scatter(x_vals, y_vals, c=c_vals, **plot_kwargs) 
1649              except ValueError: 
1650                  plot_kwargs['visible'] = False 
1651                  p = self.ax.scatter([1], [1], c=[1], **plot_kwargs) 
1652              p = self.ax.scatter(x_vals, y_vals, c=c_vals, **plot_kwargs) 
1653   
1654          if colorbar and p is not None: 
1655              add_colorbar(self.ax, mappable=p, log=logcolor, label=self.clabel,\ 
1656                           clim=clim) 
1657   
1658           
1659          self.add_legend_if_labels_exist(loc=loc, alpha=alpha) 
1660   
1661           
1662          del self.x_data_sets 
1663          del self.y_data_sets 
1664          del self.c_data_sets 
1665          del self.kwarg_sets 
  1666   
1668      """ 
1669      Horizontal bar segment plot. 
1670      """ 
1671      color_code = {'H1':'r', 'H2':'b', 'L1':'g', 'V1':'m', 'G1':'k'} 
1672   
1673 -    def __init__(self, xlabel="", ylabel="", title="", subtitle="", t0=0,\ 
1674                   dt=1): 
 1675          """ 
1676          Create a fresh plot. Provide t0 to provide reference time to use as 
1677          zero, and dt to use a different number of seconds for each unit of the 
1678          x-axis. 
1679          """ 
1680          BasicPlot.__init__(self, xlabel, ylabel, title) 
1681          self.segdict = segments.segmentlistdict() 
1682          self.keys = [] 
1683          self._time_transform = lambda t: float(t - t0)/dt 
1684          self.kwarg_sets  = [] 
 1685   
1686 -    def add_content(self, segdict, keys=None, **kwargs): 
 1687          if not keys: 
1688              keys = sorted(segdict.keys()) 
1689          for key in keys: 
1690              if key in self.segdict.keys(): 
1691                  self.segdict[key] += segdict[key] 
1692              else: 
1693                  self.keys.append(key) 
1694                  self.segdict[key] = segdict[key] 
1695              self.kwarg_sets.append(dict()) 
1696              self.kwarg_sets[-1].update(kwargs) 
 1697                   
1699          """ 
1700          Highlight a particular segment with dashed lines. 
1701          """ 
1702          a,b = map(self._time_transform,seg) 
1703          plot_args.setdefault('linestyle', '--') 
1704          plot_args.setdefault('color','r') 
1705          self.ax.axvline(a, **plot_args) 
1706          self.ax.axvline(b, **plot_args) 
 1707   
1709          """ 
1710          Define a window of interest by setting the x-limits of the plot 
1711          appropriately.  If padding is also present, protract the x-limits by 
1712          that quantity and mark the unpadded window with solid black lines. 
1713          """ 
1714          a = self._time_transform(window_seg[0]) 
1715          b = self._time_transform(window_seg[1]) 
1716          self.window = segments.segment((a - padding, b + padding)) 
1717     
1718          if padding > 0: 
1719              self.ax.axvline(a, color='k', linewidth=2) 
1720              self.ax.axvline(b, color='k', linewidth=2) 
 1721   
1722      @method_callable_once 
1723 -    def finalize(self, labels_inset=False, hidden_colorbar=False): 
 1724   
1725          for row,(key,plot_kwargs)\ 
1726          in enumerate(itertools.izip(self.keys, self.kwarg_sets)): 
1727              plot_kwargs.setdefault("edgecolor", "k") 
1728              if self.color_code.has_key(key): 
1729                  plot_kwargs.setdefault("color", self.color_code[key]) 
1730              else: 
1731                  plot_kwargs.setdefault("color", "b") 
1732              for seg in self.segdict[key]: 
1733                  a,b = map(self._time_transform, seg) 
1734                  self.ax.fill([a, b, b, a, a],\ 
1735                               [row-0.4, row-0.4, row+0.4, row+0.4, row-0.4],\ 
1736                               **plot_kwargs) 
1737              if labels_inset: 
1738                  self.ax.text(0.01, (row+1)/(len(self.keys)+1),\ 
1739                               re.sub(r'\\+_+','\_',key),\ 
1740                               horizontalalignment='left',\ 
1741                               verticalalignment='center',\ 
1742                               transform=self.ax.transAxes,\ 
1743                               backgroundcolor='white',\ 
1744                               bbox=dict(facecolor='white', alpha=0.5,\ 
1745                                         edgecolor='white')) 
1746       
1747          ticks = pylab.arange(len(self.keys)) 
1748          self.ax.set_yticks(ticks) 
1749          if labels_inset: 
1750              self.ax.set_yticklabels(ticks, color='white') 
1751          else: 
1752              self.ax.set_yticklabels([re.sub(r'\\+_+', '\_', k)\ 
1753                                         for k in self.keys], size='small') 
1754          self.ax.set_ylim(-1, len(self.keys)) 
1755   
1756           
1757          del self.keys 
1758          del self.segdict 
1759          del self.kwarg_sets 
  1760   
1762      """ 
1763      A DQ-formatted scatter plot, with those triggers below some threshold on the 
1764      colour axis get plotted tiny wee. 
1765      """ 
1766 -    def finalize(self, loc=0, alpha=0.8, colorbar=True, logcolor=False,\ 
1767                   clim=None, threshold=0): 
 1768           
1769          p = None 
1770          for x_vals, y_vals, c_vals, plot_kwargs in\ 
1771              itertools.izip(self.x_data_sets, self.y_data_sets, self.c_data_sets, 
1772                             self.kwarg_sets): 
1773              plot_kwargs.setdefault("s", 15) 
1774              if logcolor: 
1775                  plot_kwargs.setdefault("norm",pylab.matplotlib.colors.LogNorm()) 
1776              if clim: 
1777                  plot_kwargs.setdefault("vmin", clim[0]) 
1778                  plot_kwargs.setdefault("vmax", clim[1]) 
1779   
1780              if len(x_vals): 
1781                  zipped = zip(x_vals, y_vals, c_vals) 
1782                  zipped.sort(key=lambda (x,y,c): c) 
1783                  x_vals, y_vals, c_vals = map(numpy.asarray, zip(*zipped)) 
1784   
1785              t = (c_vals>=threshold).nonzero()[0] 
1786              if len(t): 
1787                  idx = t[0] 
1788                  xlow,xhigh = numpy.split(x_vals, [idx]) 
1789                  ylow,yhigh = numpy.split(y_vals, [idx]) 
1790                  clow,chigh = numpy.split(c_vals, [idx]) 
1791              else: 
1792                  xlow  = x_vals 
1793                  ylow  = y_vals 
1794                  clow  = c_vals 
1795                  xhigh = numpy.array([]) 
1796                  yhigh = numpy.array([]) 
1797                  chigh = numpy.array([]) 
1798   
1799              if xlow.size > 0: 
1800                  lowargs = copy.deepcopy(plot_kwargs) 
1801                  lowargs.pop("label", None) 
1802                  lowargs["s"] /= 4 
1803                  if lowargs.get("marker", None) != "x": 
1804                      lowargs["edgecolor"] = "none" 
1805                  self.ax.scatter(xlow, ylow, c=clow, **lowargs) 
1806              if xhigh.size > 0: 
1807                  self.ax.scatter(xhigh, yhigh, c=chigh, **plot_kwargs) 
1808              if not len(x_vals): 
1809                  plot_kwargs["visible"] = False 
1810                  self.ax.scatter([1], [1], c=1, **plot_kwargs) 
1811   
1812          if colorbar: 
1813              add_colorbar(self.ax, log=logcolor, label=self.clabel, clim=clim,\ 
1814                           cmap=plot_kwargs.get("cmap", None)) 
1815   
1816           
1817          self.add_legend_if_labels_exist(loc=loc, alpha=alpha) 
1818   
1819           
1820          del self.x_data_sets 
1821          del self.y_data_sets 
1822          del self.c_data_sets 
1823          del self.kwarg_sets 
  1824   
1826      """ 
1827      A simple line histogram plot. The values of each histogram bin are plotted 
1828      using pylab.plot(), with points centred on the x values and height equal 
1829      to the y values. 
1830   
1831      Cumulative, and rate options can be passeed to the finalize() method to 
1832      format each trace individually. 
1833      """ 
1834 -    def __init__(self, xlabel="", ylabel="", title="", subtitle=""): 
 1835          BasicPlot.__init__(self, xlabel, ylabel, title, subtitle) 
1836          self.data_sets        = [] 
1837          self.normalize_values = [] 
1838          self.kwarg_sets       = [] 
 1839   
1840 -    def add_content(self, data, normalize=1, **kwargs): 
 1841          self.data_sets.append(data) 
1842          self.normalize_values.append(normalize) 
1843          self.kwarg_sets.append(kwargs) 
 1844   
1845      @method_callable_once 
1846 -    def finalize(self, loc=0, num_bins=100, cumulative=False, rate=False,\ 
1847                   xlim=None, bar=False, fill=False, logx=False, logy=False,\ 
1848                   alpha=0.8): 
 1849           
1850          if xlim: 
1851              min_stat, max_stat = xlim 
1852          else: 
1853              min_stat, max_stat = determine_common_bin_limits(self.data_sets) 
1854          if logx: 
1855              if min_stat == max_stat == 0: 
1856                  min_stat = 1 
1857                  max_stat = 10 
1858              bins = numpy.logspace(numpy.log10(min_stat), numpy.log10(max_stat),\ 
1859                                    int(num_bins) + 1, endpoint=True) 
1860          else: 
1861              bins = numpy.linspace(min_stat, max_stat, num_bins+1, endpoint=True) 
1862   
1863           
1864          if logx: 
1865              width = list(numpy.diff(bins)) 
1866          else: 
1867              width = (1 - 0.1 * len(self.data_sets)) * (bins[1] - bins[0]) 
1868          width = numpy.asarray(width) 
1869   
1870           
1871          ymin = None 
1872   
1873          for data_set, norm, plot_kwargs in\ 
1874              itertools.izip(self.data_sets, self.normalize_values,\ 
1875                             self.kwarg_sets): 
1876               
1877              y, x = numpy.histogram(data_set, bins=bins, normed=False) 
1878              y = y.astype(float) 
1879              x = x[:-1] 
1880   
1881               
1882              if fill: 
1883                  plot_kwargs.setdefault("linewidth", 1) 
1884                  plot_kwargs.setdefault("alpha", 0.8) 
1885   
1886               
1887              if cumulative: 
1888                  y = y[::-1].cumsum()[::-1] 
1889   
1890               
1891              if norm != 1: 
1892                  y /= norm 
1893   
1894               
1895              if bar: 
1896                  x = numpy.vstack((x-width/2, x+width/2)).reshape((-1,),\ 
1897                                                               order="F") 
1898                  y = numpy.vstack((y, y)).reshape((-1,), order="F") 
1899   
1900               
1901              if logy: 
1902                  numpy.putmask(y, y==0, 1e-100) 
1903              self.ax.plot(x, y, **plot_kwargs) 
1904              if fill: 
1905                  plot_kwargs.pop("label", None) 
1906                  self.ax.fill_between(x, 1e-100, y, **plot_kwargs) 
1907   
1908          if logx: 
1909              try: 
1910                  self.ax.set_xscale("log", nonposx='clip') 
1911              except OverflowError: 
1912                  self.ax._autoscaleXon = False 
1913                  self.ax.set_xscale("log", nonposx='clip') 
1914   
1915          if logy: 
1916              try: 
1917                  self.ax.set_yscale("log", nonposy='clip') 
1918              except OverflowError: 
1919                  self.ax._autoscaleYon = False 
1920                  self.ax.set_yscale("log", nonposy='clip') 
1921   
1922           
1923          self.add_legend_if_labels_exist(loc=loc, alpha=0.8) 
1924   
1925           
1926          del self.data_sets 
1927          del self.normalize_values 
1928          del self.kwarg_sets 
  1929   
1931      """ 
1932      A spherical projection plot. 
1933      """ 
1934      @method_callable_once 
1935 -    def finalize(self, loc='lower right', projection='moll', centre=(0,0),\ 
1936                   frame=[(0, 0), (1, 1)]): 
 1937          """ 
1938          Finalize and draw plot. Can only be called once. 
1939   
1940          Keyword arguments: 
1941   
1942              toc : [ str | int ] 
1943                  compatible value for legend loc, default: 'lower right' 
1944              projection : str 
1945                  valid projection name for mpl_toolkits.basemap.Basemap 
1946              centre : list 
1947                  (ra, dec) in degrees for point to centre on plot, only works 
1948                  for some projections 
1949              frame : list 
1950                  [(xmin, ymin), (xmax, ymax)] pair of tuples for lower left 
1951                  and upper right corners of plot area. Full arei (entire 
1952                  sphere) is [(0,0), (1,1)]. Narrower range is span in, 
1953                  wider range zoomed out. 
1954          """ 
1955           
1956          projection = projection.lower() 
1957          centre = [(-(centre[0]-180)+180) % 360, centre[1]] 
1958          m1 = Basemap(projection=projection, lon_0=centre[0], lat_0=centre[1],\ 
1959                         resolution=None, ax=self.ax) 
1960   
1961           
1962          width  = m1.urcrnrx 
1963          height = m1.urcrnry 
1964          frame = [list(frame[0]), list(frame[1])] 
1965          mapframe = [[-width/2, -height/2], [width/2, height/2]] 
1966          if frame[0][0] != None: 
1967              mapframe[0][0] = width/2*(frame[0][0]-1) 
1968          if frame[0][1] != None: 
1969              mapframe[0][1] = height/2*(frame[0][1]-1) 
1970          if frame[1][0] != None: 
1971              mapframe[1][0] = width/2*(frame[1][0]) 
1972          if frame[1][1] != None: 
1973              mapframe[1][1] = height/2*(frame[1][1]) 
1974   
1975           
1976          m = Basemap(projection=projection, lon_0=centre[0], lat_0=centre[1],\ 
1977                      llcrnrx=mapframe[0][0], llcrnry=mapframe[0][1],\ 
1978                      urcrnrx=mapframe[1][0], urcrnry=mapframe[1][1],\ 
1979                      resolution=None, ax=self.ax) 
1980   
1981           
1982          if mapframe == [[-width/2, -height/2], [width/2, height/2]]: 
1983               m._fulldisk = True 
1984   
1985          xrange_ = (m.llcrnrx, m.urcrnrx) 
1986          yrange = (m.llcrnry, m.urcrnry) 
1987   
1988           
1989          for x_vals, y_vals, plot_kwargs, c in\ 
1990              itertools.izip(self.x_data_sets, self.y_data_sets,\ 
1991                             self.kwarg_sets, default_colors()): 
1992   
1993              plot_kwargs.setdefault("marker", "o") 
1994              plot_kwargs.setdefault("edgecolor", "k") 
1995              plot_kwargs.setdefault("facecolor", c) 
1996   
1997               
1998              convert = lambda x: (x>=180 and x-360) or (x<180 and x) 
1999              x_vals  = [-convert(x) for x in x_vals] 
2000              if projection in ['moll', 'hammer', 'orth']: 
2001                  convert = lambda x: (x>=0 and x) or (x<0 and x+360) 
2002              x_vals, y_vals = m(x_vals, y_vals) 
2003              m.scatter(x_vals, y_vals, **plot_kwargs) 
2004   
2005           
2006          m.drawmapboundary() 
2007   
2008           
2009          if projection in ['ortho']: 
2010              plabels = [0, 0, 0, 0] 
2011              mlabels = [0, 0, 0, 0] 
2012          else: 
2013              plabels = [1, 0, 0, 0] 
2014              mlabels = [0, 0, 0, 0] 
2015   
2016           
2017          parallels = numpy.arange(-90., 120., 30.) 
2018          m.drawparallels(parallels, labels=plabels,\ 
2019                          labelstyle='+/-', latmax=90) 
2020   
2021           
2022          if projection in ['moll', 'hammer', 'ortho']: 
2023              meridians = numpy.arange(0., 360., 45.) 
2024          else: 
2025              meridians = numpy.arange(-180, 181, 45) 
2026          m.drawmeridians(meridians, labels=mlabels,\ 
2027                          latmax=90, labelstyle='+/-') 
2028   
2029           
2030          if projection in ['ortho']: 
2031              for lon,lat in zip([0.]*len(parallels), parallels): 
2032                  x, y = m(lon, lat) 
2033                  lon, lat = m1(x, y, inverse=True) 
2034                  if x<=10**20 and y<=10**20\ 
2035                  and xrange_[0]<x<xrange_[1] and yrange[0]<=y<=yrange[1]: 
2036                      m.ax.text(x, y, r"$%0.0f^\circ$" % lat) 
2037   
2038           
2039          for lon,lat in zip(meridians, [0.]*len(meridians)): 
2040              tlon = (-(lon-180)+180) % 360 
2041              x, y = m(lon, lat) 
2042              lon, lat = m1(x, y, inverse=True) 
2043   
2044              if x<=10**20 and y<=10**20\ 
2045              and xrange_[0]<x<xrange_[1] and yrange[0]<=y<=yrange[1]: 
2046                  m.ax.text(x, y, r"$%0.0f^\circ$" % tlon) 
2047   
2048           
2049          self.add_legend_if_labels_exist(loc=loc, scatterpoints=1) 
  2050   
2051   
2052   
2053   
2054   
2055   
2056  import unittest 
2060   
2061   
2063           
2064          pylab.rcParams.update({"savefig.dpi": 120}) 
2065   
2066           
2067          plot = SimpleMapPlot(r"Range [km]", r"Take off weight [t]", "4 engine planes") 
2068   
2069           
2070           
2071           
2072          range = [ [14600], [14800], [13000, 14800], [2800], [4800], [14000]] 
2073          weight = [[365], [560], [374, 442], [46], [392], [50]] 
2074          links = ['http://de.wikipedia.org/wiki/Airbus_A340',\ 
2075                  'http://de.wikipedia.org/wiki/Airbus_A380',\ 
2076                  'http://de.wikipedia.org/wiki/Boeing_747',\ 
2077                  'http://de.wikipedia.org/wiki/Avro_RJ85',\ 
2078                  'http://de.wikipedia.org/wiki/Antonow_An-124',\ 
2079                   None] 
2080          markers = ['ro','bD','yx','cs','g^','k>'] 
2081   
2082           
2083          for x,y,link, mark in zip(range, weight, links, markers): 
2084              plot.add_content(x, y, link, color=mark[0], marker=mark[1]) 
2085   
2086           
2087          plot.finalize() 
2088   
2089           
2090          plotname = 'plotutils_TestSimpleMapPlot.png' 
2091          plot.savefig(plotname) 
2092   
2093           
2094          html = plot.create_html(plotname) 
2095          f = file('plotutils_TestSimpleMapPlot.html','w') 
2096          f.write(html) 
2097          f.close() 
  2098   
2099   
2100  if __name__ == '__main__': 
2101   
2102   
2103      unittest.main() 
2104