示例#1
0
def plotstatsimg(cbf,
                 ref_vol,
                 plot_params=None,
                 order=('z', 'x', 'y'),
                 estimate_brightness=False,
                 label=None,
                 compress='auto'):
    """
    plot zsts
    """
    plot_params = {} if plot_params is None else plot_params

    image_nii = _3d_in_file(cbf)
    data = image_nii.get_fdata()
    from nilearn.image import threshold_img
    bbox_nii = threshold_img(nb.load(cbf), 1)

    cuts = cuts_from_bbox(bbox_nii, cuts=7)

    out_files = []
    if estimate_brightness:
        plot_params = robust_set_limits(data, plot_params)

    # Plot each cut axis
    for i, mode in enumerate(list(order)):
        plot_params['display_mode'] = mode
        plot_params['cut_coords'] = cuts[mode]
        plot_params['draw_cross'] = False
        plot_params['symmetric_cbar'] = False
        plot_params['threshold'] = 0.05
        plot_params['vmax'] = 90
        plot_params['colorbar'] = False
        plot_params['cmap'] = 'gray'
        if i == 0:
            plot_params['title'] = label
            plot_params['colorbar'] = False
        else:
            plot_params['title'] = None

        # Generate nilearn figure
        from nilearn.plotting import plot_stat_map
        display = plot_stat_map(stat_map_img=cbf,
                                bg_img=ref_vol,
                                **plot_params)
        svg = extract_svg(display, compress=compress)
        display.close()
        from lxml import etree
        from .. import NIWORKFLOWS_LOG
        # Find and replace the figure_1 id.
        try:
            xml_data = etree.fromstring(svg)
        except etree.XMLSyntaxError as e:
            NIWORKFLOWS_LOG.info(e)
            return

        svg_fig = SVGFigure()
        svg_fig.root = xml_data
        out_files.append(svg_fig)

    return out_files
示例#2
0
def make_symbol(container: sg.SVGFigure, name, filepath):
    icon = sg.fromfile(filepath)
    size = get_view_box(icon)
    symbol = sg.fromstring(
        symbol_tpl.format(size['x'], size['y'], size['width'], size['height'],
                          name))
    symbol.append(icon.getroot())
    container.append(symbol)
示例#3
0
def plot_segs(image_nii,
              seg_niis,
              out_file,
              bbox_nii=None,
              masked=False,
              colors=None,
              compress='auto',
              **plot_params):
    """ plot segmentation as contours over the image (e.g. anatomical).
    seg_niis should be a list of files. mask_nii helps determine the cut
    coordinates. plot_params will be passed on to nilearn plot_* functions. If
    seg_niis is a list of size one, it behaves as if it was plotting the mask.
    """
    plot_params = {} if plot_params is None else plot_params

    image_nii = _3d_in_file(image_nii)
    data = image_nii.get_data()

    plot_params = robust_set_limits(data, plot_params)

    bbox_nii = nb.load(image_nii if bbox_nii is None else bbox_nii)
    if masked:
        bbox_nii = nlimage.threshold_img(bbox_nii, 1e-3)

    cuts = cuts_from_bbox(bbox_nii, cuts=7)
    plot_params['colors'] = colors or plot_params.get('colors', None)
    out_files = []
    for d in plot_params.pop('dimensions', ('z', 'x', 'y')):
        plot_params['display_mode'] = d
        plot_params['cut_coords'] = cuts[d]
        svg = _plot_anat_with_contours(image_nii,
                                       segs=seg_niis,
                                       compress=compress,
                                       **plot_params)

        # Find and replace the figure_1 id.
        try:
            xml_data = etree.fromstring(svg)
        except etree.XMLSyntaxError as e:
            NIWORKFLOWS_LOG.info(e)
            return
        find_text = etree.ETXPath("//{%s}g[@id='figure_1']" % SVGNS)
        find_text(xml_data)[0].set('id', 'segmentation-%s-%s' % (d, uuid4()))

        svg_fig = SVGFigure()
        svg_fig.root = xml_data
        out_files.append(svg_fig)

    return out_files
