<commit_before># Copyright 2014, Sandia Corporation. Under the terms of Contract
# DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain
# rights in this software.

from __future__ import division

from multipledispatch import dispatch
import collections
import itertools
import json
import numbers
import numpy
import toyplot.axes
import toyplot.canvas
import toyplot.color
import toyplot.compatibility
import toyplot.mark
import uuid
import xml.etree.ElementTree as xml

def apply_changes(svg, changes):
  for change_type, instructions in changes.items():
    if change_type == "set-mark-style":
      for mark_id, style in instructions:
        mark = svg.find(".//*[@id='%s']" % mark_id)
        style = toyplot.style.combine(dict([declaration.split(":") for declaration in mark.get("style").split(";") if declaration != ""]), style)
        mark.set("style", _css_style(style))
    elif change_type == "set-datum-style":
      for mark_id, series, datum, style in instructions:
        mark_xml = svg.find(".//*[@id='%s']" % mark_id)
        series_xml = mark_xml.findall("*[@class='toyplot-Series']")[series]
        datum_xml = series_xml.findall("*[@class='toyplot-Datum']")[datum]
        style = toyplot.style.combine(dict([declaration.split(":") for declaration in datum_xml.get("style").split(";") if declaration != ""]), style)
        datum_xml.set("style", _css_style(style))
    elif change_type == "set-datum-text":
      for mark_id, series, datum, text in instructions:
        mark_xml = svg.find(".//*[@id='%s']" % mark_id)
        series_xml = mark_xml.findall("*[@class='toyplot-Series']")[series]
        datum_xml = series_xml.findall("*[@class='toyplot-Datum']")[datum]
        datum_xml.text = text

def render(canvas, fobj=None, animation=False):
  """Render the SVG representation of a canvas.

  Parameters
  ----------
  canvas: :class:`toyplot.canvas.Canvas`
    The canvas to be rendered.

  fobj: file-like object or string, optional
    The file to write.  Use a string filepath to write data directly to disk.
    If `None` (the default), the SVG tree will be returned to the caller
    instead.

  animation: boolean, optional
    If `True`, return a representation of the changes to be made to the SVG
    tree for animation.

  Returns
  -------
  svg: xml.etree.ElementTree.Element or `None`
    SVG representation of `canvas`, as a DOM tree, or `None` if the caller
    specifies the `fobj` parameter.

  changes: JSON-compatible data structure, or `None`
    JSON-compatible representation of the animated changes to `canvas`.

  Notes
  -----
  The SVG representation of a canvas should be considered the "canonical"
  representation - the other toyplot backends operate by converting the output
  from toyplot.svg.render() to the desired end target.
  """

  canvas.autorender(False)

  context = _RenderContext()
  svg = xml.Element("svg", xmlns="http://www.w3.org/2000/svg", attrib={"xmlns:toyplot":"http://www.sandia.gov/toyplot"}, width="%rpx" % canvas._width, height="%rpx" % canvas._height, style=_css_style(canvas._style), id=context.get_id(canvas))
  for child in canvas._children:
    _render(canvas, child, context.push(svg))

  if isinstance(fobj, toyplot.compatibility.string_type):
    with open(fobj, "wb") as file:
      file.write(xml.tostring(svg, method="xml"))
  elif fobj is not None:
    fobj.write(xml.tostring(svg, method="xml"))
  else:
    if animation:
      svg_animation = collections.defaultdict(lambda: collections.defaultdict(list))
      for time, time_changes in canvas._animation.items():
        svg_animation[time] # Ensure we have an entry for every time, even if there aren't any changes.
        for type, type_changes in time_changes.items():
          for change in type_changes:
            svg_animation[time][type].append([context.get_id(change[0])] + list(change[1:]))
      return svg, svg_animation
    else:
      return svg



















<commit_msg>Fix an off-by-one error rendering animated canvas to svg.<commit_after># Copyright 2014, Sandia Corporation. Under the terms of Contract
# DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain
# rights in this software.

from __future__ import division

