示例#1
0
def test_svg_figure_writes_width_height_and_view_box():
    svg_fig = transform.SVGFigure(Unit("400mm"), Unit("300mm"))

    with NamedTemporaryFile() as f1:
        svg_fig.save(f1.name)
        with open(f1.name) as f2:
            written_content = f2.read()

    assert 'width="400.0mm"' in written_content
    assert 'height="300.0mm"' in written_content
    assert 'viewBox="0 0 400.0 300.0"' in written_content
示例#2
0
def test_create_svg_figure():
    svg_fig = transform.SVGFigure()
    assert "svg" in svg_fig.to_str().decode("ascii")

    svg_fig = transform.SVGFigure(Unit("2px"), Unit("2px"))
    assert "svg" in svg_fig.to_str().decode("ascii")

    svg_fig = transform.SVGFigure(2, 3)
    assert "svg" in svg_fig.to_str().decode("ascii")

    svg_fig = transform.SVGFigure("2", "3")
    assert "svg" in svg_fig.to_str().decode("ascii")
def plot_point_bar_figure(figure_one_path, figure_two_path):
    """
    Combines the pointplot and bargraph together using svg magic
    Arguments:
        figure_one_path - The pointplot figure
        figure_two_path - The barplot figure
    """
    fig1 = sg.fromfile(figure_one_path)
    fig2 = sg.fromfile(figure_two_path)

    fig1_width_size = np.round(float(fig1.root.attrib["width"][:-2]) * 1.33, 0)
    fig1_height_size = np.round(
        float(fig1.root.attrib["height"][:-2]) * 1.33, 0)

    fig2_width_size = np.round(float(fig2.root.attrib["width"][:-2]) * 1.33, 0)
    fig2_height_size = np.round(
        float(fig2.root.attrib["height"][:-2]) * 1.33, 0)

    fig = sg.SVGFigure(
        Unit((fig1_width_size + fig2_width_size) - 360),
        Unit(min(fig1_height_size, fig2_height_size) - 50),
    )

    fig.append([
        etree.Element("rect", {
            "width": "100%",
            "height": "100%",
            "fill": "white"
        })
    ])

    plot1 = fig1.getroot()
    plot1.moveto(10, 30)

    plot2 = fig2.getroot()
    plot2.moveto(fig1_width_size - 160, 12)

    text_A = sg.TextElement(10, 30, "A", size=18, weight="bold")
    text_B = sg.TextElement(fig1_width_size - 160,
                            30,
                            "B",
                            size=18,
                            weight="bold")

    fig.append([plot1, plot2, text_A, text_B])

    return fig
print(f"original: {panel_five_size}")
print(f"scaled:{(panel_five_size[0]*scale_x, panel_five_size[1]*scale_y)}")

panel_five = panel_five.getroot()
panel_five.scale(x=scale_x, y=scale_y)
panel_five.moveto(1070, 1670)
# -

panel_one_label = sg.TextElement(30, 30, "A", size=30, weight="bold")
panel_two_label = sg.TextElement(10, 800, "B", size=30, weight="bold")
panel_three_label = sg.TextElement(1100, 800, "C", size=30, weight="bold")
panel_four_label = sg.TextElement(30, 1670, "D", size=30, weight="bold")
panel_five_label = sg.TextElement(1100, 1670, "E", size=30, weight="bold")

# +
figure_one = sg.SVGFigure(Unit(2127), Unit(2433))

