text: import os
  
  import re
  import copy
  import shlex
  import tempfile
  import itertools
  import numpy as np
  import subprocess as sp
  from matplotlib.path import Path
  from scipy.spatial import cKDTree
  
  from lxml import etree
  from lxml.builder import E
  
  from .options import config
  
  svgns = "http://www.w3.org/2000/svg"
  inkns = "http://www.inkscape.org/namespaces/inkscape"
  sodins = "http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
  
  parser = etree.XMLParser(remove_blank_text=True, huge_tree=True)
  
  cwd = os.path.abspath(os.path.split(__file__)[0])
  
  class SVGOverlay(object):
      """Object to represent all vector graphic overlays (rois, sulci, etc) stored in an svg file
  
      This object facilitates interaction with the information in the overlays.svg files
      that exist for each subject in the pycortex database.
  
      Parameters
      ----------
      svgfile : string
          svg file to read in. Must be formatted like the overlays.svg files in pycortex's
          filestore
      coords : array-like
          (Unclear...)
      overlays_available : list or tuple
          list of layers of svg file to extract. If None, extracts all overlay layers 
          (i.e. all layers that do not contain images)
      """
      def __init__(self, svgfile, coords=None, overlays_available=None):
          self.svgfile = svgfile
          self.overlays_available = overlays_available
          self.reload()
          if coords is not None:
              self.set_coords(coords)
  
      def reload(self):
          """Initial load of data from svgfile
  
          Strips out `data` layer of svg file, saves only layers consisting of vector paths.
          """
          self.svg = scrub(self.svgfile, overlays_available=self.overlays_available)
          w = float(self.svg.getroot().get("width"))
          h = float(self.svg.getroot().get("height"))
          self.svgshape = w, h
  
          # Grab relevant layers
          self.layers = dict()
          
          for layer in self.svg.getroot().findall("{%s}g"%svgns):
              layer = Overlay(self, layer)
              self.layers[layer.name] = layer
  
      def set_coords(self, coords):
          """Unclear what this does. James??"""
          # Normalize coordinates 0-1
          if np.any(coords.max(0) > 1) or np.any(coords.min(0) < 0):
              coords -= coords.min(0)
              coords /= coords.max(0)
          # Renormalize coordinates to shape of svg
          self.coords = coords * self.svgshape
          # Update of scipy (0.16+) means that cKDTree hangs / takes absurdly long to compute with new default
          # balanced_tree=True. Seems only to be true on Mac OS, for whatever reason. Possibly a broken
          # C library, unclear. Setting balanced_tree=False seems to resolve the issue, thus going with that for now
          # See http://stackoverflow.com/questions/31819778/scipy-spatial-ckdtree-running-slowly
          try:
              # not compatible with scipy version < 0.16
              self.kdt = cKDTree(self.coords, balanced_tree=False)
          except:
              # Older call signature
              self.kdt = cKDTree(self.coords)
  
          for layer in self:
              for name in layer.labels.elements:
                  for element in layer.labels.elements[name]:
                      x, y = float(element.get("x")), float(element.get("y"))
                      dist, idx = self.kdt.query((x, self.svgshape[1]-y))
                      if idx >= len(self.kdt.data):
                          idx = 0
                      element.attrib['data-ptidx'] = str(idx)
  
      def __getattr__(self, attr):
          return self.layers[attr]
  
      def __dir__(self):
          return list(self.layers.keys()) + ['svg', 'svgfile', 'svgshape']
  
      def __repr__(self):
          return "<SVGOverlay with layers [%s]>"%(','.join(self.layers.keys()))
  
      def __iter__(self):
          return iter(self.layers.values())
  
      def add_layer(self, name):
          """Add a layer to the svgfile on which this object is based
  
          Adds a new layer named `name` to the svgfile by the SVGOverlay object, and
          overwrites the original file (incorporating the new layer).
          """
          svg = etree.parse(self.svgfile, parser=parser)
          layer = _make_layer(svg.getroot(), name)
          shapes = _make_layer(layer, "shapes")
          shapes.attrib['id'] = "%s_shapes"%name
          shapes.attrib['clip-path'] = "url(#edgeclip)"
          labels = _make_layer(layer, "labels")
          labels.attrib['id'] = "%s_labels"%name
          with open(self.svgfile, "wb") as fp:
              #try:
              fp.write(etree.tostring(svg, pretty_print=True)) # python2.X
              #except:
              #    fp.write(etree.tostring(svg, encoding=str, pretty_print=True)) # python3.X
          self.reload()
  
      def toxml(self, pretty=True):
          """Return a string xml version of the SVGOverlay object"""
          return etree.tostring(self.svg, pretty_print=pretty)
  
      def get_svg(self, filename=None, layers=['rois'], labels=True, with_ims=None):
          """Returns a new SVG file with images embedded
  
          Parameters
          ----------
          filename : string
              File path to which to write new svg
          layers : list
              List of layer names to show
          labels : boolean
              Whether labels should be visible or not
          with_ims : list
              list of images to incorporate into new svg file. The first image
              listed will be on the uppermost layer, the last will be lowest.
          """
          outsvg = self.svg
  
          if with_ims is not None:
              if isinstance(with_ims, (list, tuple)):
                  with_ims = zip(range(len(with_ims)), with_ims)
  
              datalayer = _make_layer(outsvg.getroot(), "data")
              for imnum,im in reversed(with_ims):
                  imlayer = _make_layer(datalayer, "image_%d" % imnum)
                  img = E.image(
                      {"{http://www.w3.org/1999/xlink}href":"data:image/png;base64,%s"%im},
                      id="image_%d"%imnum, x="0", y="0",
                      width=str(self.svgshape[0]),
                      height=str(self.svgshape[1]),
                      )
                  imlayer.append(img)
                  outsvg.getroot().insert(0, imlayer)
  
          for layer in self:
              if layer.name in layers:
                  layer.visible = True
                  layer.labels.visible = labels
                  for name_, shape_ in layer.shapes.items():
                      shape_.visible = True
                      # Set visibility of labels (by setting text alpha to 0)
                      # This could be less baroque, but text elements currently
                      # do not have individually settable visibility / style params
                      tmp_style = copy.deepcopy(layer.labels.text_style)
                      tmp_style['fill-opacity'] = '1' if labels else '0'
                      tmp_style_str = ';'.join(['%s:%s'%(k,v) for k, v in tmp_style.items() if v != 'None'])
                      for i in range(len(layer.labels.elements[name_])):
                          layer.labels.elements[name_][i].set('style', tmp_style_str)
              else:
                  layer.visible = False
                  layer.labels.visible = False
  
          with open(filename, "wb") as outfile:
              outfile.write(etree.tostring(outsvg))
          print('Saved SVG to: %s'%filename)
  
      def get_texture(self, layer_name, height, name=None, background=None, labels=True,
          shape_list=None, **kwargs):
          """Renders a specific layer of this svgobject as a png
  
          Parameters
          ----------
          layer_name : string
              Name of layer of svg file to be rendered
          height : scalar
              Height of image to be generated
          name : string
              If `background` is specified, provides a name for the background image
          background : idkwtf
              An image? Unclear.
          labels : boolean
              Whether to render labels for paths in the svg file
          shape_list : list
              list of string names for path/shape elements in this layer to be rendered
              (any elements not on this list will be set to invisible, if this list is
              provided)
          kwargs : keyword arguments
              keywords to specify display properties of svg path objects, e.g. {'stroke':'white',
              'stroke-width':2} etc. See inkscape help for names for properties. This function
              is used by quickflat.py, which provides dictionaries to map between more matplotlib-
              like properties (linecolor->stroke, linewidth->stroke-width) for an easier-to-use API.
  
          Returns
          -------
          image : array
              Rendered image of svg layer with specified parameters
  
          Notes
          -----
          missing bits=32 keyword input argument, did not seeme necessary to specify
          png bits.
          """
          import matplotlib.pyplot as plt
          # Set the size of the texture
          if background is not None:
              img = E.image(
                  {"{http://www.w3.org/1999/xlink}href":"data:image/png;base64,%s"%background},
                  id="image_%s"%name, x="0", y="0",
                  width=str(self.svgshape[0]),
                  height=str(self.svgshape[1]),
              )
              self.svg.getroot().insert(0, img)
          if height is None:
              height = self.svgshape[1]
          #label_defaults = _parse_defaults(layer+'_labels')
  
          for layer in self:
              if layer.name==layer_name:
                  layer.visible = True
                  layer.labels.visible = labels
                  if shape_list is not None:
                      for name_, shape_ in layer.shapes.items():
                          shape_.visible = name_ in shape_list
                          # Set visibility of labels (by setting text alpha to 0)
                          # This could be less baroque, but text elements currently
                          # do not have individually settable visibility / style params
                          tmp_style = copy.deepcopy(layer.labels.text_style)
                          tmp_style['fill-opacity'] = '1' if shape_.visible else '0'
                          tmp_style_str = ';'.join(['%s:%s'%(k,v) for k, v in tmp_style.items() if v != 'None'])
                          for i in range(len(layer.labels.elements[name_])):
                              layer.labels.elements[name_][i].set('style', tmp_style_str)
                  layer.set(**kwargs)
              else:
                  layer.visible = False
                  layer.labels.visible = False
  
          pngfile = name
          if name is None:
              png = tempfile.NamedTemporaryFile(suffix=".png")
              pngfile = png.name
  
          inkscape_cmd = config.get('dependency_paths', 'inkscape')
          cmd = "{inkscape_cmd} -z -h {height} -e {outfile} /dev/stdin"
          cmd = cmd.format(inkscape_cmd=inkscape_cmd, height=height, outfile=pngfile)
          proc = sp.Popen(shlex.split(cmd), stdin=sp.PIPE, stdout=sp.PIPE)
          proc.communicate(etree.tostring(self.svg))
  
          if background is not None:
              self.svg.getroot().remove(img)
  
          if name is None:
              png.seek(0)
              im = plt.imread(png)
              return im
  
  class Overlay(object):
      """Class to represent a single layer of an SVG file
      """
      def __init__(self, svgobject, layer):
          self.svgobject = svgobject
          self.svg = svgobject.svg
          self.layer = layer
          self.name = layer.attrib['{%s}label'%inkns]
          self.layer.attrib['class'] = 'display_layer'
  
          # Check to see if the layer is locked, to see if we need to override the style
          locked = '{%s}insensitive'%sodins
          self.shapes = dict()
          for layer_ in _find_layer(layer, "shapes").findall("{%s}g"%svgns):
              override = locked not in layer_.attrib or layer_.attrib[locked] == "false"
              shape = Shape(layer_, self.svgobject.svgshape[1], override_style=override)
              self.shapes[shape.name] = shape
  
          self.labels = Labels(self)
  
      def __repr__(self):
          return "<svg layer with shapes [%s]>"%(','.join(self.shapes.keys()))
  
      def __getitem__(self, name):
          return self.shapes[name]
  
      @property
      def visible(self):
          return 'none' not in self.layer.attrib['style']
  
      @visible.setter
      def visible(self, value):
          style = "display:inline;" if value else "display:none;"
          self.layer.attrib['style'] = style
  
      def set(self, **kwargs):
          for shape in list(self.shapes.values()):
              shape.set(**kwargs)
  
      def get_mask(self, name):
          return self.shapes[name].get_mask(self.svgobject.coords)
  
      def add_shape(self, name, pngdata=None, add_path=True):
          """Adds projected data for defining a new ROI to the saved overlays.svg file in a new layer"""
          # self.svg deletes the images -- we want to save those, so let's load it again
          svg = etree.parse(self.svgobject.svgfile, parser=parser)
          imglayer = _find_layer(svg, "data")
          if add_path:
              layer = _find_layer(svg, self.name)
              _make_layer(_find_layer(layer, "shapes"), name)
  
          # Hide all the other layers in the image
          for layer in imglayer.findall(".//{%s}g"%svgns):
              layer.attrib["style"] = "display:hidden;"
  
          layer = _make_layer(imglayer, "img_%s"%name)
          layer.append(E.image(
              {"{http://www.w3.org/1999/xlink}href":"data:image/png;base64,%s"%pngdata},
              id="image_%s"%name, x="0", y="0",
              width=str(self.svgobject.svgshape[0]),
              height=str(self.svgobject.svgshape[1]),
          ))
  
          with open(self.svgobject.svgfile, "wb") as xml:
              #try:
              xml.write(etree.tostring(svg, pretty_print=True)) # python2.X
              #except:
              #    xml.write(etree.tostring(svg, encoding=str, pretty_print=True)) # python3.X
  
  class Labels(object):
      def __init__(self, overlay):
          self.overlay = overlay
          self.layer = _find_layer(self.overlay.layer, "labels")
          # This should be layer-specific,and read from different fields in the options.cfg file
          # if possible, falling back to overlay_text if the speific layer defaults don't exist.
          # Don't have time to figure out how to get the layer name here (rois, sulci, etc)
          self.text_style = dict(config.items("overlay_text"))
  
          text_style = self.text_style.items()
          text_style = ';'.join(['%s:%s'%(k,v) for k, v in text_style if v != 'None'])
  
          #generate a list of labels that should be in the layer
          self.elements = dict()
          for shape in self.overlay.shapes.values():
              self.elements[shape.name] = shape.get_labelpos()
  
          # match up existing labels with their respective paths
          def close(pt, x, y):
              return np.sqrt((pt[0] - x)**2 + (pt[1]-y)**2) < 250
          for text in self.layer.findall(".//{%s}text"%svgns):
              x = float(text.get('x'))
              y = float(text.get('y'))
              #check this element against all known paths
              for name in self.elements.keys():
                  if text.text == name:
                      for i, pos in enumerate(self.elements[name]):
                          if close(pos, x, y):
                              self.elements[name][i] = text
  
          #add missing elements
          self.override = []
          for name in self.elements.keys():
              for i, pos in enumerate(self.elements[name]):
                  if isinstance(pos, np.ndarray):
                      text = etree.SubElement(self.layer, "{%s}text"%svgns)
                      text.text = name
                      text.attrib["x"] = str(pos[0])
                      text.attrib["y"] = str(pos[1])
                      text.attrib['style'] = text_style
                      self.elements[name][i] = text
                      self.override.append(text)
  
      def set(self, override=False, **kwargs):
          self.text_style.update(kwargs)
          text_style = self.text_style.items()
          text_style = ';'.join(['%s:%s'%(k,v) for k, v in text_style if v != 'None'])
  
          labels = self.override
          if override:
              labels = self.labels.findall(".//{%s}text"%svgns)
  
          for element in labels:
              element.attrib['style'] = text_style
  
      @property
      def visible(self):
          return self.text_style['display'] != "none"
  
      @visible.setter
      def visible(self, value):
          if value:
              self.text_style['display'] = 'inline'
          else:
              self.text_style['display'] = 'none'
          self.set()
  
  class Shape(object):
      def __init__(self, layer, height, override_style=True):
          self.layer = layer
          self.height = height
          self.name = layer.attrib['{%s}label'%inkns]
          self.paths = layer.findall('{%s}path'%svgns)
  
          #default style
          self.style = dict(config.items("overlay_paths"))
  
          locked = '{%s}insensitive'%sodins
          if not override_style or locked in layer.attrib:
              self._get_style()
  
          self.set()
  
      def _get_style(self):
          # populate the style dictionary with the first path that has a style tag
          for path in self.paths:
              if 'style' in path.attrib:
                  style = dict(s.split(':') for s in path.attrib['style'].split(";"))
                  self.style.update(style)
                  break
  
      def set(self, **kwargs):
          self.style.update(**kwargs)
          style = ';'.join(['%s:%s'%(k,v) for k, v in self.style.items() if v != "None"])
          for path in self.paths:
              path.attrib['style'] = style
  
      def get_labelpos(self):
          labels = []
          for path in self.paths:
              pos = _parse_svg_pts(path.attrib['d'])
              labels.append(_center_pts(pos))
  
          return labels
  
      def get_mask(self, vts):
          """get list of vertices inside this roi"""
          if len(self.splines)==0:
              # No splines defined for this (ROI). Wut.
              import warnings
              warnings.warn("Requested layer in svg file (%s) contains no splines"%self.name)
              return []
          # Annoying: The paths created are upside-down wrt vertex coordinates. So flip them.
          verts_upside_down = copy.copy(vts)
          verts_upside_down[:, 1] = self.height - verts_upside_down[:, 1]
          verts_in_any_path = [p.contains_points(verts_upside_down) for p in self.splines]
          vert_idx_list = np.hstack([np.nonzero(v)[0] for v in verts_in_any_path])
          return  vert_idx_list
  
      @property
      def splines(self):
          return [gen_path(p) for p in self.paths]
  
      @property
      def visible(self):
          return 'none' not in self.layer.attrib['style']
  
      @visible.setter
      def visible(self, value):
          style = "display:inline;" if value else "display:none;"
          self.layer.attrib['style'] = style
  
  ###################################################################################
  # SVG Helper functions
  ###################################################################################
  def _find_layer_names(svg):
      layers = svg.findall("{%s}g[@{%s}label]"%(svgns, inkns))
      layer_names = [l.get("{%s}label"%inkns) for l in layers]
      return layer_names
  
  def _find_layer(svg, label):
      layers = [l for l in svg.findall("{%s}g[@{%s}label]"%(svgns, inkns)) if l.get("{%s}label"%inkns) == label]
      if len(layers) < 1:
          raise ValueError("Cannot find layer %s"%label)
      return layers[0]
  
  def _make_layer(parent, name):
      layer = etree.SubElement(parent, "{%s}g"%svgns)
      layer.attrib['id'] = name
      layer.attrib['style'] = "display:inline;"
      layer.attrib["{%s}label"%inkns] = name
      layer.attrib["{%s}groupmode"%inkns] = "layer"
      return layer
  
  try:
      from shapely.geometry import Polygon
      def _center_pts(pts):
          '''Fancy label position generator, using erosion to get label coordinate'''
          min = pts.min(0)
          pts -= min
          max = pts.max(0)
          pts /= max
  
          #probably don't need more than 20 points, reduce detail of the polys
          if len(pts) > 20:
              pts = pts[::len(pts)//20]
  
          try:
              poly = Polygon([tuple(p) for p in pts])
              for i in np.linspace(0,1,100):
                  if poly.buffer(-i).is_empty:
                      return list(poly.buffer(-last_i).centroid.coords)[0] * max + min
                  last_i = i
  
              print("unable to find zero centroid...")
              return list(poly.buffer(-100).centroid.coords)[0] * max + min
          except:
              # This may not be worth being so verbose about... I think this is only for label positions.
              import warnings
              warnings.warn("Shapely error - computing mean of points instead of geometric center")
              return np.nanmean(pts, 0)
  
  except (ImportError, OSError):
      print("Cannot find shapely, using simple label placement")
      def _center_pts(pts):
          return pts.mean(0)
  
  def _labelpos(pts):
      if pts.ndim < 3:
          return _center_pts(pts)
  
      ptm = pts.copy().astype(float)
      ptm -= ptm.mean(0)
      u, s, v = np.linalg.svd(ptm, full_matrices=False)
      sp = np.diag(s)
      sp[-1,-1] = 0
      try:
          x, y = _center_pts(np.dot(ptm, np.dot(v.T, sp))[:,:2])
      except Exception as e:
          print(e)
  
      sp = np.diag(1./(s+np.finfo(float).eps))
      pt = np.dot(np.dot(np.array([x,y,0]), sp), v)
      return pt + pts.mean(0)
  
  def _split_multipath(pathstr):
      """Appropriately splits an SVG path with multiple sub-paths.
      """
      # m is absolute path, M is relative path (or vice versa?)
      if not pathstr[0] in ["m","M"]:
          raise ValueError("Bad path format: %s" % pathstr)
      import re
      subpaths = [sp for sp in re.split('[Mm]',pathstr) if len(sp)>0]
      headers = re.findall('[Mm]',pathstr)
      for subpath,header in zip(subpaths,headers):
          # Need further parsing of multi-path strings? perhaps no.
          yield (header + subpath).strip()
  
  def scrub(svgfile, overlays_available=None):
      """Remove data layers from an svg object prior to rendering
  
      Returns etree-parsed svg object
      """
      svg = etree.parse(svgfile, parser=parser)
      try:
          layers_to_remove = ['data']
          if overlays_available is not None:
              overlays_to_remove = [x for x in _find_layer_names(svg) if x not in overlays_available]
              layers_to_remove = overlays_to_remove
          for layer in layers_to_remove:
              rmnode = _find_layer(svg, layer)
              rmnode.getparent().remove(rmnode)
      except ValueError:
          # Seems sketch - should catch this? 
          pass
      svgtag = svg.getroot()
      svgtag.attrib['id'] = "svgoverlay"
      inkver = "{%s}version"%inkns
      if inkver in svgtag.attrib:
          del svgtag.attrib[inkver]
      try:
          for tagname in ["{%s}namedview"%sodins, "{%s}metadata"%svgns]:
              for tag in svg.findall(".//%s"%tagname):
                  tag.getparent().remove(tag)
      except:
          import traceback
          traceback.print_exc()
  
      return svg
  
  def make_svg(pts, polys):
      from .polyutils import trace_poly, boundary_edges
      pts = pts.copy()
      pts -= pts.min(0)
      pts *= 1024 / pts.max(0)[1]
      pts[:,1] = 1024 - pts[:,1]
      path = ""
      left, right = trace_poly(boundary_edges(polys))
  
      for poly in [left, right]:
          path +="M%f %f L"%tuple(pts[poly.pop(0), :2])
          path += ', '.join(['%f %f'%tuple(pts[p, :2]) for p in poly])
          path += 'Z '
  
      w, h = pts.max(0)[:2]
      with open(os.path.join(cwd, "svgbase.xml")) as fp:
          svg = fp.read().format(width=w, height=h, clip=path)
  
      return svg
  
  def get_overlay(subject, svgfile, pts, polys, remove_medial=False, 
                  overlays_available=None, **kwargs):
      """Return a python represent of the overlays present in `svgfile`
  
      """
      cullpts = pts[:,:2]
      if remove_medial:
          valid = np.unique(polys)
          cullpts = cullpts[valid]
  
      if not os.path.exists(svgfile):
          # Overlay file does not exist yet! We need to create and populate it
          # I think this should be an entirely separate function, and it should
          # be made clear when this file is created - opening a git issue on 
          # this soon...ML
          with open(svgfile, "wb") as fp:
              fp.write(make_svg(pts.copy(), polys).encode())
  
          svg = SVGOverlay(svgfile, coords=cullpts, **kwargs)
  
          ## Add default layers
          from .database import db
          import io
          from . import quickflat
          import binascii
  
          # Curvature
          curv = db.get_surfinfo(subject, 'curvature')
          curv.cmap = 'gray'
          fp = io.BytesIO()
          quickflat.make_png(fp, curv, height=1024, with_rois=False, with_labels=False)
          fp.seek(0)
          svg.rois.add_shape('curvature', binascii.b2a_base64(fp.read()).decode('utf-8'), False)
  
      else:
          svg = SVGOverlay(svgfile, 
                           coords=cullpts, 
                           overlays_available=overlays_available,
                           **kwargs)
      
      
      if overlays_available is None:
          # Assure all layers are present
          # (only if some set of overlays is not specified)
          # NOTE: this actually modifies the svg file. Do we
          # want this in all cases? (e.g. w/ external svgs?)
          for layer in ['sulci', 'cutouts', 'display']:
              if layer not in svg.layers:
                  svg.add_layer(layer)
  
      if remove_medial:
          return svg, valid
  
      return svg
  
  ## From svg.path (https://github.com/regebro/svg.path/blob/master/src/svg/path/parser.py)
  COMMANDS = set('MmZzLlHhVvCcSsQqTtAa')
  UPPERCASE = set('MZLHVCSQTA')
  
  COMMAND_RE = re.compile("([MmZzLlHhVvCcSsQqTtAa])")
  FLOAT_RE = re.compile("[-+]?[0-9]*\.?[0-9]+(?:[eE][-+]?[0-9]+)?")
  
  def _tokenize_path(pathdef):
      for x in COMMAND_RE.split(pathdef):
          if x in COMMANDS:
              yield x
          for token in FLOAT_RE.findall(x):
              yield token
  
  def _parse_svg_pts(datastr):
      data = list(_tokenize_path(datastr))
      #data = data.replace(",", " ").split()
      if data.pop(0).lower() != "m":
          raise ValueError("Unknown path format")
      #offset = np.array([float(x) for x in data[1].split(',')])
      offset = np.array([float(x) for x in [data.pop(0), data.pop(0)]])
      mode = "l"
      pts = [[offset[0], offset[1]]]
  
      def canfloat(n):
          try:
              float(n)
              return True
          except ValueError:
              return False
  
      lastlen = len(data)
      while len(data) > 0:
          #print mode, data
          if not canfloat(data[0]):
              mode = data.pop(0)
              continue
          if mode == "l":
              offset += list([float(x) for x in [data.pop(0), data.pop(0)]])
          elif mode == "L":
              offset = np.array(list([float(x) for x in [data.pop(0), data.pop(0)]]))
          elif mode == "h":
              offset += list([float(x) for x in [data.pop(0), 0]])
          elif mode == 'H':
              offset = np.array(list([float(x) for x in [data.pop(0), 0]]))
          elif mode == "v":
              offset += list([float(x) for x in [0, data.pop(0)]])
          elif mode == "V":
              offset = np.array(list([float(x) for x in [0, data.pop(0)]]))
          elif mode == "c":
              data = data[4:]
              offset += list([float(x) for x in [data.pop(0), data.pop(0)]])
          elif mode == "C":
              data = data[4:]
              offset = np.array(list([float(x) for x in [data.pop(0), data.pop(0)]]))
          #support multi-part paths, by only using one label for the whole path
          elif mode == 'm' :
              offset += list([float(x) for x in [data.pop(0), data.pop(0)]])
          elif mode == 'M' :
              offset = list([float(x) for x in [data.pop(0), data.pop(0)]])
  
          ## Check to see if nothing has happened, and, if so, fail
          if len(data) == lastlen:
              raise ValueError("Error parsing path.")
          else:
              lastlen = len(data)
  
          pts.append([offset[0],offset[1]])
  
      return np.array(pts)
  
  def import_roi(roifile, outfile):
      """Convert rois.svg file (from previous versions of pycortex) to overlays.svg"""
      import warnings
      warnings.warn("Converting rois.svg to overlays.svg")
      svg = etree.parse(roifile, parser=parser)
  
      label_layer = None
      for layer in svg.findall("{%s}g[@{%s}label]"%(svgns, inkns)):
          name = layer.get("{%s}label"%inkns)
          if name == "data":
              #maintain data layer, do not process
              pass
          elif name == "roilabels": #label layer
              label_layer = layer
              layer.getparent().remove(layer)
          else:
              parent = _make_layer(layer.getparent(), name)
              layer.getparent().remove(layer)
              layer.attrib['id'] = '%s_shapes'%name
              layer.attrib['{%s}label'%inkns] = 'shapes'
              layer.attrib['clip-path'] = "url(#edgeclip)"
              parent.append(layer)
              labels = _make_layer(parent, "labels")
              labels.attrib['id'] = '%s_labels'%name
  
      if label_layer is not None:
          rois = _find_layer(svg, "rois")
          labels = _find_layer(rois, 'labels')
          rois.remove(labels)
  
          label_layer.attrib['id'] = 'rois_labels'
          label_layer.attrib['{%s}label'%inkns] = 'labels'
          rois.append(label_layer)
  
  
      with open(outfile, "wb") as fp:
          fp.write(etree.tostring(svg, pretty_print=True))
  
      # Final check for all layers
      svgo = SVGOverlay(outfile)
      for new_layer in ['sulci', 'cutouts', 'display']:
          if new_layer not in svgo.layers:
              svgo.add_layer(new_layer)
  
  def gen_path(path):
      mdict = dict(m=Path.MOVETO, l=Path.LINETO, h=Path.LINETO, v=Path.LINETO)
      verts, codes = [], []
      mode, pen = None, np.array([0.,0.])
  
      it = iter(path.get('d').split(' '))
      run = True
      while run:
          try:
              cmd = next(it)
              if len(cmd) == 1:
                  mode = cmd
                  if cmd.lower() == 'z':
                      verts.append([0,0])
                      codes.append(Path.CLOSEPOLY)
              elif mode.lower() == 'c':
                  p1 = [float(ss) for ss in cmd.split(',')]
                  p2 = [float(ss) for ss in next(it).split(',')]
                  p3 = [float(ss) for ss in next(it).split(',')]
                  if mode == 'c':
                      verts.append(pen + p1)
                      verts.append(pen + p2)
                      verts.append(pen + p3)
                      pen += p3
                  else:
                      verts.append(p1)
                      verts.append(p2)
                      verts.append(p3)
                      pen = np.array(p3)
                  codes.append(Path.CURVE4)
                  codes.append(Path.CURVE4)
                  codes.append(Path.CURVE4)
              else:
                  if mode.lower() == 'h':
                      val = [float(cmd), 0]
                  elif mode.lower() == 'v':
                      val = [0, float(cmd)]
                  else:
                      val = [float(cc) for cc in cmd.split(',')]
                  codes.append(mdict[mode.lower()])
                  if mode.lower() == mode:
                      pen += val
                      verts.append(pen.tolist())
                  else:
                      pen = np.array(val)
                      verts.append(val)
  
                  if mode == 'm':
                      mode = 'l'
                  elif mode == 'M':
                      mode = 'L'
  
          except StopIteration:
              run = False
      return Path(verts, codes=codes)
  