scanspec.specs#

Spec and its subclasses.

Inheritance diagram of scanspec.specs

Members

DURATION

Can be used as a special key to indicate how long each point should be

Spec

A serializable representation of the type and parameters of a scan.

fly

Flyscan, zipping with fixed duration for every frame.

step

Step scan, with num frames of given duration at each frame in the spec.

scanspec.specs.DURATION = 'DURATION'#

Can be used as a special key to indicate how long each point should be

class scanspec.specs.Spec[source]#

A serializable representation of the type and parameters of a scan.

Abstract baseclass for the specification of a scan. Supports operators:

  • *: Outer Product of two Specs, nesting the second within the first. If the first operand is an integer, wrap it in a Repeat

  • &: Mask the Spec with a Region, excluding midpoints outside of it

  • ~: Snake the Spec, reversing every other iteration of it

axes() list[Axis][source]#

Return the list of axes that are present in the scan.

Ordered from slowest moving to fastest moving.

calculate(bounds: bool = True, nested: bool = False) list[Frames[Axis]][source]#

Produce a stack of nested Frames that form the scan.

Ordered from slowest moving to fastest moving.

frames() Frames[Axis][source]#

Expand all the scan Frames and return them.

midpoints() Midpoints[Axis][source]#

Return Midpoints that can be iterated point by point.

shape() tuple[int, ...][source]#

Return the final, simplified shape of the scan.

zip(other: Spec[OtherAxis]) Zip[Axis | OtherAxis][source]#

Zip the Spec with another, iterating in tandem.

concat(other: Spec[Axis]) Concat[Axis][source]#

Concat the Spec with another, iterating one after the other.

serialize() Mapping[str, Any][source]#

Serialize the Spec to a dictionary.

static deserialize(obj: Any) Spec[Any][source]#

Deserialize a Spec from a dictionary.

pydantic model scanspec.specs.Product[source]#

Outer product of two Specs, nesting inner within outer.

This means that inner will run in its entirety at each point in outer.

# Example Spec

from scanspec.plot import plot_spec
from scanspec.specs import Line

spec = Line("y", 1, 2, 3) * Line("x", 3, 4, 12)
plot_spec(spec)

(Source code, png, hires.png, pdf)

../_images/scanspec-specs-1.png

