svgdigitizer.svgfigure

Reconstructs scientific plots with units and allows reconstructing a time axis. In principle the class SVGFigure adds more functionality than the class SVGPlot.

A detailed description of different kinds of plots can be found in the documentation.

class svgdigitizer.svgfigure.SVGFigure(svgplot, metadata=None, measurement_type='custom', force_si_units=False)

A digitized plot derived from an SVG file, which provides access to the objects of the figure.

Typically, the SVG input has been created by tracing a CV from a publication with a <path> in an SVG editor such as Inkscape. Such a path can then be analyzed by this class to produce the coordinates corresponding to the original measured values.

In addition it extracts the units from the labels, and thus allows conversion of the data into SI units. Also by providing a text field with a scan rate such as scan rate: 50 K / s, allows reconstructing of the time axis of the data.

A detailed description can also be found in the documentation.

EXAMPLES:

The following plot has different kinds of axis units. These units must be compatible with the astropy unit module:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 100 L 100 0" />
...     <text x="0" y="0">curve: 0</text>
...   </g>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">T1: 0 mK</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">T2: 1 mK</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: 0 uA / cm2</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1 uA / cm2</text>
...   </g>
...   <text x="-200" y="330">scan rate: 50 K/s</text>
... </svg>'''))
>>> figure = SVGFigure(SVGPlot(svg))

In addition a text label with a scan rate is provided in the above example, which allows reconstructing a time axis from the plot:

>>> figure.df
         t    T    j
0  0.00000  0.0  0.0
1  0.00002  1.0  1.0

The data can also be directly converted into SI units:

>>> figure_si = SVGFigure(SVGPlot(svg), force_si_units=True)
>>> figure_si.df
         t      T     j
0  0.00000  0.000  0.00
1  0.00002  0.001  0.01

The units of the data can be retrieved from the data schema

>>> figure_si.data_schema
{'fields': [{'name': 'T', 'type': 'number', 'unit': 'K'},
            {'name': 'j', 'type': 'number', 'unit': 'A / m2'},
            {'name': 't', 'type': 'number', 'unit': 's'}]}

The original units in turn can be retrieved from the figure schema

>>> figure_si.figure_schema
{'fields': [{'name': 'T', 'type': 'number', 'unit': 'mK', 'orientation': 'x'},
            {'name': 'j',
             'type': 'number',
             'unit': 'uA / cm2',
             'orientation': 'y'}]}
property comment

Return a comment describing the plot.

The comment is read from a <text> field in the SVG file such as <text>comment: noisy data</text>.

EXAMPLES:

This example contains a comment:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">x1: 0 V</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">x2: 1 V</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: A / cm2</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1 A / cm2</text>
...   </g>
...   <text x="-200" y="330">scan rate: 50 V/s</text>
...   <text x="-400" y="430">comment: noisy data</text>
... </svg>'''))
>>> figure = SVGFigure(SVGPlot(svg))
>>> figure.comment
'noisy data'

This example does not contain a comment:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">x1: 0 V</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">x2: 1 V</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: A / cm2</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1 A / cm2</text>
...   </g>
...   <text x="-200" y="330">scan rate: 50 V/s</text>
... </svg>'''))
>>> figure = SVGFigure(SVGPlot(svg))
>>> figure.comment
''
static create_figure(measurement_type=None)

Creates plots for specific data such as cyclic voltammograms (CV). TODO:: Add description and docstring (see issue #177)

property curve_label

A descriptive label for this curve to distinguish it from other curves in the same figure.

The curve label read from a <text> in the SVG file such as <text>curve: solid line</text>.

EXAMPLES:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 100 L 100 0" />
...     <text x="0" y="0">curve: solid line</text>
...   </g>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">E1: 0 V</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">E2: 1 V</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: 0 A / cm2</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1 A / cm2</text>
...   </g>
... </svg>'''))
>>> figure = SVGFigure(SVGPlot(svg))
>>> figure.curve_label
'solid line'
property data_schema

