Пример #1
0
def links_to_table_notes(elem, doc):
    if isinstance(elem, pf.Link) and "table_note" in elem.classes:
        table_number = tuple(
            str(i)
            for i in utils.get_elem_count(doc, pf.Table, register="table"))

        return pf.RawInline(
            "\\tnotex{{tn{count}:{label}}}".format(
                label=elem.url, count=".".join(table_number)),
            format="latex",
        )
Пример #2
0
def render_table_footer_latex(elem, doc, tex):
    if isinstance(elem, pf.DefinitionList):
        table_number = tuple(
            str(i)
            for i in utils.get_elem_count(doc, pf.Table, register="table"))

        with tex.create(
                lc.TableNotes(
                    prefix="tn{}".format(".".join(table_number)))) as tn:

            tn.append(lc.Footnotesize())

            for definition_item in elem.content:
                term = "".join(pf.stringify(e) for e in definition_item.term)

                definitions = [
                    utils.panflute2output(d.content, format="latex", doc=doc)
                    for d in definition_item.definitions
                ]

                tn.add_item(term, pl.NoEscape("".join(definitions)))
Пример #3
0
def math(elem, doc):
    attributes = getattr(elem, "attributes", {})
    label = attributes.get("label")

    utils.count_elements(
        elem,
        doc,
        (lambda x: isinstance(x, pf.Math) and x.format == "DisplayMath"),
        type_name="equation",
        register="equations",
        scope={
            "relevant_elems": pf.Header,
            "level": 1
        },
    )

    doc.equation_name = equation_name = label or ".".join(
        str(i)
        for i in utils.get_elem_count(doc, "equation", register="equations"))
    doc.equation_prefix = equation_prefix = utils.make_label(
        doc, "equa:{}".format(equation_name))

    if (isinstance(elem, pf.Math) and elem.format == "DisplayMath"
            and doc.format == "latex"):

        if equation_name in doc.labels:
            logger.debug(
                "Equation: %s is already a defined label, overwriting it now.",
                equation_name,
            )

        doc.labels[equation_name] = equation_prefix

        head = """\\begin{equa}[htbp]
        \\eequabox{
        """
        tail = f"""
        }}{{
        $$
        {elem.text}
        $$
        }}
        \\end{{equa}}"""

        logger.debug(elem)

        caption = attributes.get("caption", "")
        caption_title = attributes.get("caption_title")

        caption_content = []

        if caption:
            caption_content = utils.make_caption(caption, caption_title)

        caption_content.append(
            pf.RawInline(f"\\label{{{equation_prefix}}}", format="latex"))

        return [
            pf.RawInline(head, format="latex"),
            *caption_content,
            pf.RawInline(tail, format="latex"),
        ]
