diff --git a/base_classes/NXdata.nxdl.xml b/base_classes/NXdata.nxdl.xml
index 67b54a7b0e..10faae6e44 100644
--- a/base_classes/NXdata.nxdl.xml
+++ b/base_classes/NXdata.nxdl.xml
@@ -50,8 +50,8 @@
The :ref:`NXdata` class is designed to encapsulate all the information required for a set of data to be plotted.
- NXdata groups contain plottable data (sometimes referred to as *signals* or *dependent variables*) and their
- associated axis coordinates (sometimes referred to as *axes* or *independent variables*).
+ NXdata groups contain plottable data (also referred to as *signals* or *dependent variables*) and their
+ associated axis coordinates (also referred to as *axes* or *independent variables*).
The actual names of the :ref:`DATA </NXdata/DATA-field>` and :ref:`AXISNAME </NXdata/AXISNAME-field>` fields
can be chosen :ref:`freely <validItemName>`, as indicated by the upper case (this is a common convention in all NeXus classes).
@@ -60,176 +60,184 @@
does not describe how the data is to be plotted or even the dimensionality of the plot.
https://www.nexusformat.org/NIAC2018Minutes.html#nxdata-plottype--attribute
+ .. include:: data/index.rst
+
+ **Usage:**
+
+ .. admonition:: Plot data versus x axis
+
+ .. code-block::
+
+ data:NXdata
+ @signal = "data"
+ @axes = ["x"]
+ data: float[100]
+ x: float[100]
+
+ More complex cases are supported
+
+ * histogram data: ``x`` has one more value than ``data``.
+ * alternative axes: instead of a single ``x`` axis you can have several axes, one of which being the default.
+ * signals with more than one dimension: ``data`` could be 2D with axes ``x`` and ``y`` along each dimension.
+ * axes with more than one dimension: ``data`` could be 2D with axes ``x`` and ``y`` also being 2D, providing a
+ unique ``(x, y)`` coordinate for each ``data`` point.
+
**Signals:**
.. index:: plotting
-
+
+ .. admonition:: Defined by
+
+ * :ref:`DATA </NXdata/DATA-field>` fields
+ * the :ref:`signal </NXdata@signal-attribute>` attribute
+ * the :ref:`auxiliary_signals</NXdata@auxiliary_signals-attribute>` attribute
+
The :ref:`DATA </NXdata/DATA-field>` fields contain the signal values to be plotted. The name of the field
to be used as the *default plot signal* is provided by the :ref:`signal </NXdata@signal-attribute>` attribute.
The names of the fields to be used as *secondary plot signals* are provided by the
:ref:`auxiliary_signals</NXdata@auxiliary_signals-attribute>` attribute.
- An example with three signals, one of which being the default
+ .. admonition:: An example with three signals, one of which being the default
- .. code-block::
+ .. code-block::
- data:NXdata
- @signal = "data1"
- @auxiliary_signals = ["data2", "data3"]
- data1: float[10,20,30] --> the default signal
- data2: float[10,20,30]
- data3: float[10,20,30]
+ data:NXdata
+ @signal = "data1"
+ @auxiliary_signals = ["data2", "data3"]
+ data1: float[10,20,30] --> the default signal
+ data2: float[10,20,30]
+ data3: float[10,20,30]
**Axes:**
.. index:: axes (attribute)
.. index:: coordinates
- The :ref:`AXISNAME </NXdata/AXISNAME-field>` fields contain the axis coordinates associated with the data values.
- The names of all :ref:`AXISNAME </NXdata/AXISNAME-field>` fields are listed in the
- :ref:`axes </NXdata@axes-attribute>` attribute.
-
- `Rank`
-
- :ref:`AXISNAME </NXdata/AXISNAME-field>` fields are typically one-dimensional arrays, which annotate one of the dimensions.
+ .. admonition:: Defined by
- An example of this would be
+ * :ref:`AXISNAME </NXdata/AXISNAME-field>` fields
+ * the :ref:`axes </NXdata@axes-attribute>` attribute
+ * :ref:`AXISNAME_indices </NXdata@AXISNAME_indices-attribute>` attributes
- .. code-block::
+ The fields and attributes are defined as follows
- data:NXdata
- @signal = "data"
- @axes = ["x", "y"] --> the order matters
- data: float[10,20]
- x: float[10] --> coordinates along the first dimension
- y: float[20] --> coordinates along the second dimension
+ 1. The :ref:`AXISNAME </NXdata/AXISNAME-field>` fields contain the axis coordinates associated with the signal values.
- In this example each data point ``data[i,j]`` has axis coordinates ``[x[i], y[j]]``.
+ 2. The :ref:`axes </NXdata@axes-attribute>` attribute provides the names of the :ref:`AXISNAME </NXdata/AXISNAME-field>`
+ fields to be used as the `default axis` for each dimension of the :ref:`DATA </NXdata/DATA-field>` fields.
- However, the fields can also have a rank greater than 1, in which case the rank of each
- :ref:`AXISNAME </NXdata/AXISNAME-field>` must be equal to the number of data dimensions it spans.
+ 3. The :ref:`AXISNAME_indices </NXdata@AXISNAME_indices-attribute>` attributes describe the :ref:`DATA </NXdata/DATA-field>`
+ dimensions spanned by the corresponding :ref:`AXISNAME </NXdata/AXISNAME-field>` fields.
- An example of this would be
+ Additional requirements for a complete definition
- .. code-block::
+ 1. The length of the :ref:`axes </NXdata@axes-attribute>` attribute must be equal to the rank of the :ref:`DATA </NXdata/DATA-field>`
+ fields. When a particular dimension has no default axis, the string “.” is used in that position.
- data:NXdata
- @signal = "data"
- @axes = ["x", "y"] --> the order does NOT matter
- @x_indices = [0, 1]
- @y_indices = [0, 1]
- data: float[10,20]
- x: float[10,20] --> coordinates along both dimensions
- y: float[10,20] --> coordinates along both dimensions
+ 2. The number of values in :ref:`AXISNAME_indices </NXdata@AXISNAME_indices-attribute>` must be equal to the rank of the corresponding
+ :ref:`AXISNAME </NXdata/AXISNAME-field>` field.
- In this example each data point ``data[i,j]`` has axis coordinates ``[x[i,j], y[i,j]]``.
+ 3. When :ref:`AXISNAME_indices </NXdata@AXISNAME_indices-attribute>` is missing for a given
+ :ref:`AXISNAME </NXdata/AXISNAME-field>` field, the positions of the :ref:`AXISNAME </NXdata/AXISNAME-field>`
+ field name in the :ref:`axes </NXdata@axes-attribute>` attribute are used.
- `Dimensions`
+ 4. When :ref:`AXISNAME_indices </NXdata@AXISNAME_indices-attribute>` is the same as the indices of "AXISNAME" in the
+ :ref:`axes </NXdata@axes-attribute>` attribute, there is no need to provide
+ :ref:`AXISNAME_indices </NXdata@AXISNAME_indices-attribute>`.
- The data dimensions annotated by an :ref:`AXISNAME </NXdata/AXISNAME-field>` field are defined by the
- :ref:`AXISNAME_indices </NXdata@AXISNAME_indices-attribute>` attribute. When this attribute is missing,
- the position(s) of the :ref:`AXISNAME </NXdata/AXISNAME-field>` string in the
- :ref:`axes </NXdata@axes-attribute>` attribute are used.
+ 5. The indices of "AXISNAME" in the :ref:`axes </NXdata@axes-attribute>` attribute must be a subset of
+ :ref:`AXISNAME_indices </NXdata@AXISNAME_indices-attribute>`.
- When all :ref:`AXISNAME </NXdata/AXISNAME-field>` fields are one-dimensional, and none of the data dimensions
- have more than one axis, the :ref:`AXISNAME_indices </NXdata@AXISNAME_indices-attribute>` attributes
- are often omitted. If one of the data dimensions has no :ref:`AXISNAME </NXdata/AXISNAME-field>` field,
- the string “.” can be used in the corresponding index of the axes list.
+ 6. The shape of an :ref:`AXISNAME </NXdata/AXISNAME-field>` field must correspond to the shape of the
+ :ref:`DATA </NXdata/DATA-field>` dimensions it spans. This means that for each dimension ``i`` in ``[0, AXISNAME.ndim)``
+ spanned by axis field :ref:`AXISNAME </NXdata/AXISNAME-field>`, the number of axis values ``AXISNAME.shape[i]``
+ along dimension ``i`` must be equal to the number of data points ``DATA.shape[AXISNAME_indices[i]]`` along dimension ``i``
+ or one more than the number of data points ``DATA.shape[AXISNAME_indices[i]]+1`` in case the
+ :ref:`AXISNAME </NXdata/AXISNAME-field>` field contains histogram bin edges along dimension ``i``.
- An example of this would be
+ Highlight consequences that follow the definition
- .. code-block::
+ 1. An :ref:`AXISNAME </NXdata/AXISNAME-field>` field can have more than one dimension and can therefore span
+ more than one :ref:`DATA </NXdata/DATA-field>` dimension. Conversely, one :ref:`DATA </NXdata/DATA-field>` dimension
+ can be spanned by more than one :ref:`AXISNAME </NXdata/AXISNAME-field>` field. The default axis name (if any)
+ of each dimension can be found in the :ref:`axes </NXdata@axes-attribute>` attribute.
- data:NXdata
- @signal = "data"
- @axes = ["x", ".", "z"] --> the order matters
- data: float[10,20,30]
- x: float[10] --> coordinates along the first dimension
- z: float[30] --> coordinates along the third dimension
+ 2. A list of all available axes is not provided directly. All strings in the :ref:`axes </NXdata@axes-attribute>` attribute
+ (excluding the “.” string) are axis field names. In addition the prefix of an attribute ending with the string "_indices" is also
+ an axis field name.
- When using :ref:`AXISNAME_indices </NXdata@AXISNAME_indices-attribute>` this becomes
+ .. admonition:: The following example covers all axes features supported
- .. code-block::
+ .. code-block::
- data:NXdata
- @signal = "data"
- @axes = ["x", "z"] --> the order does NOT matter
- data: float[10,20,30]
- @x_indices = 0
- @z_indices = 2
- x: float[10] --> coordinates along the first dimension
- z: float[30] --> coordinates along the third dimension
+ data:NXdata
+ @signal = "data"
+ @axes = ["x_set", "y_set", "."] --> default axes for all three dimensions
+ @x_encoder_indices = [0, 1]
+ @y_encoder_indices = 1 --> or [1]
+ data: float[10,7,1024]
+ x_encoder: float[11,7] --> coordinates along the first and second dimensions
+ y_encoder: float[7] --> coordinates along the second dimension
+ x_set: float[10] --> coordinates along the first dimension
+ y_set: float[7] --> coordinates along the second dimension
- When providing :ref:`AXISNAME_indices </NXdata@AXISNAME_indices-attribute>` attributes it is recommended
- to do it for all axes.
+ One scientific application that provided such data is 2D scanning X-Ray Fluorescence (XRF)
+ where the sample is scanned through a focussed X-ray beam in two dimensions and an XRF spectrum
+ with 1024 channels is recorded at each position. In addition the x motor is scanned
+ continuously and both motors have an encoder which records the actual motor position as
+ opposed to the requested or `set` position.
- `Non-trivial axes`
+ .. image:: data/example2D_hist.png
+ :width: 100%
- What follows are two examples where :ref:`AXISNAME_indices </NXdata@AXISNAME_indices-attribute>` attributes
- cannot be omitted.
+ 1. ``@axes`` has three values which corresponds to the ``data`` rank of three
- The first is an example where data dimensions have alternative axis coordinates. The NXdata group represents
- a stack of images collected at different energies. The ``wavelength`` is an alternative axis of ``energy``
- for the last dimension (or vice versa).
+ 2. ``x_set`` and ``y_set`` are the default axes for the first two dimensions while the third
+ dimension does not have a default axis or any axis for that matter.
- .. code-block::
+ 3. ``x_set_indices`` and ``y_set_indices`` are omitted because they would be equal to
+ the position of ``"x_set"`` and ``"y_set"`` in ``@axes``.
- data:NXdata
- @signal = "data"
- @axes = ["x", "y", "energy", "wavelength"] --> the order does NOT matter
- @x_indices = 0
- @y_indices = 1
- @energy_indices = 2
- @wavelength_indices = 2
- data: float[10,20,30]
- x: float[10] --> coordinates along the first dimension
- y: float[20] --> coordinates along the second dimension
- energy: float[30] --> coordinates along the third dimension
- wavelength: float[30] --> coordinates along the third dimension
+ 4. The first dimension is spanned by two axes ``x_set`` and ``x_encoder``. Since
+ the x motor is scanned continuously, the encoder records the edge of every bin
+ on which an XRF spectrum is recorded yielding 11 values instead of 10 along the
+ first dimension. The ``x_encoder`` spans two dimensions because the actual x edges
+ are slightly different for every x motion at each y position.
- The second is an example with coordinates that span more than one dimension. The NXdata group represents data
- from 2D mesh scans performed at multiple energies. Each data point ``data[i,j,k]`` has axis coordinates
- ``[x[i,j,k], y[i,j,k], energy[k]]``.
+ 5. The second dimension is spanned by two axes ``y_set`` and ``y_encoder``. The axes
+ have as many values are there are data points along the second dimension. This is
+ because the y motor moves one step after each scan of the x motor. Since the y
+ motor does not move while scanning x, there is no need for ``y_encoder`` to span
+ the first dimension because the value along this dimension remains constant.
- .. code-block::
+ **Uncertainties:**
- data:NXdata
- @signal = "data"
- @axes = ["x", "y", "energy"] --> the order does NOT matter
- @x_indices = [0, 1, 2]
- @y_indices = [0, 1, 2]
- @energy_indices = 2
- data: float[10,20,30]
- x: float[10,20,30] --> coordinates along all dimensions
- y: float[10,20,30] --> coordinates along all dimensions
- energy: float[30] --> coordinates along the third dimension
+ .. admonition:: Defined by
- **Uncertainties:**
+ * :ref:`FIELDNAME_errors </NXdata/FIELDNAME_errors-field>` fields
Standard deviations on data values as well as coordinates can be provided by
:ref:`FIELDNAME_errors </NXdata/FIELDNAME_errors-field>` fields where ``FIELDNAME`` is the name of a
:ref:`DATA </NXdata/DATA-field>` field or an :ref:`AXISNAME </NXdata/AXISNAME-field>` field.
- An example of uncertainties on the signal, auxiliary signals and axis coordinates
-
- .. code-block::
-
- data:NXdata
- @signal = "data1"
- @auxiliary_signals = ["data2", "data3"]
- @axes = ["x", "z"]
- @x_indices = 0
- @z_indices = 2
- data1: float[10,20,30]
- data2: float[10,20,30]
- data3: float[10,20,30]
- x: float[10]
- z: float[30]
- data1_errors: float[10,20,30]
- data2_errors: float[10,20,30]
- data3_errors: float[10,20,30]
- x_errors: float[10]
- z_errors: float[30]
+ .. admonition:: An example of uncertainties on the signal, auxiliary signals and axis coordinates
+
+ .. code-block::
+
+ data:NXdata
+ @signal = "data1"
+ @auxiliary_signals = ["data2", "data3"]
+ @axes = ["x", ".", "z"]
+ data1: float[10,20,30]
+ data2: float[10,20,30]
+ data3: float[10,20,30]
+ x: float[10]
+ z: float[30]
+ data1_errors: float[10,20,30]
+ data2_errors: float[10,20,30]
+ data3_errors: float[10,20,30]
+ x_errors: float[10]
+ z_errors: float[30]
@@ -316,11 +324,13 @@
-->
- The ``AXISNAME_indices`` attribute is a single integer or an array of integers that defines which :ref:`data </NXdata/DATA-field>`
- dimension(s) are spanned by the corresponding axis. The first dimension index is ``0`` (zero).
+ The ``AXISNAME_indices`` attribute is a single integer or an array of integers that defines which :ref:`DATA </NXdata/DATA-field>`
+ dimensions are spanned by the corresponding axis. The first dimension index is ``0`` (zero).
+
+ The number of indices must be equal to the rank of the :ref:`AXISNAME </NXdata/AXISNAME-field>` field.
- When the ``AXISNAME_indices`` attribute is missing for an :ref:`AXISNAME </NXdata/AXISNAME-field>` field, its value becomes the index
- (or indices) of the :ref:`AXISNAME </NXdata/AXISNAME-field>` name in the :ref:`axes </NXdata@axes-attribute>` attribute.
+ When the ``AXISNAME_indices`` attribute is missing for a given :ref:`AXISNAME </NXdata/AXISNAME-field>` field, its value becomes
+ the index (or indices) of the :ref:`AXISNAME </NXdata/AXISNAME-field>` name in the :ref:`axes </NXdata@axes-attribute>` attribute.
.. note:: When ``AXISNAME_indices`` contains multiple integers, it must be saved as an actual array
of integers and not a comma separated string.
@@ -329,26 +339,33 @@
.. index:: plotting
-
+
The ``axes`` attribute is a list of strings which are the names of the :ref:`AXISNAME </NXdata/AXISNAME-field>` fields
- that contain the values of the coordinates along the :ref:`data </NXdata/DATA-field>` dimensions.
+ to be used as the default axis along every :ref:`DATA </NXdata/DATA-field>` dimension. As a result the length must
+ be equal to the rank of the :ref:`DATA </NXdata/DATA-field>` fields. The string "." can be used for
+ dimensions without a default axis.
.. note:: When ``axes`` contains multiple strings, it must be saved as an actual array
of strings and not a single comma separated string.
+
+
+
- Coordinate values along one or more :ref:`data </NXdata/DATA-field>` dimensions. The rank must be equal
- to the number of dimensions it spans.
-
+ Coordinate values along one or more :ref:`DATA </NXdata/DATA-field>` dimensions.
+
+ The shape of an ``AXISNAME`` field must correspond to the shape of the :ref:`DATA </NXdata/DATA-field>`
+ dimensions it spans. This means that for each ``i`` in ``[0, AXISNAME.ndim)`` the number of data points
+ ``DATA.shape[AXISNAME_indices[i]]`` must be equal to the number of coordinates ``AXISNAME.shape[i]`` or the
+ number of bin edges ``AXISNAME.shape[i]+1`` in case of histogram data.
+
As the upper case ``AXISNAME`` indicates, the names of the ``AXISNAME`` fields can be chosen :ref:`freely <validItemName>`.
- The :ref:`axes </NXdata@axes-attribute>` attribute can be used to find all datasets in the
- ``NXdata`` that contain coordinate values.
- Most AXISNAME fields will be sequences of numbers but if an axis is better represented using names, such as channel names,
+ Most ``AXISNAME`` fields will be sequences of numbers but if an axis is better represented using names, such as channel names,
an array of NX_CHAR can be provided.
Axis label
@@ -380,7 +397,7 @@
.. index:: plotting
-
+
Data values to be used as the NeXus *plottable data*. As the upper case ``DATA``
indicates, the names of the ``DATA`` fields can be chosen :ref:`freely <validItemName>`. The :ref:`signal attribute </NXdata@signal-attribute>`
and :ref:`auxiliary_signals attribute</NXdata@auxiliary_signals-attribute>` can be used to find all datasets in the ``NXdata``
@@ -424,10 +441,12 @@
"Errors" (meaning *uncertainties* or *standard deviations*)
associated with any field named ``FIELDNAME`` in this ``NXdata``
- group (e.g. an axis, signal or auxiliary signal).
+ group. This can be a :ref:`DATA </NXdata/DATA-field>` field
+ (signal or auxiliary signal) or a :ref:`AXISNAME </NXdata/AXISNAME-field>`
+ field (axis).
The dimensions of the ``FIELDNAME_errors`` field must match
- the dimensions of the ``FIELDNAME`` field.
+ the dimensions of the corresponding ``FIELDNAME`` field.
diff --git a/base_classes/data/example2D_hist.excalidraw b/base_classes/data/example2D_hist.excalidraw
new file mode 100644
index 0000000000..a2ab01a928
--- /dev/null
+++ b/base_classes/data/example2D_hist.excalidraw
@@ -0,0 +1,2086 @@
+{
+ "type": "excalidraw",
+ "version": 2,
+ "source": "https://excalidraw.com",
+ "elements": [
+ {
+ "type": "text",
+ "version": 92,
+ "versionNonce": 2086153431,
+ "index": "av",
+ "isDeleted": false,
+ "id": "O4IOlsidXZtjGGLx7bkV5",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 942,
+ "y": 121,
+ "strokeColor": "#e03131",
+ "backgroundColor": "#b2f2bb",
+ "width": 144.98333740234375,
+ "height": 35,
+ "seed": 740456628,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1723712683105,
+ "link": null,
+ "locked": false,
+ "fontSize": 28,
+ "fontFamily": 5,
+ "text": "x_set (10)",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "x_set (10)",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "line",
+ "version": 191,
+ "versionNonce": 829234295,
+ "index": "b028",
+ "isDeleted": false,
+ "id": "0Peull3zXZeLrxe84K3Ra",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 671,
+ "y": 237.84596154393358,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#b2f2bb",
+ "width": 5,
+ "height": 360.6954803590299,
+ "seed": 1758717068,
+ "groupIds": [
+ "P-S6GWdd2jcWPuY9sOgk8"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723709852930,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 5,
+ 360.6954803590299
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 232,
+ "versionNonce": 1020938873,
+ "index": "b02G",
+ "isDeleted": false,
+ "id": "lpIHrlma980BuMZ22Hxys",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 738.6964704909454,
+ "y": 238.27014754734356,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#b2f2bb",
+ "width": 5,
+ "height": 360.6954803590299,
+ "seed": 1597659660,
+ "groupIds": [
+ "P-S6GWdd2jcWPuY9sOgk8"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723709852930,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 5,
+ 360.6954803590299
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 250,
+ "versionNonce": 1285584279,
+ "index": "b02V",
+ "isDeleted": false,
+ "id": "PUFCzOPsFTUt6_P7bE4-o",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 805.2806311922333,
+ "y": 237.66218893044274,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#b2f2bb",
+ "width": 5,
+ "height": 360.6954803590299,
+ "seed": 1892698892,
+ "groupIds": [
+ "P-S6GWdd2jcWPuY9sOgk8"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723709852930,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 5,
+ 360.6954803590299
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 241,
+ "versionNonce": 603755353,
+ "index": "b02d",
+ "isDeleted": false,
+ "id": "EfAasH1uSrQhLqYCV_dJ1",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 870.8811690564545,
+ "y": 237.91153860797692,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#b2f2bb",
+ "width": 5,
+ "height": 360.6954803590299,
+ "seed": 444649740,
+ "groupIds": [
+ "P-S6GWdd2jcWPuY9sOgk8"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723709852930,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 5,
+ 360.6954803590299
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 284,
+ "versionNonce": 374057655,
+ "index": "b02l",
+ "isDeleted": false,
+ "id": "2Jg7xQEPafAB7j3CZ1DG0",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 937.3420218591018,
+ "y": 238.09135773008992,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#b2f2bb",
+ "width": 5,
+ "height": 360.6954803590299,
+ "seed": 877710644,
+ "groupIds": [
+ "P-S6GWdd2jcWPuY9sOgk8"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723709852930,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 5,
+ 360.6954803590299
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 302,
+ "versionNonce": 94552121,
+ "index": "b03",
+ "isDeleted": false,
+ "id": "S3x-U6c9M12L9hdo75RnK",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 1003.9839447540695,
+ "y": 237.7882788050355,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#b2f2bb",
+ "width": 5,
+ "height": 360.6954803590299,
+ "seed": 547948212,
+ "groupIds": [
+ "P-S6GWdd2jcWPuY9sOgk8"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723709852930,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 5,
+ 360.6954803590299
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 293,
+ "versionNonce": 722680791,
+ "index": "b03G",
+ "isDeleted": false,
+ "id": "JdOPLCUGd6YqHw25CxxV9",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 1070.6258676490374,
+ "y": 236.5201690030599,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#b2f2bb",
+ "width": 5,
+ "height": 360.6954803590299,
+ "seed": 415109172,
+ "groupIds": [
+ "P-S6GWdd2jcWPuY9sOgk8"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723709852930,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 5,
+ 360.6954803590299
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 301,
+ "versionNonce": 800084249,
+ "index": "b03V",
+ "isDeleted": false,
+ "id": "9sRft8pqldmfDKi6uLgoo",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 1137.9559844374378,
+ "y": 238.17061949598,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#b2f2bb",
+ "width": 5,
+ "height": 360.6954803590299,
+ "seed": 525258164,
+ "groupIds": [
+ "P-S6GWdd2jcWPuY9sOgk8"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723709852930,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 5,
+ 360.6954803590299
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 319,
+ "versionNonce": 520857847,
+ "index": "b04",
+ "isDeleted": false,
+ "id": "hTMDH7z4306-HND5Uy428",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 1204.5979073324056,
+ "y": 237.69558633969984,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#b2f2bb",
+ "width": 5,
+ "height": 360.6954803590299,
+ "seed": 1829959476,
+ "groupIds": [
+ "P-S6GWdd2jcWPuY9sOgk8"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723709852930,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 5,
+ 360.6954803590299
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 347,
+ "versionNonce": 1738065401,
+ "index": "b04V",
+ "isDeleted": false,
+ "id": "Cnvi7-v-Og7O7mzfGRjk0",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 1269.477944775103,
+ "y": 237.11038040417975,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#b2f2bb",
+ "width": 5,
+ "height": 360.6954803590299,
+ "seed": 2020545716,
+ "groupIds": [
+ "P-S6GWdd2jcWPuY9sOgk8"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723709852930,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 5,
+ 360.6954803590299
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 364,
+ "versionNonce": 263811607,
+ "index": "b05",
+ "isDeleted": false,
+ "id": "R2dfs7C7B9g8X_NkD2ROD",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 1336.1198676700708,
+ "y": 237.90971411641078,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#b2f2bb",
+ "width": 5,
+ "height": 360.6954803590299,
+ "seed": 1754422836,
+ "groupIds": [
+ "P-S6GWdd2jcWPuY9sOgk8"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723709852930,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 5,
+ 360.6954803590299
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 815,
+ "versionNonce": 198155577,
+ "index": "b0F8",
+ "isDeleted": false,
+ "id": "qlf6NDVKWc-PfUXMB2bnY",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 679.2532792040847,
+ "y": 231.58333333333337,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#b2f2bb",
+ "width": 652.5419601267315,
+ "height": 0,
+ "seed": 226363788,
+ "groupIds": [
+ "HySgwqNRDOZS_38GUeoPR"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723709875833,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 652.5419601267315,
+ 0
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 859,
+ "versionNonce": 1983483417,
+ "index": "b0FG",
+ "isDeleted": false,
+ "id": "6sCsQLqs_tdU11glCJDsV",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 679.8150779037358,
+ "y": 281.6874653857596,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#b2f2bb",
+ "width": 652.5419601267315,
+ "height": 0,
+ "seed": 1661870604,
+ "groupIds": [
+ "HySgwqNRDOZS_38GUeoPR"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723709875833,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 652.5419601267315,
+ 0
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 877,
+ "versionNonce": 1676829433,
+ "index": "b0FV",
+ "isDeleted": false,
+ "id": "BdwAiwjE12b4f4qTwDSwe",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 678.9503475441884,
+ "y": 333.48449152659305,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#b2f2bb",
+ "width": 652.5419601267315,
+ "height": 0,
+ "seed": 133305228,
+ "groupIds": [
+ "HySgwqNRDOZS_38GUeoPR"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723709875833,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 652.5419601267315,
+ 0
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 920,
+ "versionNonce": 1367186393,
+ "index": "b0Fl",
+ "isDeleted": false,
+ "id": "D4FVyNFGYsUAIo9Uaw_-t",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 679.4407215494107,
+ "y": 386.5352084867595,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#b2f2bb",
+ "width": 652.5419601267315,
+ "height": 0,
+ "seed": 2046804492,
+ "groupIds": [
+ "HySgwqNRDOZS_38GUeoPR"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723709875833,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 652.5419601267315,
+ 0
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 845,
+ "versionNonce": 1592703161,
+ "index": "b0G",
+ "isDeleted": false,
+ "id": "KMLRntLpvwGKTkDPtGJhe",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 679.6740320062427,
+ "y": 439.93111694854036,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#b2f2bb",
+ "width": 652.5419601267315,
+ "height": 0,
+ "seed": 1203294644,
+ "groupIds": [
+ "HySgwqNRDOZS_38GUeoPR"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723709875833,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 652.5419601267315,
+ 0
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 888,
+ "versionNonce": 1575565721,
+ "index": "b0GV",
+ "isDeleted": false,
+ "id": "COWd6ZBGiICka8aWYvGpJ",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 681.0868703301162,
+ "y": 493.0385660527098,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#b2f2bb",
+ "width": 652.5419601267315,
+ "height": 0,
+ "seed": 27032372,
+ "groupIds": [
+ "HySgwqNRDOZS_38GUeoPR"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723709875833,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 652.5419601267315,
+ 0
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 855,
+ "versionNonce": 530620025,
+ "index": "b0H",
+ "isDeleted": false,
+ "id": "iihkKJF5A0Mq32M51LKkU",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 680.6645339611346,
+ "y": 546.1613624409579,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#b2f2bb",
+ "width": 652.5419601267315,
+ "height": 0,
+ "seed": 1650608308,
+ "groupIds": [
+ "HySgwqNRDOZS_38GUeoPR"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723709875833,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 652.5419601267315,
+ 0
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 898,
+ "versionNonce": 47736665,
+ "index": "b0I",
+ "isDeleted": false,
+ "id": "3-R7bwGv6ecggMjz00nf0",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "dotted",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 679.6981549367256,
+ "y": 598.7928285018907,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#b2f2bb",
+ "width": 652.5419601267315,
+ "height": 0,
+ "seed": 369037876,
+ "groupIds": [
+ "HySgwqNRDOZS_38GUeoPR"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723709875833,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 652.5419601267315,
+ 0
+ ]
+ ]
+ },
+ {
+ "type": "text",
+ "version": 185,
+ "versionNonce": 394926233,
+ "index": "b0d",
+ "isDeleted": false,
+ "id": "3nLFPdUk_WeZLC6vIVWF9",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 453.6666666666665,
+ "y": 393.16666666666674,
+ "strokeColor": "#1971c2",
+ "backgroundColor": "#b2f2bb",
+ "width": 129.73333740234375,
+ "height": 35,
+ "seed": 700169612,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1723710311231,
+ "link": null,
+ "locked": false,
+ "fontSize": 28,
+ "fontFamily": 5,
+ "text": "y_set (7)",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "y_set (7)",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "line",
+ "version": 248,
+ "versionNonce": 602645849,
+ "index": "b0n8",
+ "isDeleted": false,
+ "id": "JnzsYu_ZslnjyScLARyqu",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 616.023274319471,
+ "y": 266,
+ "strokeColor": "#1971c2",
+ "backgroundColor": "#b2f2bb",
+ "width": 12.5,
+ "height": 0,
+ "seed": 1483048244,
+ "groupIds": [
+ "jWlJ_Q_kUH1mkn9At1ziz"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723712743933,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 12.5,
+ 0
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 238,
+ "versionNonce": 504281271,
+ "index": "b0nG",
+ "isDeleted": false,
+ "id": "wE-Z234j1AJh4cvGBPnuU",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 616.3070583081071,
+ "y": 318.1035680246503,
+ "strokeColor": "#1971c2",
+ "backgroundColor": "#b2f2bb",
+ "width": 12.5,
+ "height": 0,
+ "seed": 273333004,
+ "groupIds": [
+ "jWlJ_Q_kUH1mkn9At1ziz"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723712743933,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 12.5,
+ 0
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 258,
+ "versionNonce": 434082361,
+ "index": "b0nV",
+ "isDeleted": false,
+ "id": "FdydPRu81qu86qN2zKoDG",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 616.6202041172993,
+ "y": 369.41308094485197,
+ "strokeColor": "#1971c2",
+ "backgroundColor": "#b2f2bb",
+ "width": 12.5,
+ "height": 0,
+ "seed": 1681795764,
+ "groupIds": [
+ "jWlJ_Q_kUH1mkn9At1ziz"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723712743933,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 12.5,
+ 0
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 260,
+ "versionNonce": 591694295,
+ "index": "b0nl",
+ "isDeleted": false,
+ "id": "1yZbdnRYZrurejiYu5b4T",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 616.247322592697,
+ "y": 421.3699934295827,
+ "strokeColor": "#1971c2",
+ "backgroundColor": "#b2f2bb",
+ "width": 12.5,
+ "height": 0,
+ "seed": 1706510516,
+ "groupIds": [
+ "jWlJ_Q_kUH1mkn9At1ziz"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723712743933,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 12.5,
+ 0
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 219,
+ "versionNonce": 142795545,
+ "index": "b0o",
+ "isDeleted": false,
+ "id": "NqCk5MDaAmJEgYLWP9r3M",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 616.0881400594476,
+ "y": 473.46049268803154,
+ "strokeColor": "#1971c2",
+ "backgroundColor": "#b2f2bb",
+ "width": 12.5,
+ "height": 0,
+ "seed": 1915764236,
+ "groupIds": [
+ "jWlJ_Q_kUH1mkn9At1ziz"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723712743933,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 12.5,
+ 0
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 242,
+ "versionNonce": 1608726263,
+ "index": "b0oG",
+ "isDeleted": false,
+ "id": "AsCE-HwSCbqnSMAmpaxkZ",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 616.186931647939,
+ "y": 524.9721183654877,
+ "strokeColor": "#1971c2",
+ "backgroundColor": "#b2f2bb",
+ "width": 12.5,
+ "height": 0,
+ "seed": 1350796,
+ "groupIds": [
+ "jWlJ_Q_kUH1mkn9At1ziz"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723712743933,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 12.5,
+ 0
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 261,
+ "versionNonce": 1816729593,
+ "index": "b0oV",
+ "isDeleted": false,
+ "id": "_-ECJC0D8tmzti-pi3-Ee",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 615.9144580101793,
+ "y": 577.1707388064154,
+ "strokeColor": "#1971c2",
+ "backgroundColor": "#b2f2bb",
+ "width": 12.5,
+ "height": 0,
+ "seed": 1055468300,
+ "groupIds": [
+ "jWlJ_Q_kUH1mkn9At1ziz"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723712743933,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 12.5,
+ 0
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 231,
+ "versionNonce": 711933975,
+ "index": "b0ol",
+ "isDeleted": false,
+ "id": "NObpCvXI5ttnpfAvHDJ4I",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 631.25,
+ "y": 266.5,
+ "strokeColor": "#1971c2",
+ "backgroundColor": "#b2f2bb",
+ "width": 0,
+ "height": 312.5,
+ "seed": 399783692,
+ "groupIds": [
+ "jWlJ_Q_kUH1mkn9At1ziz"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723712743933,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 312.5
+ ]
+ ]
+ },
+ {
+ "type": "arrow",
+ "version": 427,
+ "versionNonce": 1594264343,
+ "index": "b0q",
+ "isDeleted": false,
+ "id": "iLkOUg7TmkslaYgU9SdaW",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 680.25,
+ "y": 365.4292272146313,
+ "strokeColor": "#2f9e44",
+ "backgroundColor": "#b2f2bb",
+ "width": 656.25,
+ "height": 0,
+ "seed": 1372353972,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723710349411,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": "arrow",
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 656.25,
+ 0
+ ]
+ ],
+ "elbowed": false
+ },
+ {
+ "type": "arrow",
+ "version": 578,
+ "versionNonce": 1850937399,
+ "index": "b0r",
+ "isDeleted": false,
+ "id": "fsE3yUyb3qu39XzmZCM6W",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 680.1636851166654,
+ "y": 312.7047592879178,
+ "strokeColor": "#2f9e44",
+ "backgroundColor": "#b2f2bb",
+ "width": 656.25,
+ "height": 0,
+ "seed": 1513965239,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723710349411,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": "arrow",
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 656.25,
+ 0
+ ]
+ ],
+ "elbowed": false
+ },
+ {
+ "type": "arrow",
+ "version": 549,
+ "versionNonce": 672264535,
+ "index": "b0s",
+ "isDeleted": false,
+ "id": "grxeuUUFSREmLSwqtGjYB",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 680.3337634762097,
+ "y": 261.54311806311057,
+ "strokeColor": "#2f9e44",
+ "backgroundColor": "#b2f2bb",
+ "width": 656.25,
+ "height": 0,
+ "seed": 1107660567,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723710349411,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": "arrow",
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 656.25,
+ 0
+ ]
+ ],
+ "elbowed": false
+ },
+ {
+ "type": "text",
+ "version": 88,
+ "versionNonce": 1101544537,
+ "index": "b13",
+ "isDeleted": false,
+ "id": "enGL1MyA4g-tAkCJvk2CO",
+ "fillStyle": "solid",
+ "strokeWidth": 1,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 1368.75,
+ "y": 289,
+ "strokeColor": "#2f9e44",
+ "backgroundColor": "#b2f2bb",
+ "width": 245.81666564941406,
+ "height": 70,
+ "seed": 1578367961,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1723711239934,
+ "link": null,
+ "locked": false,
+ "fontSize": 28,
+ "fontFamily": 5,
+ "text": "continuous motion\nof x for each y",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "continuous motion\nof x for each y",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "text",
+ "version": 302,
+ "versionNonce": 503827127,
+ "index": "b14",
+ "isDeleted": false,
+ "id": "OXiZBby7KE7-cWu_3uP2P",
+ "fillStyle": "solid",
+ "strokeWidth": 1,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 745.5,
+ "y": 631.5,
+ "strokeColor": "#1e1e1e",
+ "backgroundColor": "#b2f2bb",
+ "width": 535,
+ "height": 35,
+ "seed": 536866169,
+ "groupIds": [],
+ "frameId": null,
+ "roundness": null,
+ "boundElements": [],
+ "updated": 1723712090669,
+ "link": null,
+ "locked": false,
+ "fontSize": 28,
+ "fontFamily": 5,
+ "text": "XRF spectra recorded at (10, 7) points",
+ "textAlign": "left",
+ "verticalAlign": "top",
+ "containerId": null,
+ "originalText": "XRF spectra recorded at (10, 7) points",
+ "autoResize": true,
+ "lineHeight": 1.25
+ },
+ {
+ "type": "line",
+ "version": 226,
+ "versionNonce": 584020119,
+ "index": "b15",
+ "isDeleted": false,
+ "id": "Jvvzf5AW1-AXaLkRpLU0r",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 707.75,
+ "y": 204,
+ "strokeColor": "#e03131",
+ "backgroundColor": "#b2f2bb",
+ "width": 599.75,
+ "height": 0,
+ "seed": 328296076,
+ "groupIds": [
+ "0eZqsfw3BdSiWeVivw9dn"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723716614076,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 599.75,
+ 0
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 190,
+ "versionNonce": 1217316953,
+ "index": "b16",
+ "isDeleted": false,
+ "id": "1oquHYfUWM7jFEPRmPJCd",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 707.4846985493728,
+ "y": 188.7146671758289,
+ "strokeColor": "#e03131",
+ "backgroundColor": "#b2f2bb",
+ "width": 0,
+ "height": 12,
+ "seed": 335175092,
+ "groupIds": [
+ "0eZqsfw3BdSiWeVivw9dn"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723716614076,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 12
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 102,
+ "versionNonce": 1659061687,
+ "index": "b17",
+ "isDeleted": false,
+ "id": "Q3qiL31W6HDgEKYSUG44h",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 773.998812262217,
+ "y": 188.64039871145502,
+ "strokeColor": "#e03131",
+ "backgroundColor": "#b2f2bb",
+ "width": 0,
+ "height": 12,
+ "seed": 1348995380,
+ "groupIds": [
+ "0eZqsfw3BdSiWeVivw9dn"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723716614076,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 12
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 158,
+ "versionNonce": 606491961,
+ "index": "b18",
+ "isDeleted": false,
+ "id": "fLh6-WEtUmLDbT4M3fmKK",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 840.5761866634622,
+ "y": 188.76089835307093,
+ "strokeColor": "#e03131",
+ "backgroundColor": "#b2f2bb",
+ "width": 0,
+ "height": 12,
+ "seed": 896199820,
+ "groupIds": [
+ "0eZqsfw3BdSiWeVivw9dn"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723716614076,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 12
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 137,
+ "versionNonce": 1476359895,
+ "index": "b19",
+ "isDeleted": false,
+ "id": "d2dHO2MXV3EZOASR9evEu",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 907.3511757106554,
+ "y": 188.7219522011722,
+ "strokeColor": "#e03131",
+ "backgroundColor": "#b2f2bb",
+ "width": 0,
+ "height": 12,
+ "seed": 351632140,
+ "groupIds": [
+ "0eZqsfw3BdSiWeVivw9dn"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723716614076,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 12
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 181,
+ "versionNonce": 1123632665,
+ "index": "b1A",
+ "isDeleted": false,
+ "id": "1nDRWGr4xXByQvmj4T75k",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 973.2610885627203,
+ "y": 188.61094508609264,
+ "strokeColor": "#e03131",
+ "backgroundColor": "#b2f2bb",
+ "width": 0,
+ "height": 12,
+ "seed": 202421132,
+ "groupIds": [
+ "0eZqsfw3BdSiWeVivw9dn"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723716614076,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 12
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 160,
+ "versionNonce": 2025358327,
+ "index": "b1B",
+ "isDeleted": false,
+ "id": "uQCHrBIsIyOaHGD4_oPNZ",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 1039.7842991070493,
+ "y": 188.73879469756733,
+ "strokeColor": "#e03131",
+ "backgroundColor": "#b2f2bb",
+ "width": 0,
+ "height": 12,
+ "seed": 1095393804,
+ "groupIds": [
+ "0eZqsfw3BdSiWeVivw9dn"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723716614076,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 12
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 167,
+ "versionNonce": 1878727417,
+ "index": "b1C",
+ "isDeleted": false,
+ "id": "OAscfoYCZDCZw-bIYAeo8",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 1106.30466623029,
+ "y": 188.67396988396297,
+ "strokeColor": "#e03131",
+ "backgroundColor": "#b2f2bb",
+ "width": 0,
+ "height": 12,
+ "seed": 119825548,
+ "groupIds": [
+ "0eZqsfw3BdSiWeVivw9dn"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723716614076,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 12
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 146,
+ "versionNonce": 1964174615,
+ "index": "b1D",
+ "isDeleted": false,
+ "id": "7IG0ZYhtA4tBldWiNqe1S",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 1172.4958883062177,
+ "y": 188.58912470689506,
+ "strokeColor": "#e03131",
+ "backgroundColor": "#b2f2bb",
+ "width": 0,
+ "height": 12,
+ "seed": 1623192332,
+ "groupIds": [
+ "0eZqsfw3BdSiWeVivw9dn"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723716614076,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 12
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 225,
+ "versionNonce": 1269781465,
+ "index": "b1E",
+ "isDeleted": false,
+ "id": "Q_IPp2bqbuRgV_0b9k7cZ",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 1305.247926274241,
+ "y": 188.81302467665165,
+ "strokeColor": "#e03131",
+ "backgroundColor": "#b2f2bb",
+ "width": 0,
+ "height": 12,
+ "seed": 1556442508,
+ "groupIds": [
+ "0eZqsfw3BdSiWeVivw9dn"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723716614076,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 12
+ ]
+ ]
+ },
+ {
+ "type": "line",
+ "version": 155,
+ "versionNonce": 142815799,
+ "index": "b1F",
+ "isDeleted": false,
+ "id": "tAImMCvx-5ghWxDuw2u48",
+ "fillStyle": "solid",
+ "strokeWidth": 2,
+ "strokeStyle": "solid",
+ "roughness": 1,
+ "opacity": 100,
+ "angle": 0,
+ "x": 1238.6946591843853,
+ "y": 188.65582932287592,
+ "strokeColor": "#e03131",
+ "backgroundColor": "#b2f2bb",
+ "width": 0,
+ "height": 12,
+ "seed": 430513529,
+ "groupIds": [
+ "0eZqsfw3BdSiWeVivw9dn"
+ ],
+ "frameId": null,
+ "roundness": {
+ "type": 2
+ },
+ "boundElements": [],
+ "updated": 1723716614076,
+ "link": null,
+ "locked": false,
+ "startBinding": null,
+ "endBinding": null,
+ "lastCommittedPoint": null,
+ "startArrowhead": null,
+ "endArrowhead": null,
+ "points": [
+ [
+ 0,
+ 0
+ ],
+ [
+ 0,
+ 12
+ ]
+ ]
+ }
+ ],
+ "appState": {
+ "gridSize": 20,
+ "gridStep": 5,
+ "gridModeEnabled": false,
+ "viewBackgroundColor": "#ffffff"
+ },
+ "files": {}
+}
\ No newline at end of file
diff --git a/base_classes/data/example2D_hist.png b/base_classes/data/example2D_hist.png
new file mode 100644
index 0000000000..8b35aeafb9
Binary files /dev/null and b/base_classes/data/example2D_hist.png differ
diff --git a/dev_tools/apps/manual_app.py b/dev_tools/apps/manual_app.py
index dfb2c1b824..f07adfde0f 100644
--- a/dev_tools/apps/manual_app.py
+++ b/dev_tools/apps/manual_app.py
@@ -6,6 +6,7 @@
from ..globals import directories
from ..nxdl import iter_definitions
from ..nxdl import validate_definition
+from ..utils.copy import copy_directories
from ..utils.copy import copy_files
from ..utils.copy import copydir
from ..utils.diff import diff_ascii
@@ -22,7 +23,7 @@ def manual_args(parser):
parser.add_argument(
"--prepare",
action="store_true",
- help="Create the build files for the NeXus Impatient Guide",
+ help="Create the build files for the NeXus documentation",
)
parser.add_argument(
"--diff",
@@ -107,14 +108,25 @@ def manual_exec(args):
with open(index_file, "w") as fh:
fh.writelines(rst_lines)
- # Generate the anchor list in several format
if args.prepare:
+ directories.manual_build_root()
print("generate anchor list files in", output_path)
anchor_registry.write()
+
+ print("copy extra files", output_path)
copy_files(EXTRA_FILES)
+ print("copy extra directories", output_path)
+ copy_directories(EXTRA_DIRECTORIES)
+
# Path relative to source directory,
# Path relative to build directory,
# Overwrite (boolean)
-EXTRA_FILES = [["NXDL_VERSION", "NXDL_VERSION", True], ["LGPL.txt", "LGPL.txt", True]]
+EXTRA_FILES = [
+ ["NXDL_VERSION", "NXDL_VERSION", True],
+ ["LGPL.txt", "LGPL.txt", True],
+]
+EXTRA_DIRECTORIES = [
+ ["galleries", "galleries", True],
+]
diff --git a/dev_tools/utils/copy.py b/dev_tools/utils/copy.py
index 099dd8d759..9a29413c37 100644
--- a/dev_tools/utils/copy.py
+++ b/dev_tools/utils/copy.py
@@ -28,3 +28,15 @@ def copy_files(files: List[Tuple[str, str, bool]]) -> None:
copyfile(from_path, to_path)
else:
print("already exists", to_path)
+
+
+def copy_directories(dirs: List[Tuple[str, str, bool]]) -> None:
+ source_root = directories.get_source_root()
+ build_root = directories.get_build_root()
+ for from_subname, to_subname, overwrite in dirs:
+ to_path = build_root / to_subname
+ if overwrite or not to_path.exists():
+ from_path = source_root / from_subname
+ copydir(from_path, to_path)
+ else:
+ print("already exists", to_path)
diff --git a/galleries/nxdata/GALLERY_HEADER.rst b/galleries/nxdata/GALLERY_HEADER.rst
new file mode 100644
index 0000000000..65bbd4031b
--- /dev/null
+++ b/galleries/nxdata/GALLERY_HEADER.rst
@@ -0,0 +1 @@
+**Usage**
\ No newline at end of file
diff --git a/galleries/nxdata/plot_curve1.py b/galleries/nxdata/plot_curve1.py
new file mode 100644
index 0000000000..b071c4646c
--- /dev/null
+++ b/galleries/nxdata/plot_curve1.py
@@ -0,0 +1,38 @@
+"""
+===============
+Curve (1D Grid)
+===============
+
+Curve (not necessarily evenly spaced)
+
+.. code::
+
+ @NX_class = "NXroot"
+ @default = "scan1"
+ scan1:NXentry
+ @NX_class = "NXentry"
+ @default = "data"
+ data:NXdata
+ @NX_class = "NXdata"
+ @auxiliary_signals = ["y2"]
+ @axes = ["x"]
+ @signal = "y1"
+ x:NX_INT64[10]
+ y1:NX_FLOAT64[10]
+ y2:NX_FLOAT64[10]
+"""
+
+import numpy as np
+import matplotlib.pyplot as plt
+
+plt.style.use("_mpl-gallery")
+
+fig, ax = plt.subplots()
+
+x = np.arange(10) ** 2
+y1 = 4 + np.sin(2 * x)
+y2 = 2 + np.sin(3 * x)
+ax.plot(x, y1, "o-", label="y1")
+ax.plot(x, y2, "go-", label="y2")
+
+plt.show()
diff --git a/galleries/nxdata/plot_curve2.py b/galleries/nxdata/plot_curve2.py
new file mode 100644
index 0000000000..cb0afffda5
--- /dev/null
+++ b/galleries/nxdata/plot_curve2.py
@@ -0,0 +1,66 @@
+"""
+===============
+Curve (1D Grid)
+===============
+
+Curve (not necessarily evenly spaced)
+
+.. code::
+
+ @NX_class = "NXroot"
+ @default = "scan1"
+ scan1:NXentry
+ @NX_class = "NXentry"
+ @default = "data"
+ data:NXdata
+ @NX_class = "NXdata"
+ @auxiliary_signals = ["y2"]
+ @axes = ["x"]
+ @signal = "y1"
+ x:NX_INT64[10]
+ y1:NX_FLOAT64[10]
+ y2:NX_FLOAT64[10]
+"""
+
+# %%
+# HDF5 example in Python.
+import h5py
+import numpy as np
+
+with h5py.File("curve.h5", "w") as root:
+ root.attrs["NX_class"] = "NXroot"
+ scan1 = root.create_group("scan1")
+ scan1.attrs["NX_class"] = "NXentry"
+ data = scan1.create_group("data")
+ data.attrs["NX_class"] = "NXdata"
+
+ data.attrs["axes"] = ["x"]
+ data.attrs["signal"] = "y1"
+ data.attrs["auxiliary_signals"] = ["y2"]
+ x = np.arange(10) ** 2
+ data["x"] = x
+ data["y1"] = 4 + np.sin(2 * x)
+ data["y2"] = 2 + np.sin(3 * x)
+
+# %%
+# Plot example in Python.
+import matplotlib.pyplot as plt
+
+plt.style.use("_mpl-gallery")
+
+fig, ax = plt.subplots()
+
+with h5py.File("curve.h5", "r") as root:
+ data = root["/scan1/data"]
+
+ xname = data.attrs["axes"][0]
+ yname1 = data.attrs["signal"]
+ yname2 = data.attrs["auxiliary_signals"][0]
+
+ x = data[xname][()]
+ y1 = data[yname1][()]
+ y2 = data[yname2][()]
+ ax.plot(x, y1, "o-", label=yname1)
+ ax.plot(x, y2, "go-", label=yname2)
+
+plt.show()
diff --git a/galleries/nxdata/plot_histogram_1d.py b/galleries/nxdata/plot_histogram_1d.py
new file mode 100644
index 0000000000..b555a5c945
--- /dev/null
+++ b/galleries/nxdata/plot_histogram_1d.py
@@ -0,0 +1,25 @@
+"""
+============
+1D Histogram
+============
+
+1D Histogram (not necessarily evenly spaced)
+"""
+
+import matplotlib.pyplot as plt
+import numpy as np
+
+plt.style.use("_mpl-gallery")
+
+# make data:
+x = 0.5 + np.arange(8)
+y = [4.8, 5.5, 3.5, 4.6, 6.5, 6.6, 2.6, 3.0]
+
+# plot
+fig, ax = plt.subplots()
+
+ax.bar(x, y, width=1, edgecolor="white", linewidth=0.7)
+
+ax.set(xlim=(0, 8), xticks=np.arange(1, 8), ylim=(0, 8), yticks=np.arange(1, 8))
+
+plt.show()
diff --git a/galleries/nxdata/plot_image.py b/galleries/nxdata/plot_image.py
new file mode 100644
index 0000000000..df7dda3531
--- /dev/null
+++ b/galleries/nxdata/plot_image.py
@@ -0,0 +1,23 @@
+"""
+===============
+Image (2D Grid)
+===============
+
+Image (not necessarily evenly spaced)
+"""
+
+import matplotlib.pyplot as plt
+import numpy as np
+
+plt.style.use("_mpl-gallery-nogrid")
+
+# make data
+X, Y = np.meshgrid(np.linspace(-3, 3, 16), np.linspace(-3, 3, 16))
+Z = (1 - X / 2 + X**5 + Y**3) * np.exp(-(X**2) - Y**2)
+
+# plot
+fig, ax = plt.subplots()
+
+ax.imshow(Z, origin="lower")
+
+plt.show()
diff --git a/manual/source/conf.py b/manual/source/conf.py
index 9b90263f10..8e871a2459 100644
--- a/manual/source/conf.py
+++ b/manual/source/conf.py
@@ -48,7 +48,8 @@
'sphinx.ext.githubpages',
'sphinx.ext.todo',
'sphinx_tabs.tabs',
- 'contrib_ext'
+ 'contrib_ext',
+ 'sphinx_gallery.gen_gallery'
]
# Show `.. todo` directives in the output
@@ -109,3 +110,9 @@ def setup(app):
\DeclareUnicodeCharacter{2906}{<=}
\listfiles'''
}
+
+# -- Options the gallery -------------------------------------------------
+sphinx_gallery_conf = {
+ 'examples_dirs': '../../galleries/nxdata', # path with .py files
+ 'gallery_dirs': 'classes/base_classes/data', # path where to save gallery generated output
+}
\ No newline at end of file
diff --git a/requirements.txt b/requirements.txt
index ba1f751d3f..9adedc9a84 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -7,6 +7,9 @@ nyaml
sphinx>=5
sphinx-tabs
sphinx-toolbox
+sphinx-gallery
+matplotlib
+h5py
# Testing
pytest