def test_show_non_plot(tmp_dir, scm, use_dvc): metric = [ {"first_val": 100, "val": 2}, {"first_val": 200, "val": 3}, ] _write_json(tmp_dir, metric, "metric.json") if use_dvc: dvc = Repo.init() else: dvc = Repo(uninitialized=True) plot_string = dvc.plots.show(targets=["metric.json"])["metric.json"] plot_content = json.loads(plot_string) assert plot_content["data"]["values"] == [ { "val": 2, PlotData.INDEX_FIELD: 0, "first_val": 100, "rev": "workspace", }, { "val": 3, PlotData.INDEX_FIELD: 1, "first_val": 200, "rev": "workspace", }, ] assert plot_content["encoding"]["x"]["field"] == PlotData.INDEX_FIELD assert plot_content["encoding"]["y"]["field"] == "val" if not use_dvc: assert not (tmp_dir / ".dvc").exists()
def test_plot_json_single_val(tmp_dir, scm, dvc, run_copy_metrics): metric = [{"val": 2}, {"val": 3}] _write_json(tmp_dir, metric, "metric_t.json") run_copy_metrics( "metric_t.json", "metric.json", plots_no_cache=["metric.json"], commit="first run", ) plot_string = dvc.plots.show()["metric.json"] plot_json = json.loads(plot_string) assert plot_json["data"]["values"] == [ { "val": 2, PlotData.INDEX_FIELD: 0, "rev": "workspace" }, { "val": 3, PlotData.INDEX_FIELD: 1, "rev": "workspace" }, ] assert plot_json["encoding"]["x"]["field"] == PlotData.INDEX_FIELD assert plot_json["encoding"]["y"]["field"] == "val"
def test_plot_confusion_normalized(tmp_dir, dvc, run_copy_metrics): confusion_matrix = [ {"predicted": "B", "actual": "A"}, {"predicted": "A", "actual": "A"}, ] _write_json(tmp_dir, confusion_matrix, "metric_t.json") run_copy_metrics( "metric_t.json", "metric.json", plots_no_cache=["metric.json"], commit="first run", ) props = { "template": "confusion_normalized", "x": "predicted", "y": "actual", } plot_string = dvc.plots.show(props=props)["metric.json"] plot_content = json.loads(plot_string) assert plot_content["data"]["values"] == [ {"predicted": "B", "actual": "A", "rev": "workspace"}, {"predicted": "A", "actual": "A", "rev": "workspace"}, ] assert plot_content["spec"]["transform"][0]["groupby"] == [ "actual", "predicted", ] assert plot_content["spec"]["transform"][1]["groupby"] == ["rev", "actual"] assert plot_content["spec"]["encoding"]["x"]["field"] == "predicted" assert plot_content["spec"]["encoding"]["y"]["field"] == "actual"
def test_plot_cache_missing(tmp_dir, scm, dvc, caplog, run_copy_metrics): metric = [{"y": 2}, {"y": 3}] _write_json(tmp_dir, metric, "metric_t.json") stage = run_copy_metrics( "metric_t.json", "metric.json", plots=["metric.json"], commit="there is metric", ) scm.tag("v1") # Make a different plot and then remove its datafile metric = [{"y": 3}, {"y": 4}] _write_json(tmp_dir, metric, "metric_t.json") stage = run_copy_metrics( "metric_t.json", "metric.json", plots=["metric.json"], commit="there is an another metric", ) scm.tag("v2") remove(stage.outs[0].fspath) remove(stage.outs[0].cache_path) plots = dvc.plots.show(revs=["v1", "v2"], targets=["metric.json"]) plot_content = json.loads(plots["metric.json"]) assert plot_content["data"]["values"] == [ {"y": 2, PlotData.INDEX_FIELD: 0, "rev": "v1"}, {"y": 3, PlotData.INDEX_FIELD: 1, "rev": "v1"}, ]
def test_plot_choose_columns(tmp_dir, scm, dvc, custom_template, run_copy_metrics): metric = [{"a": 1, "b": 2, "c": 3}, {"a": 2, "b": 3, "c": 4}] _write_json(tmp_dir, metric, "metric_t.json") run_copy_metrics( "metric_t.json", "metric.json", plots_no_cache=["metric.json"], commit="init", tag="v1", ) props = { "template": os.fspath(custom_template), "fields": {"b", "c"}, "x": "b", "y": "c", } plot_string = dvc.plots.show(props=props)["metric.json"] plot_content = json.loads(plot_string) assert plot_content["data"]["values"] == [ { "b": 2, "c": 3, "rev": "workspace" }, { "b": 3, "c": 4, "rev": "workspace" }, ] assert plot_content["encoding"]["x"]["field"] == "b" assert plot_content["encoding"]["y"]["field"] == "c"
def test_show_dir_plots(tmp_dir, dvc, run_copy_metrics): subdir = tmp_dir / "subdir" subdir.mkdir() metric = [{"first_val": 100, "val": 2}, {"first_val": 200, "val": 3}] fname = "file.json" _write_json(tmp_dir, metric, fname) p1 = os.path.join("subdir", "p1.json") p2 = os.path.join("subdir", "p2.json") tmp_dir.dvc.run( cmd=( f"mkdir subdir && python copy.py {fname} {p1} && " f"python copy.py {fname} {p2}" ), deps=[fname], single_stage=False, plots=["subdir"], name="copy_double", ) result = dvc.plots.show(targets=["subdir"]) p1_content = json.loads(result[p1]) p2_content = json.loads(result[p2]) assert p1_content == p2_content result = dvc.plots.show(targets=[p1]) assert set(result.keys()) == {p1} remove(dvc.odb.local.cache_dir) remove(subdir) with pytest.raises(NoMetricsParsedError): dvc.plots.show()
def test_dir_plots(tmp_dir, dvc, run_copy_metrics): subdir = tmp_dir / "subdir" subdir.mkdir() metric = [ { "first_val": 100, "val": 2 }, { "first_val": 200, "val": 3 }, ] fname = "file.json" _write_json(tmp_dir, metric, fname) p1 = os.path.join("subdir", "p1.json") p2 = os.path.join("subdir", "p2.json") tmp_dir.dvc.run( cmd=(f"mkdir subdir && python copy.py {fname} {p1} && " f"python copy.py {fname} {p2}"), deps=[fname], single_stage=False, plots=["subdir"], name="copy_double", ) dvc.plots.modify("subdir", {"title": "TITLE"}) result = dvc.plots.show() p1_content = json.loads(result[p1]) p2_content = json.loads(result[p2]) assert p1_content["title"] == p2_content["title"] == "TITLE"
def test_show_no_repo(tmp_dir): metric = [{"first_val": 100, "val": 2}, {"first_val": 200, "val": 3}] _write_json(tmp_dir, metric, "metric.json") dvc = Repo(uninitialized=True) dvc.plots.show(["metric.json"])
def test_plot_default_choose_column(tmp_dir, scm, dvc, run_copy_metrics): metric = [{"a": 1, "b": 2, "c": 3}, {"a": 2, "b": 3, "c": 4}] _write_json(tmp_dir, metric, "metric_t.json") run_copy_metrics( "metric_t.json", "metric.json", plots_no_cache=["metric.json"], commit="init", tag="v1", ) plot_string = dvc.plots.show(props={"fields": {"b"}})["metric.json"] plot_content = json.loads(plot_string) assert plot_content["data"]["values"] == [ { PlotData.INDEX_FIELD: 0, "b": 2, "rev": "workspace" }, { PlotData.INDEX_FIELD: 1, "b": 3, "rev": "workspace" }, ] assert plot_content["encoding"]["x"]["field"] == PlotData.INDEX_FIELD assert plot_content["encoding"]["y"]["field"] == "b"
def test_plot_even_if_metric_missing(tmp_dir, scm, dvc, caplog, run_copy_metrics): tmp_dir.scm_gen("some_file", "content", commit="there is no metric") scm.tag("v1") metric = [{"y": 2}, {"y": 3}] _write_json(tmp_dir, metric, "metric_t.json") run_copy_metrics( "metric_t.json", "metric.json", plots_no_cache=["metric.json"], commit="there is metric", tag="v2", ) caplog.clear() with caplog.at_level(logging.WARNING, "dvc"): plots = dvc.plots.show(revs=["v1", "v2"], targets=["metric.json"]) assert "'metric.json' was not found at: 'v1'." in caplog.text plot_content = json.loads(plots["metric.json"]) assert plot_content["data"]["values"] == [ { "y": 2, PlotData.INDEX_FIELD: 0, "rev": "v2" }, { "y": 3, PlotData.INDEX_FIELD: 1, "rev": "v2" }, ] assert plot_content["encoding"]["x"]["field"] == PlotData.INDEX_FIELD assert plot_content["encoding"]["y"]["field"] == "y"
def test_show_non_plot_and_plot_with_params(tmp_dir, scm, dvc, run_copy_metrics): metric = [ { "first_val": 100, "val": 2 }, { "first_val": 200, "val": 3 }, ] _write_json(tmp_dir, metric, "metric.json") run_copy_metrics("metric.json", "metric2.json", plots_no_cache=["metric2.json"]) dvc.plots.modify("metric2.json", props={"title": "TITLE"}) result = dvc.plots.show(targets=["metric.json", "metric2.json"]) plot_content = json.loads(result["metric.json"]) plot2_content = json.loads(result["metric2.json"]) assert plot2_content["title"] == "TITLE" assert plot_content != plot2_content plot_content.pop("title") plot2_content.pop("title") assert plot_content == plot2_content
def test_show_from_subdir(tmp_dir, dvc, caplog): subdir = tmp_dir / "subdir" subdir.mkdir() metric = [{"first_val": 100, "val": 2}, {"first_val": 200, "val": 3}] _write_json(subdir, metric, "metric.json") with subdir.chdir(), caplog.at_level(logging.INFO, "dvc"): assert main(["plots", "show", "metric.json"]) == 0 assert subdir.as_uri() in caplog.text assert (subdir / "plots.html").exists()
def test_should_raise_on_no_template(tmp_dir, dvc, run_copy_metrics): metric = [{"val": 2}, {"val": 3}] _write_json(tmp_dir, metric, "metric_t.json") run_copy_metrics( "metric_t.json", "metric.json", plots_no_cache=["metric.json"], commit="first run", ) with pytest.raises(TemplateNotFoundError): props = {"template": "non_existing_template.json"} dvc.plots.show("metric.json", props=props)
def test_show_from_subdir(tmp_dir, dvc, capsys): subdir = tmp_dir / "subdir" subdir.mkdir() metric = [{"first_val": 100, "val": 2}, {"first_val": 200, "val": 3}] _write_json(subdir, metric, "metric.json") with subdir.chdir(): assert main(["plots", "show", "metric.json"]) == 0 out, _ = capsys.readouterr() assert subdir.as_uri() in out assert (subdir / "plots.html").exists()
def test_unset_nonexistent(tmp_dir, dvc, run_copy_metrics, custom_template): metric = [{"a": 1, "b": 2}, {"a": 2, "b": 3}] _write_json(tmp_dir, metric, "metric_t.json") run_copy_metrics( "metric_t.json", "metric.json", plots_no_cache=["metric.json"], name="copy-metrics", single_stage=False, ) with pytest.raises(PropsNotFoundError): dvc.plots.modify("metric.json", unset=["nonexistent"])
def test_plots_modify_existing_template(tmp_dir, dvc, run_copy_metrics, custom_template): metric = [{"a": 1, "b": 2}, {"a": 2, "b": 3}] _write_json(tmp_dir, metric, "metric_t.json") stage = run_copy_metrics( "metric_t.json", "metric.json", plots_no_cache=["metric.json"], name="copy-metrics", single_stage=False, ) dvc.plots.modify("metric.json", props={"template": relpath(custom_template)}) stage = stage.reload() assert stage.outs[0].plot == {"template": relpath(custom_template)}
def test_raise_on_wrong_field(tmp_dir, scm, dvc, run_copy_metrics): metric = [{"val": 2}, {"val": 3}] _write_json(tmp_dir, metric, "metric_t.json") run_copy_metrics( "metric_t.json", "metric.json", plots_no_cache=["metric.json"], commit="first run", ) with pytest.raises(NoFieldInDataError): dvc.plots.show("metric.json", props={"x": "no_val"}) with pytest.raises(NoFieldInDataError): dvc.plots.show("metric.json", props={"y": "no_val"})
def test_bad_template(tmp_dir, dvc, run_copy_metrics): metric = [{"val": 2}, {"val": 3}] _write_json(tmp_dir, metric, "metric_t.json") run_copy_metrics( "metric_t.json", "metric.json", plots_no_cache=["metric.json"], commit="first run", ) tmp_dir.gen("template.json", json.dumps({"a": "b", "c": "d"})) with pytest.raises(BadTemplateError): props = {"template": "template.json"} dvc.plots.show("metric.json", props=props)
def test_plots_modify_should_not_change_lockfile(tmp_dir, dvc, run_copy_metrics, custom_template): _write_json(tmp_dir, [{"a": 1, "b": 2}], "metric_t.json") run_copy_metrics( "metric_t.json", "metric.json", plots_no_cache=["metric.json"], name="copy-metrics", single_stage=False, ) (tmp_dir / PIPELINE_LOCK).unlink() dvc.plots.modify("metric.json", props={"template": relpath(custom_template)}) assert not (tmp_dir / PIPELINE_LOCK).exists()
def test_multiple_plots(tmp_dir, scm, dvc, run_copy_metrics): metric1 = [ OrderedDict([("first_val", 100), ("second_val", 100), ("val", 2)]), OrderedDict([("first_val", 200), ("second_val", 300), ("val", 3)]), ] metric2 = [ OrderedDict([("first_val", 100), ("second_val", 100), ("val", 2)]), OrderedDict([("first_val", 200), ("second_val", 300), ("val", 3)]), ] _write_csv(metric1, "metric_t1.csv") _write_json(tmp_dir, metric2, "metric_t2.json") run_copy_metrics("metric_t1.csv", "metric1.csv", plots_no_cache=["metric1.csv"]) run_copy_metrics("metric_t2.json", "metric2.json", plots_no_cache=["metric2.json"]) assert len(dvc.plots.show().keys()) == 2
def test_diff_dirty(tmp_dir, scm, dvc, run_copy_metrics): metric_1 = [{"y": 2}, {"y": 3}] _write_json(tmp_dir, metric_1, "metric_t.json") run_copy_metrics( "metric_t.json", "metric.json", plots_no_cache=["metric.json"], commit="init", ) metric_2 = [{"y": 3}, {"y": 5}] _write_json(tmp_dir, metric_2, "metric_t.json") run_copy_metrics( "metric_t.json", "metric.json", plots_no_cache=["metric.json"], commit="second", ) metric_3 = [{"y": 5}, {"y": 6}] _write_json(tmp_dir, metric_3, "metric_t.json") run_copy_metrics( "metric_t.json", "metric.json", plots_no_cache=["metric.json"] ) plot_string = dvc.plots.diff(props={"fields": {"y"}})["metric.json"] plot_content = json.loads(plot_string) assert plot_content["data"]["values"] == [ {"y": 3, PlotData.INDEX_FIELD: 0, "rev": "HEAD"}, {"y": 5, PlotData.INDEX_FIELD: 1, "rev": "HEAD"}, {"y": 5, PlotData.INDEX_FIELD: 0, "rev": "workspace"}, {"y": 6, PlotData.INDEX_FIELD: 1, "rev": "workspace"}, ] assert plot_content["encoding"]["x"]["field"] == PlotData.INDEX_FIELD assert plot_content["encoding"]["y"]["field"] == "y" _write_json(tmp_dir, [{"y": 7}, {"y": 8}], "metric.json") plot_string = dvc.plots.diff(props={"fields": {"y"}})["metric.json"] plot_content = json.loads(plot_string) assert plot_content["data"]["values"] == [ {"y": 3, PlotData.INDEX_FIELD: 0, "rev": "HEAD"}, {"y": 5, PlotData.INDEX_FIELD: 1, "rev": "HEAD"}, {"y": 7, PlotData.INDEX_FIELD: 0, "rev": "workspace"}, {"y": 8, PlotData.INDEX_FIELD: 1, "rev": "workspace"}, ] assert plot_content["encoding"]["x"]["field"] == PlotData.INDEX_FIELD assert plot_content["encoding"]["y"]["field"] == "y"
def test_plot_multiple_revs(tmp_dir, scm, dvc, run_copy_metrics): templates_dir = dvc.plots.templates.templates_dir shutil.copy( os.path.join(templates_dir, "default.json"), os.path.join(templates_dir, "template.json"), ) metric_1 = [{"y": 2}, {"y": 3}] _write_json(tmp_dir, metric_1, "metric_t.json") stage = run_copy_metrics( "metric_t.json", "metric.json", plots_no_cache=["metric.json"], commit="init", tag="v1", ) metric_2 = [{"y": 3}, {"y": 5}] _write_json(tmp_dir, metric_2, "metric_t.json") assert dvc.reproduce(stage.addressing) == [stage] scm.add(["metric.json", stage.path]) scm.commit("second") scm.tag("v2") metric_3 = [{"y": 5}, {"y": 6}] _write_json(tmp_dir, metric_3, "metric_t.json") assert dvc.reproduce(stage.addressing) == [stage] scm.add(["metric.json", stage.path]) scm.commit("third") props = {"template": "template.json"} plot_string = dvc.plots.show(revs=["HEAD", "v2", "v1"], props=props)[ "metric.json" ] plot_content = json.loads(plot_string) assert plot_content["data"]["values"] == [ {"y": 5, PlotData.INDEX_FIELD: 0, "rev": "HEAD"}, {"y": 6, PlotData.INDEX_FIELD: 1, "rev": "HEAD"}, {"y": 3, PlotData.INDEX_FIELD: 0, "rev": "v2"}, {"y": 5, PlotData.INDEX_FIELD: 1, "rev": "v2"}, {"y": 2, PlotData.INDEX_FIELD: 0, "rev": "v1"}, {"y": 3, PlotData.INDEX_FIELD: 1, "rev": "v1"}, ] assert plot_content["encoding"]["x"]["field"] == PlotData.INDEX_FIELD assert plot_content["encoding"]["y"]["field"] == "y"
def test_plot_multiple_revs_default(tmp_dir, scm, dvc, run_copy_metrics): metric_1 = [{"y": 2}, {"y": 3}] _write_json(tmp_dir, metric_1, "metric_t.json") run_copy_metrics( "metric_t.json", "metric.json", plots_no_cache=["metric.json"], commit="init", tag="v1", ) metric_2 = [{"y": 3}, {"y": 5}] _write_json(tmp_dir, metric_2, "metric_t.json") run_copy_metrics( "metric_t.json", "metric.json", plots_no_cache=["metric.json"], commit="second", tag="v2", ) metric_3 = [{"y": 5}, {"y": 6}] _write_json(tmp_dir, metric_3, "metric_t.json") run_copy_metrics( "metric_t.json", "metric.json", plots_no_cache=["metric.json"], commit="third", ) plot_string = dvc.plots.show( revs=["HEAD", "v2", "v1"], props={"fields": {"y"}} )["metric.json"] plot_content = json.loads(plot_string) assert plot_content["data"]["values"] == [ {"y": 5, PlotData.INDEX_FIELD: 0, "rev": "HEAD"}, {"y": 6, PlotData.INDEX_FIELD: 1, "rev": "HEAD"}, {"y": 3, PlotData.INDEX_FIELD: 0, "rev": "v2"}, {"y": 5, PlotData.INDEX_FIELD: 1, "rev": "v2"}, {"y": 2, PlotData.INDEX_FIELD: 0, "rev": "v1"}, {"y": 3, PlotData.INDEX_FIELD: 1, "rev": "v1"}, ] assert plot_content["encoding"]["x"]["field"] == PlotData.INDEX_FIELD assert plot_content["encoding"]["y"]["field"] == "y"