示例#4
0
def plot_acpc(acpc_registered_img,
              div_id,
              plot_params=None,
              order=('z', 'x', 'y'),
              cuts=None,
              estimate_brightness=False,
              label=None,
              compress='auto'):
    """
    Plot the results of an AC-PC transformation.
    """
    plot_params = plot_params or {}

    # Do the low-b image first
    out_files = []
    if estimate_brightness:
        plot_params = robust_set_limits(
            acpc_registered_img.get_fdata(dtype='float32').reshape(-1),
            plot_params)

    # Plot each cut axis for low-b
    for i, mode in enumerate(list(order)):
        plot_params['display_mode'] = mode
        plot_params['cut_coords'] = [-20.0, 0.0, 20.0]
        if i == 0:
            plot_params['title'] = label
        else:
            plot_params['title'] = None

        # Generate nilearn figure
        display = plot_anat(acpc_registered_img, **plot_params)
        for coord, axis in display.axes.items():
            axis.ax.axvline(0, lw=1)
            axis.ax.axhline(0, lw=1)
        svg = extract_svg(display, compress=compress)
        display.close()

        # Find and replace the figure_1 id.
        xml_data = etree.fromstring(svg)
        find_text = etree.ETXPath("//{%s}g[@id='figure_1']" % SVGNS)
        find_text(xml_data)[0].set('id', '%s-%s-%s' % (div_id, mode, uuid4()))

        svg_fig = SVGFigure()
        svg_fig.root = xml_data
        out_files.append(svg_fig)

    return out_files
示例#5
0
def plot_segs(image_nii, seg_niis, out_file, bbox_nii=None, masked=False,
              colors=None, compress='auto', **plot_params):
    """ plot segmentation as contours over the image (e.g. anatomical).
    seg_niis should be a list of files. mask_nii helps determine the cut
    coordinates. plot_params will be passed on to nilearn plot_* functions. If
    seg_niis is a list of size one, it behaves as if it was plotting the mask.
    """
    plot_params = {} if plot_params is None else plot_params

    image_nii = _3d_in_file(image_nii)
    data = image_nii.get_data()

    plot_params = robust_set_limits(data, plot_params)

    bbox_nii = nb.load(image_nii if bbox_nii is None else bbox_nii)
    if masked:
        bbox_nii = nlimage.threshold_img(bbox_nii, 1e-3)

    cuts = cuts_from_bbox(bbox_nii, cuts=7)
    plot_params['colors'] = colors or plot_params.get('colors', None)
    out_files = []
    for d in plot_params.pop('dimensions', ('z', 'x', 'y')):
        plot_params['display_mode'] = d
        plot_params['cut_coords'] = cuts[d]
        svg = _plot_anat_with_contours(image_nii, segs=seg_niis, compress=compress,
                                       **plot_params)

        # Find and replace the figure_1 id.
        try:
            xml_data = etree.fromstring(svg)
        except etree.XMLSyntaxError as e:
            NIWORKFLOWS_LOG.info(e)
            return
        find_text = etree.ETXPath("//{%s}g[@id='figure_1']" % SVGNS)
        find_text(xml_data)[0].set('id', 'segmentation-%s-%s' % (d, uuid4()))

        svg_fig = SVGFigure()
        svg_fig.root = xml_data
        out_files.append(svg_fig)

    return out_files
示例#6
0
def _pixel_viewbox_of_figure(figure: SVGFigure,
                             resolution_dpi: float) -> Tuple[float, float]:
    # NOTE: Attribute "viewbox" (with lowercase "b") is ignored by Inkscape 1.0.1
    #       in practice so I'm following Inkscape here and ignore the lowercase
    #       edition, too.
    try:
        view_box = figure.root.attrib['viewBox']
    except KeyError:
        left_str, top_str = '0', '0'
        width_str, height_str = figure.get_size()
    else:
        left_str, top_str, width_str, height_str = view_box.split()

    return (
        _length_string_to_pixel(left_str, resolution_dpi),
        _length_string_to_pixel(top_str, resolution_dpi),
        _length_string_to_pixel(width_str, resolution_dpi),
        _length_string_to_pixel(height_str, resolution_dpi),
    )
