asp_plot.bundle_adjust
======================

.. py:module:: asp_plot.bundle_adjust


Attributes
----------

.. autoapisummary::

   asp_plot.bundle_adjust.logger


Classes
-------

.. autoapisummary::

   asp_plot.bundle_adjust.PlotBundleAdjustFiles
   asp_plot.bundle_adjust.ReadBundleAdjustFiles


Module Contents
---------------

.. py:class:: PlotBundleAdjustFiles(geodataframes, **kwargs)

   Bases: :py:obj:`asp_plot.utils.Plotter`


   Plot bundle adjustment results from GeoDataFrames.

   This class extends the base Plotter class to provide specialized
   plotting functionality for bundle adjustment results. It can create
   visualizations of residuals, geodiff results, and other bundle
   adjustment outputs.

   .. attribute:: geodataframes

      List of GeoDataFrames containing bundle adjustment data to plot

      :type: list of geopandas.GeoDataFrame

   .. attribute:: title

      Plot title, inherited from Plotter class

      :type: str

   .. rubric:: Examples

   >>> ba_reader = ReadBundleAdjustFiles('/path/to/asp', 'ba')
   >>> initial_gdf, final_gdf = ba_reader.get_initial_final_residuals_gdfs()
   >>> ba_plotter = PlotBundleAdjustFiles([initial_gdf, final_gdf], title="Bundle Adjustment Residuals")
   >>> ba_plotter.plot_n_gdfs(column_name="mean_residual_meters", cbar_label="Mean residual (m)")


   .. py:method:: gdf_percentile_stats(gdf, column_name='mean_residual')

      Calculate percentile statistics for a GeoDataFrame column.

      Computes the 25th, 50th, 84th, and 95th percentiles for a
      specified column in a GeoDataFrame.

      :param gdf: GeoDataFrame to analyze
      :type gdf: geopandas.GeoDataFrame
      :param column_name: Column to calculate statistics for, default is "mean_residual"
      :type column_name: str, optional

      :returns: List of statistics at the 25th, 50th, 84th, and 95th percentiles
      :rtype: list

      .. rubric:: Notes

      These percentiles are commonly used in remote sensing and
      photogrammetry to assess error distributions. The 50th percentile
      is the median, while the 84th percentile is approximately
      equivalent to one standard deviation in a normal distribution.



   .. py:method:: plot_n_gdfs(column_name='mean_residual', cbar_label='Mean residual (px)', clip_final=True, clim=None, common_clim=True, symm_clim=False, cmap='inferno', map_crs='EPSG:4326', save_dir=None, fig_fn=None, **ctx_kwargs)

      Plot multiple GeoDataFrames in a grid layout.

      Creates a figure with multiple subplots, one for each GeoDataFrame
      in the geodataframes list. Each subplot shows the spatial distribution
      of the specified column values.

      :param column_name: Column to visualize, default is "mean_residual"
      :type column_name: str, optional
      :param cbar_label: Label for the colorbar, default is "Mean residual (px)"
      :type cbar_label: str, optional
      :param clip_final: Whether to clip the final plot to prevent autoscaling,
                         default is True
      :type clip_final: bool, optional
      :param clim: Color limits as (min, max), default is None (auto)
      :type clim: tuple or None, optional
      :param common_clim: Whether to use the same color limits for all plots,
                          default is True
      :type common_clim: bool, optional
      :param symm_clim: Whether to use symmetric color limits, default is False
      :type symm_clim: bool, optional
      :param cmap: Matplotlib colormap name, default is "inferno"
      :type cmap: str, optional
      :param map_crs: Coordinate reference system for plotting, default is "EPSG:4326"
      :type map_crs: str, optional
      :param save_dir: Directory to save the figure, default is None (don't save)
      :type save_dir: str or None, optional
      :param fig_fn: Filename for the saved figure, default is None
      :type fig_fn: str or None, optional
      :param \*\*ctx_kwargs: Additional keyword arguments for contextily basemap
      :type \*\*ctx_kwargs: dict, optional

      :returns: Displays the plot and optionally saves it
      :rtype: None

      .. rubric:: Notes

      Each subplot includes a text box showing statistics for the
      displayed data, including the number of points and percentile
      values. The layout automatically adjusts based on the number
      of GeoDataFrames to plot.



   .. py:attribute:: geodataframes


.. py:class:: ReadBundleAdjustFiles(directory, bundle_adjust_directory)

   Read and process bundle adjustment output files from ASP.

   This class provides functionality to read and process the outputs
   from ASP's bundle_adjust tool, including residual point maps,
   map-projected residuals, and triangulation uncertainty. It can also
   generate geodiff files to compare bundle adjustment results with
   reference DEMs.

   .. attribute:: directory

      Root directory of ASP processing

      :type: str

   .. attribute:: bundle_adjust_directory

      Subdirectory containing bundle adjustment outputs

      :type: str

   .. attribute:: full_directory

      Full path to bundle adjustment directory

      :type: str

   .. rubric:: Examples

   >>> ba_reader = ReadBundleAdjustFiles('/path/to/asp', 'ba')
   >>> initial_gdf, final_gdf = ba_reader.get_initial_final_residuals_gdfs()
   >>> geodiff_initial, geodiff_final = ba_reader.get_initial_final_geodiff_gdfs()
   >>> mapproj_gdf = ba_reader.get_mapproj_residuals_gdf()


   .. py:method:: generate_geodiff(path)

      Generate geodiff file comparing residuals to a reference DEM.

      Uses ASP's geodiff tool to calculate height differences between
      bundle adjustment residual points and a reference DEM.

      :param path: Path to the bundle adjustment residual CSV file
      :type path: str

      .. rubric:: Notes

      The geodiff output file will be saved with the same name as the
      input file, but with "-diff.csv" appended. This method requires
      the geodiff tool from ASP and a reference DEM that was used in
      the bundle adjustment process.



   .. py:method:: get_csv_paths(geodiff_files=False)

      Get paths to bundle adjustment residual CSV files.

      Finds the paths to the initial and final residual point map CSV files
      from bundle adjustment. Can optionally find or generate geodiff files
      comparing these residuals to a reference DEM.

      :param geodiff_files: Whether to return paths to geodiff files instead of
                            regular residual CSV files, default is False
      :type geodiff_files: bool, optional

      :returns: Paths to initial and final residual CSV files or geodiff files
      :rtype: tuple of str

      :raises ValueError: If required bundle adjustment CSV files cannot be found

      .. rubric:: Notes

      If geodiff_files is True and the files don't exist, this method
      will attempt to generate them using the geodiff ASP tool.



   .. py:method:: get_geodiff_gdf(csv_path)

      Read geodiff output into a GeoDataFrame.

      Reads a geodiff output CSV file and converts it to a GeoDataFrame
      with appropriate geometry.

      :param csv_path: Path to the geodiff CSV file
      :type csv_path: str

      :returns: GeoDataFrame containing geodiff data with point geometry
      :rtype: geopandas.GeoDataFrame

      .. rubric:: Notes

      The returned GeoDataFrame has a 'filename' attribute set to the
      base name of the input file. The main data column is 'height_diff_meters',
      which contains the height differences between residual points and the
      reference DEM.



   .. py:method:: get_initial_final_geodiff_gdfs()

      Get both initial and final geodiff results as GeoDataFrames.

      A convenience method that combines get_csv_paths() and
      get_geodiff_gdf() to obtain both initial and final
      geodiff results.

      :returns: GeoDataFrames containing initial and final geodiff data
      :rtype: tuple of geopandas.GeoDataFrame

      .. rubric:: Notes

      This is a convenience method that calls get_csv_paths(geodiff_files=True)
      and get_geodiff_gdf() for both initial and final geodiff files. If the
      geodiff files don't exist, they will be generated using generate_geodiff().



   .. py:method:: get_initial_final_residuals_gdfs(residuals_in_meters=True)

      Get both initial and final residuals as GeoDataFrames.

      A convenience method that combines get_csv_paths() and
      get_residuals_gdf() to obtain both initial and final
      bundle adjustment residuals.

      :param residuals_in_meters: Whether to convert residuals from pixels to meters using
                                  the mean GSD from the stereopair metadata, default is True
      :type residuals_in_meters: bool, optional

      :returns: GeoDataFrames containing initial and final residual data
      :rtype: tuple of geopandas.GeoDataFrame

      .. rubric:: Notes

      This is a convenience method that calls get_csv_paths() and
      get_residuals_gdf() for both initial and final residual files.



   .. py:method:: get_mapproj_residuals_gdf()

      Get map-projected residuals as a GeoDataFrame.

      Reads the map-projected match offsets file produced by
      bundle_adjust and converts it to a GeoDataFrame.

      :returns: GeoDataFrame containing map-projected residual data
      :rtype: geopandas.GeoDataFrame

      :raises ValueError: If the map-projected match offsets file cannot be found

      .. rubric:: Notes

      The main data column is 'mapproj_ip_dist_meters', which contains
      the distance between matched interest points in the map-projected
      images after bundle adjustment.



   .. py:method:: get_propagated_triangulation_uncert_df()

      Get propagated triangulation uncertainty as a DataFrame.

      Reads the triangulation uncertainty file produced by
      bundle_adjust, which contains statistics on the expected
      horizontal and vertical error in the DEM.

      :returns: DataFrame containing triangulation uncertainty data
      :rtype: pandas.DataFrame

      :raises ValueError: If the triangulation uncertainty file cannot be found

      .. rubric:: Notes

      The triangulation uncertainty file contains statistics on how
      the bundle adjustment residuals propagate to uncertainty in
      triangulation. This is an estimate of the final DEM error.



   .. py:method:: get_residuals_gdf(csv_path, residuals_in_meters=True)

      Read bundle adjustment residuals into a GeoDataFrame.

      Reads a bundle adjustment residuals CSV file and converts it
      to a GeoDataFrame with appropriate geometry. Can optionally
      convert residuals from pixels to meters.

      :param csv_path: Path to the residuals CSV file
      :type csv_path: str
      :param residuals_in_meters: Whether to convert residuals from pixels to meters using
                                  the mean GSD from the stereopair metadata, default is True
      :type residuals_in_meters: bool, optional

      :returns: GeoDataFrame containing residual data with point geometry
      :rtype: geopandas.GeoDataFrame

      .. rubric:: Notes

      The returned GeoDataFrame has a 'filename' attribute set to the
      base name of the input file. If residuals_in_meters is True,
      a new column 'mean_residual_meters' will be added with pixel
      residuals converted to meters.



   .. py:attribute:: bundle_adjust_directory


   .. py:attribute:: directory


   .. py:attribute:: full_directory


.. py:data:: logger

