import altair as alt
from jinja2 import Template
import json
import pandas as pd
from vega_datasets import data
iris = data.iris()
cars = alt.Chart(iris, title="Iris Chart").mark_point().encode(
x='petalLength',
y='petalWidth',
color='species'
).interactive()
from typing import List, Optional
class EmbedChart:
template = Template("""<div id="vis-{{ id }}"></div>
<script type="text/javascript">
var spec = {{ spec }};
var opt = {"renderer": "canvas", "actions": false};
vegaEmbed("#vis-{{ id }}", spec, opt);
</script>
""")
current_id = 0
def __init__(self, chart: alt.Chart):
self.chart = chart
self._id = __class__.current_id
__class__.current_id += 1
def __str__(self):
spec = json.dumps(self.chart.to_dict(), indent=2)
return __class__.template.render(spec=spec, id=self._id)
class EmbedFrame:
def __init__(self, df: pd.DataFrame):
self.df = df
def __str__(self):
return self.df._repr_html_()
from dataclasses import dataclass
@dataclass
class Section:
title: str
content: str
tables: Optional[List[pd.DataFrame]]
charts: Optional[List[alt.Chart]]
current_id = 0
template: Template = Template("""
<div class="section" id="section-{{ id }}">
<hr>
<h2>{{ title }}</h2>
{{ content }}
{% for table in tables %}
{{ table }}
{% endfor %}
{% for chart in charts %}
{{ chart }}
{% endfor %}
</div>
""")
def __post_init__(self):
self._id = __class__.current_id
__class__.current_id += 1
def __str__(self):
charts = [EmbedChart(c) for c in self.charts]
tables = [EmbedFrame(df) for df in self.tables]
return __class__.template.render(title=self.title, content=self.content, tables=tables, charts=charts, id=self._id)
DEFAULT_CSS = """
table {
width: 750px;
border-collapse: collapse;
margin:50px auto;
}
/* Zebra striping */
tr:nth-of-type(odd) {
background: #eee;
}
th {
background: #3498db;
color: white;
font-weight: bold;
}
td, th {
padding: 10px;
border: 1px solid #ccc;
text-align: left;
font-size: 18px;
}
"""
class Report:
template = Template("""
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.jsdelivr.net/npm/vega@3"></script>
<script src="https://cdn.jsdelivr.net/npm/vega-lite@2"></script>
<script src="https://cdn.jsdelivr.net/npm/vega-embed@3"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/mini.css/3.0.1/mini-default.min.css">
<style>
body {
max-width: 700px;
margin: auto;
}
</style>
</head>
<body>
<main class="app-container">
<article>
<div id="toc_container">
<h1 class="toc_title">Contents</h1>
<ul class="toc_list">
{% for section in sections %}
<li><a href="#section-{{ section._id }}">{{ section.title }}</a></li>
{% endfor %}
</ul>
</div>
{% for section in sections %}
{{ section }}
{% endfor %}
</article>
</main>
</body>
</html>
""")
def __init__(self, sections: List[Section], css=DEFAULT_CSS):
self.sections = sections
self.css = css
def __str__(self):
return __class__.template.render(sections=self.sections, css=self.css)
css_file = "/home/evan/projects/blog/static/Blogs __ Evan's Blog_files/main.min.465c4a0bba48be825ec830b7581563541c732256bcb5ecac4b90c41fd89c318d.css"
with open(css_file) as f:
css = f.read()
secs = [Section(title=f"cars{i}", content="This is a cars section", tables=[iris.head()], charts=[cars]) for i in range(10)]
report = Report(sections=secs, css=css)
with open("test.html", "w") as f:
f.write(str(report))