Пример #4
0
def render_table_odt(elem, doc):
    table = elem.content[0]
    table_number = tuple(
        str(i) for i in utils.get_elem_count(doc, pf.Table, register="table"))
    table_name = "Table{}".format("_".join(str(i) for i in table_number))
    #
    table_root = BeautifulSoup("", "xml")

    if hasattr(table, "caption") and table.caption:
        colon = ": "
        caption = "".join(pf.stringify(c) for c in table.caption)
    else:
        colon = ""
        caption = ""

    caption_odt = utils.create_nested_tags(
        **{
            "name":
            "text:p",
            "attrs": {
                "text:style-name": "Table"
            },
            "contents": [
                {
                    "name":
                    "text:span",
                    "attrs": {
                        "text:style-name": "Strong_20_Emphasis"
                    },
                    "contents": [
                        "Table ",
                        {
                            "name": "text:sequence",
                            "attrs": {
                                "text:ref-name": f"ref{table_name}",
                                "text:name": "Table",
                                "text:formula": "ooow:Table+1",
                                "style:num-format": "1",
                            },
                            "contents": [".".join(table_number)],
                        },
                        colon,
                    ],
                },
                caption,
            ],
        })

    table_root.contents.append(caption_odt)

    table_odt = utils.create_nested_tags(
        **{
            "name": "table:table",
            "attrs": {
                "table:name": table_name,
                "table:style-name": table_name,
                "table:template-name": "Default Style",
            },
        })

    table_root.contents.append(table_odt)

    unoccupied_width = 1 - sum(table.width)
    unspecified_widths = len([w for w in table.width if not w])
    remaining_for_each = unoccupied_width / unspecified_widths

    widths = [w if w else remaining_for_each for w in table.width]

    # We want the table to occupy a maximum width
    widths = map(lambda x: x * table.total_width, widths)

    column_style_names, column_styles, column_definitions = zip(
        *create_column_definitions(widths, table_name))

    pf.debug(column_style_names, column_styles, column_definitions)

    styles = BeautifulSoup("", "xml")
    styles.contents = list(column_styles)

    table_odt.contents.extend(column_definitions)

    for r, row in enumerate(table.content):
        row_odt = Tag(name="table:table-row")
        row_odt.attrs = {
            "table:style-name":
            "{table_name}.{r}".format(table_name=table_name, r=r + 1)
        }

        row_cell_styles = []

        for c, cell in enumerate(row.content):

            if cell.covered:
                cell_odt = Tag(name="table:covered-table-cell")
                row_odt.contents.append(cell_odt)

                row_cell_styles.append(None)
            else:
                cell_odt = Tag(name="table:table-cell")

                cell_style_name = "{column_style}{r}".format(
                    column_style=column_style_names[c], r=r + 1)

                cell_style = Tag(name="style:style")
                cell_style.attrs = {
                    "style:name": cell_style_name,
                    "style:family": "table-cell",
                    "style:writing-mode": "page",
                }
                style_cell_properies = Tag(name="style:table-cell-properties")
                style_cell_properies.attrs = {
                    "fo:padding-left": "0.10cm",
                    "fo:padding-right": "0.10cm",
                    "fo:padding-top": "0.10cm",
                    "fo:padding-bottom": "0.10cm",
                    "style:vertical-align": "bottom",
                }
                style_background_image = Tag(name="style:background-image")
                style_cell_properies.contents.append(style_background_image)
                cell_style.contents.append(style_cell_properies)

                row_cell_styles.append(cell_style)

                cell_odt.attrs = {
                    "table:style-name": cell_style_name,
                    "office:value-type": "string",
                }

                if cell.col_span > 1:
                    cell_odt.attrs[
                        "table:number-columns-spanned"] = cell.col_span

                if cell.content:
                    cell_content = utils.panflute2output(
                        cell.content, format="opendocument").strip()

                    cell_content = BeautifulSoup(cell_content,
                                                 "lxml").html.body

                    text_p = re.compile("text:p")

                    for t in cell_content.find_all(text_p):
                        if cell.heading == 1:
                            t["text:style-name"] = "Table_20_Heading"
                        elif cell.heading == 2:
                            t["text:style-name"] = "Table_20_Subheading"
                        else:
                            t["text:style-name"] = "Table_20_Contents"

                        if cell.vertical:
                            t_contents = t.contents
                            t.contents = [
                                utils.create_nested_tags(
                                    **{
                                        "name": "text:span",
                                        "attrs": {
                                            "text:style-name": "Vertical"
                                        },
                                        "contents": t_contents,
                                    })
                            ]
                    cell_odt.contents = cell_content.contents
                else:
                    cell_content = Tag(name="text:p")
                    cell_content.attrs = {
                        "text:style-name": "Table_20_contents"
                    }
                    cell_odt.contents.append(cell_content)

                row_odt.contents.append(cell_odt)

        if row.underlines:
            for underline in row.underlines:
                start = underline[0]
                stop = underline[1]

                for i in range(start - 1, stop):
                    cell_style = row_cell_styles[i]

                    if cell_style is None:
                        pass
                    else:
                        cell_style.contents[0].attrs[
                            "fo:border-bottom"] = "0.5pt solid #000000"

        add_top_space = table.content[r - 1].btm_space if r else False

        if row.top_space or add_top_space:
            for cell_style in row_cell_styles:
                if cell_style is not None:
                    padding_top = cell_style.contents[0].attrs[
                        "fo:padding-top"]

                    padding_top = (float(padding_top.strip("cm")) +
                                   0.05 * add_top_space + 0.05 * row.top_space)

                    cell_style.contents[0].attrs[
                        "fo:padding-top"] = f"{padding_top}cm"

        row_cell_styles = [cs for cs in row_cell_styles if cs is not None]
        styles.contents.extend(row_cell_styles)

        table_odt.contents.append(row_odt)

    try:
        footer = elem.content[1].content[0]
    except IndexError:
        footer = None

    if footer is not None:
        for definition_item in footer.content:
            term = "".join(pf.stringify(e) for e in definition_item.term)

            definitions = [
                utils.panflute2output(d.content, format="opendocument")
                for d in definition_item.definitions
            ]
            definitions_parsed = BeautifulSoup("".join(definitions),
                                               "lxml").html.body.contents

            for t in definitions_parsed:
                if t.name == "text:p":
                    t.name = "text:span"
                    t.contents.insert(0, NavigableString(" "))

            definition = utils.create_nested_tags(
                **{
                    "name":
                    "text:p",
                    "attrs": {
                        "text:style-name": "Table_20_Legend"
                    },
                    "contents": [{
                        "name": "text:span",
                        "attrs": {
                            "text:style-name": "Superscript"
                        },
                        "contents": [term],
                    }] + definitions_parsed,
                })
            table_root.contents.append(definition)

    styles = "\n".join(c.prettify() for c in styles.contents)
    doc.auto_styles.append(styles)

    table = "\n".join(str(c) for c in table_root.contents)
    # pf.debug(table)

    return table