A frictionless Schema object, including a Field object describing the data generated with df(). When the units of the axis in the columns of the df() remain unchanged and no axis was added, such as a time axis reconstructed from a scan rate, data_schema is almost identical to figure_schema. In the individual fields the key orientation was removed. The units of the individual fields are updated upon transformation of the plot to SI units.

EXAMPLES:

A plot without a scan rate:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 100 L 100 0" />
...     <text x="0" y="0">curve: 0</text>
...   </g>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">E1: 0 V</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">E2: 1 V</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: 0 uA / cm2</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1 uA / cm2</text>
...   </g>
... </svg>'''))
>>> figure = SVGFigure(SVGPlot(svg))
>>> figure.data_schema  
{'fields': [{'name': 'E', 'type': 'number', 'unit': 'V'},
            {'name': 'j', 'type': 'number', 'unit': 'uA / cm2'}]}

A plot without a scan rate but incompatible x axis units:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 100 L 100 0" />
...     <text x="0" y="0">curve: 0</text>
...   </g>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">E1: 0 V vs. RHE</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">E2: 1 V vs. RHE</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: 0 uA / cm2</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1 uA / cm2</text>
...   </g>
... </svg>'''))
>>> figure1 = SVGFigure(SVGPlot(svg))
>>> figure1.data_schema  
{'fields': [{'name': 'E', 'type': 'number', 'unit': 'V vs. RHE'},
            {'name': 'j', 'type': 'number', 'unit': 'uA / cm2'}]}

A plot with a scan rate:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 100 L 100 0" />
...     <text x="0" y="0">curve: 0</text>
...   </g>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">E1: 0 V</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">E2: 1 V</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: 0 uA / cm2</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1 uA / cm2</text>
...   </g>
...   <text x="-200" y="330">scan rate: 50 V/s</text>
... </svg>'''))
>>> figure_rate = SVGFigure(SVGPlot(svg))
>>> figure_rate.data_schema  
{'fields': [{'name': 'E', 'type': 'number', 'unit': 'V'},
            {'name': 'j', 'type': 'number', 'unit': 'uA / cm2'},
            {'name': 't', 'type': 'number', 'unit': 's'}]}

A plot with a scan rate and converted to SI units:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 100 L 100 0" />
...     <text x="0" y="0">curve: 0</text>
...   </g>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">T1: 0 mK</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">T2: 1 mK</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: 0 uA / cm2</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1 uA / cm2</text>
...   </g>
...   <text x="-200" y="330">scan rate: 50 K/s</text>
... </svg>'''))
>>> figure_rate_si = SVGFigure(SVGPlot(svg), force_si_units=True)
>>> figure_rate_si.data_schema  
{'fields': [{'name': 'T', 'type': 'number', 'unit': 'K'},
            {'name': 'j', 'type': 'number', 'unit': 'A / m2'},
            {'name': 't', 'type': 'number', 'unit': 's'}]}
property df

Return the figure as a dataframe.

EXAMPLES:

A simple x vs. y plot without axis units:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 100 L 100 0" />
...     <text x="0" y="0">curve: 0</text>
...   </g>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">E1: 0</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">E2: 1</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: 0</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1</text>
...   </g>
... </svg>'''))
>>> figure = SVGFigure(SVGPlot(svg))
>>> figure.df
     E    j
0  0.0  0.0
1  1.0  1.0

A simple x vs. y plot with units on both axis:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 100 L 100 0" />
...     <text x="0" y="0">curve: 0</text>
...   </g>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">E1: 0 V</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">E2: 1 V</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: 0 uA / cm2</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1 uA / cm2</text>
...   </g>
... </svg>'''))
>>> figure = SVGFigure(SVGPlot(svg))
>>> figure.df
     E    j
0  0.0  0.0
1  1.0  1.0