Show JSON schema
{
   "$defs": {
      "Circle": {
         "additionalProperties": false,
         "description": "Mask contains points of axis within an xy circle of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Circle(\"x\", \"y\", 1, 2, 0.9)",
         "properties": {
            "x_axis": {
               "description": "The name matching the x axis of the spec",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "The name matching the y axis of the spec",
               "title": "Y Axis"
            },
            "x_middle": {
               "description": "The central x point of the circle",
               "title": "X Middle",
               "type": "number"
            },
            "y_middle": {
               "description": "The central y point of the circle",
               "title": "Y Middle",
               "type": "number"
            },
            "radius": {
               "description": "Radius of the circle",
               "exclusiveMinimum": 0.0,
               "title": "Radius",
               "type": "number"
            },
            "type": {
               "const": "Circle",
               "default": "Circle",
               "enum": [
                  "Circle"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_middle",
            "y_middle",
            "radius"
         ],
         "title": "Circle",
         "type": "object"
      },
      "CombinationOf": {
         "additionalProperties": false,
         "description": "Abstract baseclass for a combination of two regions, left and right.",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "CombinationOf",
               "default": "CombinationOf",
               "enum": [
                  "CombinationOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "CombinationOf",
         "type": "object"
      },
      "Concat": {
         "additionalProperties": false,
         "description": "Concatenate two Specs together, running one after the other.\n\nEach Dimension of left and right must contain the same axes. Typically\nformed using `Spec.concat`.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"x\", 1, 3, 3).concat(Line(\"x\", 4, 5, 5))",
         "properties": {
            "left": {
               "$ref": "#/$defs/Spec",
               "description": "The left-hand Spec to Concat, midpoints will appear earlier"
            },
            "right": {
               "$ref": "#/$defs/Spec",
               "description": "The right-hand Spec to Concat, midpoints will appear later"
            },
            "gap": {
               "default": false,
               "description": "If True, force a gap in the output at the join",
               "title": "Gap",
               "type": "boolean"
            },
            "check_path_changes": {
               "default": true,
               "description": "If True path through scan will not be modified by squash",
               "title": "Check Path Changes",
               "type": "boolean"
            },
            "type": {
               "const": "Concat",
               "default": "Concat",
               "enum": [
                  "Concat"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "Concat",
         "type": "object"
      },
      "DifferenceOf": {
         "additionalProperties": false,
         "description": "A point is in DifferenceOf(a, b) if in a and not in b.\n\nTypically created with the ``-`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) - Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False, False, False])",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "DifferenceOf",
               "default": "DifferenceOf",
               "enum": [
                  "DifferenceOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "DifferenceOf",
         "type": "object"
      },
      "Ellipse": {
         "additionalProperties": false,
         "description": "Mask contains points of axis within an xy ellipse of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Ellipse\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Ellipse(\"x\", \"y\", 5, 5, 2, 3, 75)",
         "properties": {
            "x_axis": {
               "description": "The name matching the x axis of the spec",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "The name matching the y axis of the spec",
               "title": "Y Axis"
            },
            "x_middle": {
               "description": "The central x point of the ellipse",
               "title": "X Middle",
               "type": "number"
            },
            "y_middle": {
               "description": "The central y point of the ellipse",
               "title": "Y Middle",
               "type": "number"
            },
            "x_radius": {
               "description": "The radius along the x axis of the ellipse",
               "exclusiveMinimum": 0.0,
               "title": "X Radius",
               "type": "number"
            },
            "y_radius": {
               "description": "The radius along the y axis of the ellipse",
               "exclusiveMinimum": 0.0,
               "title": "Y Radius",
               "type": "number"
            },
            "angle": {
               "default": 0.0,
               "description": "The angle of the ellipse (degrees)",
               "title": "Angle",
               "type": "number"
            },
            "type": {
               "const": "Ellipse",
               "default": "Ellipse",
               "enum": [
                  "Ellipse"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_middle",
            "y_middle",
            "x_radius",
            "y_radius"
         ],
         "title": "Ellipse",
         "type": "object"
      },
      "IntersectionOf": {
         "additionalProperties": false,
         "description": "A point is in IntersectionOf(a, b) if in both a and b.\n\nTypically created with the ``&`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) & Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, False,  True, False, False])",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "IntersectionOf",
               "default": "IntersectionOf",
               "enum": [
                  "IntersectionOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "IntersectionOf",
         "type": "object"
      },
      "Line": {
         "additionalProperties": false,
         "description": "Linearly spaced frames with start and stop as first and last midpoints.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"x\", 1, 2, 5)",
         "properties": {
            "axis": {
               "description": "An identifier for what to move",
               "title": "Axis"
            },
            "start": {
               "description": "Midpoint of the first point of the line",
               "title": "Start",
               "type": "number"
            },
            "stop": {
               "description": "Midpoint of the last point of the line",
               "title": "Stop",
               "type": "number"
            },
            "num": {
               "description": "Number of frames to produce",
               "minimum": 1,
               "title": "Num",
               "type": "integer"
            },
            "type": {
               "const": "Line",
               "default": "Line",
               "enum": [
                  "Line"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "axis",
            "start",
            "stop",
            "num"
         ],
         "title": "Line",
         "type": "object"
      },
      "Mask": {
         "additionalProperties": false,
         "description": "Restrict Spec to only midpoints that fall inside the given Region.\n\nTypically created with the ``&`` operator. It also pushes down the\n``& | ^ -`` operators to its `Region` to avoid the need for brackets on\ncombinations of Regions.\n\nIf a Region spans multiple Frames objects, they will be squashed together.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 3, 3) * Line(\"x\", 3, 5, 5) & Circle(\"x\", \"y\", 4, 2, 1.2)\n\nSee Also: `why-squash-can-change-path`",
         "properties": {
            "spec": {
               "$ref": "#/$defs/Spec",
               "description": "The Spec containing the source midpoints"
            },
            "region": {
               "$ref": "#/$defs/Region",
               "description": "The Region that midpoints will be inside"
            },
            "check_path_changes": {
               "default": true,
               "description": "If True path through scan will not be modified by squash",
               "title": "Check Path Changes",
               "type": "boolean"
            },
            "type": {
               "const": "Mask",
               "default": "Mask",
               "enum": [
                  "Mask"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "spec",
            "region"
         ],
         "title": "Mask",
         "type": "object"
      },
      "Polygon": {
         "additionalProperties": false,
         "description": "Mask contains points of axis within a rotated xy polygon.\n\n.. example_spec::\n\n    from scanspec.regions import Polygon\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Polygon(\"x\", \"y\", [1.0, 6.0, 8.0, 2.0], [4.0, 10.0, 6.0, 1.0])",
         "properties": {
            "x_axis": {
               "description": "The name matching the x axis of the spec",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "The name matching the y axis of the spec",
               "title": "Y Axis"
            },
            "x_verts": {
               "description": "The Nx1 x coordinates of the polygons vertices",
               "items": {
                  "type": "number"
               },
               "minItems": 3,
               "title": "X Verts",
               "type": "array"
            },
            "y_verts": {
               "description": "The Nx1 y coordinates of the polygons vertices",
               "items": {
                  "type": "number"
               },
               "minItems": 3,
               "title": "Y Verts",
               "type": "array"
            },
            "type": {
               "const": "Polygon",
               "default": "Polygon",
               "enum": [
                  "Polygon"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_verts",
            "y_verts"
         ],
         "title": "Polygon",
         "type": "object"
      },
      "Product": {
         "additionalProperties": false,
         "description": "Outer product of two Specs, nesting inner within outer.\n\nThis means that inner will run in its entirety at each point in outer.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 2, 3) * Line(\"x\", 3, 4, 12)",
         "properties": {
            "outer": {
               "$ref": "#/$defs/Spec",
               "description": "Will be executed once"
            },
            "inner": {
               "$ref": "#/$defs/Spec",
               "description": "Will be executed len(outer) times"
            },
            "type": {
               "const": "Product",
               "default": "Product",
               "enum": [
                  "Product"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "outer",
            "inner"
         ],
         "title": "Product",
         "type": "object"
      },
      "Range": {
         "additionalProperties": false,
         "description": "Mask contains points of axis >= min and <= max.\n\n>>> r = Range(\"x\", 1, 2)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True, False, False])",
         "properties": {
            "axis": {
               "description": "The name matching the axis to mask in spec",
               "title": "Axis"
            },
            "min": {
               "description": "The minimum inclusive value in the region",
               "title": "Min",
               "type": "number"
            },
            "max": {
               "description": "The minimum inclusive value in the region",
               "title": "Max",
               "type": "number"
            },
            "type": {
               "const": "Range",
               "default": "Range",
               "enum": [
                  "Range"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "axis",
            "min",
            "max"
         ],
         "title": "Range",
         "type": "object"
      },
      "Rectangle": {
         "additionalProperties": false,
         "description": "Mask contains points of axis within a rotated xy rectangle.\n\n.. example_spec::\n\n    from scanspec.regions import Rectangle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Rectangle(\"x\", \"y\", 0, 1.1, 1.5, 2.1, 30)",
         "properties": {
            "x_axis": {
               "description": "The name matching the x axis of the spec",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "The name matching the y axis of the spec",
               "title": "Y Axis"
            },
            "x_min": {
               "description": "Minimum inclusive x value in the region",
               "title": "X Min",
               "type": "number"
            },
            "y_min": {
               "description": "Minimum inclusive y value in the region",
               "title": "Y Min",
               "type": "number"
            },
            "x_max": {
               "description": "Maximum inclusive x value in the region",
               "title": "X Max",
               "type": "number"
            },
            "y_max": {
               "description": "Maximum inclusive y value in the region",
               "title": "Y Max",
               "type": "number"
            },
            "angle": {
               "default": 0.0,
               "description": "Clockwise rotation angle of the rectangle",
               "title": "Angle",
               "type": "number"
            },
            "type": {
               "const": "Rectangle",
               "default": "Rectangle",
               "enum": [
                  "Rectangle"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_min",
            "y_min",
            "x_max",
            "y_max"
         ],
         "title": "Rectangle",
         "type": "object"
      },
      "Region": {
         "discriminator": {
            "mapping": {
               "Circle": "#/$defs/Circle",
               "CombinationOf": "#/$defs/CombinationOf",
               "DifferenceOf": "#/$defs/DifferenceOf",
               "Ellipse": "#/$defs/Ellipse",
               "IntersectionOf": "#/$defs/IntersectionOf",
               "Polygon": "#/$defs/Polygon",
               "Range": "#/$defs/Range",
               "Rectangle": "#/$defs/Rectangle",
               "SymmetricDifferenceOf": "#/$defs/SymmetricDifferenceOf",
               "UnionOf": "#/$defs/UnionOf"
            },
            "propertyName": "type"
         },
         "oneOf": [
            {
               "$ref": "#/$defs/CombinationOf"
            },
            {
               "$ref": "#/$defs/UnionOf"
            },
            {
               "$ref": "#/$defs/IntersectionOf"
            },
            {
               "$ref": "#/$defs/DifferenceOf"
            },
            {
               "$ref": "#/$defs/SymmetricDifferenceOf"
            },
            {
               "$ref": "#/$defs/Range"
            },
            {
               "$ref": "#/$defs/Rectangle"
            },
            {
               "$ref": "#/$defs/Polygon"
            },
            {
               "$ref": "#/$defs/Circle"
            },
            {
               "$ref": "#/$defs/Ellipse"
            }
         ]
      },
      "Repeat": {
         "additionalProperties": false,
         "description": "Repeat an empty frame num times.\n\nCan be used on the outside of a scan to repeat the same scan many times.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = 2 * ~Line.bounded(\"x\", 3, 4, 1)\n\nIf you want snaked axes to have no gap between iterations you can do:\n\n.. example_spec::\n\n    from scanspec.specs import Line, Repeat\n\n    spec = Repeat(2, gap=False) * ~Line.bounded(\"x\", 3, 4, 1)\n\n.. note:: There is no turnaround arrow at x=4",
         "properties": {
            "num": {
               "description": "Number of frames to produce",
               "minimum": 1,
               "title": "Num",
               "type": "integer"
            },
            "gap": {
               "default": true,
               "description": "If False and the slowest of the stack of Frames is snaked then the end and start of consecutive iterations of Spec will have no gap",
               "title": "Gap",
               "type": "boolean"
            },
            "type": {
               "const": "Repeat",
               "default": "Repeat",
               "enum": [
                  "Repeat"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "num"
         ],
         "title": "Repeat",
         "type": "object"
      },
      "Snake": {
         "additionalProperties": false,
         "description": "Run the Spec in reverse on every other iteration when nested.\n\nTypically created with the ``~`` operator.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 3, 3) * ~Line(\"x\", 3, 5, 5)",
         "properties": {
            "spec": {
               "$ref": "#/$defs/Spec",
               "description": "The Spec to run in reverse every other iteration"
            },
            "type": {
               "const": "Snake",
               "default": "Snake",
               "enum": [
                  "Snake"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "spec"
         ],
         "title": "Snake",
         "type": "object"
      },
      "Spec": {
         "discriminator": {
            "mapping": {
               "Concat": "#/$defs/Concat",
               "Line": "#/$defs/Line",
               "Mask": "#/$defs/Mask",
               "Product": "#/$defs/Product",
               "Repeat": "#/$defs/Repeat",
               "Snake": "#/$defs/Snake",
               "Spiral": "#/$defs/Spiral",
               "Squash": "#/$defs/Squash",
               "Static": "#/$defs/Static",
               "Zip": "#/$defs/Zip"
            },
            "propertyName": "type"
         },
         "oneOf": [
            {
               "$ref": "#/$defs/Product"
            },
            {
               "$ref": "#/$defs/Repeat"
            },
            {
               "$ref": "#/$defs/Zip"
            },
            {
               "$ref": "#/$defs/Mask"
            },
            {
               "$ref": "#/$defs/Snake"
            },
            {
               "$ref": "#/$defs/Concat"
            },
            {
               "$ref": "#/$defs/Squash"
            },
            {
               "$ref": "#/$defs/Line"
            },
            {
               "$ref": "#/$defs/Static"
            },
            {
               "$ref": "#/$defs/Spiral"
            }
         ]
      },
      "Spiral": {
         "additionalProperties": false,
         "description": "Archimedean spiral of \"x_axis\" and \"y_axis\".\n\nStarts at centre point (\"x_start\", \"y_start\") with angle \"rotate\". Produces\n\"num\" points in a spiral spanning width of \"x_range\" and height of \"y_range\"\n\n.. example_spec::\n\n    from scanspec.specs import Spiral\n\n    spec = Spiral(\"x\", \"y\", 1, 5, 10, 50, 30)",
         "properties": {
            "x_axis": {
               "description": "An identifier for what to move for x",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "An identifier for what to move for y",
               "title": "Y Axis"
            },
            "x_start": {
               "description": "x centre of the spiral",
               "title": "X Start",
               "type": "number"
            },
            "y_start": {
               "description": "y centre of the spiral",
               "title": "Y Start",
               "type": "number"
            },
            "x_range": {
               "description": "x width of the spiral",
               "title": "X Range",
               "type": "number"
            },
            "y_range": {
               "description": "y width of the spiral",
               "title": "Y Range",
               "type": "number"
            },
            "num": {
               "description": "Number of frames to produce",
               "minimum": 1,
               "title": "Num",
               "type": "integer"
            },
            "rotate": {
               "default": 0.0,
               "description": "How much to rotate the angle of the spiral",
               "title": "Rotate",
               "type": "number"
            },
            "type": {
               "const": "Spiral",
               "default": "Spiral",
               "enum": [
                  "Spiral"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_start",
            "y_start",
            "x_range",
            "y_range",
            "num"
         ],
         "title": "Spiral",
         "type": "object"
      },
      "Squash": {
         "additionalProperties": false,
         "description": "Squash a stack of Frames together into a single expanded Frames object.\n\nSee Also:\n    `why-squash-can-change-path`\n\n.. example_spec::\n\n    from scanspec.specs import Line, Squash\n\n    spec = Squash(Line(\"y\", 1, 2, 3) * Line(\"x\", 0, 1, 4))",
         "properties": {
            "spec": {
               "$ref": "#/$defs/Spec",
               "description": "The Spec to squash the dimensions of"
            },
            "check_path_changes": {
               "default": true,
               "description": "If True path through scan will not be modified by squash",
               "title": "Check Path Changes",
               "type": "boolean"
            },
            "type": {
               "const": "Squash",
               "default": "Squash",
               "enum": [
                  "Squash"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "spec"
         ],
         "title": "Squash",
         "type": "object"
      },
      "Static": {
         "additionalProperties": false,
         "description": "A static frame, repeated num times, with axis at value.\n\nCan be used to set axis=value at every point in a scan.\n\n.. example_spec::\n\n    from scanspec.specs import Line, Static\n\n    spec = Line(\"y\", 1, 2, 3).zip(Static(\"x\", 3))",
         "properties": {
            "axis": {
               "description": "An identifier for what to move",
               "title": "Axis"
            },
            "value": {
               "description": "The value at each point",
               "title": "Value",
               "type": "number"
            },
            "num": {
               "default": 1,
               "description": "Number of frames to produce",
               "minimum": 1,
               "title": "Num",
               "type": "integer"
            },
            "type": {
               "const": "Static",
               "default": "Static",
               "enum": [
                  "Static"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "axis",
            "value"
         ],
         "title": "Static",
         "type": "object"
      },
      "SymmetricDifferenceOf": {
         "additionalProperties": false,
         "description": "A point is in SymmetricDifferenceOf(a, b) if in either a or b, but not both.\n\nTypically created with the ``^`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) ^ Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False,  True, False])",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "SymmetricDifferenceOf",
               "default": "SymmetricDifferenceOf",
               "enum": [
                  "SymmetricDifferenceOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "SymmetricDifferenceOf",
         "type": "object"
      },
      "UnionOf": {
         "additionalProperties": false,
         "description": "A point is in UnionOf(a, b) if in either a or b.\n\nTypically created with the ``|`` operator\n\n>>> r = Range(\"x\", 0.5, 2.5) | Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True,  True, False])",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "UnionOf",
               "default": "UnionOf",
               "enum": [
                  "UnionOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "UnionOf",
         "type": "object"
      },
      "Zip": {
         "additionalProperties": false,
         "description": "Run two Specs in parallel, merging their midpoints together.\n\nTypically formed using `Spec.zip`.\n\nStacks of Frames are merged by:\n\n- If right creates a stack of a single Frames object of size 1, expand it to\n  the size of the fastest Frames object created by left\n- Merge individual Frames objects together from fastest to slowest\n\nThis means that Zipping a Spec producing stack [l2, l1] with a Spec\nproducing stack [r1] will assert len(l1)==len(r1), and produce\nstack [l2, l1.zip(r1)].\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"z\", 1, 2, 3) * Line(\"y\", 3, 4, 5).zip(Line(\"x\", 4, 5, 5))",
         "properties": {
            "left": {
               "$ref": "#/$defs/Spec",
               "description": "The left-hand Spec to Zip, will appear earlier in axes"
            },
            "right": {
               "$ref": "#/$defs/Spec",
               "description": "The right-hand Spec to Zip, will appear later in axes"
            },
            "type": {
               "const": "Zip",
               "default": "Zip",
               "enum": [
                  "Zip"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "Zip",
         "type": "object"
      }
   },
   "$ref": "#/$defs/Product"
}

Fields:
field inner: Spec[Axis] [Required]#

Will be executed len(outer) times

field outer: Spec[Axis] [Required]#

Will be executed once

field type: Literal['Product'] = 'Product'#
axes() list[Axis][source]#

Return the list of axes that are present in the scan.

Ordered from slowest moving to fastest moving.

calculate(bounds: bool = True, nested: bool = False) list[Frames[Axis]][source]#

Produce a stack of nested Frames that form the scan.

Ordered from slowest moving to fastest moving.

pydantic model scanspec.specs.Repeat[source]#

Repeat an empty frame num times.

Can be used on the outside of a scan to repeat the same scan many times.

# Example Spec

from scanspec.plot import plot_spec
from scanspec.specs import Line

spec = 2 * ~Line.bounded("x", 3, 4, 1)
plot_spec(spec)

(Source code, png, hires.png, pdf)

../_images/scanspec-specs-2.png

If you want snaked axes to have no gap between iterations you can do:

# Example Spec

from scanspec.plot import plot_spec
from scanspec.specs import Line, Repeat

spec = Repeat(2, gap=False) * ~Line.bounded("x", 3, 4, 1)
plot_spec(spec)

(Source code, png, hires.png, pdf)

../_images/scanspec-specs-3.png

Note

There is no turnaround arrow at x=4

Show JSON schema
{
   "title": "Repeat",
   "description": "Repeat an empty frame num times.\n\nCan be used on the outside of a scan to repeat the same scan many times.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = 2 * ~Line.bounded(\"x\", 3, 4, 1)\n\nIf you want snaked axes to have no gap between iterations you can do:\n\n.. example_spec::\n\n    from scanspec.specs import Line, Repeat\n\n    spec = Repeat(2, gap=False) * ~Line.bounded(\"x\", 3, 4, 1)\n\n.. note:: There is no turnaround arrow at x=4",
   "type": "object",
   "properties": {
      "num": {
         "description": "Number of frames to produce",
         "minimum": 1,
         "title": "Num",
         "type": "integer"
      },
      "gap": {
         "default": true,
         "description": "If False and the slowest of the stack of Frames is snaked then the end and start of consecutive iterations of Spec will have no gap",
         "title": "Gap",
         "type": "boolean"
      },
      "type": {
         "const": "Repeat",
         "default": "Repeat",
         "enum": [
            "Repeat"
         ],
         "title": "Type",
         "type": "string"
      }
   },
   "additionalProperties": false,
   "required": [
      "num"
   ]
}

Fields:
field gap: bool = True#

If False and the slowest of the stack of Frames is snaked then the end and start of consecutive iterations of Spec will have no gap

field num: int [Required]#

Number of frames to produce

Constraints:
  • ge = 1

field type: Literal['Repeat'] = 'Repeat'#
axes() list[Axis][source]#

Return the list of axes that are present in the scan.

Ordered from slowest moving to fastest moving.

calculate(bounds: bool = True, nested: bool = False) list[Frames[Axis]][source]#

Produce a stack of nested Frames that form the scan.

Ordered from slowest moving to fastest moving.

pydantic model scanspec.specs.Zip[source]#

Run two Specs in parallel, merging their midpoints together.

Typically formed using Spec.zip.

Stacks of Frames are merged by:

  • If right creates a stack of a single Frames object of size 1, expand it to the size of the fastest Frames object created by left

  • Merge individual Frames objects together from fastest to slowest

This means that Zipping a Spec producing stack [l2, l1] with a Spec producing stack [r1] will assert len(l1)==len(r1), and produce stack [l2, l1.zip(r1)].

# Example Spec

from scanspec.plot import plot_spec
from scanspec.specs import Line

spec = Line("z", 1, 2, 3) * Line("y", 3, 4, 5).zip(Line("x", 4, 5, 5))
plot_spec(spec)

(Source code, png, hires.png, pdf)

../_images/scanspec-specs-4.png

Show JSON schema
{
   "$defs": {
      "Circle": {
         "additionalProperties": false,
         "description": "Mask contains points of axis within an xy circle of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Circle(\"x\", \"y\", 1, 2, 0.9)",
         "properties": {
            "x_axis": {
               "description": "The name matching the x axis of the spec",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "The name matching the y axis of the spec",
               "title": "Y Axis"
            },
            "x_middle": {
               "description": "The central x point of the circle",
               "title": "X Middle",
               "type": "number"
            },
            "y_middle": {
               "description": "The central y point of the circle",
               "title": "Y Middle",
               "type": "number"
            },
            "radius": {
               "description": "Radius of the circle",
               "exclusiveMinimum": 0.0,
               "title": "Radius",
               "type": "number"
            },
            "type": {
               "const": "Circle",
               "default": "Circle",
               "enum": [
                  "Circle"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_middle",
            "y_middle",
            "radius"
         ],
         "title": "Circle",
         "type": "object"
      },
      "CombinationOf": {
         "additionalProperties": false,
         "description": "Abstract baseclass for a combination of two regions, left and right.",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "CombinationOf",
               "default": "CombinationOf",
               "enum": [
                  "CombinationOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "CombinationOf",
         "type": "object"
      },
      "Concat": {
         "additionalProperties": false,
         "description": "Concatenate two Specs together, running one after the other.\n\nEach Dimension of left and right must contain the same axes. Typically\nformed using `Spec.concat`.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"x\", 1, 3, 3).concat(Line(\"x\", 4, 5, 5))",
         "properties": {
            "left": {
               "$ref": "#/$defs/Spec",
               "description": "The left-hand Spec to Concat, midpoints will appear earlier"
            },
            "right": {
               "$ref": "#/$defs/Spec",
               "description": "The right-hand Spec to Concat, midpoints will appear later"
            },
            "gap": {
               "default": false,
               "description": "If True, force a gap in the output at the join",
               "title": "Gap",
               "type": "boolean"
            },
            "check_path_changes": {
               "default": true,
               "description": "If True path through scan will not be modified by squash",
               "title": "Check Path Changes",
               "type": "boolean"
            },
            "type": {
               "const": "Concat",
               "default": "Concat",
               "enum": [
                  "Concat"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "Concat",
         "type": "object"
      },
      "DifferenceOf": {
         "additionalProperties": false,
         "description": "A point is in DifferenceOf(a, b) if in a and not in b.\n\nTypically created with the ``-`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) - Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False, False, False])",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "DifferenceOf",
               "default": "DifferenceOf",
               "enum": [
                  "DifferenceOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "DifferenceOf",
         "type": "object"
      },
      "Ellipse": {
         "additionalProperties": false,
         "description": "Mask contains points of axis within an xy ellipse of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Ellipse\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Ellipse(\"x\", \"y\", 5, 5, 2, 3, 75)",
         "properties": {
            "x_axis": {
               "description": "The name matching the x axis of the spec",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "The name matching the y axis of the spec",
               "title": "Y Axis"
            },
            "x_middle": {
               "description": "The central x point of the ellipse",
               "title": "X Middle",
               "type": "number"
            },
            "y_middle": {
               "description": "The central y point of the ellipse",
               "title": "Y Middle",
               "type": "number"
            },
            "x_radius": {
               "description": "The radius along the x axis of the ellipse",
               "exclusiveMinimum": 0.0,
               "title": "X Radius",
               "type": "number"
            },
            "y_radius": {
               "description": "The radius along the y axis of the ellipse",
               "exclusiveMinimum": 0.0,
               "title": "Y Radius",
               "type": "number"
            },
            "angle": {
               "default": 0.0,
               "description": "The angle of the ellipse (degrees)",
               "title": "Angle",
               "type": "number"
            },
            "type": {
               "const": "Ellipse",
               "default": "Ellipse",
               "enum": [
                  "Ellipse"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_middle",
            "y_middle",
            "x_radius",
            "y_radius"
         ],
         "title": "Ellipse",
         "type": "object"
      },
      "IntersectionOf": {
         "additionalProperties": false,
         "description": "A point is in IntersectionOf(a, b) if in both a and b.\n\nTypically created with the ``&`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) & Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, False,  True, False, False])",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "IntersectionOf",
               "default": "IntersectionOf",
               "enum": [
                  "IntersectionOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "IntersectionOf",
         "type": "object"
      },
      "Line": {
         "additionalProperties": false,
         "description": "Linearly spaced frames with start and stop as first and last midpoints.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"x\", 1, 2, 5)",
         "properties": {
            "axis": {
               "description": "An identifier for what to move",
               "title": "Axis"
            },
            "start": {
               "description": "Midpoint of the first point of the line",
               "title": "Start",
               "type": "number"
            },
            "stop": {
               "description": "Midpoint of the last point of the line",
               "title": "Stop",
               "type": "number"
            },
            "num": {
               "description": "Number of frames to produce",
               "minimum": 1,
               "title": "Num",
               "type": "integer"
            },
            "type": {
               "const": "Line",
               "default": "Line",
               "enum": [
                  "Line"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "axis",
            "start",
            "stop",
            "num"
         ],
         "title": "Line",
         "type": "object"
      },
      "Mask": {
         "additionalProperties": false,
         "description": "Restrict Spec to only midpoints that fall inside the given Region.\n\nTypically created with the ``&`` operator. It also pushes down the\n``& | ^ -`` operators to its `Region` to avoid the need for brackets on\ncombinations of Regions.\n\nIf a Region spans multiple Frames objects, they will be squashed together.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 3, 3) * Line(\"x\", 3, 5, 5) & Circle(\"x\", \"y\", 4, 2, 1.2)\n\nSee Also: `why-squash-can-change-path`",
         "properties": {
            "spec": {
               "$ref": "#/$defs/Spec",
               "description": "The Spec containing the source midpoints"
            },
            "region": {
               "$ref": "#/$defs/Region",
               "description": "The Region that midpoints will be inside"
            },
            "check_path_changes": {
               "default": true,
               "description": "If True path through scan will not be modified by squash",
               "title": "Check Path Changes",
               "type": "boolean"
            },
            "type": {
               "const": "Mask",
               "default": "Mask",
               "enum": [
                  "Mask"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "spec",
            "region"
         ],
         "title": "Mask",
         "type": "object"
      },
      "Polygon": {
         "additionalProperties": false,
         "description": "Mask contains points of axis within a rotated xy polygon.\n\n.. example_spec::\n\n    from scanspec.regions import Polygon\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Polygon(\"x\", \"y\", [1.0, 6.0, 8.0, 2.0], [4.0, 10.0, 6.0, 1.0])",
         "properties": {
            "x_axis": {
               "description": "The name matching the x axis of the spec",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "The name matching the y axis of the spec",
               "title": "Y Axis"
            },
            "x_verts": {
               "description": "The Nx1 x coordinates of the polygons vertices",
               "items": {
                  "type": "number"
               },
               "minItems": 3,
               "title": "X Verts",
               "type": "array"
            },
            "y_verts": {
               "description": "The Nx1 y coordinates of the polygons vertices",
               "items": {
                  "type": "number"
               },
               "minItems": 3,
               "title": "Y Verts",
               "type": "array"
            },
            "type": {
               "const": "Polygon",
               "default": "Polygon",
               "enum": [
                  "Polygon"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_verts",
            "y_verts"
         ],
         "title": "Polygon",
         "type": "object"
      },
      "Product": {
         "additionalProperties": false,
         "description": "Outer product of two Specs, nesting inner within outer.\n\nThis means that inner will run in its entirety at each point in outer.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 2, 3) * Line(\"x\", 3, 4, 12)",
         "properties": {
            "outer": {
               "$ref": "#/$defs/Spec",
               "description": "Will be executed once"
            },
            "inner": {
               "$ref": "#/$defs/Spec",
               "description": "Will be executed len(outer) times"
            },
            "type": {
               "const": "Product",
               "default": "Product",
               "enum": [
                  "Product"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "outer",
            "inner"
         ],
         "title": "Product",
         "type": "object"
      },
      "Range": {
         "additionalProperties": false,
         "description": "Mask contains points of axis >= min and <= max.\n\n>>> r = Range(\"x\", 1, 2)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True, False, False])",
         "properties": {
            "axis": {
               "description": "The name matching the axis to mask in spec",
               "title": "Axis"
            },
            "min": {
               "description": "The minimum inclusive value in the region",
               "title": "Min",
               "type": "number"
            },
            "max": {
               "description": "The minimum inclusive value in the region",
               "title": "Max",
               "type": "number"
            },
            "type": {
               "const": "Range",
               "default": "Range",
               "enum": [
                  "Range"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "axis",
            "min",
            "max"
         ],
         "title": "Range",
         "type": "object"
      },
      "Rectangle": {
         "additionalProperties": false,
         "description": "Mask contains points of axis within a rotated xy rectangle.\n\n.. example_spec::\n\n    from scanspec.regions import Rectangle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Rectangle(\"x\", \"y\", 0, 1.1, 1.5, 2.1, 30)",
         "properties": {
            "x_axis": {
               "description": "The name matching the x axis of the spec",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "The name matching the y axis of the spec",
               "title": "Y Axis"
            },
            "x_min": {
               "description": "Minimum inclusive x value in the region",
               "title": "X Min",
               "type": "number"
            },
            "y_min": {
               "description": "Minimum inclusive y value in the region",
               "title": "Y Min",
               "type": "number"
            },
            "x_max": {
               "description": "Maximum inclusive x value in the region",
               "title": "X Max",
               "type": "number"
            },
            "y_max": {
               "description": "Maximum inclusive y value in the region",
               "title": "Y Max",
               "type": "number"
            },
            "angle": {
               "default": 0.0,
               "description": "Clockwise rotation angle of the rectangle",
               "title": "Angle",
               "type": "number"
            },
            "type": {
               "const": "Rectangle",
               "default": "Rectangle",
               "enum": [
                  "Rectangle"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_min",
            "y_min",
            "x_max",
            "y_max"
         ],
         "title": "Rectangle",
         "type": "object"
      },
      "Region": {
         "discriminator": {
            "mapping": {
               "Circle": "#/$defs/Circle",
               "CombinationOf": "#/$defs/CombinationOf",
               "DifferenceOf": "#/$defs/DifferenceOf",
               "Ellipse": "#/$defs/Ellipse",
               "IntersectionOf": "#/$defs/IntersectionOf",
               "Polygon": "#/$defs/Polygon",
               "Range": "#/$defs/Range",
               "Rectangle": "#/$defs/Rectangle",
               "SymmetricDifferenceOf": "#/$defs/SymmetricDifferenceOf",
               "UnionOf": "#/$defs/UnionOf"
            },
            "propertyName": "type"
         },
         "oneOf": [
            {
               "$ref": "#/$defs/CombinationOf"
            },
            {
               "$ref": "#/$defs/UnionOf"
            },
            {
               "$ref": "#/$defs/IntersectionOf"
            },
            {
               "$ref": "#/$defs/DifferenceOf"
            },
            {
               "$ref": "#/$defs/SymmetricDifferenceOf"
            },
            {
               "$ref": "#/$defs/Range"
            },
            {
               "$ref": "#/$defs/Rectangle"
            },
            {
               "$ref": "#/$defs/Polygon"
            },
            {
               "$ref": "#/$defs/Circle"
            },
            {
               "$ref": "#/$defs/Ellipse"
            }
         ]
      },
      "Repeat": {
         "additionalProperties": false,
         "description": "Repeat an empty frame num times.\n\nCan be used on the outside of a scan to repeat the same scan many times.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = 2 * ~Line.bounded(\"x\", 3, 4, 1)\n\nIf you want snaked axes to have no gap between iterations you can do:\n\n.. example_spec::\n\n    from scanspec.specs import Line, Repeat\n\n    spec = Repeat(2, gap=False) * ~Line.bounded(\"x\", 3, 4, 1)\n\n.. note:: There is no turnaround arrow at x=4",
         "properties": {
            "num": {
               "description": "Number of frames to produce",
               "minimum": 1,
               "title": "Num",
               "type": "integer"
            },
            "gap": {
               "default": true,
               "description": "If False and the slowest of the stack of Frames is snaked then the end and start of consecutive iterations of Spec will have no gap",
               "title": "Gap",
               "type": "boolean"
            },
            "type": {
               "const": "Repeat",
               "default": "Repeat",
               "enum": [
                  "Repeat"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "num"
         ],
         "title": "Repeat",
         "type": "object"
      },
      "Snake": {
         "additionalProperties": false,
         "description": "Run the Spec in reverse on every other iteration when nested.\n\nTypically created with the ``~`` operator.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 3, 3) * ~Line(\"x\", 3, 5, 5)",
         "properties": {
            "spec": {
               "$ref": "#/$defs/Spec",
               "description": "The Spec to run in reverse every other iteration"
            },
            "type": {
               "const": "Snake",
               "default": "Snake",
               "enum": [
                  "Snake"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "spec"
         ],
         "title": "Snake",
         "type": "object"
      },
      "Spec": {
         "discriminator": {
            "mapping": {
               "Concat": "#/$defs/Concat",
               "Line": "#/$defs/Line",
               "Mask": "#/$defs/Mask",
               "Product": "#/$defs/Product",
               "Repeat": "#/$defs/Repeat",
               "Snake": "#/$defs/Snake",
               "Spiral": "#/$defs/Spiral",
               "Squash": "#/$defs/Squash",
               "Static": "#/$defs/Static",
               "Zip": "#/$defs/Zip"
            },
            "propertyName": "type"
         },
         "oneOf": [
            {
               "$ref": "#/$defs/Product"
            },
            {
               "$ref": "#/$defs/Repeat"
            },
            {
               "$ref": "#/$defs/Zip"
            },
            {
               "$ref": "#/$defs/Mask"
            },
            {
               "$ref": "#/$defs/Snake"
            },
            {
               "$ref": "#/$defs/Concat"
            },
            {
               "$ref": "#/$defs/Squash"
            },
            {
               "$ref": "#/$defs/Line"
            },
            {
               "$ref": "#/$defs/Static"
            },
            {
               "$ref": "#/$defs/Spiral"
            }
         ]
      },
      "Spiral": {
         "additionalProperties": false,
         "description": "Archimedean spiral of \"x_axis\" and \"y_axis\".\n\nStarts at centre point (\"x_start\", \"y_start\") with angle \"rotate\". Produces\n\"num\" points in a spiral spanning width of \"x_range\" and height of \"y_range\"\n\n.. example_spec::\n\n    from scanspec.specs import Spiral\n\n    spec = Spiral(\"x\", \"y\", 1, 5, 10, 50, 30)",
         "properties": {
            "x_axis": {
               "description": "An identifier for what to move for x",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "An identifier for what to move for y",
               "title": "Y Axis"
            },
            "x_start": {
               "description": "x centre of the spiral",
               "title": "X Start",
               "type": "number"
            },
            "y_start": {
               "description": "y centre of the spiral",
               "title": "Y Start",
               "type": "number"
            },
            "x_range": {
               "description": "x width of the spiral",
               "title": "X Range",
               "type": "number"
            },
            "y_range": {
               "description": "y width of the spiral",
               "title": "Y Range",
               "type": "number"
            },
            "num": {
               "description": "Number of frames to produce",
               "minimum": 1,
               "title": "Num",
               "type": "integer"
            },
            "rotate": {
               "default": 0.0,
               "description": "How much to rotate the angle of the spiral",
               "title": "Rotate",
               "type": "number"
            },
            "type": {
               "const": "Spiral",
               "default": "Spiral",
               "enum": [
                  "Spiral"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_start",
            "y_start",
            "x_range",
            "y_range",
            "num"
         ],
         "title": "Spiral",
         "type": "object"
      },
      "Squash": {
         "additionalProperties": false,
         "description": "Squash a stack of Frames together into a single expanded Frames object.\n\nSee Also:\n    `why-squash-can-change-path`\n\n.. example_spec::\n\n    from scanspec.specs import Line, Squash\n\n    spec = Squash(Line(\"y\", 1, 2, 3) * Line(\"x\", 0, 1, 4))",
         "properties": {
            "spec": {
               "$ref": "#/$defs/Spec",
               "description": "The Spec to squash the dimensions of"
            },
            "check_path_changes": {
               "default": true,
               "description": "If True path through scan will not be modified by squash",
               "title": "Check Path Changes",
               "type": "boolean"
            },
            "type": {
               "const": "Squash",
               "default": "Squash",
               "enum": [
                  "Squash"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "spec"
         ],
         "title": "Squash",
         "type": "object"
      },
      "Static": {
         "additionalProperties": false,
         "description": "A static frame, repeated num times, with axis at value.\n\nCan be used to set axis=value at every point in a scan.\n\n.. example_spec::\n\n    from scanspec.specs import Line, Static\n\n    spec = Line(\"y\", 1, 2, 3).zip(Static(\"x\", 3))",
         "properties": {
            "axis": {
               "description": "An identifier for what to move",
               "title": "Axis"
            },
            "value": {
               "description": "The value at each point",
               "title": "Value",
               "type": "number"
            },
            "num": {
               "default": 1,
               "description": "Number of frames to produce",
               "minimum": 1,
               "title": "Num",
               "type": "integer"
            },
            "type": {
               "const": "Static",
               "default": "Static",
               "enum": [
                  "Static"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "axis",
            "value"
         ],
         "title": "Static",
         "type": "object"
      },
      "SymmetricDifferenceOf": {
         "additionalProperties": false,
         "description": "A point is in SymmetricDifferenceOf(a, b) if in either a or b, but not both.\n\nTypically created with the ``^`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) ^ Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False,  True, False])",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "SymmetricDifferenceOf",
               "default": "SymmetricDifferenceOf",
               "enum": [
                  "SymmetricDifferenceOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "SymmetricDifferenceOf",
         "type": "object"
      },
      "UnionOf": {
         "additionalProperties": false,
         "description": "A point is in UnionOf(a, b) if in either a or b.\n\nTypically created with the ``|`` operator\n\n>>> r = Range(\"x\", 0.5, 2.5) | Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True,  True, False])",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "UnionOf",
               "default": "UnionOf",
               "enum": [
                  "UnionOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "UnionOf",
         "type": "object"
      },
      "Zip": {
         "additionalProperties": false,
         "description": "Run two Specs in parallel, merging their midpoints together.\n\nTypically formed using `Spec.zip`.\n\nStacks of Frames are merged by:\n\n- If right creates a stack of a single Frames object of size 1, expand it to\n  the size of the fastest Frames object created by left\n- Merge individual Frames objects together from fastest to slowest\n\nThis means that Zipping a Spec producing stack [l2, l1] with a Spec\nproducing stack [r1] will assert len(l1)==len(r1), and produce\nstack [l2, l1.zip(r1)].\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"z\", 1, 2, 3) * Line(\"y\", 3, 4, 5).zip(Line(\"x\", 4, 5, 5))",
         "properties": {
            "left": {
               "$ref": "#/$defs/Spec",
               "description": "The left-hand Spec to Zip, will appear earlier in axes"
            },
            "right": {
               "$ref": "#/$defs/Spec",
               "description": "The right-hand Spec to Zip, will appear later in axes"
            },
            "type": {
               "const": "Zip",
               "default": "Zip",
               "enum": [
                  "Zip"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "Zip",
         "type": "object"
      }
   },
   "$ref": "#/$defs/Zip"
}

Fields:
field left: Spec[Axis] [Required]#

The left-hand Spec to Zip, will appear earlier in axes

field right: Spec[Axis] [Required]#

The right-hand Spec to Zip, will appear later in axes

field type: Literal['Zip'] = 'Zip'#
axes() list[Axis][source]#

Return the list of axes that are present in the scan.

Ordered from slowest moving to fastest moving.

calculate(bounds: bool = True, nested: bool = False) list[Frames[Axis]][source]#

Produce a stack of nested Frames that form the scan.

Ordered from slowest moving to fastest moving.

pydantic model scanspec.specs.Mask[source]#

Restrict Spec to only midpoints that fall inside the given Region.

Typically created with the & operator. It also pushes down the & | ^ - operators to its Region to avoid the need for brackets on combinations of Regions.

If a Region spans multiple Frames objects, they will be squashed together.

# Example Spec

from scanspec.plot import plot_spec
from scanspec.regions import Circle
from scanspec.specs import Line

spec = Line("y", 1, 3, 3) * Line("x", 3, 5, 5) & Circle("x", "y", 4, 2, 1.2)
plot_spec(spec)

(Source code, png, hires.png, pdf)

../_images/scanspec-specs-5.png

See Also: Why Squash (and Mask) can change the Path

Show JSON schema
{
   "$defs": {
      "Circle": {
         "additionalProperties": false,
         "description": "Mask contains points of axis within an xy circle of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Circle(\"x\", \"y\", 1, 2, 0.9)",
         "properties": {
            "x_axis": {
               "description": "The name matching the x axis of the spec",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "The name matching the y axis of the spec",
               "title": "Y Axis"
            },
            "x_middle": {
               "description": "The central x point of the circle",
               "title": "X Middle",
               "type": "number"
            },
            "y_middle": {
               "description": "The central y point of the circle",
               "title": "Y Middle",
               "type": "number"
            },
            "radius": {
               "description": "Radius of the circle",
               "exclusiveMinimum": 0.0,
               "title": "Radius",
               "type": "number"
            },
            "type": {
               "const": "Circle",
               "default": "Circle",
               "enum": [
                  "Circle"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_middle",
            "y_middle",
            "radius"
         ],
         "title": "Circle",
         "type": "object"
      },
      "CombinationOf": {
         "additionalProperties": false,
         "description": "Abstract baseclass for a combination of two regions, left and right.",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "CombinationOf",
               "default": "CombinationOf",
               "enum": [
                  "CombinationOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "CombinationOf",
         "type": "object"
      },
      "Concat": {
         "additionalProperties": false,
         "description": "Concatenate two Specs together, running one after the other.\n\nEach Dimension of left and right must contain the same axes. Typically\nformed using `Spec.concat`.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"x\", 1, 3, 3).concat(Line(\"x\", 4, 5, 5))",
         "properties": {
            "left": {
               "$ref": "#/$defs/Spec",
               "description": "The left-hand Spec to Concat, midpoints will appear earlier"
            },
            "right": {
               "$ref": "#/$defs/Spec",
               "description": "The right-hand Spec to Concat, midpoints will appear later"
            },
            "gap": {
               "default": false,
               "description": "If True, force a gap in the output at the join",
               "title": "Gap",
               "type": "boolean"
            },
            "check_path_changes": {
               "default": true,
               "description": "If True path through scan will not be modified by squash",
               "title": "Check Path Changes",
               "type": "boolean"
            },
            "type": {
               "const": "Concat",
               "default": "Concat",
               "enum": [
                  "Concat"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "Concat",
         "type": "object"
      },
      "DifferenceOf": {
         "additionalProperties": false,
         "description": "A point is in DifferenceOf(a, b) if in a and not in b.\n\nTypically created with the ``-`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) - Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False, False, False])",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "DifferenceOf",
               "default": "DifferenceOf",
               "enum": [
                  "DifferenceOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "DifferenceOf",
         "type": "object"
      },
      "Ellipse": {
         "additionalProperties": false,
         "description": "Mask contains points of axis within an xy ellipse of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Ellipse\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Ellipse(\"x\", \"y\", 5, 5, 2, 3, 75)",
         "properties": {
            "x_axis": {
               "description": "The name matching the x axis of the spec",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "The name matching the y axis of the spec",
               "title": "Y Axis"
            },
            "x_middle": {
               "description": "The central x point of the ellipse",
               "title": "X Middle",
               "type": "number"
            },
            "y_middle": {
               "description": "The central y point of the ellipse",
               "title": "Y Middle",
               "type": "number"
            },
            "x_radius": {
               "description": "The radius along the x axis of the ellipse",
               "exclusiveMinimum": 0.0,
               "title": "X Radius",
               "type": "number"
            },
            "y_radius": {
               "description": "The radius along the y axis of the ellipse",
               "exclusiveMinimum": 0.0,
               "title": "Y Radius",
               "type": "number"
            },
            "angle": {
               "default": 0.0,
               "description": "The angle of the ellipse (degrees)",
               "title": "Angle",
               "type": "number"
            },
            "type": {
               "const": "Ellipse",
               "default": "Ellipse",
               "enum": [
                  "Ellipse"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_middle",
            "y_middle",
            "x_radius",
            "y_radius"
         ],
         "title": "Ellipse",
         "type": "object"
      },
      "IntersectionOf": {
         "additionalProperties": false,
         "description": "A point is in IntersectionOf(a, b) if in both a and b.\n\nTypically created with the ``&`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) & Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, False,  True, False, False])",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "IntersectionOf",
               "default": "IntersectionOf",
               "enum": [
                  "IntersectionOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "IntersectionOf",
         "type": "object"
      },
      "Line": {
         "additionalProperties": false,
         "description": "Linearly spaced frames with start and stop as first and last midpoints.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"x\", 1, 2, 5)",
         "properties": {
            "axis": {
               "description": "An identifier for what to move",
               "title": "Axis"
            },
            "start": {
               "description": "Midpoint of the first point of the line",
               "title": "Start",
               "type": "number"
            },
            "stop": {
               "description": "Midpoint of the last point of the line",
               "title": "Stop",
               "type": "number"
            },
            "num": {
               "description": "Number of frames to produce",
               "minimum": 1,
               "title": "Num",
               "type": "integer"
            },
            "type": {
               "const": "Line",
               "default": "Line",
               "enum": [
                  "Line"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "axis",
            "start",
            "stop",
            "num"
         ],
         "title": "Line",
         "type": "object"
      },
      "Mask": {
         "additionalProperties": false,
         "description": "Restrict Spec to only midpoints that fall inside the given Region.\n\nTypically created with the ``&`` operator. It also pushes down the\n``& | ^ -`` operators to its `Region` to avoid the need for brackets on\ncombinations of Regions.\n\nIf a Region spans multiple Frames objects, they will be squashed together.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 3, 3) * Line(\"x\", 3, 5, 5) & Circle(\"x\", \"y\", 4, 2, 1.2)\n\nSee Also: `why-squash-can-change-path`",
         "properties": {
            "spec": {
               "$ref": "#/$defs/Spec",
               "description": "The Spec containing the source midpoints"
            },
            "region": {
               "$ref": "#/$defs/Region",
               "description": "The Region that midpoints will be inside"
            },
            "check_path_changes": {
               "default": true,
               "description": "If True path through scan will not be modified by squash",
               "title": "Check Path Changes",
               "type": "boolean"
            },
            "type": {
               "const": "Mask",
               "default": "Mask",
               "enum": [
                  "Mask"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "spec",
            "region"
         ],
         "title": "Mask",
         "type": "object"
      },
      "Polygon": {
         "additionalProperties": false,
         "description": "Mask contains points of axis within a rotated xy polygon.\n\n.. example_spec::\n\n    from scanspec.regions import Polygon\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Polygon(\"x\", \"y\", [1.0, 6.0, 8.0, 2.0], [4.0, 10.0, 6.0, 1.0])",
         "properties": {
            "x_axis": {
               "description": "The name matching the x axis of the spec",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "The name matching the y axis of the spec",
               "title": "Y Axis"
            },
            "x_verts": {
               "description": "The Nx1 x coordinates of the polygons vertices",
               "items": {
                  "type": "number"
               },
               "minItems": 3,
               "title": "X Verts",
               "type": "array"
            },
            "y_verts": {
               "description": "The Nx1 y coordinates of the polygons vertices",
               "items": {
                  "type": "number"
               },
               "minItems": 3,
               "title": "Y Verts",
               "type": "array"
            },
            "type": {
               "const": "Polygon",
               "default": "Polygon",
               "enum": [
                  "Polygon"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_verts",
            "y_verts"
         ],
         "title": "Polygon",
         "type": "object"
      },
      "Product": {
         "additionalProperties": false,
         "description": "Outer product of two Specs, nesting inner within outer.\n\nThis means that inner will run in its entirety at each point in outer.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 2, 3) * Line(\"x\", 3, 4, 12)",
         "properties": {
            "outer": {
               "$ref": "#/$defs/Spec",
               "description": "Will be executed once"
            },
            "inner": {
               "$ref": "#/$defs/Spec",
               "description": "Will be executed len(outer) times"
            },
            "type": {
               "const": "Product",
               "default": "Product",
               "enum": [
                  "Product"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "outer",
            "inner"
         ],
         "title": "Product",
         "type": "object"
      },
      "Range": {
         "additionalProperties": false,
         "description": "Mask contains points of axis >= min and <= max.\n\n>>> r = Range(\"x\", 1, 2)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True, False, False])",
         "properties": {
            "axis": {
               "description": "The name matching the axis to mask in spec",
               "title": "Axis"
            },
            "min": {
               "description": "The minimum inclusive value in the region",
               "title": "Min",
               "type": "number"
            },
            "max": {
               "description": "The minimum inclusive value in the region",
               "title": "Max",
               "type": "number"
            },
            "type": {
               "const": "Range",
               "default": "Range",
               "enum": [
                  "Range"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "axis",
            "min",
            "max"
         ],
         "title": "Range",
         "type": "object"
      },
      "Rectangle": {
         "additionalProperties": false,
         "description": "Mask contains points of axis within a rotated xy rectangle.\n\n.. example_spec::\n\n    from scanspec.regions import Rectangle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Rectangle(\"x\", \"y\", 0, 1.1, 1.5, 2.1, 30)",
         "properties": {
            "x_axis": {
               "description": "The name matching the x axis of the spec",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "The name matching the y axis of the spec",
               "title": "Y Axis"
            },
            "x_min": {
               "description": "Minimum inclusive x value in the region",
               "title": "X Min",
               "type": "number"
            },
            "y_min": {
               "description": "Minimum inclusive y value in the region",
               "title": "Y Min",
               "type": "number"
            },
            "x_max": {
               "description": "Maximum inclusive x value in the region",
               "title": "X Max",
               "type": "number"
            },
            "y_max": {
               "description": "Maximum inclusive y value in the region",
               "title": "Y Max",
               "type": "number"
            },
            "angle": {
               "default": 0.0,
               "description": "Clockwise rotation angle of the rectangle",
               "title": "Angle",
               "type": "number"
            },
            "type": {
               "const": "Rectangle",
               "default": "Rectangle",
               "enum": [
                  "Rectangle"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_min",
            "y_min",
            "x_max",
            "y_max"
         ],
         "title": "Rectangle",
         "type": "object"
      },
      "Region": {
         "discriminator": {
            "mapping": {
               "Circle": "#/$defs/Circle",
               "CombinationOf": "#/$defs/CombinationOf",
               "DifferenceOf": "#/$defs/DifferenceOf",
               "Ellipse": "#/$defs/Ellipse",
               "IntersectionOf": "#/$defs/IntersectionOf",
               "Polygon": "#/$defs/Polygon",
               "Range": "#/$defs/Range",
               "Rectangle": "#/$defs/Rectangle",
               "SymmetricDifferenceOf": "#/$defs/SymmetricDifferenceOf",
               "UnionOf": "#/$defs/UnionOf"
            },
            "propertyName": "type"
         },
         "oneOf": [
            {
               "$ref": "#/$defs/CombinationOf"
            },
            {
               "$ref": "#/$defs/UnionOf"
            },
            {
               "$ref": "#/$defs/IntersectionOf"
            },
            {
               "$ref": "#/$defs/DifferenceOf"
            },
            {
               "$ref": "#/$defs/SymmetricDifferenceOf"
            },
            {
               "$ref": "#/$defs/Range"
            },
            {
               "$ref": "#/$defs/Rectangle"
            },
            {
               "$ref": "#/$defs/Polygon"
            },
            {
               "$ref": "#/$defs/Circle"
            },
            {
               "$ref": "#/$defs/Ellipse"
            }
         ]
      },
      "Repeat": {
         "additionalProperties": false,
         "description": "Repeat an empty frame num times.\n\nCan be used on the outside of a scan to repeat the same scan many times.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = 2 * ~Line.bounded(\"x\", 3, 4, 1)\n\nIf you want snaked axes to have no gap between iterations you can do:\n\n.. example_spec::\n\n    from scanspec.specs import Line, Repeat\n\n    spec = Repeat(2, gap=False) * ~Line.bounded(\"x\", 3, 4, 1)\n\n.. note:: There is no turnaround arrow at x=4",
         "properties": {
            "num": {
               "description": "Number of frames to produce",
               "minimum": 1,
               "title": "Num",
               "type": "integer"
            },
            "gap": {
               "default": true,
               "description": "If False and the slowest of the stack of Frames is snaked then the end and start of consecutive iterations of Spec will have no gap",
               "title": "Gap",
               "type": "boolean"
            },
            "type": {
               "const": "Repeat",
               "default": "Repeat",
               "enum": [
                  "Repeat"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "num"
         ],
         "title": "Repeat",
         "type": "object"
      },
      "Snake": {
         "additionalProperties": false,
         "description": "Run the Spec in reverse on every other iteration when nested.\n\nTypically created with the ``~`` operator.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 3, 3) * ~Line(\"x\", 3, 5, 5)",
         "properties": {
            "spec": {
               "$ref": "#/$defs/Spec",
               "description": "The Spec to run in reverse every other iteration"
            },
            "type": {
               "const": "Snake",
               "default": "Snake",
               "enum": [
                  "Snake"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "spec"
         ],
         "title": "Snake",
         "type": "object"
      },
      "Spec": {
         "discriminator": {
            "mapping": {
               "Concat": "#/$defs/Concat",
               "Line": "#/$defs/Line",
               "Mask": "#/$defs/Mask",
               "Product": "#/$defs/Product",
               "Repeat": "#/$defs/Repeat",
               "Snake": "#/$defs/Snake",
               "Spiral": "#/$defs/Spiral",
               "Squash": "#/$defs/Squash",
               "Static": "#/$defs/Static",
               "Zip": "#/$defs/Zip"
            },
            "propertyName": "type"
         },
         "oneOf": [
            {
               "$ref": "#/$defs/Product"
            },
            {
               "$ref": "#/$defs/Repeat"
            },
            {
               "$ref": "#/$defs/Zip"
            },
            {
               "$ref": "#/$defs/Mask"
            },
            {
               "$ref": "#/$defs/Snake"
            },
            {
               "$ref": "#/$defs/Concat"
            },
            {
               "$ref": "#/$defs/Squash"
            },
            {
               "$ref": "#/$defs/Line"
            },
            {
               "$ref": "#/$defs/Static"
            },
            {
               "$ref": "#/$defs/Spiral"
            }
         ]
      },
      "Spiral": {
         "additionalProperties": false,
         "description": "Archimedean spiral of \"x_axis\" and \"y_axis\".\n\nStarts at centre point (\"x_start\", \"y_start\") with angle \"rotate\". Produces\n\"num\" points in a spiral spanning width of \"x_range\" and height of \"y_range\"\n\n.. example_spec::\n\n    from scanspec.specs import Spiral\n\n    spec = Spiral(\"x\", \"y\", 1, 5, 10, 50, 30)",
         "properties": {
            "x_axis": {
               "description": "An identifier for what to move for x",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "An identifier for what to move for y",
               "title": "Y Axis"
            },
            "x_start": {
               "description": "x centre of the spiral",
               "title": "X Start",
               "type": "number"
            },
            "y_start": {
               "description": "y centre of the spiral",
               "title": "Y Start",
               "type": "number"
            },
            "x_range": {
               "description": "x width of the spiral",
               "title": "X Range",
               "type": "number"
            },
            "y_range": {
               "description": "y width of the spiral",
               "title": "Y Range",
               "type": "number"
            },
            "num": {
               "description": "Number of frames to produce",
               "minimum": 1,
               "title": "Num",
               "type": "integer"
            },
            "rotate": {
               "default": 0.0,
               "description": "How much to rotate the angle of the spiral",
               "title": "Rotate",
               "type": "number"
            },
            "type": {
               "const": "Spiral",
               "default": "Spiral",
               "enum": [
                  "Spiral"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_start",
            "y_start",
            "x_range",
            "y_range",
            "num"
         ],
         "title": "Spiral",
         "type": "object"
      },
      "Squash": {
         "additionalProperties": false,
         "description": "Squash a stack of Frames together into a single expanded Frames object.\n\nSee Also:\n    `why-squash-can-change-path`\n\n.. example_spec::\n\n    from scanspec.specs import Line, Squash\n\n    spec = Squash(Line(\"y\", 1, 2, 3) * Line(\"x\", 0, 1, 4))",
         "properties": {
            "spec": {
               "$ref": "#/$defs/Spec",
               "description": "The Spec to squash the dimensions of"
            },
            "check_path_changes": {
               "default": true,
               "description": "If True path through scan will not be modified by squash",
               "title": "Check Path Changes",
               "type": "boolean"
            },
            "type": {
               "const": "Squash",
               "default": "Squash",
               "enum": [
                  "Squash"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "spec"
         ],
         "title": "Squash",
         "type": "object"
      },
      "Static": {
         "additionalProperties": false,
         "description": "A static frame, repeated num times, with axis at value.\n\nCan be used to set axis=value at every point in a scan.\n\n.. example_spec::\n\n    from scanspec.specs import Line, Static\n\n    spec = Line(\"y\", 1, 2, 3).zip(Static(\"x\", 3))",
         "properties": {
            "axis": {
               "description": "An identifier for what to move",
               "title": "Axis"
            },
            "value": {
               "description": "The value at each point",
               "title": "Value",
               "type": "number"
            },
            "num": {
               "default": 1,
               "description": "Number of frames to produce",
               "minimum": 1,
               "title": "Num",
               "type": "integer"
            },
            "type": {
               "const": "Static",
               "default": "Static",
               "enum": [
                  "Static"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "axis",
            "value"
         ],
         "title": "Static",
         "type": "object"
      },
      "SymmetricDifferenceOf": {
         "additionalProperties": false,
         "description": "A point is in SymmetricDifferenceOf(a, b) if in either a or b, but not both.\n\nTypically created with the ``^`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) ^ Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False,  True, False])",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "SymmetricDifferenceOf",
               "default": "SymmetricDifferenceOf",
               "enum": [
                  "SymmetricDifferenceOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "SymmetricDifferenceOf",
         "type": "object"
      },
      "UnionOf": {
         "additionalProperties": false,
         "description": "A point is in UnionOf(a, b) if in either a or b.\n\nTypically created with the ``|`` operator\n\n>>> r = Range(\"x\", 0.5, 2.5) | Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True,  True, False])",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "UnionOf",
               "default": "UnionOf",
               "enum": [
                  "UnionOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "UnionOf",
         "type": "object"
      },
      "Zip": {
         "additionalProperties": false,
         "description": "Run two Specs in parallel, merging their midpoints together.\n\nTypically formed using `Spec.zip`.\n\nStacks of Frames are merged by:\n\n- If right creates a stack of a single Frames object of size 1, expand it to\n  the size of the fastest Frames object created by left\n- Merge individual Frames objects together from fastest to slowest\n\nThis means that Zipping a Spec producing stack [l2, l1] with a Spec\nproducing stack [r1] will assert len(l1)==len(r1), and produce\nstack [l2, l1.zip(r1)].\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"z\", 1, 2, 3) * Line(\"y\", 3, 4, 5).zip(Line(\"x\", 4, 5, 5))",
         "properties": {
            "left": {
               "$ref": "#/$defs/Spec",
               "description": "The left-hand Spec to Zip, will appear earlier in axes"
            },
            "right": {
               "$ref": "#/$defs/Spec",
               "description": "The right-hand Spec to Zip, will appear later in axes"
            },
            "type": {
               "const": "Zip",
               "default": "Zip",
               "enum": [
                  "Zip"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "Zip",
         "type": "object"
      }
   },
   "$ref": "#/$defs/Mask"
}

Fields:
field check_path_changes: bool = True#

If True path through scan will not be modified by squash

field region: Region[Axis] [Required]#

The Region that midpoints will be inside

field spec: Spec[Axis] [Required]#

The Spec containing the source midpoints

field type: Literal['Mask'] = 'Mask'#
axes() list[Axis][source]#

Return the list of axes that are present in the scan.

Ordered from slowest moving to fastest moving.

calculate(bounds: bool = True, nested: bool = False) list[Frames[Axis]][source]#

Produce a stack of nested Frames that form the scan.

Ordered from slowest moving to fastest moving.

pydantic model scanspec.specs.Snake[source]#

Run the Spec in reverse on every other iteration when nested.

Typically created with the ~ operator.

# Example Spec

from scanspec.plot import plot_spec
from scanspec.specs import Line

spec = Line("y", 1, 3, 3) * ~Line("x", 3, 5, 5)
plot_spec(spec)

(Source code, png, hires.png, pdf)

../_images/scanspec-specs-6.png

Show JSON schema
{
   "$defs": {
      "Circle": {
         "additionalProperties": false,
         "description": "Mask contains points of axis within an xy circle of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Circle(\"x\", \"y\", 1, 2, 0.9)",
         "properties": {
            "x_axis": {
               "description": "The name matching the x axis of the spec",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "The name matching the y axis of the spec",
               "title": "Y Axis"
            },
            "x_middle": {
               "description": "The central x point of the circle",
               "title": "X Middle",
               "type": "number"
            },
            "y_middle": {
               "description": "The central y point of the circle",
               "title": "Y Middle",
               "type": "number"
            },
            "radius": {
               "description": "Radius of the circle",
               "exclusiveMinimum": 0.0,
               "title": "Radius",
               "type": "number"
            },
            "type": {
               "const": "Circle",
               "default": "Circle",
               "enum": [
                  "Circle"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_middle",
            "y_middle",
            "radius"
         ],
         "title": "Circle",
         "type": "object"
      },
      "CombinationOf": {
         "additionalProperties": false,
         "description": "Abstract baseclass for a combination of two regions, left and right.",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "CombinationOf",
               "default": "CombinationOf",
               "enum": [
                  "CombinationOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "CombinationOf",
         "type": "object"
      },
      "Concat": {
         "additionalProperties": false,
         "description": "Concatenate two Specs together, running one after the other.\n\nEach Dimension of left and right must contain the same axes. Typically\nformed using `Spec.concat`.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"x\", 1, 3, 3).concat(Line(\"x\", 4, 5, 5))",
         "properties": {
            "left": {
               "$ref": "#/$defs/Spec",
               "description": "The left-hand Spec to Concat, midpoints will appear earlier"
            },
            "right": {
               "$ref": "#/$defs/Spec",
               "description": "The right-hand Spec to Concat, midpoints will appear later"
            },
            "gap": {
               "default": false,
               "description": "If True, force a gap in the output at the join",
               "title": "Gap",
               "type": "boolean"
            },
            "check_path_changes": {
               "default": true,
               "description": "If True path through scan will not be modified by squash",
               "title": "Check Path Changes",
               "type": "boolean"
            },
            "type": {
               "const": "Concat",
               "default": "Concat",
               "enum": [
                  "Concat"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "Concat",
         "type": "object"
      },
      "DifferenceOf": {
         "additionalProperties": false,
         "description": "A point is in DifferenceOf(a, b) if in a and not in b.\n\nTypically created with the ``-`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) - Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False, False, False])",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "DifferenceOf",
               "default": "DifferenceOf",
               "enum": [
                  "DifferenceOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "DifferenceOf",
         "type": "object"
      },
      "Ellipse": {
         "additionalProperties": false,
         "description": "Mask contains points of axis within an xy ellipse of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Ellipse\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Ellipse(\"x\", \"y\", 5, 5, 2, 3, 75)",
         "properties": {
            "x_axis": {
               "description": "The name matching the x axis of the spec",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "The name matching the y axis of the spec",
               "title": "Y Axis"
            },
            "x_middle": {
               "description": "The central x point of the ellipse",
               "title": "X Middle",
               "type": "number"
            },
            "y_middle": {
               "description": "The central y point of the ellipse",
               "title": "Y Middle",
               "type": "number"
            },
            "x_radius": {
               "description": "The radius along the x axis of the ellipse",
               "exclusiveMinimum": 0.0,
               "title": "X Radius",
               "type": "number"
            },
            "y_radius": {
               "description": "The radius along the y axis of the ellipse",
               "exclusiveMinimum": 0.0,
               "title": "Y Radius",
               "type": "number"
            },
            "angle": {
               "default": 0.0,
               "description": "The angle of the ellipse (degrees)",
               "title": "Angle",
               "type": "number"
            },
            "type": {
               "const": "Ellipse",
               "default": "Ellipse",
               "enum": [
                  "Ellipse"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_middle",
            "y_middle",
            "x_radius",
            "y_radius"
         ],
         "title": "Ellipse",
         "type": "object"
      },
      "IntersectionOf": {
         "additionalProperties": false,
         "description": "A point is in IntersectionOf(a, b) if in both a and b.\n\nTypically created with the ``&`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) & Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, False,  True, False, False])",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "IntersectionOf",
               "default": "IntersectionOf",
               "enum": [
                  "IntersectionOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "IntersectionOf",
         "type": "object"
      },
      "Line": {
         "additionalProperties": false,
         "description": "Linearly spaced frames with start and stop as first and last midpoints.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"x\", 1, 2, 5)",
         "properties": {
            "axis": {
               "description": "An identifier for what to move",
               "title": "Axis"
            },
            "start": {
               "description": "Midpoint of the first point of the line",
               "title": "Start",
               "type": "number"
            },
            "stop": {
               "description": "Midpoint of the last point of the line",
               "title": "Stop",
               "type": "number"
            },
            "num": {
               "description": "Number of frames to produce",
               "minimum": 1,
               "title": "Num",
               "type": "integer"
            },
            "type": {
               "const": "Line",
               "default": "Line",
               "enum": [
                  "Line"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "axis",
            "start",
            "stop",
            "num"
         ],
         "title": "Line",
         "type": "object"
      },
      "Mask": {
         "additionalProperties": false,
         "description": "Restrict Spec to only midpoints that fall inside the given Region.\n\nTypically created with the ``&`` operator. It also pushes down the\n``& | ^ -`` operators to its `Region` to avoid the need for brackets on\ncombinations of Regions.\n\nIf a Region spans multiple Frames objects, they will be squashed together.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 3, 3) * Line(\"x\", 3, 5, 5) & Circle(\"x\", \"y\", 4, 2, 1.2)\n\nSee Also: `why-squash-can-change-path`",
         "properties": {
            "spec": {
               "$ref": "#/$defs/Spec",
               "description": "The Spec containing the source midpoints"
            },
            "region": {
               "$ref": "#/$defs/Region",
               "description": "The Region that midpoints will be inside"
            },
            "check_path_changes": {
               "default": true,
               "description": "If True path through scan will not be modified by squash",
               "title": "Check Path Changes",
               "type": "boolean"
            },
            "type": {
               "const": "Mask",
               "default": "Mask",
               "enum": [
                  "Mask"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "spec",
            "region"
         ],
         "title": "Mask",
         "type": "object"
      },
      "Polygon": {
         "additionalProperties": false,
         "description": "Mask contains points of axis within a rotated xy polygon.\n\n.. example_spec::\n\n    from scanspec.regions import Polygon\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Polygon(\"x\", \"y\", [1.0, 6.0, 8.0, 2.0], [4.0, 10.0, 6.0, 1.0])",
         "properties": {
            "x_axis": {
               "description": "The name matching the x axis of the spec",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "The name matching the y axis of the spec",
               "title": "Y Axis"
            },
            "x_verts": {
               "description": "The Nx1 x coordinates of the polygons vertices",
               "items": {
                  "type": "number"
               },
               "minItems": 3,
               "title": "X Verts",
               "type": "array"
            },
            "y_verts": {
               "description": "The Nx1 y coordinates of the polygons vertices",
               "items": {
                  "type": "number"
               },
               "minItems": 3,
               "title": "Y Verts",
               "type": "array"
            },
            "type": {
               "const": "Polygon",
               "default": "Polygon",
               "enum": [
                  "Polygon"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_verts",
            "y_verts"
         ],
         "title": "Polygon",
         "type": "object"
      },
      "Product": {
         "additionalProperties": false,
         "description": "Outer product of two Specs, nesting inner within outer.\n\nThis means that inner will run in its entirety at each point in outer.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 2, 3) * Line(\"x\", 3, 4, 12)",
         "properties": {
            "outer": {
               "$ref": "#/$defs/Spec",
               "description": "Will be executed once"
            },
            "inner": {
               "$ref": "#/$defs/Spec",
               "description": "Will be executed len(outer) times"
            },
            "type": {
               "const": "Product",
               "default": "Product",
               "enum": [
                  "Product"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "outer",
            "inner"
         ],
         "title": "Product",
         "type": "object"
      },
      "Range": {
         "additionalProperties": false,
         "description": "Mask contains points of axis >= min and <= max.\n\n>>> r = Range(\"x\", 1, 2)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True, False, False])",
         "properties": {
            "axis": {
               "description": "The name matching the axis to mask in spec",
               "title": "Axis"
            },
            "min": {
               "description": "The minimum inclusive value in the region",
               "title": "Min",
               "type": "number"
            },
            "max": {
               "description": "The minimum inclusive value in the region",
               "title": "Max",
               "type": "number"
            },
            "type": {
               "const": "Range",
               "default": "Range",
               "enum": [
                  "Range"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "axis",
            "min",
            "max"
         ],
         "title": "Range",
         "type": "object"
      },
      "Rectangle": {
         "additionalProperties": false,
         "description": "Mask contains points of axis within a rotated xy rectangle.\n\n.. example_spec::\n\n    from scanspec.regions import Rectangle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Rectangle(\"x\", \"y\", 0, 1.1, 1.5, 2.1, 30)",
         "properties": {
            "x_axis": {
               "description": "The name matching the x axis of the spec",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "The name matching the y axis of the spec",
               "title": "Y Axis"
            },
            "x_min": {
               "description": "Minimum inclusive x value in the region",
               "title": "X Min",
               "type": "number"
            },
            "y_min": {
               "description": "Minimum inclusive y value in the region",
               "title": "Y Min",
               "type": "number"
            },
            "x_max": {
               "description": "Maximum inclusive x value in the region",
               "title": "X Max",
               "type": "number"
            },
            "y_max": {
               "description": "Maximum inclusive y value in the region",
               "title": "Y Max",
               "type": "number"
            },
            "angle": {
               "default": 0.0,
               "description": "Clockwise rotation angle of the rectangle",
               "title": "Angle",
               "type": "number"
            },
            "type": {
               "const": "Rectangle",
               "default": "Rectangle",
               "enum": [
                  "Rectangle"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_min",
            "y_min",
            "x_max",
            "y_max"
         ],
         "title": "Rectangle",
         "type": "object"
      },
      "Region": {
         "discriminator": {
            "mapping": {
               "Circle": "#/$defs/Circle",
               "CombinationOf": "#/$defs/CombinationOf",
               "DifferenceOf": "#/$defs/DifferenceOf",
               "Ellipse": "#/$defs/Ellipse",
               "IntersectionOf": "#/$defs/IntersectionOf",
               "Polygon": "#/$defs/Polygon",
               "Range": "#/$defs/Range",
               "Rectangle": "#/$defs/Rectangle",
               "SymmetricDifferenceOf": "#/$defs/SymmetricDifferenceOf",
               "UnionOf": "#/$defs/UnionOf"
            },
            "propertyName": "type"
         },
         "oneOf": [
            {
               "$ref": "#/$defs/CombinationOf"
            },
            {
               "$ref": "#/$defs/UnionOf"
            },
            {
               "$ref": "#/$defs/IntersectionOf"
            },
            {
               "$ref": "#/$defs/DifferenceOf"
            },
            {
               "$ref": "#/$defs/SymmetricDifferenceOf"
            },
            {
               "$ref": "#/$defs/Range"
            },
            {
               "$ref": "#/$defs/Rectangle"
            },
            {
               "$ref": "#/$defs/Polygon"
            },
            {
               "$ref": "#/$defs/Circle"
            },
            {
               "$ref": "#/$defs/Ellipse"
            }
         ]
      },
      "Repeat": {
         "additionalProperties": false,
         "description": "Repeat an empty frame num times.\n\nCan be used on the outside of a scan to repeat the same scan many times.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = 2 * ~Line.bounded(\"x\", 3, 4, 1)\n\nIf you want snaked axes to have no gap between iterations you can do:\n\n.. example_spec::\n\n    from scanspec.specs import Line, Repeat\n\n    spec = Repeat(2, gap=False) * ~Line.bounded(\"x\", 3, 4, 1)\n\n.. note:: There is no turnaround arrow at x=4",
         "properties": {
            "num": {
               "description": "Number of frames to produce",
               "minimum": 1,
               "title": "Num",
               "type": "integer"
            },
            "gap": {
               "default": true,
               "description": "If False and the slowest of the stack of Frames is snaked then the end and start of consecutive iterations of Spec will have no gap",
               "title": "Gap",
               "type": "boolean"
            },
            "type": {
               "const": "Repeat",
               "default": "Repeat",
               "enum": [
                  "Repeat"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "num"
         ],
         "title": "Repeat",
         "type": "object"
      },
      "Snake": {
         "additionalProperties": false,
         "description": "Run the Spec in reverse on every other iteration when nested.\n\nTypically created with the ``~`` operator.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 3, 3) * ~Line(\"x\", 3, 5, 5)",
         "properties": {
            "spec": {
               "$ref": "#/$defs/Spec",
               "description": "The Spec to run in reverse every other iteration"
            },
            "type": {
               "const": "Snake",
               "default": "Snake",
               "enum": [
                  "Snake"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "spec"
         ],
         "title": "Snake",
         "type": "object"
      },
      "Spec": {
         "discriminator": {
            "mapping": {
               "Concat": "#/$defs/Concat",
               "Line": "#/$defs/Line",
               "Mask": "#/$defs/Mask",
               "Product": "#/$defs/Product",
               "Repeat": "#/$defs/Repeat",
               "Snake": "#/$defs/Snake",
               "Spiral": "#/$defs/Spiral",
               "Squash": "#/$defs/Squash",
               "Static": "#/$defs/Static",
               "Zip": "#/$defs/Zip"
            },
            "propertyName": "type"
         },
         "oneOf": [
            {
               "$ref": "#/$defs/Product"
            },
            {
               "$ref": "#/$defs/Repeat"
            },
            {
               "$ref": "#/$defs/Zip"
            },
            {
               "$ref": "#/$defs/Mask"
            },
            {
               "$ref": "#/$defs/Snake"
            },
            {
               "$ref": "#/$defs/Concat"
            },
            {
               "$ref": "#/$defs/Squash"
            },
            {
               "$ref": "#/$defs/Line"
            },
            {
               "$ref": "#/$defs/Static"
            },
            {
               "$ref": "#/$defs/Spiral"
            }
         ]
      },
      "Spiral": {
         "additionalProperties": false,
         "description": "Archimedean spiral of \"x_axis\" and \"y_axis\".\n\nStarts at centre point (\"x_start\", \"y_start\") with angle \"rotate\". Produces\n\"num\" points in a spiral spanning width of \"x_range\" and height of \"y_range\"\n\n.. example_spec::\n\n    from scanspec.specs import Spiral\n\n    spec = Spiral(\"x\", \"y\", 1, 5, 10, 50, 30)",
         "properties": {
            "x_axis": {
               "description": "An identifier for what to move for x",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "An identifier for what to move for y",
               "title": "Y Axis"
            },
            "x_start": {
               "description": "x centre of the spiral",
               "title": "X Start",
               "type": "number"
            },
            "y_start": {
               "description": "y centre of the spiral",
               "title": "Y Start",
               "type": "number"
            },
            "x_range": {
               "description": "x width of the spiral",
               "title": "X Range",
               "type": "number"
            },
            "y_range": {
               "description": "y width of the spiral",
               "title": "Y Range",
               "type": "number"
            },
            "num": {
               "description": "Number of frames to produce",
               "minimum": 1,
               "title": "Num",
               "type": "integer"
            },
            "rotate": {
               "default": 0.0,
               "description": "How much to rotate the angle of the spiral",
               "title": "Rotate",
               "type": "number"
            },
            "type": {
               "const": "Spiral",
               "default": "Spiral",
               "enum": [
                  "Spiral"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_start",
            "y_start",
            "x_range",
            "y_range",
            "num"
         ],
         "title": "Spiral",
         "type": "object"
      },
      "Squash": {
         "additionalProperties": false,
         "description": "Squash a stack of Frames together into a single expanded Frames object.\n\nSee Also:\n    `why-squash-can-change-path`\n\n.. example_spec::\n\n    from scanspec.specs import Line, Squash\n\n    spec = Squash(Line(\"y\", 1, 2, 3) * Line(\"x\", 0, 1, 4))",
         "properties": {
            "spec": {
               "$ref": "#/$defs/Spec",
               "description": "The Spec to squash the dimensions of"
            },
            "check_path_changes": {
               "default": true,
               "description": "If True path through scan will not be modified by squash",
               "title": "Check Path Changes",
               "type": "boolean"
            },
            "type": {
               "const": "Squash",
               "default": "Squash",
               "enum": [
                  "Squash"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "spec"
         ],
         "title": "Squash",
         "type": "object"
      },
      "Static": {
         "additionalProperties": false,
         "description": "A static frame, repeated num times, with axis at value.\n\nCan be used to set axis=value at every point in a scan.\n\n.. example_spec::\n\n    from scanspec.specs import Line, Static\n\n    spec = Line(\"y\", 1, 2, 3).zip(Static(\"x\", 3))",
         "properties": {
            "axis": {
               "description": "An identifier for what to move",
               "title": "Axis"
            },
            "value": {
               "description": "The value at each point",
               "title": "Value",
               "type": "number"
            },
            "num": {
               "default": 1,
               "description": "Number of frames to produce",
               "minimum": 1,
               "title": "Num",
               "type": "integer"
            },
            "type": {
               "const": "Static",
               "default": "Static",
               "enum": [
                  "Static"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "axis",
            "value"
         ],
         "title": "Static",
         "type": "object"
      },
      "SymmetricDifferenceOf": {
         "additionalProperties": false,
         "description": "A point is in SymmetricDifferenceOf(a, b) if in either a or b, but not both.\n\nTypically created with the ``^`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) ^ Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False,  True, False])",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "SymmetricDifferenceOf",
               "default": "SymmetricDifferenceOf",
               "enum": [
                  "SymmetricDifferenceOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "SymmetricDifferenceOf",
         "type": "object"
      },
      "UnionOf": {
         "additionalProperties": false,
         "description": "A point is in UnionOf(a, b) if in either a or b.\n\nTypically created with the ``|`` operator\n\n>>> r = Range(\"x\", 0.5, 2.5) | Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True,  True, False])",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "UnionOf",
               "default": "UnionOf",
               "enum": [
                  "UnionOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "UnionOf",
         "type": "object"
      },
      "Zip": {
         "additionalProperties": false,
         "description": "Run two Specs in parallel, merging their midpoints together.\n\nTypically formed using `Spec.zip`.\n\nStacks of Frames are merged by:\n\n- If right creates a stack of a single Frames object of size 1, expand it to\n  the size of the fastest Frames object created by left\n- Merge individual Frames objects together from fastest to slowest\n\nThis means that Zipping a Spec producing stack [l2, l1] with a Spec\nproducing stack [r1] will assert len(l1)==len(r1), and produce\nstack [l2, l1.zip(r1)].\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"z\", 1, 2, 3) * Line(\"y\", 3, 4, 5).zip(Line(\"x\", 4, 5, 5))",
         "properties": {
            "left": {
               "$ref": "#/$defs/Spec",
               "description": "The left-hand Spec to Zip, will appear earlier in axes"
            },
            "right": {
               "$ref": "#/$defs/Spec",
               "description": "The right-hand Spec to Zip, will appear later in axes"
            },
            "type": {
               "const": "Zip",
               "default": "Zip",
               "enum": [
                  "Zip"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "Zip",
         "type": "object"
      }
   },
   "$ref": "#/$defs/Snake"
}

Fields:
field spec: Spec[Axis] [Required]#

The Spec to run in reverse every other iteration

field type: Literal['Snake'] = 'Snake'#
axes() list[Axis][source]#

Return the list of axes that are present in the scan.

Ordered from slowest moving to fastest moving.

calculate(bounds: bool = True, nested: bool = False) list[Frames[Axis]][source]#

Produce a stack of nested Frames that form the scan.

Ordered from slowest moving to fastest moving.

pydantic model scanspec.specs.Concat[source]#

Concatenate two Specs together, running one after the other.

Each Dimension of left and right must contain the same axes. Typically formed using Spec.concat.

# Example Spec

from scanspec.plot import plot_spec
from scanspec.specs import Line

spec = Line("x", 1, 3, 3).concat(Line("x", 4, 5, 5))
plot_spec(spec)

(Source code, png, hires.png, pdf)

../_images/scanspec-specs-7.png

Show JSON schema
{
   "$defs": {
      "Circle": {
         "additionalProperties": false,
         "description": "Mask contains points of axis within an xy circle of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Circle(\"x\", \"y\", 1, 2, 0.9)",
         "properties": {
            "x_axis": {
               "description": "The name matching the x axis of the spec",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "The name matching the y axis of the spec",
               "title": "Y Axis"
            },
            "x_middle": {
               "description": "The central x point of the circle",
               "title": "X Middle",
               "type": "number"
            },
            "y_middle": {
               "description": "The central y point of the circle",
               "title": "Y Middle",
               "type": "number"
            },
            "radius": {
               "description": "Radius of the circle",
               "exclusiveMinimum": 0.0,
               "title": "Radius",
               "type": "number"
            },
            "type": {
               "const": "Circle",
               "default": "Circle",
               "enum": [
                  "Circle"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_middle",
            "y_middle",
            "radius"
         ],
         "title": "Circle",
         "type": "object"
      },
      "CombinationOf": {
         "additionalProperties": false,
         "description": "Abstract baseclass for a combination of two regions, left and right.",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "CombinationOf",
               "default": "CombinationOf",
               "enum": [
                  "CombinationOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "CombinationOf",
         "type": "object"
      },
      "Concat": {
         "additionalProperties": false,
         "description": "Concatenate two Specs together, running one after the other.\n\nEach Dimension of left and right must contain the same axes. Typically\nformed using `Spec.concat`.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"x\", 1, 3, 3).concat(Line(\"x\", 4, 5, 5))",
         "properties": {
            "left": {
               "$ref": "#/$defs/Spec",
               "description": "The left-hand Spec to Concat, midpoints will appear earlier"
            },
            "right": {
               "$ref": "#/$defs/Spec",
               "description": "The right-hand Spec to Concat, midpoints will appear later"
            },
            "gap": {
               "default": false,
               "description": "If True, force a gap in the output at the join",
               "title": "Gap",
               "type": "boolean"
            },
            "check_path_changes": {
               "default": true,
               "description": "If True path through scan will not be modified by squash",
               "title": "Check Path Changes",
               "type": "boolean"
            },
            "type": {
               "const": "Concat",
               "default": "Concat",
               "enum": [
                  "Concat"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "Concat",
         "type": "object"
      },
      "DifferenceOf": {
         "additionalProperties": false,
         "description": "A point is in DifferenceOf(a, b) if in a and not in b.\n\nTypically created with the ``-`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) - Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False, False, False])",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "DifferenceOf",
               "default": "DifferenceOf",
               "enum": [
                  "DifferenceOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "DifferenceOf",
         "type": "object"
      },
      "Ellipse": {
         "additionalProperties": false,
         "description": "Mask contains points of axis within an xy ellipse of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Ellipse\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Ellipse(\"x\", \"y\", 5, 5, 2, 3, 75)",
         "properties": {
            "x_axis": {
               "description": "The name matching the x axis of the spec",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "The name matching the y axis of the spec",
               "title": "Y Axis"
            },
            "x_middle": {
               "description": "The central x point of the ellipse",
               "title": "X Middle",
               "type": "number"
            },
            "y_middle": {
               "description": "The central y point of the ellipse",
               "title": "Y Middle",
               "type": "number"
            },
            "x_radius": {
               "description": "The radius along the x axis of the ellipse",
               "exclusiveMinimum": 0.0,
               "title": "X Radius",
               "type": "number"
            },
            "y_radius": {
               "description": "The radius along the y axis of the ellipse",
               "exclusiveMinimum": 0.0,
               "title": "Y Radius",
               "type": "number"
            },
            "angle": {
               "default": 0.0,
               "description": "The angle of the ellipse (degrees)",
               "title": "Angle",
               "type": "number"
            },
            "type": {
               "const": "Ellipse",
               "default": "Ellipse",
               "enum": [
                  "Ellipse"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_middle",
            "y_middle",
            "x_radius",
            "y_radius"
         ],
         "title": "Ellipse",
         "type": "object"
      },
      "IntersectionOf": {
         "additionalProperties": false,
         "description": "A point is in IntersectionOf(a, b) if in both a and b.\n\nTypically created with the ``&`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) & Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, False,  True, False, False])",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "IntersectionOf",
               "default": "IntersectionOf",
               "enum": [
                  "IntersectionOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "IntersectionOf",
         "type": "object"
      },
      "Line": {
         "additionalProperties": false,
         "description": "Linearly spaced frames with start and stop as first and last midpoints.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"x\", 1, 2, 5)",
         "properties": {
            "axis": {
               "description": "An identifier for what to move",
               "title": "Axis"
            },
            "start": {
               "description": "Midpoint of the first point of the line",
               "title": "Start",
               "type": "number"
            },
            "stop": {
               "description": "Midpoint of the last point of the line",
               "title": "Stop",
               "type": "number"
            },
            "num": {
               "description": "Number of frames to produce",
               "minimum": 1,
               "title": "Num",
               "type": "integer"
            },
            "type": {
               "const": "Line",
               "default": "Line",
               "enum": [
                  "Line"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "axis",
            "start",
            "stop",
            "num"
         ],
         "title": "Line",
         "type": "object"
      },
      "Mask": {
         "additionalProperties": false,
         "description": "Restrict Spec to only midpoints that fall inside the given Region.\n\nTypically created with the ``&`` operator. It also pushes down the\n``& | ^ -`` operators to its `Region` to avoid the need for brackets on\ncombinations of Regions.\n\nIf a Region spans multiple Frames objects, they will be squashed together.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 3, 3) * Line(\"x\", 3, 5, 5) & Circle(\"x\", \"y\", 4, 2, 1.2)\n\nSee Also: `why-squash-can-change-path`",
         "properties": {
            "spec": {
               "$ref": "#/$defs/Spec",
               "description": "The Spec containing the source midpoints"
            },
            "region": {
               "$ref": "#/$defs/Region",
               "description": "The Region that midpoints will be inside"
            },
            "check_path_changes": {
               "default": true,
               "description": "If True path through scan will not be modified by squash",
               "title": "Check Path Changes",
               "type": "boolean"
            },
            "type": {
               "const": "Mask",
               "default": "Mask",
               "enum": [
                  "Mask"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "spec",
            "region"
         ],
         "title": "Mask",
         "type": "object"
      },
      "Polygon": {
         "additionalProperties": false,
         "description": "Mask contains points of axis within a rotated xy polygon.\n\n.. example_spec::\n\n    from scanspec.regions import Polygon\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Polygon(\"x\", \"y\", [1.0, 6.0, 8.0, 2.0], [4.0, 10.0, 6.0, 1.0])",
         "properties": {
            "x_axis": {
               "description": "The name matching the x axis of the spec",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "The name matching the y axis of the spec",
               "title": "Y Axis"
            },
            "x_verts": {
               "description": "The Nx1 x coordinates of the polygons vertices",
               "items": {
                  "type": "number"
               },
               "minItems": 3,
               "title": "X Verts",
               "type": "array"
            },
            "y_verts": {
               "description": "The Nx1 y coordinates of the polygons vertices",
               "items": {
                  "type": "number"
               },
               "minItems": 3,
               "title": "Y Verts",
               "type": "array"
            },
            "type": {
               "const": "Polygon",
               "default": "Polygon",
               "enum": [
                  "Polygon"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_verts",
            "y_verts"
         ],
         "title": "Polygon",
         "type": "object"
      },
      "Product": {
         "additionalProperties": false,
         "description": "Outer product of two Specs, nesting inner within outer.\n\nThis means that inner will run in its entirety at each point in outer.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 2, 3) * Line(\"x\", 3, 4, 12)",
         "properties": {
            "outer": {
               "$ref": "#/$defs/Spec",
               "description": "Will be executed once"
            },
            "inner": {
               "$ref": "#/$defs/Spec",
               "description": "Will be executed len(outer) times"
            },
            "type": {
               "const": "Product",
               "default": "Product",
               "enum": [
                  "Product"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "outer",
            "inner"
         ],
         "title": "Product",
         "type": "object"
      },
      "Range": {
         "additionalProperties": false,
         "description": "Mask contains points of axis >= min and <= max.\n\n>>> r = Range(\"x\", 1, 2)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True, False, False])",
         "properties": {
            "axis": {
               "description": "The name matching the axis to mask in spec",
               "title": "Axis"
            },
            "min": {
               "description": "The minimum inclusive value in the region",
               "title": "Min",
               "type": "number"
            },
            "max": {
               "description": "The minimum inclusive value in the region",
               "title": "Max",
               "type": "number"
            },
            "type": {
               "const": "Range",
               "default": "Range",
               "enum": [
                  "Range"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "axis",
            "min",
            "max"
         ],
         "title": "Range",
         "type": "object"
      },
      "Rectangle": {
         "additionalProperties": false,
         "description": "Mask contains points of axis within a rotated xy rectangle.\n\n.. example_spec::\n\n    from scanspec.regions import Rectangle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Rectangle(\"x\", \"y\", 0, 1.1, 1.5, 2.1, 30)",
         "properties": {
            "x_axis": {
               "description": "The name matching the x axis of the spec",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "The name matching the y axis of the spec",
               "title": "Y Axis"
            },
            "x_min": {
               "description": "Minimum inclusive x value in the region",
               "title": "X Min",
               "type": "number"
            },
            "y_min": {
               "description": "Minimum inclusive y value in the region",
               "title": "Y Min",
               "type": "number"
            },
            "x_max": {
               "description": "Maximum inclusive x value in the region",
               "title": "X Max",
               "type": "number"
            },
            "y_max": {
               "description": "Maximum inclusive y value in the region",
               "title": "Y Max",
               "type": "number"
            },
            "angle": {
               "default": 0.0,
               "description": "Clockwise rotation angle of the rectangle",
               "title": "Angle",
               "type": "number"
            },
            "type": {
               "const": "Rectangle",
               "default": "Rectangle",
               "enum": [
                  "Rectangle"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_min",
            "y_min",
            "x_max",
            "y_max"
         ],
         "title": "Rectangle",
         "type": "object"
      },
      "Region": {
         "discriminator": {
            "mapping": {
               "Circle": "#/$defs/Circle",
               "CombinationOf": "#/$defs/CombinationOf",
               "DifferenceOf": "#/$defs/DifferenceOf",
               "Ellipse": "#/$defs/Ellipse",
               "IntersectionOf": "#/$defs/IntersectionOf",
               "Polygon": "#/$defs/Polygon",
               "Range": "#/$defs/Range",
               "Rectangle": "#/$defs/Rectangle",
               "SymmetricDifferenceOf": "#/$defs/SymmetricDifferenceOf",
               "UnionOf": "#/$defs/UnionOf"
            },
            "propertyName": "type"
         },
         "oneOf": [
            {
               "$ref": "#/$defs/CombinationOf"
            },
            {
               "$ref": "#/$defs/UnionOf"
            },
            {
               "$ref": "#/$defs/IntersectionOf"
            },
            {
               "$ref": "#/$defs/DifferenceOf"
            },
            {
               "$ref": "#/$defs/SymmetricDifferenceOf"
            },
            {
               "$ref": "#/$defs/Range"
            },
            {
               "$ref": "#/$defs/Rectangle"
            },
            {
               "$ref": "#/$defs/Polygon"
            },
            {
               "$ref": "#/$defs/Circle"
            },
            {
               "$ref": "#/$defs/Ellipse"
            }
         ]
      },
      "Repeat": {
         "additionalProperties": false,
         "description": "Repeat an empty frame num times.\n\nCan be used on the outside of a scan to repeat the same scan many times.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = 2 * ~Line.bounded(\"x\", 3, 4, 1)\n\nIf you want snaked axes to have no gap between iterations you can do:\n\n.. example_spec::\n\n    from scanspec.specs import Line, Repeat\n\n    spec = Repeat(2, gap=False) * ~Line.bounded(\"x\", 3, 4, 1)\n\n.. note:: There is no turnaround arrow at x=4",
         "properties": {
            "num": {
               "description": "Number of frames to produce",
               "minimum": 1,
               "title": "Num",
               "type": "integer"
            },
            "gap": {
               "default": true,
               "description": "If False and the slowest of the stack of Frames is snaked then the end and start of consecutive iterations of Spec will have no gap",
               "title": "Gap",
               "type": "boolean"
            },
            "type": {
               "const": "Repeat",
               "default": "Repeat",
               "enum": [
                  "Repeat"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "num"
         ],
         "title": "Repeat",
         "type": "object"
      },
      "Snake": {
         "additionalProperties": false,
         "description": "Run the Spec in reverse on every other iteration when nested.\n\nTypically created with the ``~`` operator.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 3, 3) * ~Line(\"x\", 3, 5, 5)",
         "properties": {
            "spec": {
               "$ref": "#/$defs/Spec",
               "description": "The Spec to run in reverse every other iteration"
            },
            "type": {
               "const": "Snake",
               "default": "Snake",
               "enum": [
                  "Snake"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "spec"
         ],
         "title": "Snake",
         "type": "object"
      },
      "Spec": {
         "discriminator": {
            "mapping": {
               "Concat": "#/$defs/Concat",
               "Line": "#/$defs/Line",
               "Mask": "#/$defs/Mask",
               "Product": "#/$defs/Product",
               "Repeat": "#/$defs/Repeat",
               "Snake": "#/$defs/Snake",
               "Spiral": "#/$defs/Spiral",
               "Squash": "#/$defs/Squash",
               "Static": "#/$defs/Static",
               "Zip": "#/$defs/Zip"
            },
            "propertyName": "type"
         },
         "oneOf": [
            {
               "$ref": "#/$defs/Product"
            },
            {
               "$ref": "#/$defs/Repeat"
            },
            {
               "$ref": "#/$defs/Zip"
            },
            {
               "$ref": "#/$defs/Mask"
            },
            {
               "$ref": "#/$defs/Snake"
            },
            {
               "$ref": "#/$defs/Concat"
            },
            {
               "$ref": "#/$defs/Squash"
            },
            {
               "$ref": "#/$defs/Line"
            },
            {
               "$ref": "#/$defs/Static"
            },
            {
               "$ref": "#/$defs/Spiral"
            }
         ]
      },
      "Spiral": {
         "additionalProperties": false,
         "description": "Archimedean spiral of \"x_axis\" and \"y_axis\".\n\nStarts at centre point (\"x_start\", \"y_start\") with angle \"rotate\". Produces\n\"num\" points in a spiral spanning width of \"x_range\" and height of \"y_range\"\n\n.. example_spec::\n\n    from scanspec.specs import Spiral\n\n    spec = Spiral(\"x\", \"y\", 1, 5, 10, 50, 30)",
         "properties": {
            "x_axis": {
               "description": "An identifier for what to move for x",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "An identifier for what to move for y",
               "title": "Y Axis"
            },
            "x_start": {
               "description": "x centre of the spiral",
               "title": "X Start",
               "type": "number"
            },
            "y_start": {
               "description": "y centre of the spiral",
               "title": "Y Start",
               "type": "number"
            },
            "x_range": {
               "description": "x width of the spiral",
               "title": "X Range",
               "type": "number"
            },
            "y_range": {
               "description": "y width of the spiral",
               "title": "Y Range",
               "type": "number"
            },
            "num": {
               "description": "Number of frames to produce",
               "minimum": 1,
               "title": "Num",
               "type": "integer"
            },
            "rotate": {
               "default": 0.0,
               "description": "How much to rotate the angle of the spiral",
               "title": "Rotate",
               "type": "number"
            },
            "type": {
               "const": "Spiral",
               "default": "Spiral",
               "enum": [
                  "Spiral"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_start",
            "y_start",
            "x_range",
            "y_range",
            "num"
         ],
         "title": "Spiral",
         "type": "object"
      },
      "Squash": {
         "additionalProperties": false,
         "description": "Squash a stack of Frames together into a single expanded Frames object.\n\nSee Also:\n    `why-squash-can-change-path`\n\n.. example_spec::\n\n    from scanspec.specs import Line, Squash\n\n    spec = Squash(Line(\"y\", 1, 2, 3) * Line(\"x\", 0, 1, 4))",
         "properties": {
            "spec": {
               "$ref": "#/$defs/Spec",
               "description": "The Spec to squash the dimensions of"
            },
            "check_path_changes": {
               "default": true,
               "description": "If True path through scan will not be modified by squash",
               "title": "Check Path Changes",
               "type": "boolean"
            },
            "type": {
               "const": "Squash",
               "default": "Squash",
               "enum": [
                  "Squash"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "spec"
         ],
         "title": "Squash",
         "type": "object"
      },
      "Static": {
         "additionalProperties": false,
         "description": "A static frame, repeated num times, with axis at value.\n\nCan be used to set axis=value at every point in a scan.\n\n.. example_spec::\n\n    from scanspec.specs import Line, Static\n\n    spec = Line(\"y\", 1, 2, 3).zip(Static(\"x\", 3))",
         "properties": {
            "axis": {
               "description": "An identifier for what to move",
               "title": "Axis"
            },
            "value": {
               "description": "The value at each point",
               "title": "Value",
               "type": "number"
            },
            "num": {
               "default": 1,
               "description": "Number of frames to produce",
               "minimum": 1,
               "title": "Num",
               "type": "integer"
            },
            "type": {
               "const": "Static",
               "default": "Static",
               "enum": [
                  "Static"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "axis",
            "value"
         ],
         "title": "Static",
         "type": "object"
      },
      "SymmetricDifferenceOf": {
         "additionalProperties": false,
         "description": "A point is in SymmetricDifferenceOf(a, b) if in either a or b, but not both.\n\nTypically created with the ``^`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) ^ Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False,  True, False])",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "SymmetricDifferenceOf",
               "default": "SymmetricDifferenceOf",
               "enum": [
                  "SymmetricDifferenceOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "SymmetricDifferenceOf",
         "type": "object"
      },
      "UnionOf": {
         "additionalProperties": false,
         "description": "A point is in UnionOf(a, b) if in either a or b.\n\nTypically created with the ``|`` operator\n\n>>> r = Range(\"x\", 0.5, 2.5) | Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True,  True, False])",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "UnionOf",
               "default": "UnionOf",
               "enum": [
                  "UnionOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "UnionOf",
         "type": "object"
      },
      "Zip": {
         "additionalProperties": false,
         "description": "Run two Specs in parallel, merging their midpoints together.\n\nTypically formed using `Spec.zip`.\n\nStacks of Frames are merged by:\n\n- If right creates a stack of a single Frames object of size 1, expand it to\n  the size of the fastest Frames object created by left\n- Merge individual Frames objects together from fastest to slowest\n\nThis means that Zipping a Spec producing stack [l2, l1] with a Spec\nproducing stack [r1] will assert len(l1)==len(r1), and produce\nstack [l2, l1.zip(r1)].\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"z\", 1, 2, 3) * Line(\"y\", 3, 4, 5).zip(Line(\"x\", 4, 5, 5))",
         "properties": {
            "left": {
               "$ref": "#/$defs/Spec",
               "description": "The left-hand Spec to Zip, will appear earlier in axes"
            },
            "right": {
               "$ref": "#/$defs/Spec",
               "description": "The right-hand Spec to Zip, will appear later in axes"
            },
            "type": {
               "const": "Zip",
               "default": "Zip",
               "enum": [
                  "Zip"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "Zip",
         "type": "object"
      }
   },
   "$ref": "#/$defs/Concat"
}

Fields:
field check_path_changes: bool = True#

If True path through scan will not be modified by squash

field gap: bool = False#

If True, force a gap in the output at the join

field left: Spec[Axis] [Required]#

The left-hand Spec to Concat, midpoints will appear earlier

field right: Spec[Axis] [Required]#

The right-hand Spec to Concat, midpoints will appear later

field type: Literal['Concat'] = 'Concat'#
axes() list[Axis][source]#

Return the list of axes that are present in the scan.

Ordered from slowest moving to fastest moving.

calculate(bounds: bool = True, nested: bool = False) list[Frames[Axis]][source]#

Produce a stack of nested Frames that form the scan.

Ordered from slowest moving to fastest moving.

pydantic model scanspec.specs.Squash[source]#

Squash a stack of Frames together into a single expanded Frames object.

# Example Spec

from scanspec.plot import plot_spec
from scanspec.specs import Line, Squash

spec = Squash(Line("y", 1, 2, 3) * Line("x", 0, 1, 4))
plot_spec(spec)

(Source code, png, hires.png, pdf)

../_images/scanspec-specs-8.png

Show JSON schema
{
   "$defs": {
      "Circle": {
         "additionalProperties": false,
         "description": "Mask contains points of axis within an xy circle of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Circle(\"x\", \"y\", 1, 2, 0.9)",
         "properties": {
            "x_axis": {
               "description": "The name matching the x axis of the spec",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "The name matching the y axis of the spec",
               "title": "Y Axis"
            },
            "x_middle": {
               "description": "The central x point of the circle",
               "title": "X Middle",
               "type": "number"
            },
            "y_middle": {
               "description": "The central y point of the circle",
               "title": "Y Middle",
               "type": "number"
            },
            "radius": {
               "description": "Radius of the circle",
               "exclusiveMinimum": 0.0,
               "title": "Radius",
               "type": "number"
            },
            "type": {
               "const": "Circle",
               "default": "Circle",
               "enum": [
                  "Circle"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_middle",
            "y_middle",
            "radius"
         ],
         "title": "Circle",
         "type": "object"
      },
      "CombinationOf": {
         "additionalProperties": false,
         "description": "Abstract baseclass for a combination of two regions, left and right.",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "CombinationOf",
               "default": "CombinationOf",
               "enum": [
                  "CombinationOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "CombinationOf",
         "type": "object"
      },
      "Concat": {
         "additionalProperties": false,
         "description": "Concatenate two Specs together, running one after the other.\n\nEach Dimension of left and right must contain the same axes. Typically\nformed using `Spec.concat`.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"x\", 1, 3, 3).concat(Line(\"x\", 4, 5, 5))",
         "properties": {
            "left": {
               "$ref": "#/$defs/Spec",
               "description": "The left-hand Spec to Concat, midpoints will appear earlier"
            },
            "right": {
               "$ref": "#/$defs/Spec",
               "description": "The right-hand Spec to Concat, midpoints will appear later"
            },
            "gap": {
               "default": false,
               "description": "If True, force a gap in the output at the join",
               "title": "Gap",
               "type": "boolean"
            },
            "check_path_changes": {
               "default": true,
               "description": "If True path through scan will not be modified by squash",
               "title": "Check Path Changes",
               "type": "boolean"
            },
            "type": {
               "const": "Concat",
               "default": "Concat",
               "enum": [
                  "Concat"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "Concat",
         "type": "object"
      },
      "DifferenceOf": {
         "additionalProperties": false,
         "description": "A point is in DifferenceOf(a, b) if in a and not in b.\n\nTypically created with the ``-`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) - Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False, False, False])",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "DifferenceOf",
               "default": "DifferenceOf",
               "enum": [
                  "DifferenceOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "DifferenceOf",
         "type": "object"
      },
      "Ellipse": {
         "additionalProperties": false,
         "description": "Mask contains points of axis within an xy ellipse of given radius.\n\n.. example_spec::\n\n    from scanspec.regions import Ellipse\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Ellipse(\"x\", \"y\", 5, 5, 2, 3, 75)",
         "properties": {
            "x_axis": {
               "description": "The name matching the x axis of the spec",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "The name matching the y axis of the spec",
               "title": "Y Axis"
            },
            "x_middle": {
               "description": "The central x point of the ellipse",
               "title": "X Middle",
               "type": "number"
            },
            "y_middle": {
               "description": "The central y point of the ellipse",
               "title": "Y Middle",
               "type": "number"
            },
            "x_radius": {
               "description": "The radius along the x axis of the ellipse",
               "exclusiveMinimum": 0.0,
               "title": "X Radius",
               "type": "number"
            },
            "y_radius": {
               "description": "The radius along the y axis of the ellipse",
               "exclusiveMinimum": 0.0,
               "title": "Y Radius",
               "type": "number"
            },
            "angle": {
               "default": 0.0,
               "description": "The angle of the ellipse (degrees)",
               "title": "Angle",
               "type": "number"
            },
            "type": {
               "const": "Ellipse",
               "default": "Ellipse",
               "enum": [
                  "Ellipse"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_middle",
            "y_middle",
            "x_radius",
            "y_radius"
         ],
         "title": "Ellipse",
         "type": "object"
      },
      "IntersectionOf": {
         "additionalProperties": false,
         "description": "A point is in IntersectionOf(a, b) if in both a and b.\n\nTypically created with the ``&`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) & Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False, False,  True, False, False])",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "IntersectionOf",
               "default": "IntersectionOf",
               "enum": [
                  "IntersectionOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "IntersectionOf",
         "type": "object"
      },
      "Line": {
         "additionalProperties": false,
         "description": "Linearly spaced frames with start and stop as first and last midpoints.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"x\", 1, 2, 5)",
         "properties": {
            "axis": {
               "description": "An identifier for what to move",
               "title": "Axis"
            },
            "start": {
               "description": "Midpoint of the first point of the line",
               "title": "Start",
               "type": "number"
            },
            "stop": {
               "description": "Midpoint of the last point of the line",
               "title": "Stop",
               "type": "number"
            },
            "num": {
               "description": "Number of frames to produce",
               "minimum": 1,
               "title": "Num",
               "type": "integer"
            },
            "type": {
               "const": "Line",
               "default": "Line",
               "enum": [
                  "Line"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "axis",
            "start",
            "stop",
            "num"
         ],
         "title": "Line",
         "type": "object"
      },
      "Mask": {
         "additionalProperties": false,
         "description": "Restrict Spec to only midpoints that fall inside the given Region.\n\nTypically created with the ``&`` operator. It also pushes down the\n``& | ^ -`` operators to its `Region` to avoid the need for brackets on\ncombinations of Regions.\n\nIf a Region spans multiple Frames objects, they will be squashed together.\n\n.. example_spec::\n\n    from scanspec.regions import Circle\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 3, 3) * Line(\"x\", 3, 5, 5) & Circle(\"x\", \"y\", 4, 2, 1.2)\n\nSee Also: `why-squash-can-change-path`",
         "properties": {
            "spec": {
               "$ref": "#/$defs/Spec",
               "description": "The Spec containing the source midpoints"
            },
            "region": {
               "$ref": "#/$defs/Region",
               "description": "The Region that midpoints will be inside"
            },
            "check_path_changes": {
               "default": true,
               "description": "If True path through scan will not be modified by squash",
               "title": "Check Path Changes",
               "type": "boolean"
            },
            "type": {
               "const": "Mask",
               "default": "Mask",
               "enum": [
                  "Mask"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "spec",
            "region"
         ],
         "title": "Mask",
         "type": "object"
      },
      "Polygon": {
         "additionalProperties": false,
         "description": "Mask contains points of axis within a rotated xy polygon.\n\n.. example_spec::\n\n    from scanspec.regions import Polygon\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 3, 8, 10) * ~Line(\"x\", 1 ,8, 10)\n    spec = grid & Polygon(\"x\", \"y\", [1.0, 6.0, 8.0, 2.0], [4.0, 10.0, 6.0, 1.0])",
         "properties": {
            "x_axis": {
               "description": "The name matching the x axis of the spec",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "The name matching the y axis of the spec",
               "title": "Y Axis"
            },
            "x_verts": {
               "description": "The Nx1 x coordinates of the polygons vertices",
               "items": {
                  "type": "number"
               },
               "minItems": 3,
               "title": "X Verts",
               "type": "array"
            },
            "y_verts": {
               "description": "The Nx1 y coordinates of the polygons vertices",
               "items": {
                  "type": "number"
               },
               "minItems": 3,
               "title": "Y Verts",
               "type": "array"
            },
            "type": {
               "const": "Polygon",
               "default": "Polygon",
               "enum": [
                  "Polygon"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_verts",
            "y_verts"
         ],
         "title": "Polygon",
         "type": "object"
      },
      "Product": {
         "additionalProperties": false,
         "description": "Outer product of two Specs, nesting inner within outer.\n\nThis means that inner will run in its entirety at each point in outer.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 2, 3) * Line(\"x\", 3, 4, 12)",
         "properties": {
            "outer": {
               "$ref": "#/$defs/Spec",
               "description": "Will be executed once"
            },
            "inner": {
               "$ref": "#/$defs/Spec",
               "description": "Will be executed len(outer) times"
            },
            "type": {
               "const": "Product",
               "default": "Product",
               "enum": [
                  "Product"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "outer",
            "inner"
         ],
         "title": "Product",
         "type": "object"
      },
      "Range": {
         "additionalProperties": false,
         "description": "Mask contains points of axis >= min and <= max.\n\n>>> r = Range(\"x\", 1, 2)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True, False, False])",
         "properties": {
            "axis": {
               "description": "The name matching the axis to mask in spec",
               "title": "Axis"
            },
            "min": {
               "description": "The minimum inclusive value in the region",
               "title": "Min",
               "type": "number"
            },
            "max": {
               "description": "The minimum inclusive value in the region",
               "title": "Max",
               "type": "number"
            },
            "type": {
               "const": "Range",
               "default": "Range",
               "enum": [
                  "Range"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "axis",
            "min",
            "max"
         ],
         "title": "Range",
         "type": "object"
      },
      "Rectangle": {
         "additionalProperties": false,
         "description": "Mask contains points of axis within a rotated xy rectangle.\n\n.. example_spec::\n\n    from scanspec.regions import Rectangle\n    from scanspec.specs import Line\n\n    grid = Line(\"y\", 1, 3, 10) * ~Line(\"x\", 0, 2, 10)\n    spec = grid & Rectangle(\"x\", \"y\", 0, 1.1, 1.5, 2.1, 30)",
         "properties": {
            "x_axis": {
               "description": "The name matching the x axis of the spec",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "The name matching the y axis of the spec",
               "title": "Y Axis"
            },
            "x_min": {
               "description": "Minimum inclusive x value in the region",
               "title": "X Min",
               "type": "number"
            },
            "y_min": {
               "description": "Minimum inclusive y value in the region",
               "title": "Y Min",
               "type": "number"
            },
            "x_max": {
               "description": "Maximum inclusive x value in the region",
               "title": "X Max",
               "type": "number"
            },
            "y_max": {
               "description": "Maximum inclusive y value in the region",
               "title": "Y Max",
               "type": "number"
            },
            "angle": {
               "default": 0.0,
               "description": "Clockwise rotation angle of the rectangle",
               "title": "Angle",
               "type": "number"
            },
            "type": {
               "const": "Rectangle",
               "default": "Rectangle",
               "enum": [
                  "Rectangle"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_min",
            "y_min",
            "x_max",
            "y_max"
         ],
         "title": "Rectangle",
         "type": "object"
      },
      "Region": {
         "discriminator": {
            "mapping": {
               "Circle": "#/$defs/Circle",
               "CombinationOf": "#/$defs/CombinationOf",
               "DifferenceOf": "#/$defs/DifferenceOf",
               "Ellipse": "#/$defs/Ellipse",
               "IntersectionOf": "#/$defs/IntersectionOf",
               "Polygon": "#/$defs/Polygon",
               "Range": "#/$defs/Range",
               "Rectangle": "#/$defs/Rectangle",
               "SymmetricDifferenceOf": "#/$defs/SymmetricDifferenceOf",
               "UnionOf": "#/$defs/UnionOf"
            },
            "propertyName": "type"
         },
         "oneOf": [
            {
               "$ref": "#/$defs/CombinationOf"
            },
            {
               "$ref": "#/$defs/UnionOf"
            },
            {
               "$ref": "#/$defs/IntersectionOf"
            },
            {
               "$ref": "#/$defs/DifferenceOf"
            },
            {
               "$ref": "#/$defs/SymmetricDifferenceOf"
            },
            {
               "$ref": "#/$defs/Range"
            },
            {
               "$ref": "#/$defs/Rectangle"
            },
            {
               "$ref": "#/$defs/Polygon"
            },
            {
               "$ref": "#/$defs/Circle"
            },
            {
               "$ref": "#/$defs/Ellipse"
            }
         ]
      },
      "Repeat": {
         "additionalProperties": false,
         "description": "Repeat an empty frame num times.\n\nCan be used on the outside of a scan to repeat the same scan many times.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = 2 * ~Line.bounded(\"x\", 3, 4, 1)\n\nIf you want snaked axes to have no gap between iterations you can do:\n\n.. example_spec::\n\n    from scanspec.specs import Line, Repeat\n\n    spec = Repeat(2, gap=False) * ~Line.bounded(\"x\", 3, 4, 1)\n\n.. note:: There is no turnaround arrow at x=4",
         "properties": {
            "num": {
               "description": "Number of frames to produce",
               "minimum": 1,
               "title": "Num",
               "type": "integer"
            },
            "gap": {
               "default": true,
               "description": "If False and the slowest of the stack of Frames is snaked then the end and start of consecutive iterations of Spec will have no gap",
               "title": "Gap",
               "type": "boolean"
            },
            "type": {
               "const": "Repeat",
               "default": "Repeat",
               "enum": [
                  "Repeat"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "num"
         ],
         "title": "Repeat",
         "type": "object"
      },
      "Snake": {
         "additionalProperties": false,
         "description": "Run the Spec in reverse on every other iteration when nested.\n\nTypically created with the ``~`` operator.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"y\", 1, 3, 3) * ~Line(\"x\", 3, 5, 5)",
         "properties": {
            "spec": {
               "$ref": "#/$defs/Spec",
               "description": "The Spec to run in reverse every other iteration"
            },
            "type": {
               "const": "Snake",
               "default": "Snake",
               "enum": [
                  "Snake"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "spec"
         ],
         "title": "Snake",
         "type": "object"
      },
      "Spec": {
         "discriminator": {
            "mapping": {
               "Concat": "#/$defs/Concat",
               "Line": "#/$defs/Line",
               "Mask": "#/$defs/Mask",
               "Product": "#/$defs/Product",
               "Repeat": "#/$defs/Repeat",
               "Snake": "#/$defs/Snake",
               "Spiral": "#/$defs/Spiral",
               "Squash": "#/$defs/Squash",
               "Static": "#/$defs/Static",
               "Zip": "#/$defs/Zip"
            },
            "propertyName": "type"
         },
         "oneOf": [
            {
               "$ref": "#/$defs/Product"
            },
            {
               "$ref": "#/$defs/Repeat"
            },
            {
               "$ref": "#/$defs/Zip"
            },
            {
               "$ref": "#/$defs/Mask"
            },
            {
               "$ref": "#/$defs/Snake"
            },
            {
               "$ref": "#/$defs/Concat"
            },
            {
               "$ref": "#/$defs/Squash"
            },
            {
               "$ref": "#/$defs/Line"
            },
            {
               "$ref": "#/$defs/Static"
            },
            {
               "$ref": "#/$defs/Spiral"
            }
         ]
      },
      "Spiral": {
         "additionalProperties": false,
         "description": "Archimedean spiral of \"x_axis\" and \"y_axis\".\n\nStarts at centre point (\"x_start\", \"y_start\") with angle \"rotate\". Produces\n\"num\" points in a spiral spanning width of \"x_range\" and height of \"y_range\"\n\n.. example_spec::\n\n    from scanspec.specs import Spiral\n\n    spec = Spiral(\"x\", \"y\", 1, 5, 10, 50, 30)",
         "properties": {
            "x_axis": {
               "description": "An identifier for what to move for x",
               "title": "X Axis"
            },
            "y_axis": {
               "description": "An identifier for what to move for y",
               "title": "Y Axis"
            },
            "x_start": {
               "description": "x centre of the spiral",
               "title": "X Start",
               "type": "number"
            },
            "y_start": {
               "description": "y centre of the spiral",
               "title": "Y Start",
               "type": "number"
            },
            "x_range": {
               "description": "x width of the spiral",
               "title": "X Range",
               "type": "number"
            },
            "y_range": {
               "description": "y width of the spiral",
               "title": "Y Range",
               "type": "number"
            },
            "num": {
               "description": "Number of frames to produce",
               "minimum": 1,
               "title": "Num",
               "type": "integer"
            },
            "rotate": {
               "default": 0.0,
               "description": "How much to rotate the angle of the spiral",
               "title": "Rotate",
               "type": "number"
            },
            "type": {
               "const": "Spiral",
               "default": "Spiral",
               "enum": [
                  "Spiral"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "x_axis",
            "y_axis",
            "x_start",
            "y_start",
            "x_range",
            "y_range",
            "num"
         ],
         "title": "Spiral",
         "type": "object"
      },
      "Squash": {
         "additionalProperties": false,
         "description": "Squash a stack of Frames together into a single expanded Frames object.\n\nSee Also:\n    `why-squash-can-change-path`\n\n.. example_spec::\n\n    from scanspec.specs import Line, Squash\n\n    spec = Squash(Line(\"y\", 1, 2, 3) * Line(\"x\", 0, 1, 4))",
         "properties": {
            "spec": {
               "$ref": "#/$defs/Spec",
               "description": "The Spec to squash the dimensions of"
            },
            "check_path_changes": {
               "default": true,
               "description": "If True path through scan will not be modified by squash",
               "title": "Check Path Changes",
               "type": "boolean"
            },
            "type": {
               "const": "Squash",
               "default": "Squash",
               "enum": [
                  "Squash"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "spec"
         ],
         "title": "Squash",
         "type": "object"
      },
      "Static": {
         "additionalProperties": false,
         "description": "A static frame, repeated num times, with axis at value.\n\nCan be used to set axis=value at every point in a scan.\n\n.. example_spec::\n\n    from scanspec.specs import Line, Static\n\n    spec = Line(\"y\", 1, 2, 3).zip(Static(\"x\", 3))",
         "properties": {
            "axis": {
               "description": "An identifier for what to move",
               "title": "Axis"
            },
            "value": {
               "description": "The value at each point",
               "title": "Value",
               "type": "number"
            },
            "num": {
               "default": 1,
               "description": "Number of frames to produce",
               "minimum": 1,
               "title": "Num",
               "type": "integer"
            },
            "type": {
               "const": "Static",
               "default": "Static",
               "enum": [
                  "Static"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "axis",
            "value"
         ],
         "title": "Static",
         "type": "object"
      },
      "SymmetricDifferenceOf": {
         "additionalProperties": false,
         "description": "A point is in SymmetricDifferenceOf(a, b) if in either a or b, but not both.\n\nTypically created with the ``^`` operator.\n\n>>> r = Range(\"x\", 0.5, 2.5) ^ Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True, False,  True, False])",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "SymmetricDifferenceOf",
               "default": "SymmetricDifferenceOf",
               "enum": [
                  "SymmetricDifferenceOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "SymmetricDifferenceOf",
         "type": "object"
      },
      "UnionOf": {
         "additionalProperties": false,
         "description": "A point is in UnionOf(a, b) if in either a or b.\n\nTypically created with the ``|`` operator\n\n>>> r = Range(\"x\", 0.5, 2.5) | Range(\"x\", 1.5, 3.5)\n>>> r.mask({\"x\": np.array([0, 1, 2, 3, 4])})\narray([False,  True,  True,  True, False])",
         "properties": {
            "left": {
               "$ref": "#/$defs/Region",
               "description": "The left-hand Region to combine"
            },
            "right": {
               "$ref": "#/$defs/Region",
               "description": "The right-hand Region to combine"
            },
            "type": {
               "const": "UnionOf",
               "default": "UnionOf",
               "enum": [
                  "UnionOf"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "UnionOf",
         "type": "object"
      },
      "Zip": {
         "additionalProperties": false,
         "description": "Run two Specs in parallel, merging their midpoints together.\n\nTypically formed using `Spec.zip`.\n\nStacks of Frames are merged by:\n\n- If right creates a stack of a single Frames object of size 1, expand it to\n  the size of the fastest Frames object created by left\n- Merge individual Frames objects together from fastest to slowest\n\nThis means that Zipping a Spec producing stack [l2, l1] with a Spec\nproducing stack [r1] will assert len(l1)==len(r1), and produce\nstack [l2, l1.zip(r1)].\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"z\", 1, 2, 3) * Line(\"y\", 3, 4, 5).zip(Line(\"x\", 4, 5, 5))",
         "properties": {
            "left": {
               "$ref": "#/$defs/Spec",
               "description": "The left-hand Spec to Zip, will appear earlier in axes"
            },
            "right": {
               "$ref": "#/$defs/Spec",
               "description": "The right-hand Spec to Zip, will appear later in axes"
            },
            "type": {
               "const": "Zip",
               "default": "Zip",
               "enum": [
                  "Zip"
               ],
               "title": "Type",
               "type": "string"
            }
         },
         "required": [
            "left",
            "right"
         ],
         "title": "Zip",
         "type": "object"
      }
   },
   "$ref": "#/$defs/Squash"
}

Fields:
field check_path_changes: bool = True#

If True path through scan will not be modified by squash

field spec: Spec[Axis] [Required]#

The Spec to squash the dimensions of

field type: Literal['Squash'] = 'Squash'#
axes() list[Axis][source]#

Return the list of axes that are present in the scan.

Ordered from slowest moving to fastest moving.

calculate(bounds: bool = True, nested: bool = False) list[Frames[Axis]][source]#

Produce a stack of nested Frames that form the scan.

Ordered from slowest moving to fastest moving.

pydantic model scanspec.specs.Line[source]#

Linearly spaced frames with start and stop as first and last midpoints.

# Example Spec

from scanspec.plot import plot_spec
from scanspec.specs import Line

spec = Line("x", 1, 2, 5)
plot_spec(spec)

(Source code, png, hires.png, pdf)

../_images/scanspec-specs-9.png

Show JSON schema
{
   "title": "Line",
   "description": "Linearly spaced frames with start and stop as first and last midpoints.\n\n.. example_spec::\n\n    from scanspec.specs import Line\n\n    spec = Line(\"x\", 1, 2, 5)",
   "type": "object",
   "properties": {
      "axis": {
         "description": "An identifier for what to move",
         "title": "Axis"
      },
      "start": {
         "description": "Midpoint of the first point of the line",
         "title": "Start",
         "type": "number"
      },
      "stop": {
         "description": "Midpoint of the last point of the line",
         "title": "Stop",
         "type": "number"
      },
      "num": {
         "description": "Number of frames to produce",
         "minimum": 1,
         "title": "Num",
         "type": "integer"
      },
      "type": {
         "const": "Line",
         "default": "Line",
         "enum": [
            "Line"
         ],
         "title": "Type",
         "type": "string"
      }
   },
   "additionalProperties": false,
   "required": [
      "axis",
      "start",
      "stop",
      "num"
   ]
}

Fields:
field axis: Axis [Required]#

An identifier for what to move

field num: int [Required]#

Number of frames to produce

Constraints:
  • ge = 1

field start: float [Required]#

Midpoint of the first point of the line

field stop: float [Required]#

Midpoint of the last point of the line

field type: Literal['Line'] = 'Line'#
axes() list[Axis][source]#

Return the list of axes that are present in the scan.

Ordered from slowest moving to fastest moving.

bounded(lower: float = FieldInfo(annotation=float, required=True, description='Lower bound of the first point of the line'), upper: float = FieldInfo(annotation=float, required=True, description='Upper bound of the last point of the line'), num: int = FieldInfo(annotation=int, required=True, description='Number of frames to produce', metadata=[Ge(ge=1)])) Line[OtherAxis][source]#

Specify a Line by extreme bounds instead of midpoints.

# Example Spec

from scanspec.plot import plot_spec
from scanspec.specs import Line

spec = Line.bounded("x", 1, 2, 5)
plot_spec(spec)

(Source code, png, hires.png, pdf)

../_images/scanspec-specs-10.png
calculate(bounds: bool = True, nested: bool = False) list[Frames[Axis]][source]#

Produce a stack of nested Frames that form the scan.

Ordered from slowest moving to fastest moving.

pydantic model scanspec.specs.Static[source]#

A static frame, repeated num times, with axis at value.

Can be used to set axis=value at every point in a scan.

# Example Spec

from scanspec.plot import plot_spec
from scanspec.specs import Line, Static

spec = Line("y", 1, 2, 3).zip(Static("x", 3))
plot_spec(spec)

(Source code, png, hires.png, pdf)

../_images/scanspec-specs-11.png

Show JSON schema
{
   "title": "Static",
   "description": "A static frame, repeated num times, with axis at value.\n\nCan be used to set axis=value at every point in a scan.\n\n.. example_spec::\n\n    from scanspec.specs import Line, Static\n\n    spec = Line(\"y\", 1, 2, 3).zip(Static(\"x\", 3))",
   "type": "object",
   "properties": {
      "axis": {
         "description": "An identifier for what to move",
         "title": "Axis"
      },
      "value": {
         "description": "The value at each point",
         "title": "Value",
         "type": "number"
      },
      "num": {
         "default": 1,
         "description": "Number of frames to produce",
         "minimum": 1,
         "title": "Num",
         "type": "integer"
      },
      "type": {
         "const": "Static",
         "default": "Static",
         "enum": [
            "Static"
         ],
         "title": "Type",
         "type": "string"
      }
   },
   "additionalProperties": false,
   "required": [
      "axis",
      "value"
   ]
}

Fields:
field axis: Axis [Required]#

An identifier for what to move

field num: int = 1#

Number of frames to produce

Constraints:
  • ge = 1

field type: Literal['Static'] = 'Static'#
field value: float [Required]#

The value at each point

axes() list[Axis][source]#

Return the list of axes that are present in the scan.

Ordered from slowest moving to fastest moving.

calculate(bounds: bool = True, nested: bool = False) list[Frames[Axis]][source]#

Produce a stack of nested Frames that form the scan.

Ordered from slowest moving to fastest moving.

duration(num: int = FieldInfo(annotation=int, required=False, default=1, description='Number of frames to produce', metadata=[Ge(ge=1)])) Static[str][source]#

A static spec with no motion, only a duration repeated “num” times.

# Example Spec

from scanspec.plot import plot_spec
from scanspec.specs import Line, Static

spec = Line("y", 1, 2, 3).zip(Static.duration(0.1))
plot_spec(spec)

(Source code, png, hires.png, pdf)

../_images/scanspec-specs-12.png
pydantic model scanspec.specs.Spiral[source]#

Archimedean spiral of “x_axis” and “y_axis”.

Starts at centre point (“x_start”, “y_start”) with angle “rotate”. Produces “num” points in a spiral spanning width of “x_range” and height of “y_range”

# Example Spec

from scanspec.plot import plot_spec
from scanspec.specs import Spiral

spec = Spiral("x", "y", 1, 5, 10, 50, 30)
plot_spec(spec)

(Source code, png, hires.png, pdf)

../_images/scanspec-specs-13.png

Show JSON schema
{
   "title": "Spiral",
   "description": "Archimedean spiral of \"x_axis\" and \"y_axis\".\n\nStarts at centre point (\"x_start\", \"y_start\") with angle \"rotate\". Produces\n\"num\" points in a spiral spanning width of \"x_range\" and height of \"y_range\"\n\n.. example_spec::\n\n    from scanspec.specs import Spiral\n\n    spec = Spiral(\"x\", \"y\", 1, 5, 10, 50, 30)",
   "type": "object",
   "properties": {
      "x_axis": {
         "description": "An identifier for what to move for x",
         "title": "X Axis"
      },
      "y_axis": {
         "description": "An identifier for what to move for y",
         "title": "Y Axis"
      },
      "x_start": {
         "description": "x centre of the spiral",
         "title": "X Start",
         "type": "number"
      },
      "y_start": {
         "description": "y centre of the spiral",
         "title": "Y Start",
         "type": "number"
      },
      "x_range": {
         "description": "x width of the spiral",
         "title": "X Range",
         "type": "number"
      },
      "y_range": {
         "description": "y width of the spiral",
         "title": "Y Range",
         "type": "number"
      },
      "num": {
         "description": "Number of frames to produce",
         "minimum": 1,
         "title": "Num",
         "type": "integer"
      },
      "rotate": {
         "default": 0.0,
         "description": "How much to rotate the angle of the spiral",
         "title": "Rotate",
         "type": "number"
      },
      "type": {
         "const": "Spiral",
         "default": "Spiral",
         "enum": [
            "Spiral"
         ],
         "title": "Type",
         "type": "string"
      }
   },
   "additionalProperties": false,
   "required": [
      "x_axis",
      "y_axis",
      "x_start",
      "y_start",
      "x_range",
      "y_range",
      "num"
   ]
}

Fields:
field num: int [Required]#

Number of frames to produce

Constraints:
  • ge = 1

field rotate: float = 0.0#

How much to rotate the angle of the spiral

field type: Literal['Spiral'] = 'Spiral'#
field x_axis: Axis [Required]#

An identifier for what to move for x

field x_range: float [Required]#

x width of the spiral

field x_start: float [Required]#

x centre of the spiral

field y_axis: Axis [Required]#

An identifier for what to move for y

field y_range: float [Required]#

y width of the spiral

field y_start: float [Required]#

y centre of the spiral

axes() list[Axis][source]#

Return the list of axes that are present in the scan.

Ordered from slowest moving to fastest moving.

calculate(bounds: bool = True, nested: bool = False) list[Frames[Axis]][source]#

Produce a stack of nested Frames that form the scan.

Ordered from slowest moving to fastest moving.

spaced(y_axis: OtherAxis = FieldInfo(annotation=~OtherAxis, required=True, description='An identifier for what to move for y'), x_start: float = FieldInfo(annotation=float, required=True, description='x centre of the spiral'), y_start: float = FieldInfo(annotation=float, required=True, description='y centre of the spiral'), radius: float = FieldInfo(annotation=float, required=True, description='radius of the spiral'), dr: float = FieldInfo(annotation=float, required=True, description='difference between each ring'), rotate: float = FieldInfo(annotation=float, required=False, default=0.0, description='How much to rotate the angle of the spiral')) Spiral[OtherAxis][source]#

Specify a Spiral equally spaced in “x_axis” and “y_axis”.

# Example Spec

from scanspec.plot import plot_spec
from scanspec.specs import Spiral

spec = Spiral.spaced("x", "y", 0, 0, 10, 3)
plot_spec(spec)

(Source code, png, hires.png, pdf)

../_images/scanspec-specs-14.png
scanspec.specs.fly(spec: Spec[Axis], duration: float) Spec[Axis | str][source]#

Flyscan, zipping with fixed duration for every frame.

Parameters:
  • spec – The source Spec to continuously move

  • duration – How long to spend at each frame in the spec

# Example Spec

from scanspec.plot import plot_spec
from scanspec.specs import Line, fly

spec = fly(Line("x", 1, 2, 3), 0.1)
plot_spec(spec)

(Source code, png, hires.png, pdf)

../_images/scanspec-specs-15.png
scanspec.specs.step(spec: Spec[Axis], duration: float, num: int = 1) Spec[Axis | str][source]#

Step scan, with num frames of given duration at each frame in the spec.

Parameters:
  • spec – The source Spec with midpoints to move to and stop

  • duration – The duration of each scan frame

  • num – Number of frames to produce with given duration at each of frame in the spec

# Example Spec

from scanspec.plot import plot_spec
from scanspec.specs import Line, step

spec = step(Line("x", 1, 2, 3), 0.1)
plot_spec(spec)

(Source code, png, hires.png, pdf)

../_images/scanspec-specs-16.png