docs: def InitUI(self):
          """
          initialize window
          """
          self.main_sizer = wx.BoxSizer(wx.VERTICAL)
          self.init_grid_headers()
          self.grid_builder = GridBuilder(self.er_magic, self.grid_type, self.grid_headers,
                                          self.panel, self.parent_type)
          self.grid = self.grid_builder.make_grid()
          self.grid.InitUI()
  
          ## Column management buttons
          self.add_cols_button = wx.Button(self.panel, label="Add additional columns",
                                           name='add_cols_btn')
          self.Bind(wx.EVT_BUTTON, self.on_add_cols, self.add_cols_button)
          self.remove_cols_button = wx.Button(self.panel, label="Remove columns",
                                              name='remove_cols_btn')
          self.Bind(wx.EVT_BUTTON, self.on_remove_cols, self.remove_cols_button)
  
          ## Row management buttons
          self.remove_row_button = wx.Button(self.panel, label="Remove last row",
                                             name='remove_last_row_btn')
          self.Bind(wx.EVT_BUTTON, self.on_remove_row, self.remove_row_button)
          many_rows_box = wx.BoxSizer(wx.HORIZONTAL)
          self.add_many_rows_button = wx.Button(self.panel, label="Add row(s)",
                                                name='add_many_rows_btn')
          self.rows_spin_ctrl = wx.SpinCtrl(self.panel, value='1', initial=1,
                                            name='rows_spin_ctrl')
          many_rows_box.Add(self.add_many_rows_button, flag=wx.ALIGN_CENTRE)
          many_rows_box.Add(self.rows_spin_ctrl)
          self.Bind(wx.EVT_BUTTON, self.on_add_rows, self.add_many_rows_button)
  
          self.deleteRowButton = wx.Button(self.panel, id=-1, label='Delete selected row(s)', name='delete_row_btn')
          self.Bind(wx.EVT_BUTTON, lambda event: self.on_remove_row(event, False), self.deleteRowButton)
          self.deleteRowButton.Disable()
  
          ## Data management buttons
          self.importButton = wx.Button(self.panel, id=-1,
                                        label='Import MagIC-format file', name='import_btn')
          self.Bind(wx.EVT_BUTTON, self.onImport, self.importButton)
          self.exitButton = wx.Button(self.panel, id=-1,
                                      label='Save and close grid', name='save_and_quit_btn')
          self.Bind(wx.EVT_BUTTON, self.onSave, self.exitButton)
          self.cancelButton = wx.Button(self.panel, id=-1, label='Cancel', name='cancel_btn')
          self.Bind(wx.EVT_BUTTON, self.onCancelButton, self.cancelButton)
  
          ## Help message and button
          # button
          self.toggle_help_btn = wx.Button(self.panel, id=-1, label="Show help",
                                           name='toggle_help_btn')
          self.Bind(wx.EVT_BUTTON, self.toggle_help, self.toggle_help_btn)
          # message
          self.help_msg_boxsizer = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1, name='help_msg_boxsizer'), wx.VERTICAL)
          self.default_msg_text = 'Edit {} here.\nYou can add or remove both rows and columns, however required columns may not be deleted.\nControlled vocabularies are indicated by **, and will have drop-down-menus.\nTo edit all values in a column, click the column header.\nYou can cut and paste a block of cells from an Excel-like file.\nJust click the top left cell and use command "v".\nColumns that pertain to interpretations will be marked with "++".'.format(self.grid_type + 's')
          txt = ''
          if self.grid_type == 'location':
              txt = '\n\nNote: you can fill in location start/end latitude/longitude here.\nHowever, if you add sites in step 2, the program will calculate those values automatically,\nbased on site latitudes/logitudes.\nThese values will be written to your upload file.'
          if self.grid_type == 'sample':
              txt = "\n\nNote: you can fill in lithology, class, and type for each sample here.\nHowever, if the sample's class, lithology, and type are the same as its parent site,\nthose values will propagate down, and will be written to your sample file automatically."
          if self.grid_type == 'specimen':
              txt = "\n\nNote: you can fill in lithology, class, and type for each specimen here.\nHowever, if the specimen's class, lithology, and type are the same as its parent sample,\nthose values will propagate down, and will be written to your specimen file automatically."
          if self.grid_type == 'age':
              txt = "\n\nNote: only ages for which you provide data will be written to your upload file."
          self.default_msg_text += txt
          self.msg_text = wx.StaticText(self.panel, label=self.default_msg_text,
                                        style=wx.TE_CENTER, name='msg text')
          self.help_msg_boxsizer.Add(self.msg_text)
          self.help_msg_boxsizer.ShowItems(False)
  
          ## Code message and button
          # button
          self.toggle_codes_btn = wx.Button(self.panel, id=-1, label="Show method codes",
                                            name='toggle_codes_btn')
          self.Bind(wx.EVT_BUTTON, self.toggle_codes, self.toggle_codes_btn)
          # message
          self.code_msg_boxsizer = pw.MethodCodeDemystifier(self.panel, vocab)
          self.code_msg_boxsizer.ShowItems(False)
  
          ## Add content to sizers
          self.hbox = wx.BoxSizer(wx.HORIZONTAL)
          col_btn_vbox = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1, label='Columns',
                                                        name='manage columns'), wx.VERTICAL)
          row_btn_vbox = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1, label='Rows',
                                                        name='manage rows'), wx.VERTICAL)
          main_btn_vbox = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1, label='Manage data',
                                                         name='manage data'), wx.VERTICAL)
          col_btn_vbox.Add(self.add_cols_button, 1, flag=wx.ALL, border=5)
          col_btn_vbox.Add(self.remove_cols_button, 1, flag=wx.ALL, border=5)
          row_btn_vbox.Add(many_rows_box, 1, flag=wx.ALL, border=5)
          row_btn_vbox.Add(self.remove_row_button, 1, flag=wx.ALL, border=5)
          row_btn_vbox.Add(self.deleteRowButton, 1, flag=wx.ALL, border=5)
          main_btn_vbox.Add(self.importButton, 1, flag=wx.ALL, border=5)
          main_btn_vbox.Add(self.exitButton, 1, flag=wx.ALL, border=5)
          main_btn_vbox.Add(self.cancelButton, 1, flag=wx.ALL, border=5)
          self.hbox.Add(col_btn_vbox, 1)
          self.hbox.Add(row_btn_vbox, 1)
          self.hbox.Add(main_btn_vbox, 1)
  
          self.panel.Bind(wx.grid.EVT_GRID_LABEL_LEFT_CLICK, self.onLeftClickLabel, self.grid)
          self.Bind(wx.EVT_KEY_DOWN, self.on_key_down)
          self.panel.Bind(wx.EVT_TEXT_PASTE, self.do_fit)
  
          # add actual data!
          self.grid_builder.add_data_to_grid(self.grid, self.grid_type)
          if self.grid_type == 'age':
              self.grid_builder.add_age_data_to_grid()
  
          # add drop_down menus
          if self.parent_type:
              belongs_to = sorted(self.er_magic.data_lists[self.parent_type][0], key=lambda item: item.name)
          else:
              belongs_to = ''
          self.drop_down_menu = drop_down_menus.Menus(self.grid_type, self, self.grid, belongs_to)
  
          self.grid_box = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1, name='grid container'), wx.VERTICAL)
          self.grid_box.Add(self.grid, 1, flag=wx.ALL|wx.EXPAND, border=5)
  
          # a few special touches if it is a location grid
          if self.grid_type == 'location':
              lat_lon_dict = self.er_magic.get_min_max_lat_lon(self.er_magic.locations)
              for loc in self.er_magic.locations:
                  # try to fill in min/max latitudes/longitudes from sites
                  d = lat_lon_dict[loc.name]
                  col_labels = [self.grid.GetColLabelValue(col) for col in range(self.grid.GetNumberCols())]
                  row_labels = [self.grid.GetCellValue(row, 0) for row in range(self.grid.GetNumberRows())]
                  for key, value in list(d.items()):
                      if value:
                          if str(loc.er_data[key]) == str(value):
                              # no need to update
                              pass
                          else:
                              # update
                              loc.er_data[key] = value
                              col_ind = col_labels.index(key)
                              row_ind = row_labels.index(loc.name)
                              self.grid.SetCellValue(row_ind, col_ind, str(value))
                              if not self.grid.changes:
                                  self.grid.changes = set([row_ind])
                              else:
                                  self.grid.changes.add(row_ind)
  
          # a few special touches if it is an age grid
          if self.grid_type == 'age':
              self.remove_row_button.Disable()
              self.add_many_rows_button.Disable()
              self.grid.SetColLabelValue(0, 'er_site_name')
              toggle_box = wx.StaticBoxSizer(wx.StaticBox(self.panel, -1, label='Ages level', name='Ages level'), wx.VERTICAL)
  
              levels = ['specimen', 'sample', 'site', 'location']
              age_level = pw.radio_buttons(self.panel, levels, 'Choose level to assign ages')
              level_ind = levels.index(self.er_magic.age_type)
              age_level.radio_buttons[level_ind].SetValue(True)
  
              toggle_box.Add(age_level)
  
              self.Bind(wx.EVT_RADIOBUTTON, self.toggle_ages)
              self.hbox.Add(toggle_box)
  
          # a few special touches if it is a result grid
          if self.grid_type == 'result':
              # populate specimen_names, sample_names, etc.
              self.drop_down_menu.choices[2] = [sorted([spec.name for spec in self.er_magic.specimens if spec]), False]
              self.drop_down_menu.choices[3] = [sorted([samp.name for samp in self.er_magic.samples if samp]), False]
              self.drop_down_menu.choices[4] = [sorted([site.name for site in self.er_magic.sites if site]), False]
              self.drop_down_menu.choices[5] = [sorted([loc.name for loc in self.er_magic.locations if loc]), False]
              for row in range(self.grid.GetNumberRows()):
                  result_name = self.grid.GetCellValue(row, 0)
                  result = self.er_magic.find_by_name(result_name, self.er_magic.results)
                  if result:
                      if result.specimens:
                          self.grid.SetCellValue(row, 2, ' : '.join([pmag.get_attr(spec) for spec in result.specimens]))
                      if result.samples:
                          self.grid.SetCellValue(row, 3, ' : '.join([pmag.get_attr(samp) for samp in result.samples]))
                      if result.sites:
                          self.grid.SetCellValue(row, 4, ' : '.join([pmag.get_attr(site) for site in result.sites]))
                      if result.locations:
                          self.grid.SetCellValue(row, 5, ' : '.join([pmag.get_attr(loc) for loc in result.locations]))
                      self.drop_down_menu.choices[5] = [sorted([loc.name for loc in self.er_magic.locations if loc]), False]
  
          # final layout, set size
          self.main_sizer.Add(self.hbox, flag=wx.ALL|wx.ALIGN_CENTER|wx.SHAPED, border=20)
          self.main_sizer.Add(self.toggle_help_btn, .5, flag=wx.BOTTOM|wx.ALIGN_CENTRE|wx.SHAPED, border=5)
          self.main_sizer.Add(self.help_msg_boxsizer, .5, flag=wx.BOTTOM|wx.ALIGN_CENTRE|wx.SHAPED, border=10)
          self.main_sizer.Add(self.toggle_codes_btn, .5, flag=wx.BOTTOM|wx.ALIGN_CENTRE|wx.SHAPED, border=5)
          self.main_sizer.Add(self.code_msg_boxsizer, .5, flag=wx.BOTTOM|wx.ALIGN_CENTRE|wx.SHAPED, border=5)
          self.main_sizer.Add(self.grid_box, 2, flag=wx.ALL|wx.EXPAND, border=10)
          self.panel.SetSizer(self.main_sizer)
          self.main_sizer.Fit(self)
          ## this keeps sizing correct if the user resizes the window manually
          #self.Bind(wx.EVT_SIZE, self.do_fit)
          self.Centre()
          self.Show()