A dataframe with a time axis, reconstructed with a given scan rate:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 100 L 100 0" />
...     <text x="0" y="0">curve: 0</text>
...   </g>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">E1: 0 mV</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">E2: 1 mV</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: 0 uA / cm2</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1 uA / cm2</text>
...   </g>
...   <text x="-200" y="330">scan rate: 50 mV / s</text>
... </svg>'''))
>>> figure = SVGFigure(SVGPlot(svg))
>>> figure.df
      t    E    j
0  0.00  0.0  0.0
1  0.02  1.0  1.0

A dataframe with a time axis, reconstructed with a given scan rate and in SI units:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 100 L 100 0" />
...     <text x="0" y="0">curve: 0</text>
...   </g>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">E1: 0 mV</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">E2: 1 mV</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: 0 uA / cm2</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1 uA / cm2</text>
...   </g>
...   <text x="-200" y="330">scan rate: 50 mV / s</text>
... </svg>'''))
>>> figure = SVGFigure(SVGPlot(svg), force_si_units=True)
>>> figure.df
      t      E     j
0  0.00  0.000  0.00
1  0.02  0.001  0.01

TESTS:

A dataframe with a time axis, reconstructed with a given scan rate and in SI units, where the y-axis does not have compatible astropy units:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 100 L 100 0" />
...     <text x="0" y="0">curve: 0</text>
...   </g>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">E1: 0 mV</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">E2: 1 mV</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: 0 persons</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1 persons</text>
...   </g>
...   <text x="-200" y="330">scan rate: 50 mV / s</text>
... </svg>'''))
>>> figure1 = SVGFigure(SVGPlot(svg), force_si_units=True)
>>> figure1.df
      t      E    j
0  0.00  0.000  0.0
1  0.02  0.001  1.0
property figure_label

An identifier of the plot to distinguish it from other figures on the same page.

The figure name is read from a <text> in the SVG file such as <text>figure: 2b</text>.

EXAMPLES:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">E1: 0 V</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">E2: 1 V</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: 0 A / cm2</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1 A / cm2</text>
...   </g>
...   <text x="-200" y="330">Figure: 2b</text>
... </svg>'''))
>>> figure = SVGFigure(SVGPlot(svg))
>>> figure.figure_label
'2b'
property figure_schema

A frictionless Schema object, including a Fields object describing the axis of the original plot including original units.

EXAMPLES:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 100 L 100 0" />
...     <text x="0" y="0">curve: 0</text>
...   </g>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">E1: 0 V</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">E2: 1 V</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: 0 uA / cm2</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1 uA / cm2</text>
...   </g>
...   <text x="-200" y="330">scan rate: 50 V/s</text>
... </svg>'''))
>>> figure = SVGFigure(SVGPlot(svg))
>>> figure.figure_schema  
{'fields': [{'name': 'E', 'type': 'number', 'unit': 'V', 'orientation': 'x'},
            {'name': 'j', 'type': 'number', 'unit': 'uA / cm2', 'orientation': 'y'}]}

A plot without axis units:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 100 L 100 0" />
...     <text x="0" y="0">curve: 0</text>
...   </g>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">E1: 0</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">E2: 1</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: 0</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1</text>
...   </g>
... </svg>'''))
>>> figure = SVGFigure(SVGPlot(svg))
>>> figure.figure_schema  
{'fields': [{'name': 'E', 'type': 'number', 'unit': '', 'orientation': 'x'},
            {'name': 'j', 'type': 'number', 'unit': '', 'orientation': 'y'}]}
property measurement_type

A full name or acronym of the measurement shown in the plot, such as IR, Raman, I-U profile, …

EXAMPLES:

