| #!/usr/bin/python | 
 | # | 
 | # Plots the results from the 3D pose graph optimization. It will draw a line | 
 | # between consecutive vertices.  The commandline expects two optional filenames: | 
 | # | 
 | #   ./plot_results.py --initial_poses filename  --optimized_poses filename | 
 | # | 
 | # The files have the following format: | 
 | #   ID x y z q_x q_y q_z q_w | 
 |  | 
 | from mpl_toolkits.mplot3d import Axes3D | 
 | import matplotlib.pyplot as plot | 
 | import numpy | 
 | import sys | 
 | from optparse import OptionParser | 
 |  | 
 | def set_axes_equal(axes): | 
 |     ''' Sets the axes of a 3D plot to have equal scale. ''' | 
 |     x_limits = axes.get_xlim3d() | 
 |     y_limits = axes.get_ylim3d() | 
 |     z_limits = axes.get_zlim3d() | 
 |  | 
 |     x_range = abs(x_limits[1] - x_limits[0]) | 
 |     x_middle = numpy.mean(x_limits) | 
 |     y_range = abs(y_limits[1] - y_limits[0]) | 
 |     y_middle = numpy.mean(y_limits) | 
 |     z_range = abs(z_limits[1] - z_limits[0]) | 
 |     z_middle = numpy.mean(z_limits) | 
 |  | 
 |     length = 0.5 * max([x_range, y_range, z_range]) | 
 |  | 
 |     axes.set_xlim3d([x_middle - length, x_middle + length]) | 
 |     axes.set_ylim3d([y_middle - length, y_middle + length]) | 
 |     axes.set_zlim3d([z_middle - length, z_middle + length]) | 
 |  | 
 | parser = OptionParser() | 
 | parser.add_option("--initial_poses", dest="initial_poses", | 
 |                   default="", help="The filename that contains the original poses.") | 
 | parser.add_option("--optimized_poses", dest="optimized_poses", | 
 |                   default="", help="The filename that contains the optimized poses.") | 
 | parser.add_option("-e", "--axes_equal", action="store_true", dest="axes_equal", | 
 |                   default="", help="Make the plot axes equal.") | 
 | (options, args) = parser.parse_args() | 
 |  | 
 | # Read the original and optimized poses files. | 
 | poses_original = None | 
 | if options.initial_poses != '': | 
 |   poses_original = numpy.genfromtxt(options.initial_poses, | 
 |                                     usecols = (1, 2, 3)) | 
 |  | 
 | poses_optimized = None | 
 | if options.optimized_poses != '': | 
 |   poses_optimized = numpy.genfromtxt(options.optimized_poses, | 
 |                                      usecols = (1, 2, 3)) | 
 |  | 
 | # Plots the results for the specified poses. | 
 | figure = plot.figure() | 
 |  | 
 | if poses_original is not None: | 
 |   axes = plot.subplot(1, 2, 1, projection='3d') | 
 |   plot.plot(poses_original[:, 0], poses_original[:, 1], poses_original[:, 2], | 
 |             '-', alpha=0.5, color="green") | 
 |   plot.title('Original') | 
 |   if options.axes_equal: | 
 |     axes.set_aspect('equal') | 
 |     set_axes_equal(axes) | 
 |  | 
 |  | 
 | if poses_optimized is not None: | 
 |   axes = plot.subplot(1, 2, 2, projection='3d') | 
 |   plot.plot(poses_optimized[:, 0], poses_optimized[:, 1], poses_optimized[:, 2], | 
 |             '-', alpha=0.5, color="blue") | 
 |   plot.title('Optimized') | 
 |   if options.axes_equal: | 
 |     axes.set_aspect('equal') | 
 |     set_axes_equal(plot.gca()) | 
 |  | 
 |  | 
 | # Show the plot and wait for the user to close. | 
 | plot.show() |