docs: def merge_dfs(self, df1):
          """
          Description: takes new calculated data and replaces the corresponding data in self.df with the new input data preserving the most important metadata if they are not otherwise saved. Note this does not mutate self.df it simply returns the merged dataframe if you want to replace self.df you'll have to do that yourself.
  
          @param: df1 - first DataFrame whose data will preferentially be used.
          """
  
          if self.df.empty:
              return df1
          elif df1.empty:
              return self.df
  
          #copy to prevent mutation
          cdf2 = self.df.copy()
  
          #split data into types and decide which to replace
  #        if replace_dir_or_int == 'dir' and 'method_codes' in cdf2.columns:
  #            cdf2 = cdf2[cdf2['method_codes'].notnull()]
  #            acdf2 = cdf2[cdf2['method_codes'].str.contains('LP-PI')]
  #            mcdf2 = cdf2[cdf2['method_codes'].str.contains('LP-DIR')]
  #        elif replace_dir_or_int == 'int' and 'method_codes' in cdf2.columns:
  #            cdf2 = cdf2[cdf2['method_codes'].notnull()]
  #            mcdf2 = cdf2[cdf2['method_codes'].str.contains('LP-PI')]
  #            acdf2 = cdf2[cdf2['method_codes'].str.contains('LP-DIR')]
  #        else:
  #            mcdf2 = cdf2
  #            acdf2 = pd.DataFrame(columns=mcdf2.columns)
  
          #get rid of stupid duplicates
  #        [mcdf2.drop(cx,inplace=True,axis=1) for cx in mcdf2.columns if cx in df1.columns]
  
          #join the new calculated data with the old data of same type
          if self.dtype.endswith('s'): dtype = self.dtype[:-1]
          else: dtype = self.dtype
          index_name = dtype + "_name"
          for df in [df1, cdf2]:
              df.index.name = index_name
          mdf = df1.join(cdf2, how='outer', rsuffix='_remove', on=index_name)
          def keep_non_null_vals(column):
              extra_column = column + "_remove"
              if column in mdf.columns and extra_column in mdf.columns:
                  mdf[column] = np.where(mdf[column].apply(lambda x: not_null(x, False)), mdf[column], mdf[extra_column])
          # merge values in the following columns
          # e.g., combine info from specimen + specimen_remove into specimen column
          for col in ['specimen', 'sample', 'site', 'location', 'lat', 'lon']:
              keep_non_null_vals(col)
          #drop duplicate columns if they were created
          [mdf.drop(col,inplace=True,axis=1) for col in mdf.columns if col.endswith("_remove")]
          #duplicates rows for some freaking reason
          mdf.drop_duplicates(inplace=True,subset=[col for col in mdf.columns if col != 'description'])
          #merge the data of the other type with the new data
  #        mdf = mdf.merge(acdf2, how='outer')
          if dtype in mdf.columns:
              #fix freaking indecies because pandas
              mdf = mdf.set_index(dtype)
              #really? I wanted the index changed not a column deleted?!?
              mdf[dtype] = mdf.index
              mdf.index.name = index_name
              mdf.sort_index(inplace=True)
          return mdf