docs: def pandas(self, row_attr: str = None, selector: Union[List, Tuple, np.ndarray, slice] = None, columns: List[str] = None) -> pd.DataFrame:
  		"""
  		Create a Pandas DataFrame corresponding to (selected parts of) the Loom file.
  
  		Args:
  			row_attr:	Name of the row attribute to use for selecting rows to include (or None to omit row data)
  			selector:	A list, a tuple, a numpy.ndarray or a slice; used to select rows (or None to include all rows)
  			columns:	A list of column attributes to include, or None to include all
  
  		Returns:
  			Pandas DataFrame
  
  		Remarks:
  			The method returns a Pandas DataFrame with one column per row of the Loom file (i.e. transposed), which is usually
  			what is required for plotting and statistical analysis. By default, all column attributes and no rows are included.
  			To include row data, provide a ``row_attr`` and a ``selector``. The selector is matched against values of the given
  			row attribute, and matching rows are included.
  
  		Examples:
  			.. highlight:: python
  			.. code-block:: python
  
  				import loompy
  				with loompy.connect("mydata.loom") as ds:
  					# Include all column attributes, and rows where attribute "Gene" matches one of the given genes
  					df1 = ds.pandas("Gene", ["Actb", "Npy", "Vip", "Pvalb"])
  					# Include the top 100 rows and name them after values of the "Gene" attribute
  					df2 = ds.pandas("Gene", :100)
  					# Include the entire dataset, and name the rows after values of the "Accession" attribute
  					df3 = ds.pandas("Accession")
  
  		"""
  		if columns is None:
  			columns = [x for x in self.ca.keys()]
  
  		data: Dict[str, np.ndarray] = {}
  		for col in columns:
  			vals = self.ca[col]
  			if vals.ndim >= 2:
  				for i in range(vals.ndim):
  					data[col + f".{i+1}"] = vals[:, 0]
  			else:
  				data[col] = self.ca[col]
  		if row_attr is not None:  # Pick out some rows (genes)
  			if selector is None:  # Actually, pick all the rows
  				names = self.ra[row_attr]
  				vals = self[:, :]
  				for ix, name in enumerate(names):
  					data[name] = vals[ix, :][0]
  			else:  # Pick some specific rows
  				if type(selector) is slice:  # Based on a slice
  					names = self.ra[row_attr][selector]
  					vals = self[selector, :]
  					for ix, name in enumerate(names):
  						data[name] = vals[ix, :][0]
  				# Based on specific string values
  				elif all([type(s) is str for s in selector]):  # type: ignore
  					names = self.ra[row_attr][np.in1d(self.ra[row_attr], selector)]
  					for name in names:
  						vals = self[self.ra[row_attr] == name, :][0]
  						data[name] = vals
  				else:  # Give up
  					raise ValueError("Invalid selector")
  		return pd.DataFrame(data)