예제 #1
0
def main():
    import argcomplete
    basic_desc = "crappy configuration tool"
    lic = "(c) evo authors"
    shared_parser = argparse.ArgumentParser(add_help=False)
    shared_parser.add_argument("--no_color", help="don't color output",
                               action="store_true")
    main_parser = argparse.ArgumentParser(description="%s %s" %
                                          (basic_desc, lic))
    sub_parsers = main_parser.add_subparsers(dest="subcommand")
    sub_parsers.required = True

    show_parser = sub_parsers.add_parser(
        "show", description="show configuration - %s" % lic,
        parents=[shared_parser])
    show_parser.add_argument(
        "config",
        help="optional config file to display (default: package settings)",
        nargs='?')
    show_parser.add_argument("--brief", help="show only the .json data",
                             action="store_true")

    set_parser = sub_parsers.add_parser(
        "set", description=SET_HELP, parents=[shared_parser],
        formatter_class=argparse.RawTextHelpFormatter)
    set_parser.add_argument("params",
                            choices=list(DEFAULT_SETTINGS_DICT.keys()),
                            nargs=argparse.REMAINDER, help="parameters to set")
    set_parser.add_argument(
        "-c", "--config",
        help="optional config file (default: package settings)", default=None)
    set_parser.add_argument("-m", "--merge",
                            help="other config file to merge in (priority)",
                            default=None)
    set_parser.add_argument("--soft", help="do a soft-merge (no overwriting)",
                            action="store_true")

    gen_parser = sub_parsers.add_parser(
        "generate", description=GENERATE_HELP, parents=[shared_parser],
        formatter_class=argparse.RawTextHelpFormatter)
    gen_parser.add_argument("-o", "--out",
                            help="path for config file to generate")

    reset_parser = sub_parsers.add_parser(
        "reset", description="reset package settings - %s" % lic,
        parents=[shared_parser])
    reset_parser.add_argument("-y", help="acknowledge automatically",
                              action="store_true")
    reset_parser.add_argument(
        "params", choices=list(DEFAULT_SETTINGS_DICT.keys()),
        nargs=argparse.REMAINDER, help="parameters to reset")

    argcomplete.autocomplete(main_parser)
    if len(sys.argv) > 1 and sys.argv[1] == "set":
        args, other_args = main_parser.parse_known_args()
        other_args = [arg for arg in sys.argv[2:]]
    else:
        args, other_args = main_parser.parse_known_args()
    log.configure_logging()
    colorama.init()

    config = settings.DEFAULT_PATH
    if hasattr(args, "config"):
        if args.config:
            config = args.config

    if args.subcommand == "show":
        if not args.brief and not args.config:
            style = Style.BRIGHT if not args.no_color else Style.NORMAL
            doc_str = "\n".join(
                "{0}{1}{2}:\n{3}\n".format(style, k, Style.RESET_ALL, v[1])
                for k, v in sorted(DEFAULT_SETTINGS_DICT_DOC.items()))
            logger.info(doc_str)
            logger.info("{0}\n{1}\n{0}".format(SEP, config))
        show(config, colored=not args.no_color)
        if config == settings.DEFAULT_PATH and not args.brief:
            logger.info(SEP + "\nSee text above for parameter descriptions.")

    elif args.subcommand == "set":
        if not os.access(config, os.W_OK):
            logger.error("No permission to modify " + config)
            sys.exit(1)
        if other_args or args.merge:
            logger.info("{0}\nOld configuration:\n{0}".format(SEP))
            show(config, colored=not args.no_color)
            try:
                set_config(config, other_args)
            except ConfigError as e:
                logger.error(e)
                sys.exit(1)
            if args.merge:
                merge_json_union(config, args.merge, args.soft)
            logger.info(SEP + "\nNew configuration:\n" + SEP)
            show(config, colored=not args.no_color)
        else:
            logger.error("No configuration parameters given (see --help).")

    elif args.subcommand == "generate":
        if other_args:
            logger.info(
                "{0}\nParsed by argparse:\n{1}\n"
                "{0}\nWARNING:\nMake sure you use the 'long-style' -- options "
                "(e.g. --plot) if possible\nand no combined short '-' flags, "
                "(e.g. -vp)\n{0}".format(SEP, other_args))
            data = generate(other_args)
            log_info_dict_json(data, colored=not args.no_color)
            if args.out and user.check_and_confirm_overwrite(args.out):
                with open(args.out, 'w') as out:
                    out.write(json.dumps(data, indent=4, sort_keys=True))
            elif not args.out:
                logger.warning("\n(-o | --out) not specified - saving nothing")
        else:
            logger.error("No command line arguments given (see --help)")

    elif args.subcommand == "reset":
        if not os.access(config, os.W_OK):
            logger.error("No permission to modify" + config)
            sys.exit(1)
        if args.params:
            settings.reset(settings.DEFAULT_PATH, parameter_subset=args.params)
        elif args.y or user.confirm(
                "Reset all package settings to the default settings? (y/n)"):
            settings.reset()
        else:
            sys.exit()
        logger.info("{0}\nPackage settings after reset:\n{0}".format(SEP))
        show(settings.DEFAULT_PATH, colored=not args.no_color)
