mirror of
https://github.com/Stone-Red-Code/dvc.git
synced 2026-11-11 07:18:28 +01:00
* run: add --plot/--plot-no-cache Part of #3409 * plot: move show/diff to API * plots: show marked plots by default Involves some refactoring to make plots comply with the rest of the code base. * dvc.yaml: use top-level metrics and plots * dvc.yaml: add support for plot template * plots: add support for templates in dvc.yaml * dvc.yaml: allow metrics/plots to have persist/cache * plots: render single page by-default and introduce --show-json * plot: use "working tree" instead of "workspace" Just to sync this with the rest of the codebase. We should consider renaming it to "workspace" everywhere, but for now I opt to not touch it to not break something that depends on it. * plots: rename -f|--file to -o|--out Better corresponds to other commands like `import`. * plots: use RepoTree and brancher instead of api * stage: get rid of OutputParams * tests: plots: add simple diff test * plots: use `--targets` instead of `--datafile` Makes it comply with `dvc metrics/params` CLI options. * tests: unit: plots: add --show-json test * stage: cleanup exception for format error Based on feedback from the users. * lockfile: use relpath in corruption error
230 lines
6.8 KiB
Python
230 lines
6.8 KiB
Python
import argparse
|
|
import logging
|
|
import os
|
|
|
|
from dvc.command.base import CmdBase, append_doc_link, fix_subparsers
|
|
from dvc.exceptions import DvcException
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
PAGE_HTML = """<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>DVC Plot</title>
|
|
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
|
|
<script src="https://cdn.jsdelivr.net/npm/[email protected]"></script>
|
|
</head>
|
|
<body>
|
|
{divs}
|
|
</body>
|
|
</html>"""
|
|
|
|
DIV_HTML = """<div id = "{id}"></div>
|
|
<script type = "text/javascript">
|
|
var spec = {vega_json};
|
|
vegaEmbed('#{id}', spec);
|
|
</script>"""
|
|
|
|
|
|
class CmdPlots(CmdBase):
|
|
def _func(self, *args, **kwargs):
|
|
raise NotImplementedError
|
|
|
|
def run(self):
|
|
fields = None
|
|
jsonpath = None
|
|
if self.args.select:
|
|
if self.args.select.startswith("$"):
|
|
jsonpath = self.args.select
|
|
else:
|
|
fields = set(self.args.select.split(","))
|
|
try:
|
|
plots = self._func(
|
|
targets=self.args.targets,
|
|
template=self.args.template,
|
|
fields=fields,
|
|
x_field=self.args.x,
|
|
y_field=self.args.y,
|
|
path=jsonpath,
|
|
csv_header=not self.args.no_csv_header,
|
|
title=self.args.title,
|
|
x_title=self.args.xlab,
|
|
y_title=self.args.ylab,
|
|
)
|
|
|
|
if self.args.show_json:
|
|
import json
|
|
|
|
logger.info(json.dumps(plots))
|
|
return 0
|
|
|
|
divs = [
|
|
DIV_HTML.format(id=f"plot{i}", vega_json=plot)
|
|
for i, plot in enumerate(plots.values())
|
|
]
|
|
html = PAGE_HTML.format(divs="\n".join(divs))
|
|
path = self.args.out or "plots.html"
|
|
|
|
with open(path, "w") as fobj:
|
|
fobj.write(html)
|
|
|
|
logger.info(
|
|
"file://{}".format(os.path.join(self.repo.root_dir, path))
|
|
)
|
|
|
|
except DvcException:
|
|
logger.exception("")
|
|
return 1
|
|
|
|
return 0
|
|
|
|
|
|
class CmdPlotsShow(CmdPlots):
|
|
def _func(self, *args, **kwargs):
|
|
return self.repo.plots.show(*args, **kwargs)
|
|
|
|
|
|
class CmdPlotsDiff(CmdPlots):
|
|
def _func(self, *args, **kwargs):
|
|
return self.repo.plots.diff(*args, revs=self.args.revisions, **kwargs)
|
|
|
|
|
|
def add_parser(subparsers, parent_parser):
|
|
PLOTS_HELP = (
|
|
"Generating plots for metrics stored in structured files "
|
|
"(JSON, CSV, TSV)."
|
|
)
|
|
|
|
plots_parser = subparsers.add_parser(
|
|
"plots",
|
|
parents=[parent_parser],
|
|
description=append_doc_link(PLOTS_HELP, "plots"),
|
|
help=PLOTS_HELP,
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
)
|
|
plots_subparsers = plots_parser.add_subparsers(
|
|
dest="cmd",
|
|
help="Use `dvc plots CMD --help` to display command-specific help.",
|
|
)
|
|
|
|
fix_subparsers(plots_subparsers)
|
|
|
|
SHOW_HELP = "Generate a plots image file from a metrics file."
|
|
plots_show_parser = plots_subparsers.add_parser(
|
|
"show",
|
|
parents=[parent_parser],
|
|
description=append_doc_link(SHOW_HELP, "plots/show"),
|
|
help=SHOW_HELP,
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
)
|
|
plots_show_parser.add_argument(
|
|
"-t",
|
|
"--template",
|
|
nargs="?",
|
|
default=None,
|
|
help="File to be injected with data.",
|
|
)
|
|
plots_show_parser.add_argument(
|
|
"-o", "--out", default=None, help="Destination path to save plots to.",
|
|
)
|
|
plots_show_parser.add_argument(
|
|
"-s",
|
|
"--select",
|
|
default=None,
|
|
help="Choose which field(s) or JSONPath to include in the plots.",
|
|
)
|
|
plots_show_parser.add_argument(
|
|
"-x", default=None, help="Field name for x axis."
|
|
)
|
|
plots_show_parser.add_argument(
|
|
"-y", default=None, help="Field name for y axis."
|
|
)
|
|
plots_show_parser.add_argument(
|
|
"--no-csv-header",
|
|
action="store_true",
|
|
default=False,
|
|
help="Required when CSV or TSV datafile does not have a header.",
|
|
)
|
|
plots_show_parser.add_argument(
|
|
"--show-json",
|
|
action="store_true",
|
|
default=False,
|
|
help="Show output in JSON format.",
|
|
)
|
|
plots_show_parser.add_argument("--title", default=None, help="Plot title.")
|
|
plots_show_parser.add_argument(
|
|
"--xlab", default=None, help="X axis title."
|
|
)
|
|
plots_show_parser.add_argument(
|
|
"--ylab", default=None, help="Y axis title."
|
|
)
|
|
plots_show_parser.add_argument(
|
|
"targets",
|
|
nargs="*",
|
|
help="Metrics files to visualize. Shows all plots by default.",
|
|
)
|
|
plots_show_parser.set_defaults(func=CmdPlotsShow)
|
|
|
|
PLOTS_DIFF_HELP = (
|
|
"Plot differences in metrics between commits in the DVC "
|
|
"repository, or between the last commit and the workspace."
|
|
)
|
|
plots_diff_parser = plots_subparsers.add_parser(
|
|
"diff",
|
|
parents=[parent_parser],
|
|
description=append_doc_link(PLOTS_DIFF_HELP, "plots/diff"),
|
|
help=PLOTS_DIFF_HELP,
|
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
)
|
|
plots_diff_parser.add_argument(
|
|
"-t",
|
|
"--template",
|
|
nargs="?",
|
|
default=None,
|
|
help="File to be injected with data.",
|
|
)
|
|
plots_diff_parser.add_argument(
|
|
"--targets",
|
|
nargs="*",
|
|
help="Metrics file to visualize. Shows all plots by default.",
|
|
)
|
|
plots_diff_parser.add_argument(
|
|
"-o", "--out", default=None, help="Destination path to save plots to.",
|
|
)
|
|
plots_diff_parser.add_argument(
|
|
"-s",
|
|
"--select",
|
|
default=None,
|
|
help="Choose which field(s) or JSONPath to include in the plot.",
|
|
)
|
|
plots_diff_parser.add_argument(
|
|
"-x", default=None, help="Field name for x axis."
|
|
)
|
|
plots_diff_parser.add_argument(
|
|
"-y", default=None, help="Field name for y axis."
|
|
)
|
|
plots_diff_parser.add_argument(
|
|
"--no-csv-header",
|
|
action="store_true",
|
|
default=False,
|
|
help="Provided CSV ot TSV datafile does not have a header.",
|
|
)
|
|
plots_diff_parser.add_argument(
|
|
"--show-json",
|
|
action="store_true",
|
|
default=False,
|
|
help="Show output in JSON format.",
|
|
)
|
|
plots_diff_parser.add_argument("--title", default=None, help="Plot title.")
|
|
plots_diff_parser.add_argument(
|
|
"--xlab", default=None, help="X axis title."
|
|
)
|
|
plots_diff_parser.add_argument(
|
|
"--ylab", default=None, help="Y axis title."
|
|
)
|
|
plots_diff_parser.add_argument(
|
|
"revisions", nargs="*", default=None, help="Git commits to plot from",
|
|
)
|
|
plots_diff_parser.set_defaults(func=CmdPlotsDiff)
|