The default name is ‘custom’:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">x1: 0 V</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">x2: 1 V</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: A / cm2</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1 A / cm2</text>
...   </g>
... </svg>'''))
>>> figure = SVGFigure(SVGPlot(svg))
>>> figure.measurement_type
'custom'

The type can be specified explicitly.

>>> figure = SVGFigure(SVGPlot(svg), measurement_type='I-U')
>>> figure.measurement_type
'I-U'
property metadata

A dict with properties of the original figure derived from textlabels in the SVG file, as well as properties of the dataframe created with df().

EXAMPLES:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 100 L 100 0" />
...     <text x="0" y="0">curve: 0</text>
...   </g>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">E1: 0 mV</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">E2: 1 mV</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: 0 uA / cm2</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1 uA / cm2</text>
...   </g>
...   <text x="-200" y="330">scan rate: 50 V/s</text>
...   <text x="-400" y="430">comment: noisy data</text>
...   <text x="-400" y="530">linked: SXRD, SHG</text>
...   <text x="-200" y="630">Figure: 2b</text>
...   <text x="-200" y="730">tags: BCV, HER, OER</text>
... </svg>'''))
>>> figure = SVGFigure(SVGPlot(svg))
>>> figure.metadata == \
... {'experimental': {'tags': ['BCV', 'HER', 'OER']},
...  'source': {'figure': '2b', 'curve': '0'},
...  'figure description': {'version': 1,
...  'type': 'digitized',
...  'measurement type': 'custom',
...  'fields': [{'name': 'E', 'type': 'number', 'orientation': 'x', 'unit': 'mV'},
...             {'name': 'j', 'type': 'number', 'orientation': 'y', 'unit': 'uA / cm2'}],
...  'comment': 'noisy data',
...  'scan rate': {'value': 50.0, 'unit': 'V / s'},
...  'simultaneous measurements': ['SXRD', 'SHG']},
...  'data description': {'version': 1, 'type': 'digitized', 'measurement type': 'custom', 'fields':
...                       [{'name': 'E', 'type': 'number', 'unit': 'mV'},
...                       {'name': 'j', 'type': 'number', 'unit': 'uA / cm2'},
...                       {'name': 't', 'type': 'number', 'unit': 's'}]}}
True

TESTS:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 100 L 100 0" />
...     <text x="0" y="0">curve: 0</text>
...   </g>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">E1: 0 mV</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">E2: 1 mV</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: 0 uA / cm2</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1 uA / cm2</text>
...   </g>
...   <text x="-400" y="430">comment: noisy data</text>
...   <text x="-400" y="530">linked: SXRD, SHG</text>
...   <text x="-200" y="630">Figure: 2b</text>
...   <text x="-200" y="730">tags: BCV, HER, OER</text>
... </svg>'''))
>>> figure = SVGFigure(SVGPlot(svg))
>>> figure.metadata == \
... {'experimental': {'tags': ['BCV', 'HER', 'OER']},
...  'source': {'figure': '2b', 'curve': '0'},
...  'figure description': {'version': 1,
...  'type': 'digitized',
...  'measurement type': 'custom',
...  'fields': [{'name': 'E', 'type': 'number', 'orientation': 'x', 'unit': 'mV'},
...             {'name': 'j', 'type': 'number', 'orientation': 'y', 'unit': 'uA / cm2'}],
...  'comment': 'noisy data',
...  'simultaneous measurements': ['SXRD', 'SHG']},
...  'data description': {'version': 1, 'type': 'digitized', 'measurement type': 'custom', 'fields':
...                       [{'name': 'E', 'type': 'number', 'unit': 'mV'},
...                       {'name': 'j', 'type': 'number', 'unit': 'uA / cm2'}]}}
True
plot()

Visualize the data in the figure.

EXAMPLES:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 100 L 100 0" />
...     <text x="0" y="0">curve: 0</text>
...   </g>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">E1: 0 V</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">E2: 1 V</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: 0 A / cm2</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1 A / cm2</text>
...   </g>
...   <text x="-200" y="330">scan rate: 50 mV / s</text>
... </svg>'''))
>>> figure = SVGFigure(SVGPlot(svg))
>>> figure.plot()
property scan_rate

Return the scan rate of the plot as an astropy quantity, when it matches the following criteria.

The rate must be a unit divided by time or simply a frequency. It must be compatible with the unit on the x-axis, i.e., when the x-axis unit is K the rate must be K/s.

