mirror of
https://github.com/Stone-Red-Code/dvc.git
synced 2026-11-01 23:08:43 +01:00
* plots: support images initial * plots: data: unify PlotsData * plots: data conversion refactor * plots: renderers: abstract functionality * plots: uncommenting tests * plots: self implement grouping * plots: rename group * plots: extract rendering tests * plots: move rendering tests to unit * plots: add image rendering tests * plots: dont use dpath to find vega plot * plots: test find_vega * plots: test render function * plots: move rendering out of repo package * plots: refactoring * plots: self review refactor
94 lines
2.5 KiB
Python
94 lines
2.5 KiB
Python
import os
|
|
from pathlib import Path
|
|
from typing import TYPE_CHECKING, Dict, List, Optional
|
|
|
|
from dvc.exceptions import DvcException
|
|
|
|
if TYPE_CHECKING:
|
|
from dvc.render import Renderer
|
|
from dvc.types import StrPath
|
|
|
|
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>
|
|
{plot_divs}
|
|
</body>
|
|
</html>"""
|
|
|
|
|
|
class MissingPlaceholderError(DvcException):
|
|
def __init__(self, placeholder):
|
|
super().__init__(f"HTML template has to contain '{placeholder}'.")
|
|
|
|
|
|
class HTML:
|
|
PLACEHOLDER = "plot_divs"
|
|
PLACEHOLDER_FORMAT_STR = f"{{{PLACEHOLDER}}}"
|
|
|
|
def __init__(self, template: str = None):
|
|
template = template or PAGE_HTML
|
|
if self.PLACEHOLDER_FORMAT_STR not in template:
|
|
raise MissingPlaceholderError(self.PLACEHOLDER_FORMAT_STR)
|
|
|
|
self.template = template
|
|
self.elements: List[str] = []
|
|
|
|
def with_metrics(self, metrics: Dict[str, Dict]) -> "HTML":
|
|
import tabulate
|
|
|
|
header: List[str] = []
|
|
rows: List[List[str]] = []
|
|
|
|
for _, rev_data in metrics.items():
|
|
for _, data in rev_data.items():
|
|
if not header:
|
|
header.extend(sorted(data.keys()))
|
|
|
|
rows.append([data[key] for key in header])
|
|
|
|
self.elements.append(tabulate.tabulate(rows, header, tablefmt="html"))
|
|
return self
|
|
|
|
def with_element(self, html: str) -> "HTML":
|
|
self.elements.append(html)
|
|
return self
|
|
|
|
def embed(self) -> str:
|
|
kwargs = {self.PLACEHOLDER: "\n".join(self.elements)}
|
|
return self.template.format(**kwargs)
|
|
|
|
|
|
def write(
|
|
path: "StrPath",
|
|
renderers: List["Renderer"],
|
|
metrics: Optional[Dict[str, Dict]] = None,
|
|
template_path: Optional["StrPath"] = None,
|
|
):
|
|
|
|
os.makedirs(path, exist_ok=True)
|
|
|
|
page_html = None
|
|
if template_path:
|
|
with open(template_path) as fobj:
|
|
page_html = fobj.read()
|
|
|
|
document = HTML(page_html)
|
|
if metrics:
|
|
document.with_metrics(metrics)
|
|
document.with_element("<br>")
|
|
|
|
for renderer in renderers:
|
|
document.with_element(renderer.generate_html(path))
|
|
|
|
index = Path(os.path.join(path, "index.html"))
|
|
|
|
with open(index, "w") as fd:
|
|
fd.write(document.embed())
|
|
return index
|