예제 #2
0
파일: plot.py 프로젝트: zinuok/evo
 def serialize(self, dest, confirm_overwrite=True):
     logger.debug("Serializing PlotCollection to " + dest + "...")
     if confirm_overwrite and not user.check_and_confirm_overwrite(dest):
         return
     else:
         pickle.dump(self.figures, open(dest, 'wb'))
예제 #3
0
파일: main_config.py 프로젝트: danpeng2/evo
def main():
    import argcomplete
    basic_desc = "crappy configuration tool"
    lic = "(c) [email protected]"
    shared_parser = argparse.ArgumentParser(add_help=False)
    shared_parser.add_argument("--no_color", help="don't color output", action="store_true")
    main_parser = argparse.ArgumentParser(description="%s %s" % (basic_desc, lic))
    sub_parsers = main_parser.add_subparsers(dest="subcommand")
    sub_parsers.required = True

    show_parser = sub_parsers.add_parser("show", description="show configuration - %s" % lic,
                                         parents=[shared_parser])
    show_parser.add_argument("config",
                             help="optional config file to display (default: package settings)",
                             nargs='?')
    show_parser.add_argument("--brief", help="show only the .json data",
                             action="store_true")

    set_parser = sub_parsers.add_parser("set", description=SET_HELP, parents=[shared_parser],
                                        formatter_class=argparse.RawTextHelpFormatter)
    set_parser.add_argument("params", choices=list(DEFAULT_SETTINGS_DICT.keys()),
                            nargs=argparse.REMAINDER, help="parameters to set")
    set_parser.add_argument("-c", "--config",
                            help="optional config file (default: package settings)", default=None)
    set_parser.add_argument("-m", "--merge",
                            help="other config file to merge in (priority)", default=None)
    set_parser.add_argument("--soft", help="do a soft-merge (no overwriting)", action="store_true")

    gen_parser = sub_parsers.add_parser("generate", description=GENERATE_HELP,
                                        parents=[shared_parser],
                                        formatter_class=argparse.RawTextHelpFormatter)
    gen_parser.add_argument("-o", "--out", help="path for config file to generate")

    reset_parser = sub_parsers.add_parser("reset", description="reset package settings - %s" % lic,
                                          parents=[shared_parser])
    reset_parser.add_argument("-y", help="acknowledge automatically", action="store_true")

    argcomplete.autocomplete(main_parser)
    if len(sys.argv) > 1 and sys.argv[1] == "set":
        args, other_args = main_parser.parse_known_args()
        other_args = [arg for arg in sys.argv[2:] if not arg.startswith('-')]
    else:
        args, other_args = main_parser.parse_known_args()
    log.configure_logging()
    colorama.init()

    config = settings.DEFAULT_PATH
    if hasattr(args, "config"):
        if args.config:
            config = args.config

    if args.subcommand == "show":
        if not args.brief and not args.config:
            style = Style.BRIGHT if not args.no_color else Style.NORMAL
            doc_str = "\n".join("{0}{1}{2}:\n{3}\n".format(style, k, Style.RESET_ALL, v[1])
                                for k, v in sorted(DEFAULT_SETTINGS_DICT_DOC.items()))
            logger.info(doc_str)
            logger.info("{0}\n{1}\n{0}".format(SEP, config))
        show(config, colored=not args.no_color)
        if config == settings.DEFAULT_PATH and not args.brief:
            logger.info(SEP + "\nSee text above for parameter descriptions.")

    elif args.subcommand == "set":
        if not os.access(config, os.W_OK):
            logger.error("No permission to modify " + config)
            sys.exit()
        if other_args or args.merge:
            logger.info("{0}\nOld configuration:\n{0}".format(SEP))
            show(config, colored=not args.no_color)
            try:
                set_cfg(config, other_args)
            except ConfigError as e:
                logger.error(e)
                sys.exit(1)
            if args.merge:
                merge_json_union(config, args.merge, args.soft)
            logger.info(SEP + "\nNew configuration:\n" + SEP)
            show(config, colored=not args.no_color)
        else:
            logger.error("No configuration parameters given (see --help).")

    elif args.subcommand == "generate":
        if other_args:
            logger.info("{0}\nParsed by argparse:\n{1}\n"
                         "{0}\nWARNING:\n"
                         "Make sure you use the 'long-style' -- options (e.g. --plot) if possible\n"
                         "and no combined short '-' flags, (e.g. -vp)\n{0}".format(SEP, other_args))
            data = generate(other_args)
            log_info_dict_json(data, colored=not args.no_color)
            if args.out and user.check_and_confirm_overwrite(args.out):
                with open(args.out, 'w') as out:
                    out.write(json.dumps(data, indent=4, sort_keys=True))
            elif not args.out:
                logger.warning("\n(-o | --out) not specified - saving nothing")
        else:
            logger.error("No command line arguments given (see --help)")

    elif args.subcommand == "reset":
        if not os.access(config, os.W_OK):
            logger.error("No permission to modify" + config)
            sys.exit()
        if args.y or user.confirm("Reset the package settings to the default settings? (y/n)"):
            settings.reset()
            logger.info("{0}\nPackage settings after reset:\n{0}".format(SEP))
            show(settings.DEFAULT_PATH, colored=not args.no_color)