示例#7
0
def plot_denoise(lowb_nii,
                 highb_nii,
                 div_id,
                 plot_params=None,
                 highb_plot_params=None,
                 order=('z', 'x', 'y'),
                 cuts=None,
                 estimate_brightness=False,
                 label=None,
                 lowb_contour=None,
                 highb_contour=None,
                 compress='auto',
                 overlay=None,
                 overlay_params=None):
    """
    Plot the foreground and background views.
    Default order is: axial, coronal, sagittal

    Updated version from sdcflows
    """
    plot_params = plot_params or {}
    highb_plot_params = highb_plot_params or {}

    # Use default MNI cuts if none defined
    if cuts is None:
        raise NotImplementedError

    # Do the low-b image first
    out_files = []
    if estimate_brightness:
        plot_params = robust_set_limits(
            lowb_nii.get_fdata(dtype='float32').reshape(-1), plot_params)
    # Plot each cut axis for low-b
    for i, mode in enumerate(list(order)):
        plot_params['display_mode'] = mode
        plot_params['cut_coords'] = cuts[mode]
        if i == 0:
            plot_params['title'] = label + ": low-b"
        else:
            plot_params['title'] = None

        # Generate nilearn figure
        display = plot_anat(lowb_nii, **plot_params)
        if lowb_contour is not None:
            display.add_contours(lowb_contour, linewidths=1)

        svg = extract_svg(display, compress=compress)
        display.close()

        # Find and replace the figure_1 id.
        xml_data = etree.fromstring(svg)
        find_text = etree.ETXPath("//{%s}g[@id='figure_1']" % SVGNS)
        find_text(xml_data)[0].set('id', '%s-%s-%s' % (div_id, mode, uuid4()))

        svg_fig = SVGFigure()
        svg_fig.root = xml_data
        out_files.append(svg_fig)

    # Plot each cut axis for high-b
    if estimate_brightness:
        highb_plot_params = robust_set_limits(
            highb_nii.get_fdata(dtype='float32').reshape(-1),
            highb_plot_params)
    for i, mode in enumerate(list(order)):
        highb_plot_params['display_mode'] = mode
        highb_plot_params['cut_coords'] = cuts[mode]
        if i == 0:
            highb_plot_params['title'] = label + ': high-b'
        else:
            highb_plot_params['title'] = None

        # Generate nilearn figure
        display = plot_anat(highb_nii, **highb_plot_params)
        if highb_contour is not None:
            display.add_contours(highb_contour, linewidths=1)

        svg = extract_svg(display, compress=compress)
        display.close()

        # Find and replace the figure_1 id.
        xml_data = etree.fromstring(svg)
        find_text = etree.ETXPath("//{%s}g[@id='figure_1']" % SVGNS)
        find_text(xml_data)[0].set('id', '%s-%s-%s' % (div_id, mode, uuid4()))

        svg_fig = SVGFigure()
        svg_fig.root = xml_data
        out_files.append(svg_fig)

    return out_files
示例#8
0
文件: utils.py 项目: nipreps/sdcflows
def plot_registration(
    anat_nii,
    div_id,
    plot_params=None,
    order=("z", "x", "y"),
    cuts=None,
    estimate_brightness=False,
    label=None,
    contour=None,
    compress="auto",
    overlay=None,
    overlay_params=None,
):
    """
    Plot the foreground and background views.

    Default order is: axial, coronal, sagittal
    """
    from uuid import uuid4

    from lxml import etree
    import matplotlib.pyplot as plt
    from nilearn.plotting import plot_anat
    from svgutils.transform import SVGFigure
    from niworkflows.viz.utils import robust_set_limits, extract_svg, SVGNS

    plot_params = plot_params or {}

    # Use default MNI cuts if none defined
    if cuts is None:
        raise NotImplementedError  # TODO

    out_files = []
    if estimate_brightness:
        plot_params = robust_set_limits(
            anat_nii.get_fdata(dtype="float32").reshape(-1), plot_params)

    # Plot each cut axis
    for i, mode in enumerate(list(order)):
        plot_params["display_mode"] = mode
        plot_params["cut_coords"] = cuts[mode]
        if i == 0:
            plot_params["title"] = label
        else:
            plot_params["title"] = None

        # Generate nilearn figure
        display = plot_anat(anat_nii, **plot_params)
        if overlay is not None:
            _overlay_params = {
                "vmin": overlay.get_fdata(dtype="float32").min(),
                "vmax": overlay.get_fdata(dtype="float32").max(),
                "cmap": plt.cm.gray,
                "interpolation": "nearest",
            }
            _overlay_params.update(overlay_params)
            display.add_overlay(overlay, **_overlay_params)
        if contour is not None:
            display.add_contours(contour,
                                 colors="g",
                                 levels=[0.5],
                                 linewidths=0.5)

        svg = extract_svg(display, compress=compress)
        display.close()

        # Find and replace the figure_1 id.
        xml_data = etree.fromstring(svg)
        find_text = etree.ETXPath("//{%s}g[@id='figure_1']" % SVGNS)
        find_text(xml_data)[0].set("id", "%s-%s-%s" % (div_id, mode, uuid4()))

        svg_fig = SVGFigure()
        svg_fig.root = xml_data
        out_files.append(svg_fig)

    return out_files