EXAMPLES:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 100 L 100 0" />
...     <text x="0" y="0">curve: 0</text>
...   </g>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">E1: 0 V</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">E2: 1 V</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: 0 A / cm2</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1 A / cm2</text>
...   </g>
...   <text x="-200" y="330">scan rate: 50 mV / s</text>
... </svg>'''))
>>> figure = SVGFigure(SVGPlot(svg))
>>> figure.scan_rate
<Quantity 50. mV / s>

TESTS:

A plot without a scan rate:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 100 L 100 0" />
...     <text x="0" y="0">curve: 0</text>
...   </g>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">E1: 0 V</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">E2: 1 V</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: 0 A / cm2</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1 A / cm2</text>
...   </g>
... </svg>'''))
>>> figure2 = SVGFigure(SVGPlot(svg))
>>> figure2.scan_rate

A plot with a scan rate that does not match with the x-axis units:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 100 L 100 0" />
...     <text x="0" y="0">curve: 0</text>
...   </g>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">E1: 0 V</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">E2: 1 V</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: 0 A / cm2</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1 A / cm2</text>
...   </g>
...   <text x="-200" y="330">scan rate: 50 m / s</text>
... </svg>'''))
>>> figure3 = SVGFigure(SVGPlot(svg))
>>> figure3.scan_rate
property scan_rate_labels

Return the scan rate of the plot.

The scan rate is read from a <text> in the SVG file such as <text>scan rate: 50 V / s</text>.

EXAMPLES:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 100 L 100 0" />
...     <text x="0" y="0">curve: 0</text>
...   </g>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">E1: 0 V</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">E2: 1 V</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: 0 A / cm2</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1 A / cm2</text>
...   </g>
...   <text x="-200" y="330">scan rate: 50 mV / s</text>
... </svg>'''))
>>> figure = SVGFigure(SVGPlot(svg))
>>> figure.scan_rate_labels
[<text>scan rate: 50 mV / s</text>]
property simultaneous_measurements

A list of names of additional measurements which are plotted along with the digitized data in the same figure or subplot.

The names are read from a <text> in the SVG file such as <text>simultaneous measurements: SXRD, SHG</text>. Besides simultaneous measurements, also linked measurement or simply linked are acceptable in the text field.

EXAMPLES:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">x1: 0 V</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">x2: 1 V</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: A / cm2</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1 A / cm2</text>
...   </g>
...   <text x="-200" y="330">scan rate: 50 V/s</text>
...   <text x="-400" y="430">linked: SXRD, SHG</text>
... </svg>'''))
>>> figure = SVGFigure(SVGPlot(svg))
>>> figure.simultaneous_measurements
['SXRD', 'SHG']
property tags

A list of acronyms commonly used in the community to describe the measurement.

The names are read from a <text> in the SVG file such as <text>tags: BCV, HER, OER </text>.

EXAMPLES:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">x1: 0 V</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">x2: 1 V</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: A / cm2</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1 A / cm2</text>
...   </g>
...   <text x="-200" y="330">scan rate: 50 V/s</text>
...   <text x="-300" y="330">tags: BCV, HER, OER</text>
... </svg>'''))
>>> figure = SVGFigure(SVGPlot(svg))
>>> figure.tags
['BCV', 'HER', 'OER']
classmethod unit_is_astropy(unit)

Verify if a string is a compatible astropy unit.

EXAMPLES:

>>> from svgdigitizer.svgfigure import  SVGFigure
>>> SVGFigure.unit_is_astropy('mV/s')
True

TESTS:

>>> from svgdigitizer.svgfigure import  SVGFigure
>>> SVGFigure.unit_is_astropy('mv/s')
False
property xunit

Returns the unit of the x-axis.