예제 #4
0
파일: main_res.py 프로젝트: tutuxh/evo
def run(args):
    import sys

    import pandas as pd

    from evo.tools import file_interface, log, user, settings, pandas_bridge
    from evo.tools.settings import SETTINGS

    pd.options.display.width = 80
    pd.options.display.max_colwidth = 20

    log.configure_logging(args.verbose,
                          args.silent,
                          args.debug,
                          local_logfile=args.logfile)
    if args.debug:
        import pprint
        arg_dict = {arg: getattr(args, arg) for arg in vars(args)}
        logger.debug("main_parser config:\n{}\n".format(
            pprint.pformat(arg_dict)))

    df = pd.DataFrame()
    for result_file in args.result_files:
        result = file_interface.load_res_file(result_file)
        name = result_file if args.use_filenames else None
        df = pd.concat([df, pandas_bridge.result_to_df(result, name)],
                       axis="columns")

    keys = df.columns.values.tolist()
    if SETTINGS.plot_usetex:
        keys = [key.replace("_", "\\_") for key in keys]
        df.columns = keys
    duplicates = [x for x in keys if keys.count(x) > 1]
    if duplicates:
        logger.error("Values of 'est_name' must be unique - duplicates: {}\n"
                     "Try using the --use_filenames option to use filenames "
                     "for labeling instead.".format(", ".join(duplicates)))
        sys.exit(1)

    # derive a common index type if possible - preferably timestamps
    common_index = None
    time_indices = ["timestamps", "seconds_from_start", "sec_from_start"]
    if args.use_rel_time:
        del time_indices[0]
    for idx in time_indices:
        if idx not in df.loc["np_arrays"].index:
            continue
        if df.loc["np_arrays", idx].isnull().values.any():
            continue
        else:
            common_index = idx
            break

    # build error_df (raw values) according to common_index
    if common_index is None:
        # use a non-timestamp index
        error_df = pd.DataFrame(df.loc["np_arrays", "error_array"].tolist(),
                                index=keys).T
    else:
        error_df = pd.DataFrame()
        for key in keys:
            new_error_df = pd.DataFrame(
                {key: df.loc["np_arrays", "error_array"][key]},
                index=df.loc["np_arrays", common_index][key])
            duplicates = new_error_df.index.duplicated(keep="first")
            if any(duplicates):
                logger.warning(
                    "duplicate indices in error array of {} - "
                    "keeping only first occurrence of duplicates".format(key))
                new_error_df = new_error_df[~duplicates]
            error_df = pd.concat([error_df, new_error_df], axis=1)

    # check titles
    first_title = df.loc["info", "title"][0]
    first_file = args.result_files[0]
    if not args.no_warnings:
        checks = df.loc["info", "title"] != first_title
        for i, differs in enumerate(checks):
            if not differs:
                continue
            else:
                mismatching_title = df.loc["info", "title"][i]
                mismatching_file = args.result_files[i]
                logger.debug(SEP)
                logger.warning(
                    CONFLICT_TEMPLATE.format(first_file, first_title,
                                             mismatching_title,
                                             mismatching_file))
                if not user.confirm(
                        "Go on anyway? - enter 'y' or any other key to exit"):
                    sys.exit()

    logger.debug(SEP)
    logger.debug("Aggregated dataframe:\n{}".format(
        df.to_string(line_width=80)))

    # show a statistics overview
    logger.debug(SEP)
    logger.info("\n{}\n\n{}\n".format(
        first_title, df.loc["stats"].T.to_string(line_width=80)))

    if args.save_table:
        logger.debug(SEP)
        if args.no_warnings or user.check_and_confirm_overwrite(
                args.save_table):
            if SETTINGS.table_export_data.lower() == "error_array":
                data = error_df
            elif SETTINGS.table_export_data.lower() in ("info", "stats"):
                data = df.loc[SETTINGS.table_export_data.lower()]
            else:
                raise ValueError(
                    "unsupported export data specifier: {}".format(
                        SETTINGS.table_export_data))
            if SETTINGS.table_export_transpose:
                data = data.T

            if SETTINGS.table_export_format == "excel":
                writer = pd.ExcelWriter(args.save_table)
                data.to_excel(writer)
                writer.save()
                writer.close()
            else:
                getattr(data,
                        "to_" + SETTINGS.table_export_format)(args.save_table)
            logger.debug("{} table saved to: {}".format(
                SETTINGS.table_export_format, args.save_table))

    if args.plot or args.save_plot or args.serialize_plot:
        # check if data has NaN "holes" due to different indices
        inconsistent = error_df.isnull().values.any()
        if inconsistent and common_index != "timestamps" and not args.no_warnings:
            logger.debug(SEP)
            logger.warning("Data lengths/indices are not consistent, "
                           "raw value plot might not be correctly aligned")

        from evo.tools import plot
        import matplotlib.pyplot as plt
        import seaborn as sns
        import math

        # use default plot settings
        figsize = (SETTINGS.plot_figsize[0], SETTINGS.plot_figsize[1])
        use_cmap = SETTINGS.plot_multi_cmap.lower() != "none"
        colormap = SETTINGS.plot_multi_cmap if use_cmap else None
        linestyles = ["-o" for x in args.result_files
                      ] if args.plot_markers else None

        # labels according to first dataset
        title = first_title
        if "xlabel" in df.loc["info"].index and not df.loc[
                "info", "xlabel"].isnull().values.any():
            index_label = df.loc["info", "xlabel"][0]
        else:
            index_label = "$t$ (s)" if common_index else "index"
        metric_label = df.loc["info", "label"][0]

        plot_collection = plot.PlotCollection(title)
        # raw value plot
        fig_raw = plt.figure(figsize=figsize)
        # handle NaNs from concat() above
        error_df.interpolate(method="index").plot(
            ax=fig_raw.gca(),
            colormap=colormap,
            style=linestyles,
            title=first_title,
            alpha=SETTINGS.plot_trajectory_alpha)
        plt.xlabel(index_label)
        plt.ylabel(metric_label)
        plt.legend(frameon=True)
        plot_collection.add_figure("raw", fig_raw)

        # statistics plot
        fig_stats = plt.figure(figsize=figsize)
        exclude = df.loc["stats"].index.isin(["sse"])  # don't plot sse
        df.loc["stats"][~exclude].plot(kind="barh",
                                       ax=fig_stats.gca(),
                                       colormap=colormap,
                                       stacked=False)
        plt.xlabel(metric_label)
        plt.legend(frameon=True)
        plot_collection.add_figure("stats", fig_stats)

        # grid of distribution plots
        raw_tidy = pd.melt(error_df,
                           value_vars=list(error_df.columns.values),
                           var_name="estimate",
                           value_name=metric_label)
        col_wrap = 2 if len(args.result_files) <= 2 else math.ceil(
            len(args.result_files) / 2.0)
        dist_grid = sns.FacetGrid(raw_tidy, col="estimate", col_wrap=col_wrap)
        # TODO: see issue #98
        import warnings
        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            dist_grid.map(sns.distplot, metric_label)  # fits=stats.gamma
        plot_collection.add_figure("histogram", dist_grid.fig)

        # box plot
        fig_box = plt.figure(figsize=figsize)
        ax = sns.boxplot(x=raw_tidy["estimate"],
                         y=raw_tidy[metric_label],
                         ax=fig_box.gca())
        # ax.set_xticklabels(labels=[item.get_text() for item in ax.get_xticklabels()], rotation=30)
        plot_collection.add_figure("box_plot", fig_box)

        # violin plot
        fig_violin = plt.figure(figsize=figsize)
        ax = sns.violinplot(x=raw_tidy["estimate"],
                            y=raw_tidy[metric_label],
                            ax=fig_violin.gca())
        # ax.set_xticklabels(labels=[item.get_text() for item in ax.get_xticklabels()], rotation=30)
        plot_collection.add_figure("violin_histogram", fig_violin)

        if args.plot:
            plot_collection.show()
        if args.save_plot:
            logger.debug(SEP)
            plot_collection.export(args.save_plot,
                                   confirm_overwrite=not args.no_warnings)
        if args.serialize_plot:
            logger.debug(SEP)
            plot_collection.serialize(args.serialize_plot,
                                      confirm_overwrite=not args.no_warnings)
