mirror of
https://github.com/Stone-Red-Code/dvc.git
synced 2026-11-02 07:18:25 +01:00
experiments: add options to include/exclude columns in exp show (#4375)
* experiments: add options to include/exclude specific metrics/params columns in `dvc exp show` * allow param/metric file to be provided to keep consistency with other dvc commands * match nested params/metrics names
This commit is contained in:
+118
-5
@@ -2,14 +2,57 @@ import argparse
|
||||
import io
|
||||
import logging
|
||||
from collections import OrderedDict
|
||||
from itertools import groupby
|
||||
from typing import Iterable, Optional
|
||||
|
||||
from dvc.command.base import CmdBase, append_doc_link, fix_subparsers
|
||||
from dvc.command.metrics import DEFAULT_PRECISION
|
||||
from dvc.exceptions import DvcException
|
||||
from dvc.exceptions import DvcException, InvalidArgumentError
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def _filter_names(
|
||||
names: Iterable,
|
||||
label: str,
|
||||
include: Optional[Iterable],
|
||||
exclude: Optional[Iterable],
|
||||
):
|
||||
if include and exclude:
|
||||
intersection = set(include) & set(exclude)
|
||||
if intersection:
|
||||
values = ", ".join(intersection)
|
||||
raise InvalidArgumentError(
|
||||
f"'{values}' specified in both --include-{label} and"
|
||||
f" --exclude-{label}"
|
||||
)
|
||||
|
||||
names = {tuple(name.split(".")) for name in names}
|
||||
|
||||
def _filter(filters, update_func):
|
||||
filters = {tuple(name.split(".")) for name in filters}
|
||||
for length, groups in groupby(filters, len):
|
||||
for group in groups:
|
||||
matches = [name for name in names if name[:length] == group]
|
||||
if not matches:
|
||||
name = ".".join(group)
|
||||
raise InvalidArgumentError(
|
||||
f"'{name}' does not match any known {label}"
|
||||
)
|
||||
update_func(matches)
|
||||
|
||||
if include:
|
||||
ret = set()
|
||||
_filter(include, ret.update)
|
||||
else:
|
||||
ret = set(names)
|
||||
|
||||
if exclude:
|
||||
_filter(exclude, ret.difference_update)
|
||||
|
||||
return {".".join(name) for name in ret}
|
||||
|
||||
|
||||
def _update_names(names, items):
|
||||
from flatten_json import flatten
|
||||
|
||||
@@ -21,7 +64,7 @@ def _update_names(names, items):
|
||||
names.add(name)
|
||||
|
||||
|
||||
def _collect_names(all_experiments):
|
||||
def _collect_names(all_experiments, **kwargs):
|
||||
metric_names = set()
|
||||
param_names = set()
|
||||
|
||||
@@ -30,6 +73,19 @@ def _collect_names(all_experiments):
|
||||
_update_names(metric_names, exp.get("metrics", {}).items())
|
||||
_update_names(param_names, exp.get("params", {}).items())
|
||||
|
||||
metric_names = _filter_names(
|
||||
metric_names,
|
||||
"metrics",
|
||||
kwargs.get("include_metrics"),
|
||||
kwargs.get("exclude_metrics"),
|
||||
)
|
||||
param_names = _filter_names(
|
||||
param_names,
|
||||
"params",
|
||||
kwargs.get("include_params"),
|
||||
kwargs.get("exclude_params"),
|
||||
)
|
||||
|
||||
return sorted(metric_names), sorted(param_names)
|
||||
|
||||
|
||||
@@ -83,11 +139,33 @@ def _collect_rows(
|
||||
yield row, style
|
||||
|
||||
|
||||
def _show_experiments(all_experiments, console, precision=None):
|
||||
def _parse_list(param_list):
|
||||
ret = []
|
||||
for param_str in param_list:
|
||||
# we don't care about filename prefixes for show, silently
|
||||
# ignore it if provided to keep usage consistent with other
|
||||
# metric/param list command options
|
||||
_, _, param_str = param_str.rpartition(":")
|
||||
ret.extend(param_str.split(","))
|
||||
return ret
|
||||
|
||||
|
||||
def _show_experiments(all_experiments, console, precision=None, **kwargs):
|
||||
from rich.table import Table
|
||||
from dvc.scm.git import Git
|
||||
|
||||
metric_names, param_names = _collect_names(all_experiments)
|
||||
include_metrics = _parse_list(kwargs.get("include_metrics", []))
|
||||
exclude_metrics = _parse_list(kwargs.get("exclude_metrics", []))
|
||||
include_params = _parse_list(kwargs.get("include_params", []))
|
||||
exclude_params = _parse_list(kwargs.get("exclude_params", []))
|
||||
|
||||
metric_names, param_names = _collect_names(
|
||||
all_experiments,
|
||||
include_metrics=include_metrics,
|
||||
exclude_metrics=exclude_metrics,
|
||||
include_params=include_params,
|
||||
exclude_params=exclude_params,
|
||||
)
|
||||
|
||||
table = Table()
|
||||
table.add_column("Experiment", no_wrap=True)
|
||||
@@ -136,7 +214,14 @@ class CmdExperimentsShow(CmdBase):
|
||||
file=io.StringIO(), force_terminal=True, width=9999
|
||||
)
|
||||
|
||||
_show_experiments(all_experiments, console)
|
||||
_show_experiments(
|
||||
all_experiments,
|
||||
console,
|
||||
include_metrics=self.args.include_metrics,
|
||||
exclude_metrics=self.args.exclude_metrics,
|
||||
include_params=self.args.include_params,
|
||||
exclude_params=self.args.exclude_params,
|
||||
)
|
||||
|
||||
if not self.args.no_pager:
|
||||
pager(console.file.getvalue())
|
||||
@@ -285,6 +370,34 @@ def add_parser(subparsers, parent_parser):
|
||||
default=False,
|
||||
help="Do not pipe output into a pager.",
|
||||
)
|
||||
experiments_show_parser.add_argument(
|
||||
"--include-metrics",
|
||||
action="append",
|
||||
default=[],
|
||||
help="Include the specified metrics in output table.",
|
||||
metavar="<metrics_list>",
|
||||
)
|
||||
experiments_show_parser.add_argument(
|
||||
"--exclude-metrics",
|
||||
action="append",
|
||||
default=[],
|
||||
help="Exclude the specified metrics from output table.",
|
||||
metavar="<metrics_list>",
|
||||
)
|
||||
experiments_show_parser.add_argument(
|
||||
"--include-params",
|
||||
action="append",
|
||||
default=[],
|
||||
help="Include the specified params in output table.",
|
||||
metavar="<params_list>",
|
||||
)
|
||||
experiments_show_parser.add_argument(
|
||||
"--exclude-params",
|
||||
action="append",
|
||||
default=[],
|
||||
help="Exclude the specified params from output table.",
|
||||
metavar="<params_list>",
|
||||
)
|
||||
experiments_show_parser.set_defaults(func=CmdExperimentsShow)
|
||||
|
||||
EXPERIMENTS_CHECKOUT_HELP = "Checkout experiments."
|
||||
|
||||
Reference in New Issue
Block a user