from multipledispatch import dispatch
import collections
import itertools
import json
import numbers
import numpy
import toyplot.axes
import toyplot.canvas
import toyplot.color
import toyplot.compatibility
import toyplot.mark
import uuid
import xml.etree.ElementTree as xml

def apply_changes(svg, changes):
  for change_type, instructions in changes.items():
    if change_type == "set-mark-style":
      for mark_id, style in instructions:
        mark = svg.find(".//*[@id='%s']" % mark_id)
        style = toyplot.style.combine(dict([declaration.split(":") for declaration in mark.get("style").split(";") if declaration != ""]), style)
        mark.set("style", _css_style(style))
    elif change_type == "set-datum-style":
      for mark_id, series, datum, style in instructions:
        mark_xml = svg.find(".//*[@id='%s']" % mark_id)
        series_xml = mark_xml.findall("*[@class='toyplot-Series']")[series]
        datum_xml = series_xml.findall("*[@class='toyplot-Datum']")[datum]
        style = toyplot.style.combine(dict([declaration.split(":") for declaration in datum_xml.get("style").split(";") if declaration != ""]), style)
        datum_xml.set("style", _css_style(style))
    elif change_type == "set-datum-text":
      for mark_id, series, datum, text in instructions:
        mark_xml = svg.find(".//*[@id='%s']" % mark_id)
        series_xml = mark_xml.findall("*[@class='toyplot-Series']")[series]
        datum_xml = series_xml.findall("*[@class='toyplot-Datum']")[datum]
        datum_xml.text = text

def render(canvas, fobj=None, animation=False):
  """Render the SVG representation of a canvas.

  Parameters
  ----------
  canvas: :class:`toyplot.canvas.Canvas`
    The canvas to be rendered.

  fobj: file-like object or string, optional
    The file to write.  Use a string filepath to write data directly to disk.
    If `None` (the default), the SVG tree will be returned to the caller
    instead.

  animation: boolean, optional
    If `True`, return a representation of the changes to be made to the SVG
    tree for animation.

  Returns
  -------
  svg: xml.etree.ElementTree.Element or `None`
    SVG representation of `canvas`, as a DOM tree, or `None` if the caller
    specifies the `fobj` parameter.

  changes: JSON-compatible data structure, or `None`
    JSON-compatible representation of the animated changes to `canvas`.

  Notes
  -----
  The SVG representation of a canvas should be considered the "canonical"
  representation - the other toyplot backends operate by converting the output
  from toyplot.svg.render() to the desired end target.
  """

  canvas.autorender(False)

  context = _RenderContext()
  svg = xml.Element("svg", xmlns="http://www.w3.org/2000/svg", attrib={"xmlns:toyplot":"http://www.sandia.gov/toyplot"}, width="%rpx" % canvas._width, height="%rpx" % canvas._height, style=_css_style(canvas._style), id=context.get_id(canvas))
  for child in canvas._children:
    _render(canvas, child, context.push(svg))

  if isinstance(fobj, toyplot.compatibility.string_type):
    with open(fobj, "wb") as file:
      file.write(xml.tostring(svg, method="xml"))
  elif fobj is not None:
    fobj.write(xml.tostring(svg, method="xml"))
  else:
    if animation:
      svg_animation = collections.defaultdict(lambda: collections.defaultdict(list))
      for time, time_changes in canvas._animation.items()[:-1]:
        svg_animation[time] # Ensure we have an entry for every time, even if there aren't any changes.
        for type, type_changes in time_changes.items():
          for change in type_changes:
            svg_animation[time][type].append([context.get_id(change[0])] + list(change[1:]))
      return svg, svg_animation
    else:
      return svg




















{'fraction_non_alphanumeric': 0.12770481550969356, 'fraction_numerical': 0.005128205128205128, 'mean_word_length': 3.6952436876101, 'pattern_counts': {'":': 12, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, 'xml': 46}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4352076', 'n_tokens_mistral': 2482, 'n_tokens_neox': 2419, 'n_words': 712}