Source code for penkit.write

import xml.etree.ElementTree as ET
import numpy as np

# Landscape Letter
DEFAULT_PAGE_WIDTH = 11
DEFAULT_PAGE_HEIGHT = 8.5
DEFAULT_PAGE_UNIT = 'in'

# Plot-related defaults
DEFAULT_VIEW_BOX_MARGIN = 0.1
STROKE_THICKNESS = 0.003  # Fraction of width of image
PLOT_COLORS = ['black', 'red', 'green', 'blue', 'cyan', 'orange']


[docs]def calculate_view_box(layers, aspect_ratio, margin=DEFAULT_VIEW_BOX_MARGIN): """Calculates the size of the SVG viewBox to use. Args: layers (list): the layers in the image aspect_ratio (float): the height of the output divided by the width margin (float): minimum amount of buffer to add around the image, relative to the total dimensions Returns: tuple: a 4-tuple of floats representing the viewBox according to SVG specifications ``(x, y, width, height)``. """ min_x = min(np.nanmin(x) for x, y in layers) max_x = max(np.nanmax(x) for x, y in layers) min_y = min(np.nanmin(y) for x, y in layers) max_y = max(np.nanmax(y) for x, y in layers) height = max_y - min_y width = max_x - min_x if height > width * aspect_ratio: adj_height = height * (1. + margin) adj_width = adj_height / aspect_ratio else: adj_width = width * (1. + margin) adj_height = adj_width * aspect_ratio width_buffer = (adj_width - width) / 2. height_buffer = (adj_height - height) / 2. return ( min_x - width_buffer, min_y - height_buffer, adj_width, adj_height )
def _layer_to_path_gen(layer): """Generates an SVG path from a given layer. Args: layer (layer): the layer to convert Yields: str: the next component of the path """ draw = False for x, y in zip(*layer): if np.isnan(x) or np.isnan(y): draw = False elif not draw: yield 'M {} {}'.format(x, y) draw = True else: yield 'L {} {}'.format(x, y)
[docs]def layer_to_path(layer): """Generates an SVG path from a given layer. Args: layer (layer): the layer to convert Returns: str: an SVG path """ return ' '.join(_layer_to_path_gen(layer))
[docs]def plot_to_svg(plot, width, height, unit=''): """Converts a plot (list of layers) into an SVG document. Args: plot (list): list of layers that make up the plot width (float): the width of the resulting image height (float): the height of the resulting image unit (str): the units of the resulting image if not pixels Returns: str: A stringified XML document representing the image """ flipped_plot = [(x, -y) for x, y in plot] aspect_ratio = height / width view_box = calculate_view_box(flipped_plot, aspect_ratio=aspect_ratio) view_box_str = '{} {} {} {}'.format(*view_box) stroke_thickness = STROKE_THICKNESS * (view_box[2]) svg = ET.Element('svg', attrib={ 'xmlns': 'http://www.w3.org/2000/svg', 'xmlns:inkscape': 'http://www.inkscape.org/namespaces/inkscape', 'width': '{}{}'.format(width, unit), 'height': '{}{}'.format(height, unit), 'viewBox': view_box_str}) for i, layer in enumerate(flipped_plot): group = ET.SubElement(svg, 'g', attrib={ 'inkscape:label': '{}-layer'.format(i), 'inkscape:groupmode': 'layer', }) color = PLOT_COLORS[i % len(PLOT_COLORS)] ET.SubElement(group, 'path', attrib={ 'style': 'stroke-width: {}; stroke: {};'.format(stroke_thickness, color), 'fill': 'none', 'd': layer_to_path(layer) }) try: return ET.tostring(svg, encoding='unicode') except LookupError: # Python 2.x return ET.tostring(svg)
[docs]def layer_to_svg(layer, **kwargs): """Converts a layer into an SVG image. Wrapper around ``plot_to_svg``. Args: layer (layer): the layer to plot width (float): the width of the resulting image height (float): the height of the resulting image unit (str): the units of the resulting image if not pixels Returns: str: A stringified XML document representing the image """ return plot_to_svg([layer], **kwargs)
[docs]def write_plot(plot, filename, width=DEFAULT_PAGE_WIDTH, height=DEFAULT_PAGE_HEIGHT, unit=DEFAULT_PAGE_UNIT): """Writes a plot SVG to a file. Args: plot (list): a list of layers to plot filename (str): the name of the file to write width (float): the width of the output SVG height (float): the height of the output SVG unit (str): the unit of the height and width """ svg = plot_to_svg(plot, width, height, unit) with open(filename, 'w') as outfile: outfile.write(svg)