示例#9
0
def plot_registration(anat_nii,
                      div_id,
                      plot_params=None,
                      order=('z', 'x', 'y'),
                      cuts=None,
                      estimate_brightness=False,
                      label=None,
                      contour=None,
                      compress='auto'):
    """
    Plots the foreground and background views
    Default order is: axial, coronal, sagittal
    """
    plot_params = {} if plot_params is None else plot_params

    # Use default MNI cuts if none defined
    if cuts is None:
        raise NotImplementedError  # TODO

    out_files = []
    if estimate_brightness:
        plot_params = robust_set_limits(anat_nii.get_data().reshape(-1),
                                        plot_params)

    # FreeSurfer ribbon.mgz
    ribbon = contour is not None and np.array_equal(
        np.unique(contour.get_data()), [0, 2, 3, 41, 42])

    if ribbon:
        contour_data = contour.get_data() % 39
        white = nlimage.new_img_like(contour, contour_data == 2)
        pial = nlimage.new_img_like(contour, contour_data >= 2)

    # dual mask
    dual_mask = contour is not None and np.array_equal(
        np.unique(contour.get_data().astype(np.uint8)), [0, 1, 2])

    if dual_mask:
        contour_data = contour.get_data()
        outer_mask = nlimage.new_img_like(contour, contour_data == 1)
        inner_mask = nlimage.new_img_like(contour, contour_data == 2)
        all_mask = nlimage.new_img_like(contour, contour_data > 0)

    # Plot each cut axis
    for i, mode in enumerate(list(order)):
        plot_params['display_mode'] = mode
        plot_params['cut_coords'] = cuts[mode]
        if i == 0:
            plot_params['title'] = label
        else:
            plot_params['title'] = None

        # Generate nilearn figure
        display = plot_anat(anat_nii, **plot_params)
        if ribbon:
            kwargs = {'levels': [0.5], 'linewidths': 0.5}
            display.add_contours(white, colors='b', **kwargs)
            display.add_contours(pial, colors='r', **kwargs)
        elif dual_mask:
            kwargs = {'levels': [0.5], 'linewidths': 0.75}
            display.add_contours(inner_mask, colors='b', **kwargs)
            display.add_contours(outer_mask, colors='r', **kwargs)
            display.add_contours(all_mask, colors='c', **kwargs)
        elif contour is not None:
            display.add_contours(contour,
                                 colors='b',
                                 levels=[0.5],
                                 linewidths=0.5)

        svg = extract_svg(display, compress=compress)
        display.close()

        # Find and replace the figure_1 id.
        try:
            xml_data = etree.fromstring(svg)
        except etree.XMLSyntaxError as e:
            NIWORKFLOWS_LOG.info(e)
            return
        find_text = etree.ETXPath("//{%s}g[@id='figure_1']" % SVGNS)
        find_text(xml_data)[0].set('id', '%s-%s-%s' % (div_id, mode, uuid4()))

        svg_fig = SVGFigure()
        svg_fig.root = xml_data
        out_files.append(svg_fig)

    return out_files