figure_one.append([
    etree.Element("rect", {
        "width": "100%",
        "height": "100%",
        "fill": "white"
    }),
    panel_one,
    panel_two,
    panel_three,
    panel_four,
    panel_five,
    panel_one_label,
    panel_two_label,
    panel_three_label,
示例#5
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)
示例#6
0
def unit(val, to='px'):
    assert type(val) == str
    return Unit(val).to(to).value
示例#7
0
def _compose_view(bg_svgs, fg_svgs, ref=0):
    from svgutils.compose import Unit
    from svgutils.transform import SVGFigure, GroupElement

    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(Unit(f"{width}px"), Unit(f"{heights[:nsvgs].sum()}px"))

    yoffset = 0
    for i, r in enumerate(roots):
        r.moveto(0, yoffset, scale_x=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", None)
    fig.root.attrib.pop("height", None)
    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
示例#8
0
def plot_scatter_clouds(
    scatter_plot_path,
    word_cloud_x_path,
    word_cloud_y_path,
    final_figure_path="output/pca_plots/figures/final_figure.png",
):

    # Save the matplotlfigures
    scatter_plot = Path(scatter_plot_path)
    word_cloud_x = Path(word_cloud_x_path)
    word_cloud_y = Path(word_cloud_y_path)

    # create new SVG figure
    fig = sg.SVGFigure()
    fig.width = Unit("1280")
    fig.height = Unit("768")

    fig.append([
        etree.Element("rect", {
            "width": "100%",
            "height": "100%",
            "fill": "white"
        })
    ])

    # load matpotlib-generated figures

    fig1 = load_clouds(str(word_cloud_y))
    fig2 = sg.fromfile(scatter_plot)
    fig3 = load_clouds(str(word_cloud_x))

    # get the plot objects
    plot1 = fig1.getroot()
    plot1.moveto(30, 30, scale_x=1, scale_y=1)

    plot2 = fig2.getroot()
    plot2.moveto(650, 0, scale_x=1)

    plot3 = fig3.getroot()
    plot3.moveto(650, 384, scale_x=1, scale_y=1)

    # append plots and labels to figure
    fig.append([plot2, plot3, plot1])

    text_A = sg.TextElement(10, 30, "A", size=22, weight="bold")
    text_B = sg.TextElement(620, 30, "B", size=22, weight="bold")
    text_C = sg.TextElement(620, 390, "C", size=22, weight="bold")

    fig.append([text_A, text_B, text_C])

    second_pc = int(re.search(r"pca_(\d+)", word_cloud_y.stem).group(1))

    first_pc = int(re.search(r"pca_(\d+)", word_cloud_x.stem).group(1))

    word_cloud_title_1 = sg.TextElement(225,
                                        400,
                                        f"PC{second_pc}",
                                        size=22,
                                        weight="bold")

    word_cloud_title_2 = sg.TextElement(850,
                                        760,
                                        f"PC{first_pc}",
                                        size=22,
                                        weight="bold")

    fig.append([word_cloud_title_1, word_cloud_title_2])

    # save generated SVG files
    svg2png(bytestring=fig.to_str(), write_to=final_figure_path, dpi=250)

    return Image(final_figure_path)
# +
fig1 = sg.fromfile(
    "output/figures/version_count_vs_publication_time_violin_filtered.svg"
)
fig2 = sg.fromfile(
    "output/figures/article_distance_vs_publication_time_hex_filtered.svg"
)

fig1_width_size = np.round(float(fig1.root.attrib["width"][:-2]) * 1.33, 0)
fig1_height_size = np.round(float(fig1.root.attrib["height"][:-2]) * 1.33, 0)

fig2_width_size = np.round(float(fig2.root.attrib["width"][:-2]) * 1.33, 0)
fig2_height_size = np.round(float(fig2.root.attrib["height"][:-2]) * 1.33, 0)

fig = sg.SVGFigure(
    Unit((fig1_width_size + fig2_width_size) - 360),
    Unit(min(fig1_height_size, fig2_height_size) - 50),
)

fig.append(
    [etree.Element("rect", {"width": "100%", "height": "100%", "fill": "white"})]
)

plot1 = fig1.getroot()
plot1.moveto(10, 30)

plot2 = fig2.getroot()
plot2.moveto(fig1_width_size - 160, 12)

text_A = sg.TextElement(10, 30, "A", size=22, weight="bold")
text_B = sg.TextElement(fig1_width_size - 160, 30, "B", size=22, weight="bold")
示例#10
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)