예제 #5
0
def save_res_file(zip_path,
                  pe_metric,
                  pe_statistics,
                  title,
                  ref_name,
                  est_name,
                  seconds_from_start=None,
                  traj_ref=None,
                  traj_est=None,
                  xlabel=None,
                  confirm_overwrite=False):
    """
    save results of a pose error metric (pe_metric) to a zip file
    :param zip_path: path to zip file
    :param pe_metric: instance of metrics.APE or metrics.RPE
    :param pe_statistics: dictionary with statistics from pe_metric.get_[all_]statistic[s]
    :param title: the title of the experiment
    :param ref_name: name of the reference (ground_truth)
    :param est_name: name of the estimate
    :param seconds_from_start: optional time array (useful for plotting the time instead of index)
    :param traj_ref: optional - save trajectory that was used as the reference (requires traj_est)
    :param traj_est: optional - save trajectory that was used as the estimate (requires traj_ref)
    :param xlabel: optional custom (plot) xlabel to save
    :param confirm_overwrite: whether to require user interaction to overwrite existing files
    """
    from tempfile import TemporaryFile
    from evo.algorithms.metrics import APE
    logging.debug("saving results to " + zip_path + "...")
    if confirm_overwrite and not user.check_and_confirm_overwrite(zip_path):
        return
    with zipfile.ZipFile(zip_path, 'w') as archive:
        pe_type = "APE" if isinstance(pe_metric, APE) else "RPE"
        info = {
            "title":
            title,
            "ref_name":
            ref_name,
            "est_name":
            est_name,
            "label":
            pe_type +
            (" (" + pe_metric.unit.value + ")") if pe_metric.unit else ""
        }
        if xlabel:
            info["xlabel"] = xlabel
        archive.writestr("info.json", json.dumps(info))
        archive.writestr("stats.json", json.dumps(pe_statistics))
        # save np arrays in .npz format
        tmp_file_err = TemporaryFile()
        np.save(tmp_file_err, pe_metric.error)
        tmp_file_err.seek(0)
        archive.writestr("error_array.npz", tmp_file_err.read())
        tmp_file_err.close()
        if seconds_from_start:
            tmp_file_sec = TemporaryFile()
            if seconds_from_start:
                np.save(tmp_file_sec, seconds_from_start)
            tmp_file_sec.seek(0)
            archive.writestr("sec_from_start.npz", tmp_file_sec.read())
            tmp_file_sec.close()
        if SETTINGS.save_traj_in_zip and traj_ref is not None and traj_est is not None:
            tmp_file_ref = TemporaryFile()
            tmp_file_est = TemporaryFile()
            if type(traj_ref) is PosePath3D or type(traj_est) is PosePath3D:
                traj_type = ".kitti"
                write_kitti_poses_file(tmp_file_ref, traj_ref)
                write_kitti_poses_file(tmp_file_est, traj_est)
            else:
                traj_type = ".tum"
                write_tum_trajectory_file(tmp_file_ref, traj_ref)
                write_tum_trajectory_file(tmp_file_est, traj_est)
            tmp_file_ref.seek(0)
            tmp_file_est.seek(0)
            archive.writestr("traj_ref" + traj_type, tmp_file_ref.read())
            archive.writestr("traj_est" + traj_type, tmp_file_est.read())
            tmp_file_ref.close()
            tmp_file_est.close()
