Forms
Forms are automatically generated using react-jsonschema-form from JSONSchema, which in turn is generated from marshmallow schemas on the server side in python.
An example schema may be as follows:
class MySchema(Schema):
energy = fields.Float(title="Energy", unit="eV", required=True)
dwell = fields.Float(title="Dwell", unit="s", required=True)
counters = fields.List(
fields.Str(enum=["temperature", "pressure"]), uniqueItems=True, title="Counters"
)
Which will generate the following form:
Field Order
Fields can be specifically ordered by adding the Meta.uiorder
property to the Schema
, for example:
class MySchema(Schema):
class Meta:
uiorder: ["dwell", "energy", "counters"]
Will order the fields as follows:
When ordering, all fields must be specified, even those which are hidden.
Customising Fields
react-jsonschema-form will by default render a field type with a sensible input widget. However sometimes it is useful to be able to override this with a custom field type. This can be done by specifying the Meta.uischema
property on the Schema
.
For example:
class MySchema(Schema):
class Meta:
uischema = {
"sampleid": {"classNames": "hidden-row", "ui:widget": "hidden"},
"plot": {"ui:field": "plot0d"},
}
Hidden field
A hidden field is specified with:
class MySchema(Schema):
class Meta:
uischema = {
"sampleid": {"classNames": "hidden-row", "ui:widget": "hidden"},
}
0d Plot
class MySchema(Schema):
class Meta:
uischema = {
"plot": {"ui:field": "plot0d"},
}
With the schema calculating the following data structure for the plot:
class MySchema(Schema):
def calculated(self, data):
plot = {
"x": [...],
"series": [
{"name": "Energy", "data": [...]},
{"name": "Delta", "data": [...], "yaxis": "y2"},
],
"nodata": "Awaiting Data...",
"lines": [
{
"x0": ...,
"x1": ...,
"y0": ...,
"y1": ...,
}
]
}
return { "plot": plot }
Where:
x
is a list of the x dataseries
is a list of the series to plot with names and optionally a second y axisnodata
is a label before the field is populatedlines
is a series of lines to annotate onto the plot
Optional / Typeahead
A typeahead style input can be used to select fields from a nested schema, for example:
class BeamlineParamsSchema(Schema):
detector_distance = fields.Float(
title="Detector Distance",
validate=validate.Range(min=20, max=400),
unit="mm",
description="Move the detector to specified distance",
)
fast_shutter = fields.Bool(
title="Fast Shutter", description="Open fast shutter before and close after"
)
class MySchema(Schema):
beamlineparams = fields.Nested(BeamlineParamsSchema, title="Beamline Parameters")
class Meta:
uischema = {
"beamlineparams": {"ui:field": "optionalParams"},
}
Will generate:
Array Table
A table with add / remove buttons can be generated for a field that is an array of Nested schemas, for example:
class MotorSchema(Schema):
name = fields.Str(enum=["x", "y", "z"])
value = fields.Int()
class MySchema(Schema):
motors = fields.List(fields.Nested(MotorSchema))
class Meta:
uischema = {
"motors": {"ui:field": "arrayTable"},
}
Will generate:
Field Grouping
To optimise space usage and provide UI hints to the user fields can be grouped together:
class MySchema(Schema):
class Meta:
uigroups = [
{
"Params": ["energy", "dwell"]
},
"counters"
]
Will generate:
The label:input proportion can be modified using the ui:colwidth
property, this will scale automatically with the label length, but can also be set for a group of fields. This number relates to the number of columns to take of 12 in the standard bootstrap grid system. For example ui:colwidth = 4 would take 1/3 of the space for the label.
class MySchema(Schema):
class Meta:
uigroups = [
{
"Params": ["energy", "dwell"],
"ui:colwidth": 5,
},
"counters"
]
The size of each field group can also be explicitly specified. By default the number of fields per row is 2. This can be changed by specifying ui:minwidth
. Again this relates to the default bootstrap grid. Where two fields = 6 / 12 columns. Specifying ui:minwidth = 4 would give 3 fields per row.
class MySchema(Schema):
class Meta:
uigroups = [
{
"Params": ["energy", "dwell"],
"ui:minwidth": 4,
},
"counters"
]