mirror of
https://github.com/Stone-Red-Code/dvc.git
synced 2026-11-02 07:18:25 +01:00
plots: standardise across DVC/Studio/VS Code (#9931)
* standardise plot data output * add data required for new anchors to renderer properties * feed dvc-render updates into API output * update --json --split api with new data types (send split anchor definitions as strings) * accomodate zoom and pan anchor * switch anchor_revs to revs_with_datapoints * accomodate height and width anchors * drop terrible idea of holding all data as strings * fix plot having multiple x fields * move inferred properties off vega converter class
This commit is contained in:
@@ -11,7 +11,7 @@ from bs4 import BeautifulSoup
|
||||
from funcy import first
|
||||
|
||||
from dvc.cli import main
|
||||
from dvc.render import REVISION_FIELD, VERSION_FIELD
|
||||
from dvc.render import ANCHOR_DEFINITIONS, FILENAME, REVISION
|
||||
|
||||
JSON_OUT = "vis_data"
|
||||
|
||||
@@ -102,6 +102,9 @@ def verify_vega(
|
||||
html_result,
|
||||
json_result,
|
||||
split_json_result,
|
||||
title,
|
||||
x_label,
|
||||
y_label,
|
||||
):
|
||||
if isinstance(versions, str):
|
||||
versions = [versions]
|
||||
@@ -111,27 +114,60 @@ def verify_vega(
|
||||
assert j[0]["type"] == "vega"
|
||||
assert set(j[0]["revisions"]) == set(versions)
|
||||
|
||||
assert json_result[0]["datapoints"] == split_json_result[0]["datapoints"]
|
||||
assert set(versions) == set(json_result[0]["datapoints"].keys())
|
||||
assert (
|
||||
json_result[0]["content"]["data"]["values"]
|
||||
== split_json_result[0][ANCHOR_DEFINITIONS]["<DVC_METRIC_DATA>"]
|
||||
)
|
||||
|
||||
assert set(versions) == set(json_result[0]["revisions"])
|
||||
|
||||
assert json_result[0]["content"]["data"]["values"]
|
||||
assert html_result["data"]["values"]
|
||||
assert split_json_result[0]["content"]["data"]["values"] == "<DVC_METRIC_DATA>"
|
||||
|
||||
def _assert_templates_equal(html_template, filled_template, split_template):
|
||||
# besides data, json and split json should be equal
|
||||
path = ["data", "values"]
|
||||
content_str = json.dumps(split_json_result[0]["content"])
|
||||
assert "<DVC_METRIC_DATA>" in content_str
|
||||
assert "<DVC_METRIC_X_LABEL>" in content_str
|
||||
assert "<DVC_METRIC_Y_LABEL>" in content_str
|
||||
|
||||
def _assert_templates_equal(
|
||||
html_template, filled_template, split_template, title, x_label, y_label
|
||||
):
|
||||
# besides split anchors, json and split json should be equal
|
||||
paths = [["data", "values"], ["encoding", "color"]]
|
||||
tmp1 = deepcopy(html_template)
|
||||
tmp2 = deepcopy(filled_template)
|
||||
tmp3 = deepcopy(split_template)
|
||||
dpath.set(tmp1, path, {})
|
||||
dpath.set(tmp2, path, {})
|
||||
dpath.set(tmp3, path, {})
|
||||
tmp3 = json.loads(
|
||||
json.dumps(split_template)
|
||||
.replace('"<DVC_METRIC_PLOT_HEIGHT>"', "300")
|
||||
.replace('"<DVC_METRIC_PLOT_WIDTH>"', "300")
|
||||
.replace("<DVC_METRIC_TITLE>", title)
|
||||
.replace("<DVC_METRIC_X_LABEL>", x_label)
|
||||
.replace("<DVC_METRIC_Y_LABEL>", y_label)
|
||||
.replace(
|
||||
'"<DVC_METRIC_ZOOM_AND_PAN>"',
|
||||
json.dumps(
|
||||
{
|
||||
"name": "grid",
|
||||
"select": "interval",
|
||||
"bind": "scales",
|
||||
}
|
||||
),
|
||||
)
|
||||
)
|
||||
for path in paths:
|
||||
dpath.set(tmp1, path, {})
|
||||
dpath.set(tmp2, path, {})
|
||||
dpath.set(tmp3, path, {})
|
||||
|
||||
assert tmp1 == tmp2 == tmp3
|
||||
|
||||
_assert_templates_equal(
|
||||
html_result, json_result[0]["content"], split_json_result[0]["content"]
|
||||
html_result,
|
||||
json_result[0]["content"],
|
||||
split_json_result[0]["content"],
|
||||
title,
|
||||
x_label,
|
||||
y_label,
|
||||
)
|
||||
|
||||
|
||||
@@ -193,17 +229,13 @@ def test_repo_with_plots(tmp_dir, scm, dvc, capsys, run_copy_metrics, repo_with_
|
||||
] == _update_datapoints(
|
||||
linear_v1,
|
||||
{
|
||||
VERSION_FIELD: {
|
||||
"revision": "workspace",
|
||||
"filename": "linear.json",
|
||||
"field": "y",
|
||||
},
|
||||
REVISION: "workspace",
|
||||
},
|
||||
)
|
||||
assert html_result["linear.json"]["data"]["values"] == _update_datapoints(
|
||||
linear_v1,
|
||||
{
|
||||
REVISION_FIELD: "workspace",
|
||||
REVISION: "workspace",
|
||||
},
|
||||
)
|
||||
assert json_data["confusion.json"][0]["content"]["data"][
|
||||
@@ -211,27 +243,29 @@ def test_repo_with_plots(tmp_dir, scm, dvc, capsys, run_copy_metrics, repo_with_
|
||||
] == _update_datapoints(
|
||||
confusion_v1,
|
||||
{
|
||||
VERSION_FIELD: {
|
||||
"revision": "workspace",
|
||||
"filename": "confusion.json",
|
||||
"field": "actual",
|
||||
},
|
||||
REVISION: "workspace",
|
||||
},
|
||||
)
|
||||
assert html_result["confusion.json"]["data"]["values"] == _update_datapoints(
|
||||
confusion_v1,
|
||||
{
|
||||
REVISION_FIELD: "workspace",
|
||||
REVISION: "workspace",
|
||||
},
|
||||
)
|
||||
verify_image(tmp_dir, "workspace", "image.png", image_v1, html_path, json_data)
|
||||
|
||||
for plot in ["linear.json", "confusion.json"]:
|
||||
for plot, title, x_label, y_label in [
|
||||
("linear.json", "linear", "x", "y"),
|
||||
("confusion.json", "confusion matrix", "predicted", "actual"),
|
||||
]:
|
||||
verify_vega(
|
||||
"workspace",
|
||||
html_result[plot],
|
||||
json_data[plot],
|
||||
split_json_data[plot],
|
||||
title,
|
||||
x_label,
|
||||
y_label,
|
||||
)
|
||||
|
||||
verify_vega_props("confusion.json", json_data, **confusion_props)
|
||||
@@ -250,12 +284,18 @@ def test_repo_with_plots(tmp_dir, scm, dvc, capsys, run_copy_metrics, repo_with_
|
||||
verify_image(tmp_dir, "workspace", "image.png", image_v2, html_path, json_data)
|
||||
verify_image(tmp_dir, "HEAD", "image.png", image_v1, html_path, json_data)
|
||||
|
||||
for plot in ["linear.json", "confusion.json"]:
|
||||
for plot, title, x_label, y_label in [
|
||||
("linear.json", "linear", "x", "y"),
|
||||
("confusion.json", "confusion matrix", "predicted", "actual"),
|
||||
]:
|
||||
verify_vega(
|
||||
["HEAD", "workspace"],
|
||||
html_result[plot],
|
||||
json_data[plot],
|
||||
split_json_data[plot],
|
||||
title,
|
||||
x_label,
|
||||
y_label,
|
||||
)
|
||||
verify_vega_props("confusion.json", json_data, **confusion_props)
|
||||
path = tmp_dir / "subdir"
|
||||
@@ -277,31 +317,23 @@ def test_repo_with_plots(tmp_dir, scm, dvc, capsys, run_copy_metrics, repo_with_
|
||||
] == _update_datapoints(
|
||||
linear_v2,
|
||||
{
|
||||
VERSION_FIELD: {
|
||||
"revision": "workspace",
|
||||
"filename": "../linear.json",
|
||||
"field": "y",
|
||||
},
|
||||
REVISION: "workspace",
|
||||
},
|
||||
) + _update_datapoints(
|
||||
linear_v1,
|
||||
{
|
||||
VERSION_FIELD: {
|
||||
"revision": "HEAD",
|
||||
"filename": "../linear.json",
|
||||
"field": "y",
|
||||
},
|
||||
REVISION: "HEAD",
|
||||
},
|
||||
)
|
||||
assert html_result["../linear.json"]["data"]["values"] == _update_datapoints(
|
||||
linear_v2,
|
||||
{
|
||||
REVISION_FIELD: "workspace",
|
||||
REVISION: "workspace",
|
||||
},
|
||||
) + _update_datapoints(
|
||||
linear_v1,
|
||||
{
|
||||
REVISION_FIELD: "HEAD",
|
||||
REVISION: "HEAD",
|
||||
},
|
||||
)
|
||||
assert json_data["../confusion.json"][0]["content"]["data"][
|
||||
@@ -309,43 +341,38 @@ def test_repo_with_plots(tmp_dir, scm, dvc, capsys, run_copy_metrics, repo_with_
|
||||
] == _update_datapoints(
|
||||
confusion_v2,
|
||||
{
|
||||
VERSION_FIELD: {
|
||||
"revision": "workspace",
|
||||
"filename": "../confusion.json",
|
||||
"field": "actual",
|
||||
},
|
||||
REVISION: "workspace",
|
||||
},
|
||||
) + _update_datapoints(
|
||||
confusion_v1,
|
||||
{
|
||||
VERSION_FIELD: {
|
||||
"revision": "HEAD",
|
||||
"filename": "../confusion.json",
|
||||
"field": "actual",
|
||||
},
|
||||
REVISION: "HEAD",
|
||||
},
|
||||
)
|
||||
assert html_result["../confusion.json"]["data"]["values"] == _update_datapoints(
|
||||
confusion_v2,
|
||||
{
|
||||
REVISION_FIELD: "workspace",
|
||||
REVISION: "workspace",
|
||||
},
|
||||
) + _update_datapoints(
|
||||
confusion_v1,
|
||||
{
|
||||
REVISION_FIELD: "HEAD",
|
||||
REVISION: "HEAD",
|
||||
},
|
||||
)
|
||||
|
||||
for plot in [
|
||||
"../linear.json",
|
||||
"../confusion.json",
|
||||
for plot, title, x_label, y_label in [
|
||||
("../linear.json", "linear", "x", "y"),
|
||||
("../confusion.json", "confusion matrix", "predicted", "actual"),
|
||||
]:
|
||||
verify_vega(
|
||||
["HEAD", "workspace"],
|
||||
html_result[plot],
|
||||
json_data[plot],
|
||||
split_json_data[plot],
|
||||
title,
|
||||
x_label,
|
||||
y_label,
|
||||
)
|
||||
verify_image(
|
||||
path,
|
||||
@@ -434,7 +461,7 @@ def test_repo_with_config_plots(tmp_dir, capsys, repo_with_config_plots):
|
||||
repo_state = repo_with_config_plots()
|
||||
plots = next(repo_state)
|
||||
|
||||
html_path, _, __ = call(capsys)
|
||||
html_path, _, split_json_result = call(capsys)
|
||||
|
||||
assert os.path.exists(html_path)
|
||||
html_result = extract_vega_specs(
|
||||
@@ -444,20 +471,28 @@ def test_repo_with_config_plots(tmp_dir, capsys, repo_with_config_plots):
|
||||
"confusion_train_vs_test",
|
||||
],
|
||||
)
|
||||
|
||||
ble = _update_datapoints(
|
||||
plots["data"]["linear_train.json"],
|
||||
{
|
||||
REVISION_FIELD: "linear_train.json",
|
||||
REVISION: "workspace",
|
||||
FILENAME: "linear_train.json",
|
||||
},
|
||||
) + _update_datapoints(
|
||||
plots["data"]["linear_test.json"],
|
||||
{
|
||||
REVISION_FIELD: "linear_test.json",
|
||||
REVISION: "workspace",
|
||||
FILENAME: "linear_test.json",
|
||||
},
|
||||
)
|
||||
|
||||
assert html_result["linear_train_vs_test"]["data"]["values"] == ble
|
||||
# TODO check json results once vscode is able to handle flexible plots
|
||||
assert (
|
||||
split_json_result["data"]["linear_train_vs_test"][0][ANCHOR_DEFINITIONS][
|
||||
"<DVC_METRIC_DATA>"
|
||||
]
|
||||
== ble
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.vscode
|
||||
@@ -466,7 +501,7 @@ def test_repo_with_dvclive_plots(tmp_dir, capsys, repo_with_dvclive_plots):
|
||||
|
||||
for s in ("show", "diff"):
|
||||
_, json_result, split_json_result = call(capsys, subcommand=s)
|
||||
expected_result = {
|
||||
expected_result: Dict[str, Dict[str, list[str]]] = {
|
||||
"data": {
|
||||
"dvclive/plots/metrics/metric.tsv": [],
|
||||
},
|
||||
|
||||
@@ -1,109 +1,87 @@
|
||||
from dvc.render import REVISION_FIELD, REVISIONS_KEY, SRC_FIELD, TYPE_KEY, VERSION_FIELD
|
||||
import json
|
||||
|
||||
import pytest
|
||||
|
||||
from dvc.render import ANCHOR_DEFINITIONS, FILENAME, REVISION, REVISIONS, SRC, TYPE_KEY
|
||||
from dvc.render.convert import to_json
|
||||
|
||||
|
||||
def test_to_json_vega(mocker):
|
||||
vega_renderer = mocker.MagicMock()
|
||||
vega_renderer.TYPE = "vega"
|
||||
vega_renderer.get_revs.return_value = ["bar", "foo"]
|
||||
vega_renderer.get_filled_template.return_value = {"this": "is vega"}
|
||||
vega_renderer.datapoints = [
|
||||
{
|
||||
"x": 1,
|
||||
"y": 2,
|
||||
VERSION_FIELD: {"revision": "foo"},
|
||||
"filename": "foo.json",
|
||||
},
|
||||
{
|
||||
"x": 2,
|
||||
"y": 1,
|
||||
VERSION_FIELD: {"revision": "bar"},
|
||||
"filename": "foo.json",
|
||||
},
|
||||
]
|
||||
result = to_json(vega_renderer)
|
||||
assert result[0] == {
|
||||
TYPE_KEY: vega_renderer.TYPE,
|
||||
REVISIONS_KEY: ["bar", "foo"],
|
||||
REVISIONS: ["bar", "foo"],
|
||||
"content": {"this": "is vega"},
|
||||
"datapoints": {
|
||||
"foo": [
|
||||
{
|
||||
"x": 1,
|
||||
"y": 2,
|
||||
"filename": "foo.json",
|
||||
VERSION_FIELD: {"revision": "foo"},
|
||||
},
|
||||
],
|
||||
"bar": [
|
||||
{
|
||||
"x": 2,
|
||||
"y": 1,
|
||||
"filename": "foo.json",
|
||||
VERSION_FIELD: {"revision": "bar"},
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
vega_renderer.get_filled_template.assert_called()
|
||||
|
||||
|
||||
@pytest.mark.vscode
|
||||
def test_to_json_vega_split(mocker):
|
||||
revs = ["bar", "foo"]
|
||||
content = json.dumps(
|
||||
{
|
||||
"this": "is split vega",
|
||||
"encoding": {"color": "<DVC_METRIC_COLOR>"},
|
||||
"data": {"values": "<DVC_METRIC_DATA>"},
|
||||
}
|
||||
)
|
||||
anchor_definitions = {
|
||||
"<DVC_METRIC_COLOR>": {
|
||||
"field": "rev",
|
||||
"scale": {
|
||||
"domain": revs,
|
||||
"range": ["#ff0000", "#00ff00"],
|
||||
},
|
||||
},
|
||||
"<DVC_METRIC_DATA>": [
|
||||
{
|
||||
"x": 1,
|
||||
"y": 2,
|
||||
REVISION: "foo",
|
||||
FILENAME: "foo.json",
|
||||
},
|
||||
{
|
||||
"x": 2,
|
||||
"y": 1,
|
||||
REVISION: "bar",
|
||||
FILENAME: "foo.json",
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
vega_renderer = mocker.MagicMock()
|
||||
vega_renderer.TYPE = "vega"
|
||||
vega_renderer.get_filled_template.return_value = {"this": "is split vega"}
|
||||
vega_renderer.datapoints = [
|
||||
{
|
||||
"x": 1,
|
||||
"y": 2,
|
||||
VERSION_FIELD: {"revision": "foo"},
|
||||
"filename": "foo.json",
|
||||
},
|
||||
{
|
||||
"x": 2,
|
||||
"y": 1,
|
||||
VERSION_FIELD: {"revision": "bar"},
|
||||
"filename": "foo.json",
|
||||
},
|
||||
]
|
||||
vega_renderer.get_partial_filled_template.return_value = (
|
||||
content,
|
||||
{ANCHOR_DEFINITIONS: anchor_definitions},
|
||||
)
|
||||
vega_renderer.get_revs.return_value = ["bar", "foo"]
|
||||
|
||||
result = to_json(vega_renderer, split=True)
|
||||
assert result[0] == {
|
||||
ANCHOR_DEFINITIONS: anchor_definitions,
|
||||
TYPE_KEY: vega_renderer.TYPE,
|
||||
REVISIONS_KEY: ["bar", "foo"],
|
||||
"content": {"this": "is split vega"},
|
||||
"datapoints": {
|
||||
"foo": [
|
||||
{
|
||||
"x": 1,
|
||||
"y": 2,
|
||||
"filename": "foo.json",
|
||||
VERSION_FIELD: {"revision": "foo"},
|
||||
}
|
||||
],
|
||||
"bar": [
|
||||
{
|
||||
"x": 2,
|
||||
"y": 1,
|
||||
"filename": "foo.json",
|
||||
VERSION_FIELD: {"revision": "bar"},
|
||||
}
|
||||
],
|
||||
},
|
||||
REVISIONS: revs,
|
||||
"content": content,
|
||||
}
|
||||
vega_renderer.get_filled_template.assert_called_with(
|
||||
as_string=False, skip_anchors=["data"]
|
||||
)
|
||||
vega_renderer.get_partial_filled_template.assert_called_once()
|
||||
|
||||
|
||||
def test_to_json_image(mocker):
|
||||
image_renderer = mocker.MagicMock()
|
||||
image_renderer.TYPE = "image"
|
||||
image_renderer.datapoints = [
|
||||
{SRC_FIELD: "contentfoo", REVISION_FIELD: "foo"},
|
||||
{SRC_FIELD: "contentbar", REVISION_FIELD: "bar"},
|
||||
{SRC: "contentfoo", REVISION: "foo"},
|
||||
{SRC: "contentbar", REVISION: "bar"},
|
||||
]
|
||||
result = to_json(image_renderer)
|
||||
assert result[0] == {
|
||||
"url": image_renderer.datapoints[0].get(SRC_FIELD),
|
||||
REVISIONS_KEY: [image_renderer.datapoints[0].get(REVISION_FIELD)],
|
||||
"url": image_renderer.datapoints[0].get(SRC),
|
||||
REVISIONS: [image_renderer.datapoints[0].get(REVISION)],
|
||||
TYPE_KEY: image_renderer.TYPE,
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from dvc.render import REVISION_FIELD, SRC_FIELD
|
||||
from dvc.render import FILENAME, REVISION, SRC
|
||||
from dvc.render.converter.image import ImageConverter
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@ def test_image_converter_no_out():
|
||||
datapoints, _ = converter.flat_datapoints("r")
|
||||
|
||||
assert datapoints[0] == {
|
||||
REVISION_FIELD: "r",
|
||||
"filename": "image.png",
|
||||
SRC_FIELD: converter._encode_image(b"content"),
|
||||
REVISION: "r",
|
||||
FILENAME: "image.png",
|
||||
SRC: converter._encode_image(b"content"),
|
||||
}
|
||||
|
||||
|
||||
@@ -21,9 +21,9 @@ def test_image_converter_with_out(tmp_dir):
|
||||
datapoints, _ = converter.flat_datapoints("r")
|
||||
|
||||
assert datapoints[0] == {
|
||||
REVISION_FIELD: "r",
|
||||
"filename": "image.png",
|
||||
SRC_FIELD: str(tmp_dir / "foo" / "r_image.png"),
|
||||
REVISION: "r",
|
||||
FILENAME: "image.png",
|
||||
SRC: str(tmp_dir / "foo" / "r_image.png"),
|
||||
}
|
||||
|
||||
assert (tmp_dir / "foo" / "r_image.png").read_bytes() == b"content"
|
||||
@@ -37,9 +37,9 @@ def test_image_converter_with_slash_in_revision(tmp_dir):
|
||||
datapoints, _ = converter.flat_datapoints("feature/r")
|
||||
|
||||
assert datapoints[0] == {
|
||||
REVISION_FIELD: "feature/r",
|
||||
"filename": "image.png",
|
||||
SRC_FIELD: str(tmp_dir / "foo" / "feature_r_image.png"),
|
||||
REVISION: "feature/r",
|
||||
FILENAME: "image.png",
|
||||
SRC: str(tmp_dir / "foo" / "feature_r_image.png"),
|
||||
}
|
||||
|
||||
assert (tmp_dir / "foo" / "feature_r_image.png").read_bytes() == b"content"
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import pytest
|
||||
from funcy import set_in
|
||||
|
||||
from dvc.render import VERSION_FIELD
|
||||
from dvc.render import FIELD, FILENAME, REVISION
|
||||
from dvc.render.converter.vega import VegaConverter
|
||||
from dvc.render.match import PlotsData, _squash_plots_properties, match_defs_renderers
|
||||
from dvc.render.match import (
|
||||
PlotsData,
|
||||
_squash_plots_properties,
|
||||
match_defs_renderers,
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
@@ -158,25 +162,23 @@ def test_match_renderers(M):
|
||||
renderer = renderer_with_errors[0]
|
||||
assert renderer.datapoints == [
|
||||
{
|
||||
VERSION_FIELD: {
|
||||
"revision": "v1",
|
||||
"filename": "file.json",
|
||||
"field": "y",
|
||||
},
|
||||
REVISION: "v1",
|
||||
FILENAME: "file.json",
|
||||
FIELD: "y",
|
||||
"x": 1,
|
||||
"y": 1,
|
||||
},
|
||||
{
|
||||
VERSION_FIELD: {
|
||||
"revision": "v1",
|
||||
"filename": "file.json",
|
||||
"field": "y",
|
||||
},
|
||||
REVISION: "v1",
|
||||
FILENAME: "file.json",
|
||||
FIELD: "y",
|
||||
"x": 2,
|
||||
"y": 2,
|
||||
},
|
||||
]
|
||||
assert renderer.properties == {
|
||||
"anchors_y_definitions": [{FILENAME: "file.json", FIELD: "y"}],
|
||||
"revs_with_datapoints": ["v1"],
|
||||
"title": "plot_id_1",
|
||||
"x": "x",
|
||||
"y": "y",
|
||||
|
||||
@@ -3,7 +3,7 @@ from collections import OrderedDict
|
||||
import pytest
|
||||
|
||||
from dvc.exceptions import DvcException
|
||||
from dvc.render import VERSION_FIELD
|
||||
from dvc.render import FIELD, FILENAME, REVISION
|
||||
from dvc.render.converter.vega import FieldNotFoundError, VegaConverter, _lists
|
||||
|
||||
|
||||
@@ -35,23 +35,25 @@ def test_finding_lists(dictionary, expected_result):
|
||||
{
|
||||
"v": 1,
|
||||
"step": 0,
|
||||
VERSION_FIELD: {
|
||||
"revision": "r",
|
||||
"filename": "f",
|
||||
"field": "v",
|
||||
},
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "v",
|
||||
},
|
||||
{
|
||||
"v": 2,
|
||||
"step": 1,
|
||||
VERSION_FIELD: {
|
||||
"revision": "r",
|
||||
"filename": "f",
|
||||
"field": "v",
|
||||
},
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "v",
|
||||
},
|
||||
],
|
||||
{"x": "step", "y": "v", "x_label": "step", "y_label": "v"},
|
||||
{
|
||||
"anchors_y_definitions": [{FILENAME: "f", FIELD: "v"}],
|
||||
"x": "step",
|
||||
"y": "v",
|
||||
"x_label": "step",
|
||||
"y_label": "v",
|
||||
},
|
||||
id="default_x_y",
|
||||
),
|
||||
pytest.param(
|
||||
@@ -61,23 +63,25 @@ def test_finding_lists(dictionary, expected_result):
|
||||
{
|
||||
"v": 1,
|
||||
"v2": 0.1,
|
||||
VERSION_FIELD: {
|
||||
"revision": "r",
|
||||
"filename": "f",
|
||||
"field": "v2",
|
||||
},
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "v2",
|
||||
},
|
||||
{
|
||||
"v": 2,
|
||||
"v2": 0.2,
|
||||
VERSION_FIELD: {
|
||||
"revision": "r",
|
||||
"filename": "f",
|
||||
"field": "v2",
|
||||
},
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "v2",
|
||||
},
|
||||
],
|
||||
{"x": "v", "y": "v2", "x_label": "v", "y_label": "v2"},
|
||||
{
|
||||
"anchors_y_definitions": [{FILENAME: "f", FIELD: "v2"}],
|
||||
"x": "v",
|
||||
"y": "v2",
|
||||
"x_label": "v",
|
||||
"y_label": "v2",
|
||||
},
|
||||
id="choose_x_y",
|
||||
),
|
||||
pytest.param(
|
||||
@@ -99,23 +103,25 @@ def test_finding_lists(dictionary, expected_result):
|
||||
{
|
||||
"v": 1,
|
||||
"v2": 0.1,
|
||||
VERSION_FIELD: {
|
||||
"revision": "r",
|
||||
"filename": "f",
|
||||
"field": "v2",
|
||||
},
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "v2",
|
||||
},
|
||||
{
|
||||
"v": 2,
|
||||
"v2": 0.2,
|
||||
VERSION_FIELD: {
|
||||
"revision": "r",
|
||||
"filename": "f",
|
||||
"field": "v2",
|
||||
},
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "v2",
|
||||
},
|
||||
],
|
||||
{"x": "v", "y": "v2", "x_label": "x", "y_label": "y"},
|
||||
{
|
||||
"anchors_y_definitions": [{FILENAME: "f", FIELD: "v2"}],
|
||||
"x": "v",
|
||||
"y": "v2",
|
||||
"x_label": "x",
|
||||
"y_label": "y",
|
||||
},
|
||||
id="find_in_nested_structure",
|
||||
),
|
||||
pytest.param(
|
||||
@@ -123,44 +129,36 @@ def test_finding_lists(dictionary, expected_result):
|
||||
{"y": {"f": ["v", "v2"]}},
|
||||
[
|
||||
{
|
||||
VERSION_FIELD: {
|
||||
"revision": "r",
|
||||
"filename": "f",
|
||||
"field": "v",
|
||||
},
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "v",
|
||||
"dvc_inferred_y_value": 1,
|
||||
"v": 1,
|
||||
"v2": 0.1,
|
||||
"step": 0,
|
||||
},
|
||||
{
|
||||
VERSION_FIELD: {
|
||||
"revision": "r",
|
||||
"filename": "f",
|
||||
"field": "v",
|
||||
},
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "v",
|
||||
"dvc_inferred_y_value": 2,
|
||||
"v": 2,
|
||||
"v2": 0.2,
|
||||
"step": 1,
|
||||
},
|
||||
{
|
||||
VERSION_FIELD: {
|
||||
"revision": "r",
|
||||
"filename": "f",
|
||||
"field": "v2",
|
||||
},
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "v2",
|
||||
"dvc_inferred_y_value": 0.1,
|
||||
"v2": 0.1,
|
||||
"v": 1,
|
||||
"step": 0,
|
||||
},
|
||||
{
|
||||
VERSION_FIELD: {
|
||||
"revision": "r",
|
||||
"filename": "f",
|
||||
"field": "v2",
|
||||
},
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "v2",
|
||||
"v": 2,
|
||||
"v2": 0.2,
|
||||
"dvc_inferred_y_value": 0.2,
|
||||
@@ -168,6 +166,10 @@ def test_finding_lists(dictionary, expected_result):
|
||||
},
|
||||
],
|
||||
{
|
||||
"anchors_y_definitions": [
|
||||
{FILENAME: "f", FIELD: "v"},
|
||||
{FILENAME: "f", FIELD: "v2"},
|
||||
],
|
||||
"x": "step",
|
||||
"y": "dvc_inferred_y_value",
|
||||
"y_label": "y",
|
||||
@@ -189,47 +191,43 @@ def test_finding_lists(dictionary, expected_result):
|
||||
"z": 3,
|
||||
"v": 1,
|
||||
"step": 0,
|
||||
VERSION_FIELD: {
|
||||
"revision": "r",
|
||||
"filename": "f",
|
||||
"field": "v",
|
||||
},
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "v",
|
||||
},
|
||||
{
|
||||
"dvc_inferred_y_value": 2,
|
||||
"z": 4,
|
||||
"step": 1,
|
||||
"v": 2,
|
||||
VERSION_FIELD: {
|
||||
"revision": "r",
|
||||
"filename": "f",
|
||||
"field": "v",
|
||||
},
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "v",
|
||||
},
|
||||
{
|
||||
"dvc_inferred_y_value": 3,
|
||||
"v": 1,
|
||||
"z": 3,
|
||||
"step": 0,
|
||||
VERSION_FIELD: {
|
||||
"revision": "r",
|
||||
"filename": "f",
|
||||
"field": "z",
|
||||
},
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "z",
|
||||
},
|
||||
{
|
||||
"dvc_inferred_y_value": 4,
|
||||
"v": 2,
|
||||
"z": 4,
|
||||
"step": 1,
|
||||
VERSION_FIELD: {
|
||||
"revision": "r",
|
||||
"filename": "f",
|
||||
"field": "z",
|
||||
},
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "z",
|
||||
},
|
||||
],
|
||||
{
|
||||
"anchors_y_definitions": [
|
||||
{FILENAME: "f", FIELD: "v"},
|
||||
{FILENAME: "f", FIELD: "z"},
|
||||
],
|
||||
"x": "step",
|
||||
"y": "dvc_inferred_y_value",
|
||||
"y_label": "y",
|
||||
@@ -247,32 +245,35 @@ def test_finding_lists(dictionary, expected_result):
|
||||
{
|
||||
"v": 1,
|
||||
"v2": 0.1,
|
||||
VERSION_FIELD: {
|
||||
"revision": "r",
|
||||
"filename": "f",
|
||||
"field": "v2",
|
||||
},
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "v2",
|
||||
},
|
||||
{
|
||||
"v": 2,
|
||||
"v2": 0.2,
|
||||
VERSION_FIELD: {
|
||||
"revision": "r",
|
||||
"filename": "f",
|
||||
"field": "v2",
|
||||
},
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "v2",
|
||||
},
|
||||
{
|
||||
"v": 3,
|
||||
"v2": 0.3,
|
||||
VERSION_FIELD: {
|
||||
"revision": "r",
|
||||
"filename": "f2",
|
||||
"field": "v2",
|
||||
},
|
||||
REVISION: "r",
|
||||
FILENAME: "f2",
|
||||
FIELD: "v2",
|
||||
},
|
||||
],
|
||||
{"x": "v", "y": "v2", "x_label": "v", "y_label": "v2"},
|
||||
{
|
||||
"anchors_y_definitions": [
|
||||
{FILENAME: "f", FIELD: "v2"},
|
||||
{FILENAME: "f2", FIELD: "v2"},
|
||||
],
|
||||
"x": "v",
|
||||
"y": "v2",
|
||||
"x_label": "v",
|
||||
"y_label": "v2",
|
||||
},
|
||||
id="multi_file_json",
|
||||
),
|
||||
pytest.param(
|
||||
@@ -284,47 +285,43 @@ def test_finding_lists(dictionary, expected_result):
|
||||
"v": 1,
|
||||
"v2": 0.1,
|
||||
"step": 0,
|
||||
VERSION_FIELD: {
|
||||
"revision": "r",
|
||||
"filename": "f",
|
||||
"field": "v",
|
||||
},
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "v",
|
||||
},
|
||||
{
|
||||
"dvc_inferred_y_value": 2,
|
||||
"v": 2,
|
||||
"v2": 0.2,
|
||||
"step": 1,
|
||||
VERSION_FIELD: {
|
||||
"revision": "r",
|
||||
"filename": "f",
|
||||
"field": "v",
|
||||
},
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "v",
|
||||
},
|
||||
{
|
||||
"dvc_inferred_y_value": 0.1,
|
||||
"v": 1,
|
||||
"v2": 0.1,
|
||||
"step": 0,
|
||||
VERSION_FIELD: {
|
||||
"revision": "r",
|
||||
"filename": "f",
|
||||
"field": "v2",
|
||||
},
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "v2",
|
||||
},
|
||||
{
|
||||
"dvc_inferred_y_value": 0.2,
|
||||
"v": 2,
|
||||
"v2": 0.2,
|
||||
"step": 1,
|
||||
VERSION_FIELD: {
|
||||
"revision": "r",
|
||||
"filename": "f",
|
||||
"field": "v2",
|
||||
},
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "v2",
|
||||
},
|
||||
],
|
||||
{
|
||||
"anchors_y_definitions": [
|
||||
{FILENAME: "f", FIELD: "v"},
|
||||
{FILENAME: "f", FIELD: "v2"},
|
||||
],
|
||||
"x": "step",
|
||||
"y": "dvc_inferred_y_value",
|
||||
"x_label": "step",
|
||||
@@ -344,35 +341,34 @@ def test_finding_lists(dictionary, expected_result):
|
||||
"v": 1,
|
||||
"v2": 0.1,
|
||||
"v3": 0.01,
|
||||
VERSION_FIELD: {
|
||||
"revision": "r",
|
||||
"filename": "f",
|
||||
"field": "v2",
|
||||
},
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "v2",
|
||||
},
|
||||
{
|
||||
"dvc_inferred_y_value": 0.01,
|
||||
"v": 1,
|
||||
"v2": 0.1,
|
||||
"v3": 0.01,
|
||||
VERSION_FIELD: {
|
||||
"revision": "r",
|
||||
"filename": "f",
|
||||
"field": "v3",
|
||||
},
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "v3",
|
||||
},
|
||||
{
|
||||
"dvc_inferred_y_value": 0.1,
|
||||
"v": 1,
|
||||
"v2": 0.1,
|
||||
VERSION_FIELD: {
|
||||
"revision": "r",
|
||||
"filename": "f2",
|
||||
"field": "v2",
|
||||
},
|
||||
REVISION: "r",
|
||||
FILENAME: "f2",
|
||||
FIELD: "v2",
|
||||
},
|
||||
],
|
||||
{
|
||||
"anchors_y_definitions": [
|
||||
{FILENAME: "f", FIELD: "v2"},
|
||||
{FILENAME: "f", FIELD: "v3"},
|
||||
{FILENAME: "f2", FIELD: "v2"},
|
||||
],
|
||||
"x": "v",
|
||||
"y": "dvc_inferred_y_value",
|
||||
"x_label": "v",
|
||||
@@ -390,23 +386,23 @@ def test_finding_lists(dictionary, expected_result):
|
||||
{
|
||||
"v": 1,
|
||||
"v2": 0.1,
|
||||
VERSION_FIELD: {
|
||||
"revision": "r",
|
||||
"filename": "f",
|
||||
"field": "v2",
|
||||
},
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "v2",
|
||||
},
|
||||
{
|
||||
"v": 1,
|
||||
"v2": 0.1,
|
||||
VERSION_FIELD: {
|
||||
"revision": "r",
|
||||
"filename": "f2",
|
||||
"field": "v2",
|
||||
},
|
||||
REVISION: "r",
|
||||
FILENAME: "f2",
|
||||
FIELD: "v2",
|
||||
},
|
||||
],
|
||||
{
|
||||
"anchors_y_definitions": [
|
||||
{FILENAME: "f", FIELD: "v2"},
|
||||
{FILENAME: "f2", FIELD: "v2"},
|
||||
],
|
||||
"x": "v",
|
||||
"y": "v2",
|
||||
"x_label": "v",
|
||||
@@ -414,6 +410,107 @@ def test_finding_lists(dictionary, expected_result):
|
||||
},
|
||||
id="multi_file_y_same_prefix",
|
||||
),
|
||||
pytest.param(
|
||||
{
|
||||
"f": {"metric": [{"x1": 1, "v": 0.1}]},
|
||||
"f2": {"metric": [{"x2": 100, "v": 0.1}]},
|
||||
},
|
||||
{"y": {"f": ["v"], "f2": ["v"]}, "x": {"f": "x1", "f2": "x2"}},
|
||||
[
|
||||
{
|
||||
"x1": 1,
|
||||
"v": 0.1,
|
||||
"dvc_inferred_x_value": 1,
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "v",
|
||||
},
|
||||
{
|
||||
"x2": 100,
|
||||
"v": 0.1,
|
||||
"dvc_inferred_x_value": 100,
|
||||
REVISION: "r",
|
||||
FILENAME: "f2",
|
||||
FIELD: "v",
|
||||
},
|
||||
],
|
||||
{
|
||||
"anchors_y_definitions": [
|
||||
{FILENAME: "f", FIELD: "v"},
|
||||
{FILENAME: "f2", FIELD: "v"},
|
||||
],
|
||||
"x": "dvc_inferred_x_value",
|
||||
"y": "v",
|
||||
"x_label": "x",
|
||||
"y_label": "v",
|
||||
},
|
||||
id="multiple_x_fields",
|
||||
),
|
||||
pytest.param(
|
||||
{
|
||||
"f": {
|
||||
"metric": [
|
||||
{"v": 1, "v2": 0.1, "x1": 100},
|
||||
{"v": 2, "v2": 0.2, "x1": 1000},
|
||||
]
|
||||
},
|
||||
"f2": {"metric": [{"x2": -2}, {"x2": -4}]},
|
||||
},
|
||||
{"y": ["v", "v2"], "x": {"f": "x1", "f2": "x2"}},
|
||||
[
|
||||
{
|
||||
"dvc_inferred_x_value": 100,
|
||||
"dvc_inferred_y_value": 1,
|
||||
"v": 1,
|
||||
"v2": 0.1,
|
||||
"x1": 100,
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "v",
|
||||
},
|
||||
{
|
||||
"dvc_inferred_x_value": 1000,
|
||||
"dvc_inferred_y_value": 2,
|
||||
"v": 2,
|
||||
"v2": 0.2,
|
||||
"x1": 1000,
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "v",
|
||||
},
|
||||
{
|
||||
"dvc_inferred_x_value": -2,
|
||||
"dvc_inferred_y_value": 0.1,
|
||||
"v": 1,
|
||||
"v2": 0.1,
|
||||
"x1": 100,
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "v2",
|
||||
},
|
||||
{
|
||||
"dvc_inferred_x_value": -4,
|
||||
"dvc_inferred_y_value": 0.2,
|
||||
"v": 2,
|
||||
"v2": 0.2,
|
||||
"x1": 1000,
|
||||
REVISION: "r",
|
||||
FILENAME: "f",
|
||||
FIELD: "v2",
|
||||
},
|
||||
],
|
||||
{
|
||||
"anchors_y_definitions": [
|
||||
{FILENAME: "f", FIELD: "v"},
|
||||
{FILENAME: "f", FIELD: "v2"},
|
||||
],
|
||||
"x": "dvc_inferred_x_value",
|
||||
"y": "dvc_inferred_y_value",
|
||||
"x_label": "x",
|
||||
"y_label": "y",
|
||||
},
|
||||
id="y_list_x_dict",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_convert(
|
||||
|
||||
Reference in New Issue
Block a user