Skip to content

Commit

Permalink
Merge pull request #77 from hdmf-dev/add/rstfigure
Browse files Browse the repository at this point in the history
Add helper class for creating RSTFigure
  • Loading branch information
oruebel authored Aug 24, 2022
2 parents 96d381e + 65b08a3 commit c1d796d
Show file tree
Hide file tree
Showing 2 changed files with 230 additions and 54 deletions.
280 changes: 228 additions & 52 deletions hdmf_docutils/doctools/rst.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,28 @@ def __init__(self):
self.newline = "\n"
self.default_indent = ' '

def __str__(self):
return self.document

def __iadd__(self, other):
"""Add other to this document"""
if isinstance(other, str):
self.document += other
return self
elif isinstance(other, RSTDocument):
self.document += other.document
return self
else:
raise ValueError("+= for RSTDocument only supported with string and RSTDocument objects")

def __add__(self, other):
"""Create a new RSTDocument containing the text of this and the other document"""
new_rst_doc = RSTDocument()
new_rst_doc.document = self.document + other.document
new_rst_doc.newline = self.newline
new_rst_doc.default_indent = self.default_indent
return new_rst_doc

@staticmethod
def __get_headingline(title, heading_char):
"""Create a heading line for a given title"""
Expand Down Expand Up @@ -210,59 +232,14 @@ def add_include(self, filename, indent=None):
self.document += self.newline

def add_figure(self,
img,
caption=None,
legend=None,
alt=None,
height=None,
width=None,
scale=None,
align=None,
target=None):
"""
:param img: Path to the image to be shown as part of the figure.
:param caption: Optional caption for the figure
:type caption: String or RSTDocument
:param legend: Figure legend
:type legend: String or RST Document
:param alt: Alternate text. A short description of the image used when the image cannot be displayed.
:param height: Height of the figure in pixel
:type height: Int
:param width: Width of the figure in pixel
:type width: Int
:param scale: Uniform scaling of the figure in %. Default is 100.
:type scale: Int
:param align: Alignment of the figure. One of RTDDocument.ALIGN
:param target: Hyperlink to be placed on the image.
figure):
"""
self.document += self.newline
self.document += ".. figure:: %s" % img
self.document += self.newline
if scale is not None:
self.document += (self.indent_text(':scale: %i' % scale) + ' %' + self.newline)
if alt is not None:
self.document += (self.indent_text(':alt: %s' % alt) + self.newline)
if height is not None:
self.document += (self.indent_text(':height: %i px' % height) + self.newline)
if width is not None:
self.document += (self.indent_text(':width: %i px' % width) + self.newline)
if align is not None:
if align not in self.ALIGN:
raise ValueError('align not valid. Found %s expected one of %s' % (str(align), str(self.ALIGN)))
self.document += (self.indent_text(':align: %s' % align) + self.newline)
if target is not None:
self.document += (self.indent_text(':target: %s' % target) + self.newline)
self.document += self.newline
if caption is not None:
curr_caption = caption if not isinstance(caption, RSTDocument) else caption.document
self.document += (self.indent_text(curr_caption) + self.newline)
if legend is not None:
if caption is None:
self.document += (self.indent_text('.. ') + self.newline + self.default_indent + self.newline)
curr_legend = legend if not isinstance(legend, RSTDocument) else legend.document
self.document += (self.indent_text(curr_legend) + self.newline)
self.document += self.newline
Add a Figure to the document
:param figure: RSTFigure to add to the document. If set to None then do nothing
"""
if figure is not None:
figure.render(rst_doc=self)

def add_sidebar(self, text, title, subtitle=None):
"""
Expand Down Expand Up @@ -346,6 +323,16 @@ def add_table(self, rst_table, **kwargs):
"""
rst_table.render(self, **kwargs)

def add_toc(self, rst_toc):
"""
Render an RSTToc in this document
:param rst_toc: RST table of contents object to render
:type rst_toc: RSTToc
:return:
"""
rst_toc.render(self)

def write(self, filename, mode='w'):
"""
Write the document to file
Expand Down Expand Up @@ -438,6 +425,10 @@ def set_cell(self, row, col, text):
def __len__(self):
return self.num_rows()