Пример #5
0
def format_table(elem, doc):
    attributes = getattr(elem, "attributes", {})
    label = attributes.get("label")

    doc.table_name = table_name = label or ".".join(
        str(i) for i in utils.get_elem_count(doc, pf.Table, register="table"))
    doc.table_prefix = table_prefix = utils.make_label(
        doc, "tab:{}".format(table_name))

    if table_name in doc.labels:
        logger.debug(
            "Table %s is already a defined label, overwriting it now.",
            table_name)

    doc.labels[table_name] = table_prefix

    doc.table_note_prefix = table_note_prefix = utils.make_label(
        doc, "tn:{}".format(table_name))

    has_table_notes = False

    if isinstance(elem.next, pf.DefinitionList):
        has_table_notes = True
        table_notes_list = elem.next
    else:
        head = tail = ""

    cols = get_cols(elem, doc)

    elem = elem.walk(_table_links)
    # elem = elem.walk(table_special_stringexpressions)
    elem = elem.walk(table_emph)

    alignment = attributes.setdefault(
        "alignment", ",".join(_ALIGNMEN_DICT[a] for a in elem.alignment))

    alignment = list(
        column_specifiers_from_string(alignment, ignore_errors=True))
    alignment = [a.indent(cols[i]) for i, a in enumerate(alignment)]
    alignment = [a_ for a in alignment for a_ in a]

    attributes["alignment"] = alignment

    environment = attributes.get("environment")
    env_head, env_tail = _get_env(attributes, environment)

    head = env_head

    head += """\\toprule
    """
    tail = """ \\bottomrule
    """

    tail += env_tail

    rows = []
    caption = []

    if elem.caption:
        caption_title = attributes.get("caption_title")

        caption = utils.make_caption(elem.caption, caption_title)

    caption.append(pf.RawInline(f"\\label{{{table_prefix}}}", format="latex"))

    if _has_header(elem):
        row = format_row(elem.header,
                         doc,
                         cols,
                         alignment,
                         attributes,
                         is_header=True)

        if row is not None:
            rows.extend(row)

    for row in elem.content:
        row = format_row(row, doc, cols, alignment, attributes)

        if row is not None:
            rows.extend(row)

    table_notes = []

    if has_table_notes:
        tablenotesoptions = attributes.get("tablenotesoptions")
        table_notes_head = """
        \\vspace{.5\\skip\\footins}
        """
        table_notes_head += """
        \\begin{{tablenotes}}{}""".format(
            f"[{tablenotesoptions}]" if tablenotesoptions else "")

        table_notes_tail = """
        \\end{tablenotes}
        \\end{threeparttable}
        """

        for table_note in table_notes_list.content:
            term = "".join(pf.stringify(e) for e in table_note.term)
            term = _num_label_to_symbol(term)
            label = _format_label(term)

            definition = pf.Span(*gather_inline(table_note.definitions))

            table_notes.extend([
                pf.RawInline(
                    f"""
                        \\item[{term}] \\label{{{table_note_prefix}:{label}}}""",
                    format="latex",
                ),
                definition,
            ])

        if table_notes:
            head = ("""\\begin{threeparttable}
            """ + head)
            table_notes = [
                pf.RawInline(table_notes_head, format="latex"),
                *table_notes,
                pf.RawInline(table_notes_tail, format="latex"),
            ]

    if not rows:
        return None
    else:
        return (
            [
                pf.RawInline(head, format="latex"),
                *rows,
                pf.RawInline(tail, format="latex"),
            ],
            caption,
            table_notes,
        )
