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", )
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)))
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"), ]
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
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, )
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