docs: def polemap_magic(loc_file="locations.txt", dir_path=".", interactive=False, crd="",
                    sym='ro', symsize=40, rsym='g^', rsymsize=40,
                    fmt="pdf", res="c", proj="ortho",
                    flip=False, anti=False, fancy=False,
                    ell=False, ages=False, lat_0=90., lon_0=0., save_plots=True):
      """
      Use a MagIC format locations table to plot poles.
  
      Parameters
      ----------
      loc_file : str, default "locations.txt"
      dir_path : str, default "."
          directory name to find loc_file in (if not included in loc_file)
      interactive : bool, default False
         if True, interactively plot and display
          (this is best used on the command line only)
      crd : str, default ""
         coordinate system [g, t] (geographic, tilt_corrected)
      sym : str, default "ro"
          symbol color and shape, default red circles
          (see matplotlib documentation for more options)
      symsize : int, default 40
          symbol size
      rsym : str, default "g^"
          symbol for plotting reverse poles
      rsymsize : int, default 40
          symbol size for reverse poles
      fmt : str, default "pdf"
          format for figures, ["svg", "jpg", "pdf", "png"]
      res : str, default "c"
          resolution [c, l, i, h] (crude, low, intermediate, high)
      proj : str, default "ortho"
          ortho = orthographic
          lcc = lambert conformal
          moll = molweide
          merc = mercator
      flip : bool, default False
          if True, flip reverse poles to normal antipode
      anti : bool, default False
          if True, plot antipodes for each pole
      fancy : bool, default False
          if True, plot topography (not yet implementedj)
      ell : bool, default False
          if True, plot ellipses
      ages : bool, default False
          if True, plot ages
      lat_0 : float, default 90.
          eyeball latitude
      lon_0 : float, default 0.
          eyeball longitude
      save_plots : bool, default True
          if True, create and save all requested plots
      """
      # initialize and format variables
      saved = []
      lats, lons = [], []
      Pars = []
      dates, rlats, rlons = [], [], []
      polarities = []
      if interactive:
          save_plots = False
      full_path = pmag.resolve_file_name(loc_file, dir_path)
      dir_path, loc_file = os.path.split(full_path)
      # create MagIC contribution
      con = cb.Contribution(dir_path, single_file=loc_file)
      if not list(con.tables.keys()):
          print("-W - Couldn't read in data")
          return False, "Couldn't read in data"
      FIG = {'map': 1}
      pmagplotlib.plot_init(FIG['map'], 6, 6)
  
  
      pole_container = con.tables['locations']
      pole_df = pole_container.df
      if 'pole_lat' not in pole_df.columns or 'pole_lon' not in pole_df.columns:
          print("-W- pole_lat and pole_lon are required columns to run polemap_magic.py")
          return False, "pole_lat and pole_lon are required columns to run polemap_magic.py"
      # use records with pole_lat and pole_lon
      cond1, cond2 = pole_df['pole_lat'].notnull(), pole_df['pole_lon'].notnull()
      Results = pole_df[cond1 & cond2]
      # don't plot identical poles twice
      Results.drop_duplicates(subset=['pole_lat', 'pole_lon', 'location'], inplace=True)
      # use tilt correction if available
      # prioritize tilt-corrected poles
      if 'dir_tilt_correction' in Results.columns:
          if not crd:
              coords = Results['dir_tilt_correction'].unique()
              if 100. in coords:
                  crd = 't'
              elif 0. in coords:
                  crd = 'g'
              else:
                  crd = ''
      coord_dict = {'g': 0, 't': 100}
      coord = coord_dict[crd] if crd else ""
      # filter results by dir_tilt_correction if available
      if (coord or coord == 0) and 'dir_tilt_correction' in Results.columns:
          Results = Results[Results['dir_tilt_correction'] == coord]
      # get location name and average ages
      loc_list = Results['location'].values
      locations = ":".join(Results['location'].unique())
      if 'age' not in Results.columns and 'age_low' in Results.columns and 'age_high' in Results.columns:
          Results['age'] = Results['age_low']+0.5 * \
              (Results['age_high']-Results['age_low'])
      if 'age' in Results.columns and ages:
          dates = Results['age'].unique()
  
      if not any(Results.index):
          print("-W- No poles could be plotted")
          return False, "No poles could be plotted"
  
      # go through rows and extract data
      for ind, row in Results.iterrows():
          lat, lon = float(row['pole_lat']), float(row['pole_lon'])
          if 'dir_polarity' in row:
              polarities.append(row['dir_polarity'])
          if anti:
              lats.append(-lat)
              lon = lon + 180.
              if lon > 360:
                  lon = lon - 360.
              lons.append(lon)
          elif not flip:
              lats.append(lat)
              lons.append(lon)
          elif flip:
              if lat < 0:
                  rlats.append(-lat)
                  lon = lon + 180.
                  if lon > 360:
                      lon = lon - 360
                  rlons.append(lon)
              else:
                  lats.append(lat)
                  lons.append(lon)
          ppars = []
          ppars.append(lon)
          ppars.append(lat)
          ell1, ell2 = "", ""
          if 'pole_dm' in list(row.keys()) and row['pole_dm']:
              ell1 = float(row['pole_dm'])
          if 'pole_dp' in list(row.keys()) and row['pole_dp']:
              ell2 = float(row['pole_dp'])
          if 'pole_alpha95' in list(row.keys()) and row['pole_alpha95']:
              ell1, ell2 = float(row['pole_alpha95']), float(row['pole_alpha95'])
          if ell1 and ell2 and lons:
              ppars = []
              ppars.append(lons[-1])
              ppars.append(lats[-1])
              ppars.append(ell1)
              ppars.append(lons[-1])
              try:
                  isign = abs(lats[-1]) / lats[-1]
              except ZeroDivisionError:
                  isign = 1
              ppars.append(lats[-1] - isign * 90.)
              ppars.append(ell2)
              ppars.append(lons[-1] + 90.)
              ppars.append(0.)
              Pars.append(ppars)
  
      locations = locations.strip(':')
      Opts = {'latmin': -90, 'latmax': 90, 'lonmin': 0., 'lonmax': 360.,
              'lat_0': lat_0, 'lon_0': lon_0, 'proj': proj, 'sym': 'b+',
              'symsize': 40, 'pltgrid': 0, 'res': res, 'boundinglat': 0.,
              'edgecolor': 'face'}
      Opts['details'] = {'coasts': 1, 'rivers': 0, 'states': 0,
                         'countries': 0, 'ocean': 1, 'fancy': fancy}
      base_Opts = Opts.copy()
  
      # make the base map with a blue triangle at the pole
      pmagplotlib.plot_map(FIG['map'], [90.], [0.], Opts)
  
      #Opts['pltgrid'] = -1
      if proj=='merc':Opts['pltgrid']=1
      Opts['sym'] = sym
      Opts['symsize'] = symsize
      if len(dates) > 0:
          Opts['names'] = dates
      if len(lats) > 0:
          pole_lats = []
          pole_lons = []
          for num, lat in enumerate(lats):
              lon = lons[num]
              if lat > 0:
                  pole_lats.append(lat)
                  pole_lons.append(lon)
          # plot the lats and lons of the poles
          pmagplotlib.plot_map(FIG['map'], pole_lats, pole_lons, Opts)
  
      # do reverse poles
      if len(rlats) > 0:
          reverse_Opts = Opts.copy()
          reverse_Opts['sym'] = rsym
          reverse_Opts['symsize'] = rsymsize
          reverse_Opts['edgecolor'] = 'black'
          # plot the lats and lons of the reverse poles
          pmagplotlib.plot_map(FIG['map'], rlats, rlons, reverse_Opts)
  
      Opts['names'] = []
      titles = {}
      files = {}
  
      if pmagplotlib.isServer:
          # plot each indvidual pole for the server
          for ind in range(len(lats)):
              lat = lats[ind]
              lon = lons[ind]
              polarity = ""
              if 'polarites' in locals():
                  polarity = polarities[ind]
              polarity = "_" + polarity if polarity else ""
              location = loc_list[ind]
              FIG["map_{}".format(ind)] = ind+2
              pmagplotlib.plot_init(FIG['map_{}'.format(ind)], 6, 6)
              pmagplotlib.plot_map(FIG['map_{}'.format(ind)], [90.], [0.], base_Opts)
              pmagplotlib.plot_map(ind+2, [lat], [lon], Opts)
              titles["map_{}".format(ind)] = location
              if crd:
                  fname = "LO:_{}{}_TY:_POLE_map_{}.{}".format(location, polarity, crd, fmt)
                  fname_short = "LO:_{}{}_TY:_POLE_map_{}".format(location, polarity, crd)
              else:
                  fname = "LO:_{}{}_TY:_POLE_map.{}".format(location, polarity, fmt)
                  fname_short = "LO:_{}{}_TY:_POLE_map".format(location, polarity)
  
              # don't allow identically named files
              if files:
                  file_values = files.values()
                  file_values_short = [fname.rsplit('.')[0] for fname in file_values]
                  if fname_short in file_values_short:
                      for val in [str(n) for n in range(1, 10)]:
                          fname = fname_short + "_{}.".format(val) + fmt
                          if fname not in file_values:
                              break
              files["map_{}".format(ind)] = fname
  
      # truncate location names so that ultra long filenames are not created
      if len(locations) > 50:
          locations = locations[:50]
      if pmagplotlib.isServer:
          # use server plot naming convention
          con_id = ''
          if 'contribution' in con.tables:
              # try to get contribution id
              if 'id' in con.tables['contribution'].df.columns:
                  con_id = con.tables['contribution'].df.iloc[0]['id']
              files['map'] = 'MC:_{}_TY:_POLE_map_{}.{}'.format(con_id, crd, fmt)
          else:
              # no contribution id available
              files['map'] = 'LO:_' + locations + '_TY:_POLE_map_{}.{}'.format(crd, fmt)
      else:
          # use readable naming convention for non-database use
          files['map'] = '{}_POLE_map_{}.{}'.format(locations, crd, fmt)
  
      #
      if interactive and (not set_env.IS_WIN):
          pmagplotlib.draw_figs(FIG)
      if ell:  # add ellipses if desired.
          Opts['details'] = {'coasts': 0, 'rivers': 0, 'states': 0,
                             'countries': 0, 'ocean': 0, 'fancy': fancy}
          Opts['pltgrid'] = -1  # turn off meridian replotting
          Opts['symsize'] = 2
          Opts['sym'] = 'g-'
          for ppars in Pars:
              if ppars[2] != 0:
                  PTS = pmagplotlib.plot_ell(FIG['map'], ppars, 'g.', 0, 0)
                  elats, elons = [], []
                  for pt in PTS:
                      elons.append(pt[0])
                      elats.append(pt[1])
                  # make the base map with a blue triangle at the pole
                  pmagplotlib.plot_map(FIG['map'], elats, elons, Opts)
                  if interactive and (not set_env.IS_WIN):
                      pmagplotlib.draw_figs(FIG)
  
      if pmagplotlib.isServer:
          black = '#000000'
          purple = '#800080'
          titles['map'] = 'LO:_' + locations + '_POLE_map'
          con_id = ''
          if 'contribution' in con.tables:
              if 'id' in con.tables['contribution'].df.columns:
                  con_id = con.tables['contribution'].df.iloc[0]['id']
  
              loc_string = ""
              if 'locations' in con.tables:
                  num_locs = len(con.tables['locations'].df.index.unique())
                  loc_string = "{} location{}".format(num_locs, 's' if num_locs > 1 else '')
                  num_lats = len([lat for lat in lats if lat > 0])
                  num_rlats = len(rlats)
                  npole_string = ""
                  rpole_string = ""
                  if num_lats:
                      npole_string = "{} normal ".format(num_lats) #, 's' if num_lats > 1 else '')
                  if num_rlats:
                      rpole_string = "{} reverse".format(num_rlats)
                  if num_lats + num_rlats > 1:
                      pole_string = "poles"
                  elif num_lats + num_rlats == 0:
                      pole_string = ""
                  else:
                      pole_string = "pole"
              title = "MagIC contribution {}\n {} {}{} {}".format(con_id, loc_string, npole_string, rpole_string, pole_string)
              titles['map'] = title.replace('  ', ' ')
          FIG = pmagplotlib.add_borders(FIG, titles, black, purple, con_id)
          saved = pmagplotlib.save_plots(FIG, files)
      elif interactive:
          pmagplotlib.draw_figs(FIG)
          ans = input(" S[a]ve to save plot, Return to quit:  ")
          if ans == "a":
              saved = pmagplotlib.save_plots(FIG, files)
          else:
              print("Good bye")
      elif save_plots:
          saved = pmagplotlib.save_plots(FIG, files)
  
      return True, saved