dbt-selly/dbt-env/lib/python3.8/site-packages/leather/grid.py

121 lines
3.1 KiB
Python

#!/usr/bin/env python
import math
import os
import xml.etree.ElementTree as ET
import six
import leather.svg as svg
from leather import theme
from leather.utils import IPythonSVG
class Grid(object):
"""
A container for a set of :class:`.Chart` instances that are rendered in a
grid layout.
"""
def __init__(self):
self._charts = []
def add_one(self, chart):
"""
Add a :class:`.Chart` to the grid.
"""
self._charts.append(chart)
def add_many(self, charts):
"""
Add a sequence of charts to this grid.
"""
self._charts.extend(charts)
def to_svg(self, path=None, width=None, height=None):
"""
Render the grid to an SVG.
The :code:`width` and :code:`height` arguments refer to the size of the
entire grid. The size of individual charts will be inferred
automatically.
See :meth:`.Chart.to_svg` for arguments.
"""
if not width or not height:
count = len(self._charts)
columns = math.ceil(math.sqrt(count))
rows = math.ceil(count / columns)
width = columns * theme.default_chart_width
height = rows * theme.default_chart_height
root = ET.Element('svg',
width=six.text_type(width),
height=six.text_type(height),
version='1.1',
xmlns='http://www.w3.org/2000/svg'
)
# Root / background
root_group = ET.Element('g')
root_group.append(ET.Element('rect',
x=six.text_type(0),
y=six.text_type(0),
width=six.text_type(width),
height=six.text_type(height),
fill=theme.background_color
))
root.append(root_group)
# Charts
grid_group = ET.Element('g')
chart_count = len(self._charts)
grid_width = math.ceil(math.sqrt(chart_count))
grid_height = math.ceil(chart_count / grid_width)
chart_width = width / grid_width
chart_height = height / grid_height
for i, chart in enumerate(self._charts):
x = (i % grid_width) * chart_width
y = math.floor(i / grid_width) * chart_height
group = ET.Element('g')
group.set('transform', svg.translate(x, y))
chart = chart.to_svg_group(chart_width, chart_height)
group.append(chart)
grid_group.append(group)
root_group.append(grid_group)
svg_text = svg.stringify(root)
close = True
if path:
f = None
try:
if hasattr(path, 'write'):
f = path
close = False
else:
dirpath = os.path.dirname(path)
if dirpath and not os.path.exists(dirpath):
os.makedirs(dirpath)
f = open(path, 'w')
f.write(svg.HEADER)
f.write(svg_text)
finally:
if close and f is not None:
f.close()
else:
return IPythonSVG(svg_text)