Пример #6
0
def figure(elem, doc):
    attributes = getattr(elem, "attributes", {})
    label = attributes.get("label")
    float_row = attributes.get("float_row", None)
    sub_float_rows = attributes.get("sub_float_rows", None)

    utils.count_elements(
        elem,
        doc,
        lambda e: isinstance(e, pf.Image) and "sub_float_rows" in getattr(
            e, "attributes", {}),
        type_name="subfigures",
        register="figures",
        scope={
            "relevant_elems": _is_figure_or_subfloatrow,
            "type_name": "figures_and_subfloatrows",
            "level": 1,
            "scope": {
                "relevant_elems": pf.Header,
                "level": 1
            },
        },
    )

    yield

    if isinstance(elem, pf.Image) and doc.format == "latex":
        doc.figure_name = figure_name = label or ".".join(
            str(i) for i in utils.get_elem_count(
                doc,
                "figures_and_subfloatrows"
                if sub_float_rows is None else "subfigures",
                register="figures",
            ))
        doc.figure_prefix = figure_prefix = utils.make_label(
            doc, "fig:{}".format(figure_name))

        if figure_name in doc.labels:
            logger.debug(
                "Figure: %s is already a defined label, overwriting it now.",
                figure_name,
            )

        doc.labels[figure_name] = figure_prefix

        url = getattr(elem, "url", "")
        use_input = any(url.endswith(s) for s in (".pgf", ".pdf_tex"))

        if doc.format == "latex":

            for fr in (sub_float_rows, float_row):
                if fr:
                    floatrow_type = fr.attributes.setdefault(
                        "float_type", "figure")

                    if floatrow_type != "figure":
                        raise Exception(
                            "Mixed floatrows / subfloatrows aren't possible.")

                    break

            lineheight = elem.attributes.get("lineheight", None)

            if use_input:
                graphic = f"\\input{{{url}}}"
            else:
                graphic = f"\\includegraphics{{{url}}}"

            if "scale" in elem.attributes:
                scale = elem.attributes["scale"]
                graphic = f"\\scalebox{{{scale}}}{{{graphic}}}"
            else:
                width = float(elem.attributes.get("width", "1"))

                width = f"{width}\\textwidth"

                if url.endswith(".pgf"):
                    graphic = f"\\resizebox{{{width}}}{{!}}{{{graphic}}}"
                elif url.endswith(".pdf_tex"):
                    graphic = f"\\def\\svgwidth{{{width}}}{{{graphic}}}"
                else:
                    graphic = f"\\includegraphics[width={width}]{{{url}}}"

            fontsize = elem.attributes.get("fontsize", "")
            svgbaselineskip = ""

            if fontsize:
                fontsize = fontsize.split(",")
                fontsize = [s.strip() for s in fontsize]

                if len(fontsize) == 1:
                    fontsize = fontsize[0]
                    size, unit = utils.string_to_float_unit(fontsize)

                    baselineskip = size * 1.2
                    baselineskip = f"{baselineskip}{unit}"
                else:
                    fontsize, baselineskip = fontsize

                fontsize = f"\\fontsize{{{fontsize}}}{{{baselineskip}}}\\selectfont"

            if lineheight:
                lineheight = float(lineheight)
                svgbaselineskip = f"""
                    \\setstretch{{{lineheight:.2f}}}"""

            placement = elem.attributes.get("placement", "htbp")

            head = ("" if any(
                (float_row,
                 sub_float_rows)) else f"\\begin{{figure}}[{placement}]")

            ffigboxoptions = attributes.get("ffigboxoptions")

            head += """
            \\ffigbox{}{{
            """.format(f"[{ffigboxoptions}]" if ffigboxoptions else "")

            head += f"""
            \\tcfamily{svgbaselineskip}{fontsize}
            """

            mid = """
            }{
            """

            tail = "" if any((sub_float_rows, float_row)) else "\\end{figure}"
            tail = ("""}
            """ + tail)

            head = pf.RawInline((head + graphic + mid), format="latex")

            caption = list(elem.content)
            if caption:
                caption = utils.make_caption(
                    elem.content,
                    elem.attributes.get("caption_title"),
                    subcaption=bool(sub_float_rows),
                )

            caption.append(
                pf.RawInline(f"\\label{{{figure_prefix}}}", format="latex"))

            tail = pf.RawInline(tail, format="latex")

            yield [head, *caption, tail]

        else:
            yield None

    elif isinstance(elem, pf.Div) and "subfloatrows" in elem.classes:
        # We already get them here and store the values so we don't have to count elements twice
        # In render_sub_float_rows we use them again
        figure_name = label or ".".join(
            str(i) for i in utils.get_elem_count(
                doc,
                "figures_and_subfloatrows"
                if sub_float_rows is None else "subfigures",
                register="figures",
            ))
        figure_prefix = utils.make_label(doc, "fig:{}".format(figure_name))
        elem.attributes["_figure_name"] = figure_name
        elem.attributes["_figure_prefix"] = figure_prefix