예제 #6
0
파일: main_config.py 프로젝트: skylook/evo
def main():
    import argcomplete
    basic_desc = "crappy configuration tool"
    lic = "(c) [email protected]"
    shared_parser = argparse.ArgumentParser(add_help=False)
    shared_parser.add_argument("--no_color",
                               help="don't color output",
                               action="store_false",
                               default=True)
    main_parser = argparse.ArgumentParser(description="%s %s" %
                                          (basic_desc, lic))
    sub_parsers = main_parser.add_subparsers(dest="subcommand")
    sub_parsers.required = True

    show_parser = sub_parsers.add_parser(
        "show",
        description="show configuration - %s" % lic,
        parents=[shared_parser])
    show_parser.add_argument(
        "config",
        help="optional config file to display (default: package settings)",
        nargs='?')
    show_parser.add_argument("--brief",
                             help="show only the .json data",
                             action="store_true")

    set_parser = sub_parsers.add_parser(
        "set",
        description=SET_HELP,
        parents=[shared_parser],
        formatter_class=argparse.RawTextHelpFormatter)
    set_parser.add_argument(
        "-c",
        "--config",
        help="optional config file (default: package settings)",
        default=None)
    set_parser.add_argument(
        "-m",
        "--merge",
        help="optional config file (priority) for union merging",
        default=None)

    gen_parser = sub_parsers.add_parser(
        "generate",
        description=GENERATE_HELP,
        parents=[shared_parser],
        formatter_class=argparse.RawTextHelpFormatter)
    gen_parser.add_argument("-o",
                            "--out",
                            help="path for config file to generate")

    reset_parser = sub_parsers.add_parser(
        "reset",
        description="reset package settings - %s" % lic,
        parents=[shared_parser])

    argcomplete.autocomplete(main_parser)
    args, other_args = main_parser.parse_known_args()
    settings.configure_logging()
    colorama.init()

    config = settings.DEFAULT_PATH
    if hasattr(args, "config"):
        if args.config:
            config = args.config

    if args.subcommand == "show":
        if not args.brief and not args.config:
            logging.info(settings.DEFAULT_SETTINGS_HELP)
            logging.info(SEP + "\n" + config + "\n" + SEP)
        show(config, colored=args.no_color)
        if config == settings.DEFAULT_PATH and not args.brief:
            logging.info(SEP + "\nsee text above for parameter descriptions")

    elif args.subcommand == "set":
        if not os.access(config, os.W_OK):
            logging.info("no permission to modify " + config)
            sys.exit()
        if other_args or args.merge:
            logging.info(SEP + "\nold configuration:\n" + SEP)
            show(config, colored=args.no_color)
            try:
                set_cfg(config, other_args)
            except ConfigError as e:
                logging.error(e)
                sys.exit(1)
            if args.merge:
                merge_json_union(config, args.merge)
            logging.info(SEP + "\nnew configuration:\n" + SEP)
            show(config, colored=args.no_color)
        else:
            logging.info("no configuration parameters given (see --help)")

    elif args.subcommand == "generate":
        if other_args:
            logging.info(SEP + "\nparsed by argparse:\n" + str(other_args))
            logging.info(
                SEP + "\nWARNING:\n" +
                "make sure you use the 'long-style' -- options (e.g. --plot) if possible\n"
                + "and no combined 'short' - flags, (e.g. -avp)\n" + SEP)
            data = generate(other_args)
            log_info_dict_json(data, colored=args.no_color)
            if args.out and user.check_and_confirm_overwrite(args.out):
                with open(args.out, 'w') as out:
                    out.write(json.dumps(data, indent=4, sort_keys=True))
            elif not args.out:
                logging.info(
                    SEP +
                    "\nno output file specified (-o / --out) - doing nothing\n"
                    + SEP)
        else:
            logging.info("no command line arguments given (see --help)")

    elif args.subcommand == "reset":
        if not os.access(config, os.W_OK):
            logging.info("no permission to modify" + config)
            sys.exit()
        if user.confirm(
                "reset the package settings to the default settings? (y/n)"):
            reset_pkg_settings(settings.DEFAULT_PATH)
            logging.info(SEP + "\npackage settings after reset:\n" + SEP)
            show(settings.DEFAULT_PATH, colored=args.no_color)