Creates a SVG tile image from a Mapbox Vector Tile.
"""
from __future__ import print_function
import os
import math
import argparse
import mapbox_vector_tile
from enum import Enum
from lxml import etree
from tempfile import NamedTemporaryFile
from django.contrib.gis.geos import LineString, Polygon
from svgutils.transform import SVG, SVGFigure, FigureElement, LineElement
# `mapbox-vector-tile` has a hardcoded tile extent of 4096 units.
MVT_EXTENT = 4096
TILE_SIZE = 256
fig = SVGFigure(width=TILE_SIZE, height=TILE_SIZE)


class CustomLineElement(LineElement):
    """
    Inherits from LineElement, gives access to style attribute.
    """
    def __init__(self, points, width=1, color='black', style=''):
        linedata = "M{} {} ".format(*points[0])
        linedata += " ".join(map(lambda x: "L{} {}".format(*x), points[1:]))
        line = etree.Element(
            SVG + "path", {
                "d": linedata,
                "stroke-width": str(width),
                "stroke": color,
                "style": style
示例#11
0
def _compose_view(bg_svgs, fg_svgs, ref=0):

    if fg_svgs is None:
        fg_svgs = []

    # Merge SVGs and get roots
    svgs = bg_svgs + fg_svgs
    roots = [f.getroot() for f in svgs]

    # Query the size of each
    sizes = []
    for f in svgs:
        viewbox = [float(v) for v in f.root.get("viewBox").split(" ")]
        width = int(viewbox[2])
        height = int(viewbox[3])
        sizes.append((width, height))
    nsvgs = len(bg_svgs)

    sizes = np.array(sizes)

    # Calculate the scale to fit all widths
    width = sizes[ref, 0]
    scales = width / sizes[:, 0]
    heights = sizes[:, 1] * scales

    # Compose the views panel: total size is the width of
    # any element (used the first here) and the sum of heights
    fig = SVGFigure(width, heights[:nsvgs].sum())

    yoffset = 0
    for i, r in enumerate(roots):
        r.moveto(0, yoffset, scale=scales[i])
        if i == (nsvgs - 1):
            yoffset = 0
        else:
            yoffset += heights[i]

    # Group background and foreground panels in two groups
    if fg_svgs:
        newroots = [
            GroupElement(roots[:nsvgs], {"class": "background-svg"}),
            GroupElement(roots[nsvgs:], {"class": "foreground-svg"}),
        ]
    else:
        newroots = roots
    fig.append(newroots)
    fig.root.attrib.pop("width")
    fig.root.attrib.pop("height")
    fig.root.set("preserveAspectRatio", "xMidYMid meet")

    with TemporaryDirectory() as tmpdirname:
        out_file = Path(tmpdirname) / "tmp.svg"
        fig.save(str(out_file))
        # Post processing
        svg = out_file.read_text().splitlines()

    # Remove <?xml... line
    if svg[0].startswith("<?xml"):
        svg = svg[1:]

    # Add styles for the flicker animation
    if fg_svgs:
        svg.insert(
            2,
            """\
