MichaelGrupp / evo

Python package for the evaluation of odometry and SLAM
https://michaelgrupp.github.io/evo/
GNU General Public License v3.0
3.32k stars 743 forks source link

Error Fix: plot_trajectory_length_unit | TypeError: formatter argument should be instance of matplotlib.ticker.Formatter #654

Closed xbbao-metis closed 2 months ago

xbbao-metis commented 2 months ago

Description: Whenever I set plot_trajectory_length_unit to km, cm, and or mm, I'm seeing an issue on in plot.py where the plot length unit is not correctly creating a 'matplotlib.ticker.Formatter' and is instead giving me a type 'function'.

Command:

evo_config set plot_trajectory_length_unit mm
evo_traj tum -v --full_check -p --plot_mode xy <dataset.tum>

Console output:


--------------------------------------------------------------------------------
Loaded 23313 stamps and poses from: 20240405_2308_mob_nav_nocrew_manual_r1-loc_pose.tum
--------------------------------------------------------------------------------
name:   20240405_2308_mob_nav_nocrew_manual_r1-loc_pose
infos:
    duration (s)    271.23836374282837
    nr. of poses    23313
    path length (m) 17.88176427087539
    pos_end (m) [-0.03279668  0.59085541 -0.6735922 ]
    pos_start (m)   [-0.10684743  0.65817474 -0.67286066]
    t_end (s)   1712358756.2146993
    t_start (s) 1712358484.9763355
checks:
    SE(3) conform   yes
    array shapes    ok
    nr. of stamps   ok
    quaternions ok
    timestamps  ok
stats:
    dt_avg (s)  0.011635
    dt_max (s)  0.054397
    dt_min (s)  0.002527
    v_avg (km/h)    0.249250
    v_avg (m/s) 0.069236
    v_max (km/h)    76.241085
    v_max (m/s) 21.178079
    v_min (km/h)    0.000000
    v_min (m/s) 0.000000
[ERROR] Unhandled error in evo.main_traj
Traceback (most recent call last):
  File "/home/metis/.local/lib/python3.8/site-packages/evo/entry_points.py", line 95, in launch
    main_module.run(args)
  File "/home/metis/.local/lib/python3.8/site-packages/evo/main_traj.py", line 318, in run
    ax_traj = plot.prepare_axis(fig_traj, plot_mode,
  File "/home/metis/.local/lib/python3.8/site-packages/evo/tools/plot.py", line 327, in prepare_axis
    ax.xaxis.set_major_formatter(formatter)
  File "/usr/lib/python3/dist-packages/matplotlib/axis.py", line 1612, in set_major_formatter
    raise TypeError("formatter argument should be instance of "
TypeError: formatter argument should be instance of matplotlib.ticker.Formatter

[ERROR] evo module evo.main_traj crashed - no logfile written (disabled)

Additional files: Please attach all the files needed to reproduce the error.

Please give also the following information:

{ "console_logging_format": "%(message)s", "euler_angle_sequence": "sxyz", "global_logfile_enabled": false, "plot_axis_marker_scale": 0.005, "plot_backend": "Qt5Agg", "plot_figsize": [ 6, 6 ], "plot_fontfamily": "sans-serif", "plot_fontscale": 1.0, "plot_invert_xaxis": false, "plot_invert_yaxis": false, "plot_linewidth": 1.5, "plot_mode_default": "xy", "plot_multi_cmap": "none", "plot_pose_correspondences": true, "plot_pose_correspondences_linestyle": "dotted", "plot_reference_alpha": 0.5, "plot_reference_axis_marker_scale": 0.0, "plot_reference_color": "black", "plot_reference_linestyle": "--", "plot_seaborn_enabled": true, "plot_seaborn_palette": "deep6", "plot_seaborn_style": "darkgrid", "plot_show_axis": true, "plot_show_legend": true, "plot_split": false, "plot_start_end_markers": false, "plot_statistics": [ "rmse", "median", "mean", "std", "min", "max" ], "plot_texsystem": "pdflatex", "plot_trajectory_alpha": 0.75, "plot_trajectory_cmap": "jet", "plot_trajectory_length_unit": "mm", "plot_trajectory_linestyle": "-", "plot_usetex": false, "plot_xyz_realistic": true, "pygments_style": "monokai", "ros_map_alpha_value": 1.0, "ros_map_cmap": "Greys_r", "ros_map_enable_masking": true, "ros_map_unknown_cell_value": 205, "ros_map_viewport": "keep_unchanged", "save_traj_in_zip": false, "table_export_data": "stats", "table_export_format": "csv", "table_export_transpose": true, "tf_cache_lookup_frequency": 10, "tf_cache_max_time": 10000.0 }


How to fix:

go to evo/tools/plot.py  line 281 in function "_get_length_formatter"

Instead of 

def _get_length_formatter(lengthunit: Unit) -> typing.Callable: def formatter(x, ): return "{0:g}".format(x / METER_SCALE_FACTORS[length_unit])

return formatter

use this:

def _get_length_formatter(lengthunit: Unit) -> typing.Callable: def formatter(x, ): return "{0:g}".format(x / METER_SCALE_FACTORS[length_unit])

return FuncFormatter(formatter)


This was able to get the other length_units properly instanced. I noticed that not doing this causes _get_length_formatter() to only return a function callable and not a matplotlib.ticker.Formatter type, which seemed to be the cause of the exception being thrown whenever the axis tick format was being set.
xbbao-metis commented 2 months ago

make sure to add

from matplotlib.ticker import FuncFormatter
MichaelGrupp commented 2 months ago

I could not reproduce this, but it might depend on matplotlib's version. Independent of that, your solution is much cleaner. I patched it and released it as version 1.26.3

Thank you!