Source code for opstool.vis.save_tikz

import h5py
import numpy as np

COLORS = dict(
    point="Maroon",
    line="Blue",
    face="Green",
    solid="Violet",
    truss="pink",
    link="SkyBlue",
    constraint="Lime",
)


def _write_head(file, width=12, height=30, d3: bool = True):
    with open(file, "w", encoding="utf8") as f:
        f.write("% This file was created by opstool, all rights reserved!\n")
        f.write("\\documentclass{standalone}\n")
        f.write("\\usepackage[dvipsnames, svgnames, x11names]{xcolor}\n")
        f.write(
            "\\usepackage[left=0cm,top=0cm,right=0cm,nohead,nofoot]{geometry}\n")
        f.write("\\usepackage{tikz}\n")
        if d3:
            f.write("\\usepackage{tikz-3dplot}\n")
        f.write("\\usepackage[siunitx]{circuitikz} %[symbols]\n")
        f.write("\\usepackage[outline]{contour} % glow around text\n")
        f.write("\\usetikzlibrary{arrows,arrows.meta}\n")
        f.write("\\usetikzlibrary{decorations.markings}\n")
        f.write("\\usepackage[active,tightpage]{preview}\n")
        f.write("\\PreviewEnvironment{tikzpicture}\n")
        if d3:
            # 120 degree azimuth and 30 degree of elevation
            f.write("\\tdplotsetmaincoords{120}{30}\n")
        f.write("\\setlength\\PreviewBorder{2mm}\n\n")
        f.write(
            f"\\geometry{{paperwidth={width}cm, paperheight={height}cm, margin=0cm}}\n")
        f.write(
            f"\n\\tikzstyle{{link}}=[R,color={COLORS['link']},thick,{COLORS['link']}]\n")
        f.write(
            f"\\tikzstyle{{constraint}}=[short,color={COLORS['constraint']},thick,{COLORS['constraint']}]\n")
        f.write("\n\\begin{document}\n")
        if d3:
            f.write(
                "\n\\begin{tikzpicture}[tdplot_main_coords]\n\n")
        else:
            f.write("\n\\begin{tikzpicture}\n\n")


def _write_end(file):
    with open(file, "a", encoding="utf8") as f:
        f.write(r"\n\end{tikzpicture}\n")
        f.write(r"\n\end{document}\n")


def _def_points(file, points, d3):
    with open(file, "a", encoding="utf8") as f:
        if d3:
            for i, p in enumerate(points):
                f.write(
                    f"\\coordinate (P{i}) at ({p[0]}, {p[1]}, {p[2]});\n")
        else:
            for i, p in enumerate(points):
                f.write(
                    f"\\coordinate (P{i}) at ({p[0]}, {p[1]});\n")


def _write_points(file, points, size, opacity=1.0, color="black"):
    with open(file, "a", encoding="utf8") as f:
        for i, p in enumerate(points):
            f.write(
                f"\\shade[ball color={color}, fill opacity={opacity}] (P{i}) circle ({size}pt);\n")


def _write_lines(file, cells, line_width, opacity,
                 line_color="black"):
    cells = np.reshape(cells, (-1, 3))
    if len(cells) > 0:
        with open(file, "a", encoding="utf8") as f:
            for cell in cells:
                idx1 = cell[1]
                idx2 = cell[2]
                f.write(
                    f"\\draw[{line_color},line width={line_width}pt, opacity={opacity}] "
                    f"(P{idx1}) -- (P{idx2});\n")
                # if line_type.lower() == "link":
                #     f.write(
                #         f"\draw[line width={line_width}pt] "
                #         f"(P{idx1}) to[link] (P{idx2});\n")
                # else:
                #     f.write(
                #         f"\draw[{line_color},line width={line_width}pt] "
                #         f"(P{idx1}) -- (P{idx2});\n")