<style type="text/css">
@keyframes flickerAnimation%s { 0%% {opacity: 1;} 100%% { opacity: 0; }}
.foreground-svg { animation: 1s ease-in-out 0s alternate none infinite paused flickerAnimation%s;}
.foreground-svg:hover { animation-play-state: running;}
</style>""" % tuple([uuid4()] * 2),
        )

    return svg
示例#12
0
def fromfile(fname):
    fig = SVGFigure()
    svg_file = etree.parse(fname)
    fig.root = svg_file.getroot()
    return fig
示例#13
0
 def write_svg(self, filename):
     WIDTH = self._outer_board_width_pixel()
     HEIGHT = self._outer_board_height_pixel()
     output_fig = SVGFigure(Unit(f'{WIDTH}px'), Unit(f'{HEIGHT}px'))
     output_fig.append(self._lines)
     output_fig.save(filename)
示例#14
0
文件: utils.py 项目: mgxd/sdcflows
def plot_registration(anat_nii,
                      div_id,
                      plot_params=None,
                      order=('z', 'x', 'y'),
                      cuts=None,
                      estimate_brightness=False,
                      label=None,
                      contour=None,
                      compress='auto'):
    """
    Plot the foreground and background views.

    Default order is: axial, coronal, sagittal
    """
    from uuid import uuid4

    from lxml import etree
    from nilearn.plotting import plot_anat
    from svgutils.transform import SVGFigure
    from niworkflows.viz.utils import robust_set_limits, extract_svg, SVGNS

    plot_params = plot_params or {}

    # Use default MNI cuts if none defined
    if cuts is None:
        raise NotImplementedError  # TODO

    out_files = []
    if estimate_brightness:
        plot_params = robust_set_limits(anat_nii.get_data().reshape(-1),
                                        plot_params)

    # Plot each cut axis
    for i, mode in enumerate(list(order)):
        plot_params['display_mode'] = mode
        plot_params['cut_coords'] = cuts[mode]
        if i == 0:
            plot_params['title'] = label
        else:
            plot_params['title'] = None

        # Generate nilearn figure
        display = plot_anat(anat_nii, **plot_params)
        if contour is not None:
            display.add_contours(contour,
                                 colors='g',
                                 levels=[0.5],
                                 linewidths=0.5)

        svg = extract_svg(display, compress=compress)
        display.close()

        # Find and replace the figure_1 id.
        xml_data = etree.fromstring(svg)
        find_text = etree.ETXPath("//{%s}g[@id='figure_1']" % SVGNS)
        find_text(xml_data)[0].set('id', '%s-%s-%s' % (div_id, mode, uuid4()))

        svg_fig = SVGFigure()
        svg_fig.root = xml_data
        out_files.append(svg_fig)

    return out_files
示例#15
0
def plot_registration(anat_nii, div_id, plot_params=None,
                      order=('z', 'x', 'y'), cuts=None,
                      estimate_brightness=False, label=None, contour=None,
                      compress='auto'):
    """
    Plots the foreground and background views
    Default order is: axial, coronal, sagittal
    """
    plot_params = {} if plot_params is None else plot_params

    # Use default MNI cuts if none defined
    if cuts is None:
        raise NotImplementedError  # TODO

    out_files = []
    if estimate_brightness:
        plot_params = robust_set_limits(anat_nii.get_data().reshape(-1),
                                        plot_params)

    # FreeSurfer ribbon.mgz
    ribbon = contour is not None and np.array_equal(
        np.unique(contour.get_data()), [0, 2, 3, 41, 42])

    if ribbon:
        contour_data = contour.get_data() % 39
        white = nlimage.new_img_like(contour, contour_data == 2)
        pial = nlimage.new_img_like(contour, contour_data >= 2)

    # Plot each cut axis
    for i, mode in enumerate(list(order)):
        plot_params['display_mode'] = mode
        plot_params['cut_coords'] = cuts[mode]
        if i == 0:
            plot_params['title'] = label
        else:
            plot_params['title'] = None

        # Generate nilearn figure
        display = plot_anat(anat_nii, **plot_params)
        if ribbon:
            kwargs = {'levels': [0.5], 'linewidths': 0.5}
            display.add_contours(white, colors='b', **kwargs)
            display.add_contours(pial, colors='r', **kwargs)
        elif contour is not None:
            display.add_contours(contour, colors='b', levels=[0.5],
                                 linewidths=0.5)

        svg = extract_svg(display, compress=compress)
        display.close()

        # Find and replace the figure_1 id.
        try:
            xml_data = etree.fromstring(svg)
        except etree.XMLSyntaxError as e:
            NIWORKFLOWS_LOG.info(e)
            return
        find_text = etree.ETXPath("//{%s}g[@id='figure_1']" % SVGNS)
        find_text(xml_data)[0].set('id', '%s-%s-%s' % (div_id, mode, uuid4()))

        svg_fig = SVGFigure()
        svg_fig.root = xml_data
        out_files.append(svg_fig)

    return out_files
示例#16
0
def compose_svg(atoms_to_put, options):
    board_svg_filename = os.path.join(options.board_theme_dir,
                                      _BOARD_SVG_BASENAME)
    board_ini_filename = os.path.join(options.board_theme_dir,
                                      _BOARD_INI_BASENAME)

    # Check for existance ourselves since configparser would throw NoSectionError
    # at us for a missing file.
    if not os.path.exists(board_ini_filename):
        raise OSError(errno.ENOENT,
                      "No such file or directory: '%s'" % board_ini_filename)

    config = configparser.RawConfigParser(defaults={'river': 0.0})
    config.read(board_ini_filename)

    output_board_offset_left_pixel = config.getfloat(_BOARD_CONFIG_SECTION,
                                                     'left')
    output_board_offset_top_pixel = config.getfloat(_BOARD_CONFIG_SECTION,
                                                    'top')
    output_board_width_pixel = config.getfloat(_BOARD_CONFIG_SECTION, 'width')
    output_board_height_pixel = config.getfloat(_BOARD_CONFIG_SECTION,
                                                'height')
    output_board_river_height_pixel = config.getfloat(_BOARD_CONFIG_SECTION,
                                                      'river')

    # Regular pieces are at level 0; level 1 and above is drawn on top of (i.e. after)
    # the pieces while -1 and below is drawn below (i.e. before) the pieces.
    jobs_at_z_index = defaultdict(list)

    annotation_theme_config_filename = os.path.join(
        options.annotation_theme_dir, 'config.yml')
    with open(annotation_theme_config_filename) as f:
        annotation_theme_config = yaml.safe_load(f)

    for put_atom in atoms_to_put:
        if isinstance(put_atom, PutAnnotation):
            put_annotation: PutAnnotation = put_atom
            x_rel = float(put_annotation.x) / _MAX_X
            y_rel = float(_MAX_Y - put_annotation.y) / _MAX_Y
            filename = os.path.join(options.annotation_theme_dir,
                                    f'{put_annotation.annotation_name}.svg')
            annotation_scale = options.annotation_scale if annotation_theme_config[
                'allow_scaling'][put_annotation.annotation_name] else 1.0
            atom_z_index = int(annotation_theme_config['z_index'][
                put_annotation.annotation_name])
            jobs_at_z_index[atom_z_index].append(
                (x_rel, y_rel, filename, annotation_scale))
        else:
            assert isinstance(put_atom, PutPiece)
            put_piece: PutPiece = put_atom
            x_rel = float(put_piece.x) / _MAX_X
            y_rel = float(_MAX_Y - put_piece.y) / _MAX_Y
            basename = _FILENAME_OF_PARTY_PIECE[put_piece.party][
                put_piece.piece]
            filename = os.path.join(options.piece_theme_dir, basename)
            jobs_at_z_index[_Z_INDEX_PIECE_LEVEL].append(
                (x_rel, y_rel, filename, options.piece_scale))

    if options.debug:
        for x_rel in (0.0, 1.0):
            for y_rel in (0.0, 1.0):
                jobs_at_z_index[_Z_INDEX_DEBUG_DIAMOND].append(
                    (x_rel, y_rel,
                     os.path.join(options.piece_theme_dir,
                                  _DIAMOND_FILE_NAME), options.piece_scale))

    # Read board
    board_fig = fromfile(board_svg_filename)
    board_root = board_fig.getroot()

    # Scale board to output
    board_width_pixel, board_height_pixel = _pixel_viewbox_of_figure(
        board_fig, options.resolution_dpi)[2:]
    height_factor = board_height_pixel / float(board_width_pixel)
    board_scale = options.width_pixel / board_width_pixel
    board_root.moveto(0, 0, scale_x=board_scale, scale_y=board_scale)

    output_board_offset_left_pixel *= board_scale
    output_board_offset_top_pixel *= board_scale
    output_board_width_pixel *= board_scale
    output_board_height_pixel *= board_scale
    output_board_river_height_pixel *= board_scale

    # Initialize output figure
    output_fig = SVGFigure(Unit(f'{options.width_pixel}px'),
                           Unit(f'{options.width_pixel * height_factor}px'))
    output_fig.append([
        board_root,
    ])

    for _z_index, jobs in sorted(jobs_at_z_index.items()):
        for (x_rel, y_rel, filename, element_scale) in jobs:
            piece_fig = fromfile(filename)
            piece_root = piece_fig.getroot()
            original_piece_width_pixel, original_piece_height_pixel = \
                _pixel_viewbox_of_figure(piece_fig, options.resolution_dpi)[2:]

            # Scale and put piece onto board
            center_x_pixel = output_board_offset_left_pixel + output_board_width_pixel * x_rel
            center_y_pixel = output_board_offset_top_pixel + (output_board_height_pixel - output_board_river_height_pixel) * y_rel \
                    + (output_board_river_height_pixel if (y_rel >= 0.5) else 0.0)

            maximum_future_piece_width_pixel = output_board_width_pixel / _MAX_X * element_scale
            maximum_future_piece_height_pixel = output_board_height_pixel / _MAX_Y * element_scale

            scale = min(
                maximum_future_piece_width_pixel / original_piece_width_pixel,
                maximum_future_piece_height_pixel /
                original_piece_height_pixel)

            future_piece_width_pixel = original_piece_width_pixel * scale
            future_piece_height_pixel = original_piece_height_pixel * scale

            x_pixel = center_x_pixel - future_piece_width_pixel / 2.0
            y_pixel = center_y_pixel - future_piece_height_pixel / 2.0
            piece_root.moveto(x_pixel, y_pixel, scale_x=scale, scale_y=scale)
            output_fig.append([
                piece_root,
            ])

    output_fig.save(options.output_file)
示例#17
0
 def __init__(self):
     SVGFigure.__init__(self)
     self.figures = []
示例#18
0
 def save(self, fname):
     self._generate_layout()
     SVGFigure.save(self, fname)