def run(self): required_arguments = 0 optional_arguments = 2 align = self.options.pop('align', None) capalign = self.options.pop('capalign', None) odsatable_node = odsatable() odsatable_node['align'] = align odsatable_node['capalign'] = capalign if align: odsatable_node['align'] = align if self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, '', *first_node.children) caption['align']= capalign odsatable_node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = self.state_machine.reporter.error( 'Table caption must be a paragraph or empty comment.', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [odsatable_node, error] if len(node) > 1: odsatable_node += nodes.legend('', *node[1:]) return [odsatable_node]
def run(self): figclasses = self.options.pop('figclass', None) (image_node, ) = Image.run(self) if isinstance(image_node, nodes.system_message): return [image_node] figure_node = nodes.figure('', image_node) if figclasses: figure_node['classes'] += figclasses figure_node['classes'] += ['m-figure'] if self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, '', *first_node.children) caption.source = first_node.source caption.line = first_node.line figure_node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = self.state_machine.reporter.error( 'Figure caption must be a paragraph or empty comment.', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend('', *node[1:]) return [figure_node]
def run(self): env = self.state.document.settings.env node = nodes.Element() node.document = self.state.document self.state.nested_parse(self.content, self.content_offset, node) images = [] caption_and_legend = [] for child in node: if isinstance(child, (nodes.target, nodes.image, nodes.figure)): images.append(child) else: caption_and_legend.append(child) items = [] row_item_count = min( len(images), self.options.get('rowitems', DEFAULT_ROW_ITEM_COUNT)) labels = self.options.get('labels', []) for img, label in itertools.zip_longest(images, labels): item_node = multifigure_item('', img) item_node['item-width'] = 100 // row_item_count if label is not None: item_node['label'] = label items.append(item_node) caption, legend = caption_and_legend[0], caption_and_legend[1:] resultnode = nodes.figure('', multifigure_content('', *items)) resultnode['labels'] = labels resultnode.append(nodes.caption(caption.rawsource, '', *caption)) if legend: resultnode.append(nodes.legend('', *legend)) return [resultnode]
def run(self): figclasses = self.options.pop('figclass', None) (image_node,) = Image.run(self) if isinstance(image_node, nodes.system_message): return [image_node] figure_node = nodes.figure('', image_node) if figclasses: figure_node['classes'] += figclasses figure_node['classes'] += ['m-figure'] if self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, '', *first_node.children) caption.source = first_node.source caption.line = first_node.line figure_node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = self.state_machine.reporter.error( 'Figure caption must be a paragraph or empty comment.', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend('', *node[1:]) return [figure_node]
def run(self): try: data = retrieve_glue_data(self.document, self.arguments[0]) except RetrievalError as exc: return [glue_warning(str(exc), self.document, self.line)] render: Dict[str, Any] = {} for key in ("alt", "height", "width", "scale", "class"): if key in self.options: render.setdefault("image", {})[key.replace("classes", "class")] = self.options[key] paste_nodes = render_variable_output(data, self.document, self.line, self.source, render=render) # note: most of this is copied directly from sphinx.Figure # create figure node figure_node = nodes.figure("", *paste_nodes) self.set_source_info(figure_node) # add attributes figwidth = self.options.pop("figwidth", None) figclasses = self.options.pop("figclass", None) align = self.options.pop("align", None) if figwidth is not None: figure_node["width"] = figwidth if figclasses: figure_node["classes"] += figclasses if align: figure_node["align"] = align # add target self.add_name(figure_node) # create the caption and legend if self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, "", *first_node.children) caption.source = first_node.source caption.line = first_node.line figure_node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = glue_warning( "Figure caption must be a paragraph or empty comment.", self.document, self.lineno, ) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend("", *node[1:]) return [figure_node]
def run(self): required_arguments = 0 optional_arguments = 2 align = self.options.pop('align', None) capalign = self.options.pop('capalign', None) odsatable_node = odsatable() odsatable_node['align'] = align odsatable_node['capalign'] = capalign if align: odsatable_node['align'] = align if self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, '', *first_node.children) caption['align'] = capalign odsatable_node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = self.state_machine.reporter.error( 'Table caption must be a paragraph or empty comment.', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [odsatable_node, error] if len(node) > 1: odsatable_node += nodes.legend('', *node[1:]) return [odsatable_node]
def run(self): figwidth = self.options.pop('figwidth', None) figclasses = self.options.pop('figclass', None) align = self.options.pop('align', None) (media_node,) = Media.run(self) if isinstance(media_node, nodes.system_message): return [media_node] figure_node = nodes.figure('', media_node) if figwidth == 'image': if PIL and self.state.document.settings.file_insertion_enabled: # PIL doesn't like Unicode paths: try: i = PIL.open(str(media_node['uri'])) except (IOError, UnicodeError): pass else: self.state.document.settings.record_dependencies.add( media_node['uri']) figure_node['width'] = i.size[0] elif figwidth is not None: figure_node['width'] = figwidth if figclasses: figure_node['classes'] += figclasses if align: figure_node['align'] = align if self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, '', *first_node.children) figure_node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = self.state_machine.reporter.error( 'Figure caption must be a paragraph or empty comment.', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend('', *node[1:]) node = figure_node node['label'] = self.options.get('label', None) if not node['label']: node['label'] = self.options.get('uri') node['number'] = None ret = [node] if node['label']: key = node['label'] tnode = nodes.target('', '', ids=['figure-' + node['label']]) self.state.document.note_explicit_target(tnode) ret.insert(0, tnode) return ret
def run(self): figwidth = self.options.pop('figwidth', None) figclasses = self.options.pop('figclass', ["right"]) align = self.options.pop('align', None) (media_node, ) = Media.run(self) if isinstance(media_node, nodes.system_message): return [media_node] figure_node = nodes.figure('', media_node) if figwidth == 'image': if PIL and self.state.document.settings.file_insertion_enabled: # PIL doesn't like Unicode paths: try: i = PIL.open(str(media_node['uri'])) except (IOError, UnicodeError): pass else: self.state.document.settings.record_dependencies.add( media_node['uri']) figure_node['width'] = i.size[0] elif figwidth is not None: figure_node['width'] = figwidth if figclasses: figure_node['classes'] += figclasses if align: figure_node['align'] = align if self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, '', *first_node.children) figure_node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = self.state_machine.reporter.error( 'Figure caption must be a paragraph or empty comment.', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend('', *node[1:]) node = figure_node node['label'] = self.options.get('label', None) if not node['label']: node['label'] = self.options.get('uri') node['number'] = None ret = [node] if node['label']: key = node['label'] tnode = nodes.target('', '', ids=['figure-' + node['label']]) self.state.document.note_explicit_target(tnode) ret.insert(0, tnode) return ret
def run(self): figwidth = self.options.pop('figwidth', None) position = self.options.pop('position', None) figclasses = self.options.pop('figclass', None) align = self.options.pop('align', None) (image_node,) = Image.run(self) if isinstance(image_node, nodes.system_message): return [image_node] figure_node = nodes.figure('', image_node) if figwidth == 'image': if PIL and self.state.document.settings.file_insertion_enabled: # PIL doesn't like Unicode paths: try: i = PIL.open(str(image_node['uri'])) except (IOError, UnicodeError): pass else: self.state.document.settings.record_dependencies.add( image_node['uri']) figure_node['width'] = i.size[0] elif figwidth is not None: figure_node['width'] = figwidth if figclasses: figure_node['classes'] += figclasses if align: figure_node['align'] = align if position: figure_node['position'] = position if self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.content_offset, node) first_node = node[0] cap = first_node.astext().strip() if re.match('[Tt]he.*',cap): print >>sys.stderr, "WARNING: Style: Caption '%s' begins with 'The'" % cap if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, '', *first_node.children) figure_node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = self.state_machine.reporter.error( 'Figure caption must be a paragraph or empty comment.', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend('', *node[1:]) else: self.state.document.reporter.error('Figure without caption\n', line = self.lineno) return [figure_node]
def figure(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine): figwidth = options.get('figwidth') if figwidth: del options['figwidth'] figclasses = options.get('figclass') if figclasses: del options['figclass'] align = options.get('align') if align: del options['align'] (image_node, ) = image(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine) if isinstance(image_node, nodes.system_message): return [image_node] figure_node = nodes.figure('', image_node) if figwidth == 'image': if Image and state.document.settings.file_insertion_enabled: # PIL doesn't like Unicode paths: try: i = Image.open(str(image_node['uri'])) except (IOError, UnicodeError): pass else: state.document.settings.record_dependencies.add( image_node['uri']) figure_node['width'] = i.size[0] elif figwidth is not None: figure_node['width'] = figwidth if figclasses: figure_node['classes'] += figclasses if align: figure_node['align'] = align if content: node = nodes.Element() # anonymous container for parsing state.nested_parse(content, content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, '', *first_node.children) figure_node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = state_machine.reporter.error( 'Figure caption must be a paragraph or empty comment.', nodes.literal_block(block_text, block_text), line=lineno) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend('', *node[1:]) return [figure_node]
def run(self): figwidth = self.options.pop('figwidth', None) figclasses = self.options.pop('figclass', None) align = self.options.pop('align', None) (image_node, ) = Image.run(self) if isinstance(image_node, nodes.system_message): return [image_node] figure_node = nodes.figure('', image_node) if figwidth == 'image': if PIL and self.state.document.settings.file_insertion_enabled: imagepath = urllib.url2pathname(image_node['uri']) try: if isinstance(imagepath, str): imagepath_str = imagepath else: imagepath_str = imagepath.encode( sys.getfilesystemencoding()) img = PIL.Image.open(imagepath_str) except (IOError, UnicodeEncodeError): pass # TODO: warn? else: self.state.document.settings.record_dependencies.add( imagepath.replace('\\', '/')) figure_node['width'] = '%dpx' % img.size[0] del img elif figwidth is not None: figure_node['width'] = figwidth if figclasses: figure_node['classes'] += figclasses if align: figure_node['align'] = align if self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, '', *first_node.children) caption.source = first_node.source caption.line = first_node.line figure_node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = self.state_machine.reporter.error( 'Figure caption must be a paragraph or empty comment.', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend('', *node[1:]) return [figure_node]
def run(self): figwidth = self.options.pop('figwidth', None) figclasses = self.options.pop('figclass', None) align = self.options.pop('align', None) (image_node,) = Image.run(self) if isinstance(image_node, nodes.system_message): return [image_node] figure_node = nodes.figure('', image_node) if figwidth == 'image': if PIL and self.state.document.settings.file_insertion_enabled: imagepath = urllib.url2pathname(image_node['uri']) try: if isinstance(imagepath, str): imagepath_str = imagepath else: imagepath_str = imagepath.encode(sys.getfilesystemencoding()) img = PIL.Image.open(imagepath_str) except (IOError, UnicodeEncodeError): pass # TODO: warn? else: self.state.document.settings.record_dependencies.add( imagepath.replace('\\', '/')) figure_node['width'] = '%dpx' % img.size[0] del img elif figwidth is not None: figure_node['width'] = figwidth if figclasses: figure_node['classes'] += figclasses if align: figure_node['align'] = align if self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, '', *first_node.children) caption.source = first_node.source caption.line = first_node.line figure_node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = self.state_machine.reporter.error( 'Figure caption must be a paragraph or empty comment.', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend('', *node[1:]) return [figure_node]
def run(self): figwidth = self.options.get('figwidth') if figwidth: del self.options['figwidth'] figclasses = self.options.get('figclass') if figclasses: del self.options['figclass'] align = self.options.get('align') if align: del self.options['align'] (image_node,) = Image.run(self) if isinstance(image_node, nodes.system_message): return [image_node] figure_node = nodes.figure('', image_node) if figwidth == 'image': if PIL and self.state.document.settings.file_insertion_enabled: # PIL doesn't like Unicode paths: try: i = PIL.open(str(image_node['uri'])) except (IOError, UnicodeError): pass else: self.state.document.settings.record_dependencies.add( image_node['uri']) figure_node['width'] = i.size[0] elif figwidth is not None: figure_node['width'] = figwidth if figclasses: figure_node['classes'] += figclasses if align: figure_node['align'] = align if self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, '', *first_node.children) figure_node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = self.state_machine.reporter.error( 'Figure caption must be a paragraph or empty comment.', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend('', *node[1:]) return [figure_node]
def run(self): figwidth = self.options.pop("figwidth", None) figclasses = self.options.pop("figclass", None) align = self.options.pop("align", None) (image_node, ) = Image.run(self) if isinstance(image_node, nodes.system_message): return [image_node] figure_node = nodes.figure("", image_node) if figwidth == "image": if PIL and self.state.document.settings.file_insertion_enabled: imagepath = url2pathname(image_node["uri"]) try: img = PIL.Image.open( imagepath.encode(sys.getfilesystemencoding())) except (IOError, UnicodeEncodeError): pass # TODO: warn? else: self.state.document.settings.record_dependencies.add( imagepath.replace("\\", "/")) figure_node["width"] = "%dpx" % img.size[0] del img elif figwidth is not None: figure_node["width"] = figwidth if figclasses: figure_node["classes"] += figclasses if align: figure_node["align"] = align if self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, "", *first_node.children) caption.source = first_node.source caption.line = first_node.line figure_node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = self.state_machine.reporter.error( "Figure caption must be a paragraph or empty comment.", nodes.literal_block(self.block_text, self.block_text), line=self.lineno, ) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend("", *node[1:]) return [figure_node]
def separate_legend_from_content(self): """ I can't just nested_parse(self.content...) because I want to support any directive, even if it is not available locally. That bit of rst might just get parsed in an external service """ content_offset = self.content_offset # This is 0-based """:type content_offset: int""" content_block = self.content """:type content_block: docutils.statemachine.StringList""" state = self.state """:type state: docutils.parsers.rst.states.Body""" # we only use the first legend, don't overwrite. (limit=1) directives_list = list_directives_in_block(content_offset, content_block, type_limit=['legend'], limit=1) if not directives_list: # then there is no legend return None, content_block (offset_in_block, directive_offset, directive_name, match) = directives_list[0] legend_directive \ = make_dummy_directive(directive_name, optional_arguments=0, final_argument_whitespace=False) block, indent, blank_finish \ = content_block.get_indented(start=offset_in_block, first_indent=match.end()) arguments, options, legend_content, legend_content_offset \ = state.parse_directive_block(block, directive_offset, legend_directive, option_presets={}) legend = nodes.legend(legend_content) state.nested_parse(legend_content, legend_content_offset, legend) last_offset = legend_content.offset(-1) - content_offset + 1 if blank_finish: last_offset += 1 visual_content = content_block[:] """copy of content_block that will have legend removed""" visual_content.disconnect() # disconnect from content_block del visual_content[offset_in_block:last_offset] # legend_block = content_block[offset_in_block:last_offset] return legend, visual_content
def run(self): self.options['width'] = '95%' label = self.options.get('label', None) (image_node, ) = Image.run(self) if isinstance(image_node, nodes.system_message): return [image_node] figure_node = nodes.figure('', image_node, ids=[label] if label is not None else []) figure_node['align'] = 'center' if self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption_node = nodes.caption(first_node.rawsource, '', *first_node.children) caption_node.source = first_node.source caption_node.line = first_node.line figure_node += caption_node elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = self.state_machine.reporter.error( 'Subfigure caption must be a paragraph or empty comment.', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend('', *node[1:]) else: rst = ViewList() rst.append(self.options['caption'], "", 0) parsed_node = nodes.section() parsed_node.document = self.state.document nested_parse_with_titles(self.state, rst, parsed_node) node = parsed_node[0] caption_node = nodes.caption(node.rawsource, '', *node.children) caption_node.source = node.source caption_node.line = node.line figure_node += caption_node return [figure_node]
def figure(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine): figwidth = options.setdefault("figwidth") figclasses = options.setdefault("figclass") align = options.setdefault("align") del options["figwidth"] del options["figclass"] del options["align"] (image_node,) = image(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine) if isinstance(image_node, nodes.system_message): return [image_node] figure_node = nodes.figure("", image_node) if figwidth == "image": if Image and state.document.settings.file_insertion_enabled: # PIL doesn't like Unicode paths: try: i = Image.open(str(image_node["uri"])) except (IOError, UnicodeError): pass else: state.document.settings.record_dependencies.add(image_node["uri"]) figure_node["width"] = i.size[0] elif figwidth is not None: figure_node["width"] = figwidth if figclasses: figure_node["classes"] += figclasses if align: figure_node["align"] = align if content: node = nodes.Element() # anonymous container for parsing state.nested_parse(content, content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, "", *first_node.children) figure_node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = state_machine.reporter.error( "Figure caption must be a paragraph or empty comment.", nodes.literal_block(block_text, block_text), line=lineno, ) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend("", *node[1:]) return [figure_node]
def run(self): figwidth = self.options.pop("figwidth", None) figclasses = self.options.pop("figclass", None) align = self.options.pop("align", None) # On the Paste node we should add an attribute to specify that only image # type mimedata is allowed, then this would be used by # PasteNodesToDocutils -> CellOutputsToNodes to alter the render priority # and/or log warnings if that type of mimedata is not available (paste_node, ) = Paste.run(self) if isinstance(paste_node, nodes.system_message): return [paste_node] figure_node = nodes.figure("", paste_node) figure_node.line = paste_node.line figure_node.source = paste_node.source if figwidth is not None: figure_node["width"] = figwidth if figclasses: figure_node["classes"] += figclasses if align: figure_node["align"] = align self.add_name(figure_node) # note: this is copied directly from sphinx.Figure if self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, "", *first_node.children) caption.source = first_node.source caption.line = first_node.line figure_node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = self.state_machine.reporter.error( "Figure caption must be a paragraph or empty comment.", nodes.literal_block(self.block_text, self.block_text), line=self.lineno, ) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend("", *node[1:]) return [figure_node]
def figure(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine): figwidth = options.setdefault('figwidth') figclass = options.setdefault('figclass') del options['figwidth'] del options['figclass'] (image_node,) = image(name, arguments, options, content, lineno, content_offset, block_text, state, state_machine) if isinstance(image_node, nodes.system_message): return [image_node] figure_node = nodes.figure('', image_node) if figwidth == 'image': if Image: # PIL doesn't like Unicode paths: try: i = Image.open(str(image_node['uri'])) except (IOError, UnicodeError): pass else: figure_node['width'] = i.size[0] elif figwidth is not None: figure_node['width'] = figwidth if figclass: figure_node.set_class(figclass) if content: node = nodes.Element() # anonymous container for parsing state.nested_parse(content, content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, '', *first_node.children) figure_node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = state_machine.reporter.error( 'Figure caption must be a paragraph or empty comment.', nodes.literal_block(block_text, block_text), line=lineno) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend('', *node[1:]) return [figure_node]
def _make_figure_node(self, *children): # Build figure node. if isinstance(children[0], nodes.system_message): return children[:1] figure_node = nodes.figure('', *children) # Pop options. figwidth = self.options.pop('figwidth', None) figclasses = self.options.pop('figclass', None) align = self.options.pop('align', None) # Figure property "figwidth". if figwidth: figure_node['width'] = figwidth # Figure property "figclass". if figclasses: figure_node['classes'] += figclasses # Figure property "align". if align: figure_node['align'] = align # Figure property "caption". Only valid when texpath is used. if self.content: node = nodes.Element() # Anonymous container for parsing. self.state.nested_parse(self.content, self.content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, '', *first_node.children) caption.source = first_node.source caption.line = first_node.line figure_node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = self.state_machine.reporter.error( 'Figure caption must be a paragraph or empty comment.', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend('', *node[1:]) return [figure_node]
def _make_figure_node(self, *children): # Build figure node. if isinstance(children[0], nodes.system_message): return children[:1] figure_node = nodes.figure('', *children) # Pop options. figwidth = self.options.pop('figwidth', None) figclasses = self.options.pop('figclass', None) align = self.options.pop('align', None) # Figure property "figwidth". if figwidth: figure_node['width'] = figwidth # Figure property "figclass". if figclasses: figure_node['classes'] += figclasses # Figure property "align". if align: figure_node['align'] = align # Figure property "caption". Only valid when texpath is used. if self.content: node = nodes.Element() # anonymous container for parsing self.state.nested_parse(self.content, self.content_offset, node) first_node = node[0] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, '', *first_node.children) caption.source = first_node.source caption.line = first_node.line figure_node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = self.state_machine.reporter.error( 'Figure caption must be a paragraph or empty comment.', nodes.literal_block(self.block_text, self.block_text), line=self.lineno) return [figure_node, error] if len(node) > 1: figure_node += nodes.legend('', *node[1:]) return [figure_node]
def run(self): """ Parse a plotly chart directive """ self.assert_has_content() env = self.state.document.settings.env # Ensure the current chart ID is initialised in the environment if "next_chart_id" not in env.temp_data: env.temp_data["next_chart_id"] = 0 # Get the ID of this chart id = env.temp_data["next_chart_id"] # Handle the src and destination URI of the *.json asset uri = directives.uri(self.arguments[0].strip()) src_uri = os.path.join(env.app.builder.srcdir, uri) # Where to get the asset during build build_uri = os.path.join(env.app.builder.outdir, "_charts", uri) # Where to put the asset during build page_uri = os.path.join( env.app.builder.outdir, env.docname) # The location of the current page relative_uri = relative_path( page_uri, build_uri) # Ultimate path of the asset relative to current page # Create the main node container and store the URI of the file which will be collected later node = nodes.container(id="ffs") node["classes"] = ["sphinx-charts"] # Increment the ID counter ready for the next chart env.temp_data["next_chart_id"] += 1 # Only if its a supported builder do we proceed (otherwise return an empty node) if env.app.builder.name in get_compatible_builders(env.app): # Make the directories and copy file (if file has changed) ensuredir(os.path.dirname(build_uri)) copyfile(src_uri, build_uri) download_name = self.options.pop("download_name", DEFAULT_DOWNLOAD_NAME) chart_node = nodes.container() chart_node["classes"] = [ "sphinx-charts-chart", f"sphinx-charts-chart-id-{id}", f"sphinx-charts-chart-uri-{relative_uri}", f"sphinx-charts-chart-dn-{download_name}", ] chart_node.replace_attr("ids", [f"sphinx-charts-chart-id-{id}"]) # This is a botch. Purely here to force inclusion of mathjax on pages with charts but without latex in the # document, because it doesn't find the $$ in the chart data (which isn't part of the document tree) math_node = nodes.paragraph("$$", "") math_node["classes"] = ["sphinx-charts-hidden"] placeholder_node = nodes.container() placeholder_node["classes"] = [ "sphinx-charts-placeholder", f"sphinx-charts-placeholder-{id}" ] placeholder_node += nodes.caption("", "Loading...") node += chart_node node += math_node node += placeholder_node # Add optional chart caption and legend (as per figure directive) if self.content: caption_node = nodes.Element( ) # Anonymous container for parsing self.state.nested_parse(self.content, self.content_offset, caption_node) first_node = caption_node[0] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, "", *first_node.children) caption.source = first_node.source caption.line = first_node.line node += caption elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): error = self.state_machine.reporter.error( "Chart caption must be a paragraph or empty comment.", nodes.literal_block(self.block_text, self.block_text), line=self.lineno, ) return [node, error] if len(caption_node) > 1: node += nodes.legend("", *caption_node[1:]) return [node]
def create_figure_context( self: DocutilsNbRenderer | SphinxNbRenderer, figure_options: dict[str, Any] | None, line: int, ) -> Iterator: """Create a context manager, which optionally wraps new nodes in a figure node. A caption may also be added before or after the nodes. """ if not isinstance(figure_options, dict): yield return # note: most of this is copied directly from sphinx.Figure # create figure node figure_node = nodes.figure() figure_node.line = line figure_node.source = self.document["source"] # add attributes to figure node if figure_options.get("classes"): # TODO change to class? figure_node["classes"] += str(figure_options["classes"]).split() if figure_options.get("align") in ("center", "left", "right"): figure_node["align"] = figure_options["align"] # add target name if figure_options.get("name"): name = nodes.fully_normalize_name(str(figure_options.get("name"))) figure_node["names"].append(name) self.document.note_explicit_target(figure_node, figure_node) # create caption node caption = None if figure_options.get("caption", ""): node = nodes.Element() # anonymous container for parsing with self.current_node_context(node): self.nested_render_text(str(figure_options["caption"]), line) first_node = node.children[0] legend_nodes = node.children[1:] if isinstance(first_node, nodes.paragraph): caption = nodes.caption(first_node.rawsource, "", *first_node.children) caption.source = self.document["source"] caption.line = line elif not (isinstance(first_node, nodes.comment) and len(first_node) == 0): self.create_warning( "Figure caption must be a paragraph or empty comment.", line=line, wtype=DEFAULT_LOG_TYPE, subtype="fig_caption", ) self.current_node.append(figure_node) old_current_node = self.current_node self.current_node = figure_node if caption and figure_options.get("caption_before", False): figure_node.append(caption) if legend_nodes: figure_node += nodes.legend("", *legend_nodes) yield if caption and not figure_options.get("caption_before", False): figure_node.append(caption) if legend_nodes: figure_node += nodes.legend("", *legend_nodes) self.current_node = old_current_node