예제 #7
0
파일: main_res.py 프로젝트: YacongWang/evo
def run(args):
    import os
    import sys
    import logging

    import pandas as pd
    import numpy as np
    from natsort import natsorted

    from evo.tools import file_interface, user, settings
    from evo.tools.settings import SETTINGS

    settings.configure_logging(args.verbose, args.silent, args.debug)
    if args.debug:
        import pprint
        logging.debug("main_parser config:\n"
                      + pprint.pformat({arg: getattr(args, arg) for arg in vars(args)}) + "\n")

    # store data in Pandas data frames for easier analysis
    raw_df = pd.DataFrame()
    stat_df = pd.DataFrame()
    info_df = pd.DataFrame()
    use_seconds = False

    for result_file in args.result_files:
        logging.debug(SEP)
        result_obj = file_interface.load_res_file(result_file, True)
        short_est_name = os.path.splitext(os.path.basename(result_obj.info["est_name"]))[0]
        error_array = result_obj.np_arrays["error_array"]
        if "seconds_from_start" in result_obj.np_arrays:
            seconds_from_start = result_obj.np_arrays["seconds_from_start"]
        else:
            seconds_from_start = None

        if not args.no_warnings and (short_est_name in info_df.columns):
            logging.warning("double entry detected: " + short_est_name)
            if not user.confirm("ignore? enter 'y' to go on or any other key to quit"):
                sys.exit()

        if SETTINGS.plot_usetex:
            short_est_name = short_est_name.replace("_", "\\_")

        if args.use_abs_time:
            if "timestamps" in result_obj.np_arrays:
                index = result_obj.np_arrays["timestamps"]
                use_seconds = True
            else:
                raise RuntimeError("no timestamps found for --use_abs_time")
        elif seconds_from_start is not None:
            index = seconds_from_start.tolist()
            use_seconds = True
        else:
            index = np.arange(0, error_array.shape[0])

        result_obj.info["traj. backup?"] = \
            all(k in result_obj.trajectories for k in ("traj_ref", "traj_est"))
        result_obj.info["res_file"] = result_file
        new_raw_df = pd.DataFrame({short_est_name: error_array.tolist()}, index=index)
        duplicates = new_raw_df.index.get_level_values(0).get_duplicates()
        if len(duplicates) != 0:
            logging.warning("duplicate indices in error array of {} - "
                            "keeping only first occurrence of duplicates".format(result_file))
            new_raw_df.drop_duplicates(keep="first", inplace=True)

        new_info_df = pd.DataFrame({short_est_name: result_obj.info})
        new_stat_df = pd.DataFrame({short_est_name: result_obj.stats})
        # natural sort num strings "10" "100" "20" -> "10" "20" "100"
        new_stat_df = new_stat_df.reindex(index=natsorted(new_stat_df.index))
        # column-wise concatenation
        raw_df = pd.concat([raw_df, new_raw_df], axis=1)
        info_df = pd.concat([info_df, new_info_df], axis=1)
        stat_df = pd.concat([stat_df, new_stat_df], axis=1)
        # if verbose: log infos of the current data
        logging.debug("\n" + result_obj.pretty_str(title=True, stats=False, info=True))

    logging.debug(SEP)
    logging.info("\nstatistics overview:\n" + stat_df.T.to_string(line_width=80) + "\n")

    # check titles
    first_title = info_df.ix["title", 0]
    first_res_file = info_df.ix["res_file", 0]
    if args.save_table or args.plot or args.save_plot:
        for short_est_name, column in info_df.iteritems():
            if column.ix["title"] != first_title and not args.no_warnings:
                logging.info(SEP)
                msg = ("mismatching titles, you probably use data from different metrics"
                       + "\nconflict:\n{} {}\n{}\n".format("<"*7, first_res_file, first_title)
                       + "{}\n{}\n".format("="*7, column.ix["title"])
                       + "{} {}\n\n".format(">"*7, column.ix["res_file"])
                       + "only the first one will be used as the title!")
                logging.warning(msg)
                if not user.confirm("plot/save anyway? - enter 'y' or any other key to exit"):
                    sys.exit()

    if args.save_table:
        logging.debug(SEP)
        if args.no_warnings or user.check_and_confirm_overwrite(args.save_table):
            table_fmt = SETTINGS.table_export_format
            if SETTINGS.table_export_transpose:
                getattr(stat_df.T, "to_" + table_fmt)(args.save_table)
            else:
                getattr(stat_df, "to_" + table_fmt)(args.save_table)
            logging.debug(table_fmt + " table saved to: " + args.save_table)

    if args.plot or args.save_plot or args.serialize_plot:
        # check if data has NaN "holes" due to different indices
        inconsistent = raw_df.isnull().values.any()
        if inconsistent and not args.no_warnings:
            logging.debug(SEP)
            logging.warning("data lengths/indices are not consistent, plotting could make no sense")

        from evo.tools import plot
        import matplotlib.pyplot as plt
        import seaborn as sns
        import math
        from scipy import stats

        # use default plot settings
        figsize = (SETTINGS.plot_figsize[0], SETTINGS.plot_figsize[1])
        use_cmap = SETTINGS.plot_multi_cmap.lower() != "none"
        colormap = SETTINGS.plot_multi_cmap if use_cmap else None
        linestyles = ["-o" for x in args.result_files] if args.plot_markers else None

        # labels according to first dataset
        title = first_title
        if "xlabel" in info_df.ix[:, 0].index:
            index_label = info_df.ix["xlabel", 0]
        else:
            index_label = "$t$ (s)" if use_seconds else "index"
        metric_label = info_df.ix["label", 0]

        plot_collection = plot.PlotCollection(title)
        # raw value plot
        fig_raw = plt.figure(figsize=figsize)
        # handle NaNs from concat() above
        raw_df.interpolate(method="index").plot(ax=fig_raw.gca(), colormap=colormap,
                                                style=linestyles, title=first_title)
        plt.xlabel(index_label)
        plt.ylabel(metric_label)
        plt.legend(frameon=True)
        plot_collection.add_figure("raw", fig_raw)

        # statistics plot
        fig_stats = plt.figure(figsize=figsize)
        exclude = stat_df.index.isin(["sse"])  # don't plot sse
        stat_df[~exclude].plot(kind="barh", ax=fig_stats.gca(), colormap=colormap, stacked=False)
        plt.xlabel(metric_label)
        plt.legend(frameon=True)
        plot_collection.add_figure("stats", fig_stats)

        # grid of distribution plots
        raw_tidy = pd.melt(raw_df, value_vars=list(raw_df.columns.values), var_name="estimate",
                           value_name=metric_label)
        col_wrap = 2 if len(args.result_files) <= 2 else math.ceil(len(args.result_files) / 2.0)
        dist_grid = sns.FacetGrid(raw_tidy, col="estimate", col_wrap=col_wrap)
        dist_grid.map(sns.distplot, metric_label)  # fits=stats.gamma
        plot_collection.add_figure("histogram", dist_grid.fig)

        # box plot
        fig_box = plt.figure(figsize=figsize)
        ax = sns.boxplot(x=raw_tidy["estimate"], y=raw_tidy[metric_label], ax=fig_box.gca())
        # ax.set_xticklabels(labels=[item.get_text() for item in ax.get_xticklabels()], rotation=30)
        plot_collection.add_figure("box_plot", fig_box)

        # violin plot
        fig_violin = plt.figure(figsize=figsize)
        ax = sns.violinplot(x=raw_tidy["estimate"], y=raw_tidy[metric_label], ax=fig_violin.gca())
        # ax.set_xticklabels(labels=[item.get_text() for item in ax.get_xticklabels()], rotation=30)
        plot_collection.add_figure("violin_histogram", fig_violin)

        if args.plot:
            plot_collection.show()
        if args.save_plot:
            logging.debug(SEP)
            plot_collection.export(args.save_plot, confirm_overwrite=not args.no_warnings)
        if args.serialize_plot:
            logging.debug(SEP)
            plot_collection.serialize(args.serialize_plot, confirm_overwrite=not args.no_warnings)