EXAMPLES:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 100 L 100 0" />
...     <text x="0" y="0">curve: solid line</text>
...   </g>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">E1: 0 V vs. RHE</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">E2: 1 V vs. RHE</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: 0 A / cm2</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1 A / cm2</text>
...   </g>
... </svg>'''))
>>> figure = SVGFigure(SVGPlot(svg))
>>> figure.xunit
'V vs. RHE'

Returns the SI unit when the the plot is converted to SI units:

>>> from svgdigitizer.svg import SVG
>>> from svgdigitizer.svgplot import SVGPlot
>>> from svgdigitizer.svgfigure import SVGFigure
>>> from io import StringIO
>>> svg = SVG(StringIO(r'''
... <svg>
...   <g>
...     <path d="M 0 100 L 100 0" />
...     <text x="0" y="0">curve: solid line</text>
...   </g>
...   <g>
...     <path d="M 0 200 L 0 100" />
...     <text x="0" y="200">E1: 0 mK</text>
...   </g>
...   <g>
...     <path d="M 100 200 L 100 100" />
...     <text x="100" y="200">E2: 1 mK</text>
...   </g>
...   <g>
...     <path d="M -100 100 L 0 100" />
...     <text x="-100" y="100">j1: 0 A / cm2</text>
...   </g>
...   <g>
...     <path d="M -100 0 L 0 0" />
...     <text x="-100" y="0">j2: 1 A / cm2</text>
...   </g>
... </svg>'''))
>>> figure = SVGFigure(SVGPlot(svg), force_si_units=True)
>>> figure.xunit
'K'
property yunit

Returns the unit of the y-axis.

EXAMPLES:

   >>> from svgdigitizer.svg import SVG
   >>> from svgdigitizer.svgplot import SVGPlot
   >>> from svgdigitizer.svgfigure import SVGFigure
   >>> from io import StringIO
   >>> svg = SVG(StringIO(r'''
   ... <svg>
   ...   <g>
   ...     <path d="M 0 100 L 100 0" />
   ...     <text x="0" y="0">curve: solid line</text>
   ...   </g>
   ...   <g>
   ...     <path d="M 0 200 L 0 100" />
   ...     <text x="0" y="200">E1: 0 V</text>
   ...   </g>
   ...   <g>
   ...     <path d="M 100 200 L 100 100" />
   ...     <text x="100" y="200">E2: 1 V</text>
   ...   </g>
   ...   <g>
   ...     <path d="M -100 100 L 0 100" />
   ...     <text x="-100" y="100">j1: 0 A / cm2</text>
   ...   </g>
   ...   <g>
   ...     <path d="M -100 0 L 0 0" />
   ...     <text x="-100" y="0">j2: 1 A / cm2</text>
   ...   </g>
   ... </svg>'''))
   >>> figure = SVGFigure(SVGPlot(svg))
   >>> figure.yunit
   'A / cm2'

Returns the SI unit when the the plot is converted to SI units::

   >>> from svgdigitizer.svg import SVG
   >>> from svgdigitizer.svgplot import SVGPlot
   >>> from svgdigitizer.svgfigure import SVGFigure
   >>> from io import StringIO
   >>> svg = SVG(StringIO(r'''
   ... <svg>
   ...   <g>
   ...     <path d="M 0 100 L 100 0" />
   ...     <text x="0" y="0">curve: solid line</text>
   ...   </g>
   ...   <g>
   ...     <path d="M 0 200 L 0 100" />
   ...     <text x="0" y="200">E1: 0 V</text>
   ...   </g>
   ...   <g>
   ...     <path d="M 100 200 L 100 100" />
   ...     <text x="100" y="200">E2: 1 V</text>
   ...   </g>
   ...   <g>
   ...     <path d="M -100 100 L 0 100" />
   ...     <text x="-100" y="100">j1: 0 A / cm2</text>
   ...   </g>
   ...   <g>
   ...     <path d="M -100 0 L 0 0" />
   ...     <text x="-100" y="0">j2: 1 A / cm2</text>
   ...   </g>
   ... </svg>'''))
   >>> figure = SVGFigure(SVGPlot(svg), force_si_units=True)
   >>> figure.yunit
   'A / m2'