def _write_constraint(file, model_info, scale, line_width, d3,
                      line_color="black"):
    points = model_info["ConstrainedCoords"] * scale
    cells = model_info["ConstrainedCells"]
    cells = np.reshape(cells, (-1, 3))
    midcoords = model_info["ConstrainedMidCoords"] * scale
    dofs = model_info["ConstrainedDofs"]
    dofs = ["".join([str(k) for k in dof]) for dof in dofs]
    if len(cells) > 0:
        if d3:
            with open(file, "a", encoding="utf8") as f:
                for cell, mp, dof in zip(cells, midcoords, dofs):
                    p1 = points[cell[1]]
                    p2 = points[cell[2]]
                    f.write(
                        f"\\draw[{line_color},line width={line_width}pt] "
                        f"({p1[0]}, {p1[1]}, {p1[2]}) to[constraint] ({p2[0]}, {p2[1]}, {p2[2]});\n")
                    # f.write(
                    #     f"\path ({mp[0]}, {mp[1]}, {mp[2]}) "
                    #     f"node[above,{line_color},font=\\fontsize{{{label_size}pt}}{{{label_size}pt}}] {{{dof}}};\n")
        else:
            with open(file, "a", encoding="utf8") as f:
                for cell, mp, dof in zip(cells, midcoords, dofs):
                    p1 = points[cell[1]]
                    p2 = points[cell[2]]
                    f.write(
                        f"\\draw[{line_color},line width={line_width}pt] "
                        f"({p1[0]}, {p1[1]}) to[constraint] ({p2[0]}, {p2[1]});\n")
                    # f.write(
                    #     f"\path ({mp[0]}, {mp[1]}) "
                    #     f"node[above,{line_color},font=\\fontsize{{{label_size}pt}}{{{label_size}pt}}] {{{dof}}};\n")


def _write_faces(file, cells, color, opacity):
    if len(cells) > 0:
        with open(file, "a", encoding="utf8") as f:
            i = 0
            while i < len(cells):
                num = cells[i]
                idxs = cells[i + 1:i + num + 1]
                i += num+1
                txt = ""
                for idx in idxs:
                    txt += f"(P{idx}) -- "
                txt += "cycle;\n"
                f.write(
                    f"\\draw [line width=1pt, draw=black, fill={color}, fill opacity={opacity}]\n" + txt)


[docs]def save_tikz(input_file: str, output_file: str = "ModelData.tex", point_size: float = 5, line_width: float = 3, face_opacity: float = 0.6, solid_opacity: float = 0.6, point_opacity: float = 0.8, line_opacity: float = 1.0, color_dict: dict = None,): """Save the ``OpenSeesPy`` model data as a ``tikz`` command file in ``latex``, and then you can open it in your local tex editor, or run it online in ``overleaf``. Parameters ---------- input_file : str The input model data file, e.g., "opstool_output/ModelData.hdf5". output_file : str, optional The output tex file contains the tikz commands, by default "ModelData.tex" point_size : float, optional The point size in ``pt`` unit, by default 5 line_width : float, optional The line width in ``pt`` unit, by default 3 face_opacity : float, optional The opacity of face elements, by default 0.75 solid_opacity : float, optional The opacity of solid elements, by default 0.75 point_opacity : float, optional The opacity of point, by default 0.75 line_opacity : float, optional The opacity of line elements, by default 1.0 color_dict : dict, optional The color of each type of element, by default None. The valid color string must be one of the ``xcolor`` package. If None, color_dict = dict(point="Maroon", line="Blue", face="Green", solid="Violet", truss="pink", link="SkyBlue", constraint="Lime") """ if color_dict: COLORS.update(color_dict) # get hdf5 data model_info = dict() cells = dict() with h5py.File(input_file, "r") as f: grp1 = f["ModelInfo"] for name in grp1.keys(): model_info[name] = grp1[name][...] grp2 = f["Cell"] for name in grp2.keys(): cells[name] = grp2[name][...] points = model_info["coord_no_deform"] D3 = False if np.max(np.abs(points[:, -1])) < 1e-5 else True bound = np.max(points, axis=0) - np.min(points, axis=0) aspect_ratio = np.max([bound[1] / bound[0], bound[2] / bound[0]]) if aspect_ratio > 1: paperwidth, paperheight = 100 / aspect_ratio, 100 else: paperwidth, paperheight = 100, 100 * aspect_ratio scale = paperwidth / bound[0] / 1.2 points *= scale # write head _write_head(output_file, width=paperwidth, height=paperheight, d3=D3) # plot _def_points(output_file, points, d3=D3) cell_types = ["truss", "link", "beam", "other_line"] keys = ["truss", "link", "line", "line"] widths = [line_width, line_width/2, line_width, line_width] for ctype, key, width in zip(cell_types, keys, widths): _write_lines(output_file, cells[ctype], line_width=width, opacity=line_opacity, line_color=COLORS[key]) _write_constraint(output_file, model_info, scale, line_width=line_width / 2, d3=D3, line_color=COLORS['constraint']) _write_faces(output_file, cells["plane"], color=COLORS['face'], opacity=face_opacity) _write_faces(output_file, cells["tetrahedron"], color=COLORS['solid'], opacity=solid_opacity) _write_faces(output_file, cells["brick"], color=COLORS['solid'], opacity=solid_opacity) _write_points(output_file, points, size=point_size, opacity=point_opacity, color=COLORS['point']) # write end _write_end(output_file)