diff --git a/dvc/render/match.py b/dvc/render/match.py index b93d22654..0af628326 100644 --- a/dvc/render/match.py +++ b/dvc/render/match.py @@ -8,6 +8,7 @@ import dpath.options from funcy import get_in, last from dvc.repo.plots import _normpath, infer_data_sources +from dvc.utils.plots import get_plot_id from .convert import _get_converter @@ -35,13 +36,22 @@ class PlotsData: def group_definitions(self): groups = defaultdict(list) for rev, rev_content in self.data.items(): - for config_file_content in ( - rev_content.get("definitions", {}).get("data", {}).values() + groups_by_id: Dict = defaultdict(dict) + for config_file, config_file_content in ( + rev_content.get("definitions", {}).get("data", {}).items() ): for plot_id, plot_definition in config_file_content.get( "data", {} ).items(): - groups[plot_id].append((rev, plot_id, plot_definition)) + groups_by_id[plot_id][config_file] = (rev, plot_id, plot_definition) + # only keep config_file if the same plot_id is in multiple config_files + for plot_id, configs in groups_by_id.items(): + if len(configs) == 1: + groups[plot_id].append(next(iter(configs.values()))) + else: + for config_file, content in configs.items(): + full_id = get_plot_id(plot_id, config_file) + groups[full_id].append(content) return dict(groups) def get_definition_data(self, target_files, rev): diff --git a/dvc/repo/plots/__init__.py b/dvc/repo/plots/__init__.py index fa3d4c7be..4225e3a50 100644 --- a/dvc/repo/plots/__init__.py +++ b/dvc/repo/plots/__init__.py @@ -364,14 +364,17 @@ def infer_data_sources(plot_id, config=None): return ldistinct(source for source in sources) -def _matches(targets, plot_id): +def _matches(targets, config_file, plot_id): import re + from dvc.utils.plots import get_plot_id + if not targets: return True + full_id = get_plot_id(plot_id, config_file) if any( - (re.match(target, plot_id) or re.match(target, plot_id)) for target in targets + (re.match(target, plot_id) or re.match(target, full_id)) for target in targets ): return True return False @@ -400,9 +403,9 @@ def _collect_output_plots(repo, targets, props, onerror: Optional[Callable] = No for plot in repo.index.plots: plot_props = _plot_props(plot) dvcfile = plot.stage.dvcfile - _relpath(fs, dvcfile.path) + config_path = _relpath(fs, dvcfile.path) wdir_relpath = _relpath(fs, plot.stage.wdir) - if _matches(targets, str(plot)): + if _matches(targets, config_path, str(plot)): unpacked = unpack_if_dir( fs, _normpath(fs.path.join(wdir_relpath, plot.def_path)), @@ -451,7 +454,7 @@ def _resolve_definitions( plot_props = {} if _id_is_path(plot_props): data_path = _normpath(fs.path.join(config_dir, plot_id)) - if _matches(targets, plot_id): + if _matches(targets, config_path, plot_id): unpacked = unpack_if_dir( fs, data_path, @@ -462,7 +465,7 @@ def _resolve_definitions( result, unpacked, ) - elif _matches(targets, plot_id): + elif _matches(targets, config_path, plot_id): adjusted_props = _adjust_sources(fs, plot_props, config_dir) dpath.merge(result, {"data": {plot_id: {**adjusted_props, **props}}}) diff --git a/dvc/utils/plots.py b/dvc/utils/plots.py new file mode 100644 index 000000000..636a22059 --- /dev/null +++ b/dvc/utils/plots.py @@ -0,0 +1,4 @@ +def get_plot_id(config_plot_id: str, config_file_path: str = ""): + return ( + f"{config_file_path}::{config_plot_id}" if config_file_path else config_plot_id + )