docs: def LogoOverlay(sites, overlayfile, overlay, nperline, sitewidth, rmargin, logoheight, barheight, barspacing, fix_limits={}, fixlongname=False, overlay_cmap=None, underlay=False, scalebar=False):
      """Makes overlay for *LogoPlot*.
  
      This function creates colored bars overlay bars showing up to two
      properties.
      The trick of this function is to create the bars the right
      size so they align when they overlay the logo plot. 
  
      CALLING VARIABLES:
  
      * *sites* : same as the variable of this name used by *LogoPlot*.
  
      * *overlayfile* is a string giving the name of created PDF file containing
        the overlay. It must end in the extension ``.pdf``.
  
      * *overlay* : same as the variable of this name used by *LogoPlot*.
  
      * *nperline* : same as the variable of this name used by *LogoPlot*.
  
      * *sitewidth* is the width of each site in points.
  
      * *rmargin* is the right margin in points.
  
      * *logoheight* is the total height of each logo row in points.
  
      * *barheight* is the total height of each bar in points.
  
      * *barspacing* is the vertical spacing between bars in points.
  
      * *fix_limits* has the same meaning of the variable of this name used by *LogoPlot*.
  
      * *fixlongname* has the same meaning of the variable of this name used by *LogoPlot*.
  
      * *overlay_cmap* has the same meaning of the variable of this name used by *LogoPlot*.
  
      * *underlay* is a bool. If `True`, make an underlay rather than an overlay.
  
      * *scalebar: if not `False`, is 2-tuple `(scalebarheight, scalebarlabel)`
        where `scalebarheight` is in points.
      """
      if os.path.splitext(overlayfile)[1] != '.pdf':
          raise ValueError("overlayfile must end in .pdf: %s" % overlayfile)
      if not overlay_cmap:
          (cmap, mapping_d, mapper) = KyteDoolittleColorMapping()
      else:
          mapper = pylab.cm.ScalarMappable(cmap=overlay_cmap)
          cmap = mapper.get_cmap()
      pts_per_inch = 72.0 # to convert between points and inches
      # some general properties of the plot
      matplotlib.rc('text', usetex=True)
      matplotlib.rc('xtick', labelsize=8)
      matplotlib.rc('xtick', direction='out')
      matplotlib.rc('ytick', direction='out')
      matplotlib.rc('axes', linewidth=0.5)
      matplotlib.rc('ytick.major', size=3)
      matplotlib.rc('xtick.major', size=2.5)
      # define sizes (still in points)
      colorbar_bmargin = 20 # margin below color bars in points
      colorbar_tmargin = 15 # margin above color bars in points
      nlines = int(math.ceil(len(sites) / float(nperline)))
      lmargin = 25 # left margin in points
      barwidth = nperline * sitewidth
      figwidth = lmargin + rmargin + barwidth
      figheight = nlines * (logoheight + len(overlay) * (barheight +
              barspacing)) + (barheight + colorbar_bmargin + colorbar_tmargin) + (
              int(underlay) * len(overlay) * (barheight + barspacing))
      # set up the figure and axes
      fig = pylab.figure(figsize=(figwidth / pts_per_inch, figheight / pts_per_inch))
      # determine property types
      prop_types = {}
      for (prop_d, shortname, longname) in overlay:
          if shortname == longname == 'wildtype':
              assert all([(isinstance(prop, str) and len(prop) == 1) for 
                      prop in prop_d.values()]), 'prop_d does not give letters'
              proptype = 'wildtype'
              (vmin, vmax) = (0, 1) # not used, but need to be assigned
              propcategories = None # not used, but needs to be assigned
          elif all([isinstance(prop, str) for prop in prop_d.values()]):
              proptype = 'discrete'
              propcategories = list(set(prop_d.values()))
              propcategories.sort()
              (vmin, vmax) = (0, len(propcategories) - 1)
          elif all ([isinstance(prop, (int, float)) for prop in prop_d.values()]):
              proptype = 'continuous'
              propcategories = None
              (vmin, vmax) = (min(prop_d.values()), max(prop_d.values()))
              # If vmin is slightly greater than zero, set it to zero. This helps for RSA properties.
              if vmin >= 0 and vmin / float(vmax - vmin) < 0.05:
                  vmin = 0.0
                  # And if vmax is just a bit less than one, set it to that...
                  if 0.9 <= vmax <= 1.0:
                      vmax = 1.0
          else:
              raise ValueError("Property %s is neither continuous or discrete. Values are:\n%s" % (shortname, str(prop_d.items())))
          if shortname in fix_limits:
              (vmin, vmax) = (min(fix_limits[shortname][0]), max(fix_limits[shortname][0]))
          assert vmin < vmax, "vmin >= vmax, did you incorrectly use fix_vmin and fix_vmax?"
          prop_types[shortname] = (proptype, vmin, vmax, propcategories)
      assert len(prop_types) == len(overlay), "Not as many property types as overlays. Did you give the same name (shortname) to multiple properties in the overlay?"
      # loop over each line of the multi-lined plot
      prop_image = {}
      for iline in range(nlines):
          isites = sites[iline * nperline : min(len(sites), (iline + 1) * nperline)]
          xlength = len(isites) * sitewidth
          logo_ax = pylab.axes([lmargin / figwidth, ((nlines - iline - 1) * (logoheight + len(overlay) * (barspacing + barheight))) / figheight, xlength / figwidth, logoheight / figheight], frameon=False)
          logo_ax.yaxis.set_ticks_position('none')
          logo_ax.xaxis.set_ticks_position('none')
          pylab.yticks([])
          pylab.xlim(0.5, len(isites) + 0.5)
          pylab.xticks([])
          for (iprop, (prop_d, shortname, longname)) in enumerate(overlay):
              (proptype, vmin, vmax, propcategories) = prop_types[shortname]
              prop_ax = pylab.axes([
                      lmargin / figwidth, 
                      ((nlines - iline - 1) * (logoheight + 
                          len(overlay) * (barspacing + barheight)) + 
                          (1 - int(underlay)) * logoheight + int(underlay) * 
                          barspacing + iprop * (barspacing + barheight)) 
                          / figheight, 
                      xlength / figwidth, 
                      barheight / figheight], 
                      frameon=(proptype != 'wildtype'))
              prop_ax.xaxis.set_ticks_position('none')
              pylab.xticks([])
              pylab.xlim((0, len(isites)))
              pylab.ylim(-0.5, 0.5)
              if proptype == 'wildtype':
                  pylab.yticks([])
                  prop_ax.yaxis.set_ticks_position('none')
                  for (isite, site) in enumerate(isites):
                      pylab.text(isite + 0.5, -0.5, prop_d[site], size=9, 
                              horizontalalignment='center', family='monospace')
                  continue
              pylab.yticks([0], [shortname], size=8)
              prop_ax.yaxis.set_ticks_position('left')
              propdata = pylab.zeros(shape=(1, len(isites)))
              propdata[ : ] = pylab.nan # set to nan for all entries
              for (isite, site) in enumerate(isites):
                  if site in prop_d:
                      if proptype == 'continuous':
                          propdata[(0, isite)] = prop_d[site]
                      elif proptype == 'discrete':
                          propdata[(0, isite)] = propcategories.index(prop_d[site])
                      else:
                          raise ValueError('neither continuous nor discrete')
              prop_image[shortname] = pylab.imshow(propdata, interpolation='nearest', aspect='auto', extent=[0, len(isites), 0.5, -0.5], cmap=cmap, vmin=vmin, vmax=vmax)
              pylab.yticks([0], [shortname], size=8)
  
      # set up colorbar axes, then color bars
      ncolorbars = len([p for p in prop_types.values() if p[0] != 'wildtype'])
      if scalebar:
          ncolorbars += 1
      if ncolorbars == 1:
          colorbarwidth = 0.4
          colorbarspacingwidth = 1.0 - colorbarwidth
      elif ncolorbars:
          colorbarspacingfrac = 0.5 # space between color bars is this fraction of bar width
          colorbarwidth = 1.0 / (ncolorbars * (1.0 + colorbarspacingfrac)) # width of color bars in fraction of figure width
          colorbarspacingwidth = colorbarwidth * colorbarspacingfrac # width of color bar spacing in fraction of figure width
      # bottom of color bars
      ybottom = 1.0 - (colorbar_tmargin + barheight) / figheight
      propnames = {}
      icolorbar = -1
      icolorbarshift = 0
      while icolorbar < len(overlay):
          if icolorbar == -1:
              # show scale bar if being used
              icolorbar += 1
              if scalebar:
                  (scalebarheight, scalebarlabel) = scalebar
                  xleft = (colorbarspacingwidth * 0.5 + icolorbar *
                          (colorbarwidth + colorbarspacingwidth))
                  ytop = 1 - colorbar_tmargin / figheight
                  scalebarheightfrac = scalebarheight / figheight
                  # follow here for fig axes: https://stackoverflow.com/a/5022412
                  fullfigax = pylab.axes([0, 0, 1, 1], facecolor=(1, 1, 1, 0))
                  fullfigax.axvline(x=xleft, ymin=ytop - scalebarheightfrac,
                          ymax=ytop, color='black', linewidth=1.5)
                  pylab.text(xleft + 0.005, ytop - scalebarheightfrac / 2.0,
                          scalebarlabel, verticalalignment='center',
                          horizontalalignment='left',
                          transform=fullfigax.transAxes)
              continue
  
          (prop_d, shortname, longname) = overlay[icolorbar]
          icolorbar += 1
          (proptype, vmin, vmax, propcategories) = prop_types[shortname]
          if proptype == 'wildtype':
              icolorbarshift += 1
              continue
          if shortname == longname or not longname:
              propname = shortname
          elif fixlongname:
              propname = longname
          else:
              propname = "%s (%s)" % (longname, shortname)
          colorbar_ax = pylab.axes([colorbarspacingwidth * 0.5 + (icolorbar - icolorbarshift - int(not bool(scalebar))) * (colorbarwidth + colorbarspacingwidth), ybottom, colorbarwidth, barheight / figheight], frameon=True)
          colorbar_ax.xaxis.set_ticks_position('bottom')
          colorbar_ax.yaxis.set_ticks_position('none')
          pylab.xticks([])
          pylab.yticks([])
          pylab.title(propname, size=9)
          if proptype == 'continuous':
              cb = pylab.colorbar(prop_image[shortname], cax=colorbar_ax, orientation='horizontal')
              # if range is close to zero to one, manually set tics to 0, 0.5, 1. This helps for RSA
              if -0.1 <= vmin <= 0 and 1.0 <= vmax <= 1.15:
                  cb.set_ticks([0, 0.5, 1])
                  cb.set_ticklabels(['0', '0.5', '1'])
              # if it seems plausible, set integer ticks
              if 4 < (vmax - vmin) <= 11:
                  fixedticks = [itick for itick in range(int(vmin), int(vmax) + 1)]
                  cb.set_ticks(fixedticks)
                  cb.set_ticklabels([str(itick) for itick in fixedticks])
          elif proptype == 'discrete':
              cb = pylab.colorbar(prop_image[shortname], cax=colorbar_ax, orientation='horizontal', boundaries=[i for i in range(len(propcategories) + 1)], values=[i for i in range(len(propcategories))])
              cb.set_ticks([i + 0.5 for i in range(len(propcategories))])
              cb.set_ticklabels(propcategories)
          else:
              raise ValueError("Invalid proptype")
          if shortname in fix_limits:
              (ticklocs, ticknames) = fix_limits[shortname]
              cb.set_ticks(ticklocs)
              cb.set_ticklabels(ticknames)
  
      # save the plot
      pylab.savefig(overlayfile, transparent=True)