def __str__(self):
"""Render figure as string"""
return self.render(rst_doc=None).document

def num_rows(self):
"""
:return: Number of rows in the table
Expand Down Expand Up @@ -564,6 +555,8 @@ def render(self,
:param table_ref: Name of the reference to be used for the table
:param latex_tablecolumns: Latex columns description to be rendered as part of the Sphinx tabularcolumns::
argument. E.g. '|p{3.5cm}|p{1cm}|p{10.5cm}|'
:returns: RSTDocument with the rendered table.
"""
if len(self.__table) == 0 and ignore_empty:
return rst_doc if rst_doc is not None else RSTDocument()
Expand Down Expand Up @@ -604,3 +597,186 @@ def render(self,

# Return the table
return rst_doc


class RSTToc:
"""
Helper class for defining a table of contents
"""
def __init__(
self,
entries: list = None,
caption: str = None,
name: str = None,
maxdepth: int = None,
titlesonly: bool = False,
hidden: bool = False,
numbered: bool = False,
glob: bool = False,
includehidden: bool = False,
reversed: bool = False
):
self.entries = entries if entries is not None else []
self.caption = caption
self.name = name
self.maxdepth = maxdepth
self.titlesonly = titlesonly
self.hidden = hidden
self.numbered = numbered
self.glob = glob
self.includehidden = includehidden
self.reversed = reversed

def __iadd__(self, other):
"""
Add and entry to the table of contents
:param other: String for a single entry or list, tuple, or set of strings with multiple entries, or
another RSTToc object with the entries to add
:return:
"""
if isinstance(other, str):
self.entries.append(other)
elif isinstance(other, (list, tuple, set)):
self.entries += list(other)
elif isinstance(other, RSTToc):
self.entries.append(other.entries)
else:
raise ValueError("Adding to an RSTDoc with += only supported for str, list, tuple, set, and RSTToc")
return self

def render(self,
rst_doc: RSTDocument = None):
"""
Render the toc to an RSTDocument
:param rst_doc: RSTDocument where the table should be rendered in or None if a new document should be created
:return: RSTDocument with the rendered toc
"""
rst_doc = rst_doc if rst_doc is not None else RSTDocument()
rst_doc += rst_doc.newline
rst_doc += ".. toctree::"
rst_doc += rst_doc.newline
if self.caption is not None:
rst_doc += (rst_doc.indent_text(":caption: %s" % self.caption) + rst_doc.newline)
if self.name is not None:
rst_doc += (rst_doc.indent_text(":name: %s" % self.name) + rst_doc.newline)
if self.maxdepth is not None:
rst_doc += (rst_doc.indent_text(":maxdepth: %i" % self.maxdepth) + rst_doc.newline)

# Add all the bool options
bool_options = {
'titlesonly': self.titlesonly,
'hidden': self.hidden,
'numbered': self.numbered,
'glob': self.glob,
'includehidden': self.includehidden,
'reversed': self.reversed
}
for option_name, option_value in bool_options.items():
if option_value:
rst_doc += (rst_doc.indent_text(":%s:" % option_name) + rst_doc.newline)
rst_doc += rst_doc.newline

# Add all the entries
for entry in self.entries:
rst_doc += (rst_doc.indent_text(entry) + rst_doc.newline)
rst_doc += rst_doc.newline

# Return the document
return rst_doc


class RSTFigure:
"""
Helper class to describe an RST Figure
:ivar image_path: Path to the image to be shown as part of the figure.
:ivar caption: Optional caption for the figure
:ivar legend: Figure legend
:ivar alt: Alternate text. A short description of the image used when the image cannot be displayed.
:ivar height: Integer height of the figure in pixel or string which may include the metric (e.g., 50%)
:ivar width: Integer width of the figure in pixel or string which may include the metric (e.g., 50%)
:ivar scale: Uniform scaling of the figure in %. Default is 100.
:ivar align: Alignment of the figure. One of RTDDocument.ALIGN
:ivar target: Hyperlink to be placed on the image.
"""
def __init__(
self,
image_path,
caption=None,
legend=None,
alt=None,
height=None,
width=None,
scale=None,
align=None,
target=None):
"""
:param image_path: Path to the image to be shown as part of the figure.
:param caption: Optional caption for the figure
:type caption: String or RSTDocument
:param legend: Figure legend
:type legend: String or RST Document
:param alt: Alternate text. A short description of the image used when the image cannot be displayed.
:param height: Integer height of the figure in pixel or string which may include the metric (e.g., 50%)
:param width: Integer width of the figure in pixel or string which may include the metric (e.g., 50%)
:param scale: Uniform scaling of the figure in %. Default is 100.
:param align: Alignment of the figure. One of RTDDocument.ALIGN
:param target: Hyperlink to be placed on the image.
"""
self.image_path = image_path
self.caption = caption
self.legend = legend
self.alt = alt
self.height = height
self.width = width
self.scale = scale
self.align = align
self.target = target

def render(self,
rst_doc: RSTDocument = None):
"""
Render the figure to an RSTDocument
:param rst_doc: RSTDocument where the table should be rendered in or None if a new document should be created
:return: RSTDocument with the rendered figure.
"""
rst_doc = rst_doc if rst_doc is not None else RSTDocument()
rst_doc += rst_doc.newline
rst_doc += ".. figure:: %s" % self.image_path
rst_doc += rst_doc.newline
if self.scale is not None:
rst_doc += (rst_doc.indent_text(':scale: %i' % self.scale) + ' %' + rst_doc.newline)
if self.alt is not None:
rst_doc += (rst_doc.indent_text(':alt: %s' % self.alt) + rst_doc.newline)
if self.height is not None:
height_str = self.height if isinstance(self.height, str) else ("%i px" % self.height)
rst_doc += (rst_doc.indent_text(':height: %s' % height_str) + rst_doc.newline)
if self.width is not None:
width_str = self.width if isinstance(self.width, str) else ("%i px" % self.width)
rst_doc += (rst_doc.indent_text(':width: %s' % width_str) + rst_doc.newline)
if self.align is not None:
if self.align not in self.ALIGN:
raise ValueError('align not valid. Found %s expected one of %s' % (str(self.align), str(self.ALIGN)))
rst_doc += (rst_doc.indent_text(':align: %s' % self.align) + rst_doc.newline)
if self.target is not None:
rst_doc += (rst_doc.indent_text(':target: %s' % self.target) + rst_doc.newline)
rst_doc += rst_doc.newline
if self.caption is not None:
curr_caption = self.caption if not isinstance(self.caption, RSTDocument) else self.caption.document
rst_doc += (rst_doc.indent_text(curr_caption) + rst_doc.newline)
if self.legend is not None:
if self.caption is None:
rst_doc += (rst_doc.indent_text('.. ') + rst_doc.newline + self.default_indent + rst_doc.newline)
curr_legend = self.legend if not isinstance(self.legend, RSTDocument) else self.legend.document
rst_doc += (rst_doc.indent_text(curr_legend) + rst_doc.newline)
rst_doc += rst_doc.newline
return rst_doc

def __str__(self):
"""Render figure as string"""
return self.render(rst_doc=None).document
4 changes: 2 additions & 2 deletions hdmf_docutils/generate_format_docs.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import os

from .doctools.rst import RSTSectionLabelHelper as LabelHelper
from .doctools.rst import RSTDocument
from .doctools.rst import RSTDocument, RSTFigure
from .doctools.renderrst import SpecToRST, DataTypeSection
from .doctools.output import PrintHelper, GitHashHelper

Expand Down Expand Up @@ -280,7 +280,7 @@ def render_data_type_section(section,
bbox_inches='tight',
pad_inches=0)
plt.close()
type_desc_doc.add_figure(img='./_format_auto_docs/'+rt+".*", alt=rt)
type_desc_doc.add_figure(RSTFigure(image_path='./_format_auto_docs/'+rt+".*", alt=rt))
if print_status:
PrintHelper.print(" " + rt + '-- RENDER OK.',
PrintHelper.OKGREEN)
Expand Down

0 comments on commit c1d796d

Please sign in to comment.