To Top

Credits

  • Web development by:
    • Rob Kent
  • Photos by:
    • Angus Lamond
    • Rob Kent
    • Barry Carr
    • Sara ten Have
  • Graphic design by:
    • Rob Kent
  • Icons by:

Workflow And Step Specification

Posted by: Rob Kent, May 16, 2018, 10:09 a.m.

Introduction

The Data Manager application supports the modelling of both standard operating procedures and laboratory protocols in the form of highly-customisable 'workflows'. As with a laboratory procedure, each 'workflow' can be subdivided into a series of logical, discreet steps through which samples are progressed. Workflows provides a flexible framework which ensures consistent and reliable recording of procedures, sample states, data, reagent and instrument usage and configuration. The data collected, the degree of user input, and the granularity of the steps is dictated by a specification uploaded by an author via the 'administration' console (labelled 'Load YAML'). Specifications for workflows, and their constituent steps, can be uploaded and versioned within Data Manager in the form of YAML (YAML Ain't Markup Language; http://yaml.org/start.html). The aim of this document is to provide an introduction to defining simple workflows and steps, and provide examples which demonstrate the flexibility of the workflows framework and advanced concepts.

Minimum Workflow Step

The minimum specification required to create a workflow step is shown below (see 'Simple Workflow Step'). A step consists of a label, a unique identifier and a version. The label provides a human readable name for the step , whilst the combination of the identifier and version number (which can be a floating point number as well) are used to uniquely identify this particular specification. Each step specification may be modified any number of times, with each revision of the specification being attributed a new version number. 

Simple Worlflow Step
- step: label='SimpleStep' identifier="simple1" version=1

Minimum Workflow

A workflow step has been specified and now can be incorporated into a workflow. Below is an example of a simple workflow specification which uses the "Simple Workflow Step" created previously (see 'Simple Workflow'). As before with the specification of a workflow step, a workflow requires a label, an identifier and a version number which serves to facilitate an iterative authoring process. The 'steps' property is mandatory and details the workflow step specification to be included within the workflow. Each workflow step is declared on a new line beginning with the dash symbol, which indicates a list item in YAML syntax, and must include the 'key', 'identifier' and 'version' values. The latter values uniquely identify the version of the workflow step specification to be included. The 'key' value is internal to the workflow specification and is used to identify the step specification within the list of step transitions. The 'transitions' property details the ordering and connections between the various steps. Each transition typically consists of a pair of 'from_key' and 'to_key' properties, whose values must be one of the 'key' values declared in the 'steps' attribute. In the example provided, a single transition is specified. As this simple workflow consists of a single step, the key 's1' references the root node of the workflow and hence only the 'to_key' attribute is necessary in the first transition. Each workflow may consist of a single root step, whose specification is the lone exception when only the 'to_key' is mandatory and not the 'from_key'. In more complex workflows, the transitions do not have to follow a linear path and branching may also be achieved. However, it is important to note that at present a sample may only follow a linear path along one branch of the workflow and must be split in order to proceed along numerous branches. In addition, there is an assertion in the current version of the system that transitions are specified in a top down manner, so that the steps in the level above in the tree are specified before their child nodes, however, this is likely to be resolved in subsequent releases of Data Manager.

Simple Workflow
- workflow: label='SimpleWorkflow' identifier='workflow1'  version=1
  steps:
    - key='s1' identifier='simple1' version=1
  transitions:
    - to_key='s1' # This is the root node, hence no from_key

Adding Context to a Workflow Step

Following on from the 'Minimum Workflow Step', the 'Context Step' example below provides additional context and fulfils the optional parameters which may be associated with a workflow step. As discussed previously, workflows and workflow steps are likely to be reviewed and revised when necessary, as experimental protocols and standard operating procedures are reevaluated. As such, the 'derived_from' attribute of a step can provide the identifier and version of the previous iteration of a workflow step. The Data Manager application stores each iteration of both the workflow and step specifications as YAML, which ensures that a historical audit trail can be evaluated at any time. Whilst not mandatory, the 'author' property can be specified ensuring that those who use the workflow step are provisioned with a point of contact for questions with regards to the protocol. When viewing the step in Data Manager, as part of a larger workflow, the context of the step may not be readily apparent from the step name alone. The "description" property provides the author with a mechanism to summarise, in a human readable form, the purpose and theory of the workflow step. Steps may also be categorised. While this property is not currently utilised extensively in Data Manager, the intention is that these groups will form the basis of a library of steps which are reusable. If the step requires specific training, technical proficiency or certification then the 'training_requirements' field can be populated to prevent users who have not yet attained the prerequisites necessary for performing the step from progressing samples. Finally, urls can be associated with the workflow step. In the example below, the link directs to a published protocol, however, this may link to repository of standard operating procedures, instrument manuals or safety documentation/ chemical data sheets.

Context Step
- step: label='SimpleStep' identifier="simple1" version=2
  derived_from: step='simple1'  version=1
  author: 'Jack Jones'
  description: 'This description is displayed to the user to describe the protocol step.'
  categories:
    - 'Sample Processing'
  training_requirements:
    - 'Sample Handling'
  links:
    - name='Simple SOP 1' url='https://www.nature.com/articles/nprot.2018.024.pdf'

Adding User Input to a Workflow Step

A key aim of the 'workflows' framework is to ensure that the meta-data which describes an experimental protocol is captured in a standardised manner throughout the laboratory. To ensure flexibility, user inputs are configrable and the author of the workflow may determine which data to collect, the format of the data and and at which juncture it should be collected. Data Manager allows for instrument, reagent and custom properties to be populated and the data associated with a collection of samples. Presently, procedural meta-data is asosciated with the samples upon assignment or upon completion of the workflow step. Further development is planned to extend the capture of such data to the initiation of the step itself.

Instrument Usage

The 'instruments' property refers to the usage of laboratory equipment throughout the step. For each item of equipment necessary to undertake the workflow step, a new line initiated by the dash symbol should be created. Each instrument consists of a label, a type and whether the instrument 'is_required' or is not mandatory. The 'label' attribute refers to the name of the form field the user will be shown and will have to select the instrument instance from. As such, it is recommended that this label describes the instrument and it's purpose as concisely as possible to provide context to the user. User's select instrument instances from a pre-populated dropdown menu in Data Manager. The dropdown comprises those instruments within the user's facility that are available for use (i.e. are active instruments). It should also be noted that 'instrument' fields always have a singular selection and so multiple instrument instances cannot be associated with a single form field. This is to ensure that the audit trail for a given sample is complete and conclusive (i.e. not ambiguity whether the sample was processed on this instrument or another).

BioChemical Stocks

Via the 'Labware' tab of the main menu of Data Manager, consumables such as antibodies, reagents, salts and buffer stocks can be recorded. The 'workflows' framework extends this concept and consumable usage can be recorded and associated with samples as they transition through a particular step. Both required and optional consumables are declared within the 'bio_chemical_stocks' attribute of the step. The 'User Input Step' specification, provided below, includes examples of reagents required for the step and each instance is declared on a new line beginning with the dash symbol (indicating a list item in YAML syntax). The 'label' property reflects the label the user of the workflow will see associated with the form field for the required consumable. In addition, each consumable requires a 'type' property which is validated when the YAML specification is uploaded into Data Manager. The 'type' property defines the category of the expected consumable to be used and therefore must match a ConsumableType instance in the system. Presently, new ConsumableType instances must be specified from the 'admin' Django interface. However, further development is scheduled to migrate this functionality to the 'Lookup' tab of the 'administrator' interface in Data Manager. In the example provided, the 'mAb' field expects that a barcode for a consumable of ConsumableType 'Antibody' will be provided and this is a required field. As such, an error will be thrown if the user tries to allocate a consumable of a disparate type from 'Antibody' to the 'mAb' field. In addition to declaring the instance of a consumable, the user of the workflow may enter a quantity for the consumable usage. Presently, the system works on the assertion that consumables always directly contribute to the sample and that volumes are specified in microlitres. Consequently, the sample volumes are adjusted accordingly. This functionality is currently under revision and will allow the user to specify in the step specification whether or the consumable is added to the samples directly. An additional aspect of this work is to improve the user experience and flexibility of the system to optionally specify a target concentration, as opposed to volume, for the consumable. The volume to be added to each sample can then be derived from the target concentration. As such, the current 'units' attribute of the biochemical stock is ignored at present and defaults to 'μl'.

Custom Fields

To support record keeping and auditing of the protocol, the author of a workflow can specify custom fields to capture additional meta data. Custom fields capture data in the format of a boolean (i.e. True or False), a float (i.e. a floating point number or number which has a decimal place), an integer (i.e. a whole number) or a string (i.e. a sequence of textual characters). Each 'custom_field' must include a description of the type of data which is expected in the form of the "type" property. The 'name' of the custom field is the label of the field that the user of the workflow will see. As above, custom fields may be optional or manditory and this is flagged by the "is_required" property. Unlike both instruments and biochemical stocks, custom fields can allow for multiple values to be associated with a single field which is indicated by the "is_multiple" flag. When the field may accept multiple values, the author must provide a list of values in the form of the "allowed_values" property. A list of allowed values is specified in the format '[ element1, element2, element3, element4, ..., ... ]'. As part of the YAML validation, a check ensures that if a default value is specified for the field (via the 'default' property) then it must also exist within the list of 'allowed_values' if these values have been explicitly specified. The workflow module also supports additional field validation in the form of range validation for both float and integer type fields and regular expression validation for string fields. The former is specified by either or both a 'min' and 'max' property associated with the numerical field (see 'MinMaxRangeInt' example in 'User Input Step'). An example of string validation is provided as the 'ValidatedString (AB123)' in the example below. The 'validation' attribute requires a javascript regular expression pattern. A tutorial in how to write regular expressions is provided at https://www.w3schools.com/js/js_regexp.asp. In the example field below, the expected input is a string of characters where the first two characters are capital letters ([A-Z]{2}) followed by a sequence of threee numbers ([0-9]{3}). The '^' and '$' symbols match to the beginning and end of the string respectively. When writing a validation regular expression, it is highly recommended that the author test the pattern using an online tool such as https://regex101.com/ where the flavour is 'javascript' prior to deployment of the workflow step.

User Input Step
- step: label='User Input' identifier='simple2' version=1
  author: 'Jacqueline Jones'
  description: 'This step demonstrates the flexibility of data collection.'
  instruments:
    on_assign:
      - label='Benchtop Centrifuge' type='Centrifuge' is_required=yes
      - label='P200 Pipette'   type='Pipette'   is_required=no
    on_finish:
      - label='MS System' type='Mass Spectrometer' is_required=yes
  bio_chemical_stocks:
    on_assign:
      - label='mAb'  type='Antibody'   is_required=yes   default_amount=10  units='μl'
      - label='HPLC Water' type='LC grade' is_required=no units='ml'
    on_finish:
      - label='Ethanol' type='Normal grade' units='ml'
      - label='NaCl' type='Salt' is_required=no default_amount=10 units='g'
  custom_fields:
    on_assign:
      - name='RequiredChoiceInteger' type='integer' default=1000 is_required=yes is_multiple=no allowed_values='[ 500, 1000, 15000]' units='rpm'
      - name='MultipleChoiceInt' type='integer' is_required=yes is_multiple=yes allowed_values='[ 1, 5, 10, 50, 100, 500, 1000, 5000]' units='g'
      - name='MinMaxRangeInt' type='integer' units='degrees C' min=0 max=100
      - name='DefaultInt' type='integer' default=2 is_required=no is_multiple=no units='nm' min=0 max=25
      - name='StringChoiceDefault' type='string' default='60 min' is_required=yes is_multiple=no allowed_values='[ "30 min", "60 min", "Pulse"]'
      - name='MultipleChoiceString' type='string' is_required=no is_multiple=yes allowed_values='[ "30 min", "60 min", "Pulse"]'
    on_finish:
      - name='BasicString' type='string'
      - name='ValidatedString (AB123)' type='string' is_required=no is_multiple=no validation='^[A-Z]{2}[0-9]{3}$'
      - name='BooleanDefaultTrue' type='boolean' default=true is_required=yes
      - name='BooleanDefaultFalse' type='boolean' default=false
      - name='FloatRequired' type='float' default=0.001 is_required=yes
      - name='FloatDefault' type='float' default=0.1
      - name='FloatMinMax' type='float' min=0.001 max=100.1
      - name='FloatMulti' type='float' is_multiple=yes allowed_values='[1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 9.9]'

Sample State Changes within a Workflow Step

Within a workflow, a step is likely to result in a change in the state of a given sample, which may comprise a change in the volume / mass of the sample, concentration or the category of the sample type. For the purposes of maintaining an audit trail, the complete history of a sample's state changes are recorded within the Data Manager application. The author of a workflow step may specify whether and when either automatic or manual transitions of sample state occur within the step.

Sample Transitions

Each step may include a 'sample_transitions' declaration. In this block, the user can list pairs of input and output sample types. In previous examples, there has been no explicit declaration of allowed sample_transitions and this conveys that any sample, of any sample type, can be added to the workflow step. However, the sample type will remain unchanged by the process of transitioning through the workflow step. However, the most common use case is that a workflow step is likely to only be applicable to specific sample types. As a list in the YAML specification, denoted by the 'dash' initiated entries in the 'sample_transitions' property, pairs of input and output sample types can be specified. In the 'SampleStateAlteration' example below, consider a generic workflow step for a DNA extraction protocol which may be applicable for many different sources of biological sample (e.g. Blood, Urine, Biopsy, Hair, Seman etc.) but always yields a DNA pellet. The addition of explicit 'sample_transitions' ensures that samples which are of the incorrect sample type cannot be added to a workflow step in error. For both input and output sample types, the name of the sample type must match an existing SampleType declared within the application. New SampleType instances can be created from the 'Manage Lookups' panel of the administrator interface. Furthermore, when a workflow is defined additional validation is performed to ensure that there is a valid sample type path through the workflow. For example, workflow step A precedes step B and step A is authored to transition samples from 'Biopsy → DNA'. As the next step in the workflow, workflow step B must accept samples of any type or 'DNA' or the samples will be blocked from progressing further on the workflow chain. In addition, it should be noted that for a given step a sample input type can only be used once so there is no ambiguity of the intended transition for a sample. Output types do not have to be unique across transitions and can be used in as many as is necessary.

Configurable Sample Properties

Whilst the workflows framework will attempt to calculate volumes, weights and concentrations of samples as they are progressed, there may be scenarios in which manual intervention will be necessary. Unlike the user input fields (namely instruments, biochemical_stocks and custom_fields), the automatic aliquoting (split samples), pooling (combine samples) or configuration of sample properties (i.e. adjusting sample weights, concentrations and volumes) can be undertaken at any stage of the workflow step at the discretion of the author. Each workflow step consists of three distinct points of declaration - on_assign (when samples are added to the workflow step), on_start (the protocol modelled by the step is initiated) and on_finish (when associated samples have completed the protocol for the step). The configuration of sample properties, authored as 'configurable_sample_properties="yes" ', allows the user to modify the current sample amount (i.e. volume or weight) and concentration of those samples selected for a given transition to the next phase of the workflow step. When the properties of the sample are modified by the user, a new sample state is recorded for the sample, however, the historical state persists indefinately to ensure that a complete audit trail is maintained.

Split Samples

The workflows framework supports both the manual and automatic aliquoting of samples. The later is specified in the form of the 'auto_split_samples' property of the 'transition_options' attribute of the 'step'. For the aliquoting of samples, the 'num' attribute reflects the number of child samples to be derived from a single parent sample. In addition, the author can specify the amount of sample required for each aliqout via the "amount" attribute. By default, the units of the amount specified are assumed to be the same as those of the samples being transitioned. The 'select' property defines the behaviour of the application in terms of selecting which samples are to be grouped for each child sample. The options for this attribute will be discussed further in the 'Combine Samples' section as there is only a single eligible setting for the splitting of samples at present, which is 'each'. The 'workflow' attribute defines how the application should behave in regards to the allocation of the generated child samples to the workflow. Presently, there are three options for describing this behaviour - namely, 'inherit', 'root' and 'none'. The 'inherit' behaviour is the default and specifies that each child sample should be added to the same workflow step as the parent, and progresses onto the next phase of the workflow step with the parent sample. For example, if a parent sample is on the 'assigned samples' phase of the second step of workflow A, then the resulting child sample is created and allocated to the 'assigned samples' of the second step in workflow A but is also progressed to the 'started samples' phase with the parent if this split is performed during a transition. The 'root' behaviour is distinct in that each child sample is added as an eligible sample of the first step in the workflow of the parent, thereby allowing for an iterative process. Finally, the 'none' value specifies that each child sample should be added to the pool of active samples in the study but should not be assigned to any workflow. This final scenario encompasses use cases whereby a product of a workflow is no longer necessary in the current protocol but may be used in another. For example, when collecting ex-vivo samples from a model organism it is common to harvest all available tissues and store for later use. As the external reference of a sample may serve multiple requirements, the 'ref_template' attribute provides functionality to define the naming convension for the generated child samples. The template consists of free text, which allows for the use of keywords wrapped in braces ( i.e. "{ }" ) to denote variables which are plugged into the template during the process of aliquoting the samples. Currently, the following keyword arguments are valid inserts into the 'ref_template' attribute - {p.id}, {p.internal_reference}, {p.external_reference} and {unique}. The 'p.id' , the 'p.internal_reference' and the 'p.external_reference' are the numerical identifier, the Data Manager internal reference and the external reference of the parent sample. The 'unique' keyword generates a unique hash code for the child sample, which would be required if unique external references are required in the study. The final property which can be set for the automated splitting of samples is the 'parent_condition'. Following the automatic splitting of the samples, the parent physical sample state can be altered to ensure that parent sample is not progressed regardless of residual volume. For example, in the protocol below it could be conceived that residual amounts of biological material for extraction would be insufficient for further analysis and so would be discarded following the generation of the child samples. The 'parent_condition' attribute is validated upon upload of the YAML specification and the value must match an existing SamplePhysicalCondition, which must be specified in the database directly at present. By default, the physical sample state of the parent sample is set to 'Consumed' if either a split or combine results in the complete usage of the parent sample amount. Conversely, parent samples with residual volumes or weights are progressed alongside the child sample into the next phase of the workflow step.

Combine Samples

The automated combining of samples is specified in a manner similar to that of splitting. However, there are some notable variations to the attributes which can be set. The "num" attribute associated with splitting samples is not applicable to the combining of samples as parent samples are always pooled into a single child sample. The "select" property, governing which samples contribute to the generation of the child sample, has two options for the combining of samples. The 'all' value groups all the selected samples for the transition and generates a single child sample. The 'common_relations' behaviour works by grouping the selected samples based upon a common root or origin sample. For example, consider an experiment where a single sample is split into three aliquots for three distinct treatments. Following the three treatments, the samples can be pooled together and analysed by mass spec as a single injection. The 'common_relations' behaviour would regroup the trio of aliquots as they originate from the same source sample. The 'workflow', 'ref_template', 'amount' and 'parent_condition' attributes behave as described above.

Either Split or Combine Samples

It should be noted that the manual splitting and combining of samples can be performed at any juncture within a workflow step. The automatic splitting and combining of samples is conducted as part of the process of transitioning samples between phases of the workflow step. Whilst the configuration of sample properties can be performed in conjuncture with either the splitting or combining of samples, both splitting and combining of samples cannot be conducted within a single transition.

Sample State Alteration
- step: label='ChangeSampleState' identifier='simple3' version=1
  author: 'Davie Jones'
  description: 'An example to demonstrate features which modify the state of samples within a step'
  sample_transitions:
    - input='Biopsy' output='DNA'
    - input='Blood with anti-coagulant' output='DNA'
    - input='Serum' output='DNA'
  transition_options:
    on_assign:
      configurable_sample_properties: "yes"
      auto_split_samples: num=3 amount=2 select='each' workflow='inherit' ref_template='replicate_{p.external_reference}' parent_condition='Consumed'
    on_start:
      configurable_sample_properties: "no"
    on_finish:
      configurable_sample_properties: "yes"
      auto_combine_samples: select='common_relations' amount=4 workflow='inherit'

Example of a Complex Workflow

Detailed below is an example of a Western Blot protocol.

Western Blot Steps
- step: label='Sample Lysis' identifier='lysis' version=1
  author: 'A Scientist'
  description: 'Lysate preparation from cell culture or tissue'
  sample_transitions:
    - input='Biopsy' output='Lysate'
    - input='Cell lines' output='Lysate'
  instruments:
    on_assign:
      - label='Microcentrifuge' type='Centrifuge' is_required=yes
      - label='Shaker' type='Orbital Shaker' is_required=yes
      - label='Electric Homogeniser' type='Homogeniser' is_required=no
  custom_fields:
    on_assign:
      - name='Centrifuge Temp' units='degrees C' type='int' default=4 is_required=yes
      - name='Centrifuge Duration' units='min' type='int' default=20 is_required=yes
      - name='Centrifuge Speed' units='rpm' type='int' default=12000 is_required=yes
      - name='Agitation Time' units='min' type='int' default=30 is_required=yes allowed_values='[30, 120]'
      - name='Agitation Temp' units='degrees C' type='int' default=4 is_required=yes
  bio_chemical_stocks:
    on_assign:
      - label='PBS'  type='Buffer'   is_required=yes  units='μl'
      - label='Lysis Buffer'  type='Buffer'   is_required=yes  units='μl'
  transition_options:
    on_finish:
      configurable_sample_properties: "yes"
 
- step: label='Sample Prep' identifier='prep' version=1
  author: 'A Scientist'
  description: 'Determine protein conc for each lysate.'
  sample_transitions:
    - input='Lysate' output='Lysate'
  instruments:
   on_assign:
      - label='Water Bath' type='Water Bath' is_required=no
  custom_fields:
   on_assign:
      - name='Denature Duration' units='mins' type='int' is_required=no
      - name='Denature Temp' units='degrees C' type='int' is_required=no
  bio_chemical_stocks:
   on_assign:
      - label='Protein Quantification Kit'  type='Kits'   is_required=yes  units='μl' default=0
      - label='Laemmli Buffer'  type='Buffer'   is_required=yes  units='μl'
 
- step: label='Run Gel' identifier='gel' version=1
  author: 'A Scientist'
  description: 'Run the gel.'
  sample_transitions:
    - input='Lysate' output='Gel'
  instruments:
    on_assign:
     - label='Electrophoresis Kit' type='Electrophoresis System' is_required=yes
  custom_fields:
    on_assign:
     - name='Gel Run Duration' units='mins' type='int' is_required=no
     - name='Gel Run Voltage' units='V' type='int' default=100 is_required=no
  bio_chemical_stocks:
   on_assign:
     - label='Water'  type='Solvent'   is_required=yes  units='μl' default=0
     - label='Acrylamide / Bis'  type='Reagent'   is_required=yes  units='μl' default=0
     - label='Tris'  type='Buffer'   is_required=yes  units='μl' default=0
     - label='SDS 10%'  type='Reagent'   is_required=yes  units='μl' default=0
     - label='TEMED'  type='Reagent'   is_required=yes  units='μl' default=0
     - label='APS 10%'  type='Reagent'   is_required=yes  units='μl' default=0
     - label='Ladder'  type='Loading Ladder'   is_required=yes  units='μl' default=0
   transition_options:
     on_finish:
       configurable_sample_properties: "yes"
       auto_combine_samples: select='all' workflow='inherit' ref_template='gel_{unique}' parent_condition='Consumed'
 
- step: label='Membrane Transfer' identifier='transfer' version=1
  author: 'A Scientist'
  description: 'Transfer the protein from the gel to the membrane.'
  sample_transitions:
     - input='Gel' output='Membrane'
  instruments:
     on_assign:
       - label='Electrophoresis Kit' type='Electrophoresis System' is_required=yes
  custom_fields:
    on_assign:
     - name='Transfer Duration' units='mins' type='int' is_required=yes
     - name='Transfer Voltage' units='V' type='int' is_required=yes
 
- step: label='Antibody Staining' identifier='staining' version=1
  author: 'A Scientist'
  description: 'Incubate the membrane with primary and secondary antibodies.'
  sample_transitions:
    - input='Membrane' output='Membrane'
  custom_fields:
    on_assign:
      - name='Block Duration' units='mins' type='int' default=60 is_required=yes
      - name='Block Temp' units='degrees C' type='int' default=4 is_required=yes
  bio_chemical_stocks:
   on_assign:
     - label='Primary Antibody'  type='Antibody'   is_required=yes  units='μl' default=0
     - label='Secondary Antibody'  type='Antibody'   is_required=yes  units='μl' default=0
     - label='TBST'  type='Buffer'   is_required=yes  units='μl' default=0
     - label='BSA'  type='Buffer'   is_required=yes  units='μl' default=0
Workflow Spec
- workflow: label='Western Blot' identifier='wblot'  version=1
  author: 'A Scientist'
  description: 'Detection of specific proteins in a sample of tissue or culture homogenate.'
  steps:
    - key='s1' identifier='lysis' version=1
    - key='s2' identifier='prep' version=1
    - key='s3' identifier='gel' version=1
    - key='s4' identifier='transfer' version=1
    - key='s5' identifier='staining' version=1
  transitions:
    - to_key='s1'   # This is the root node, hence no from_key
    - from_key='s1' to_key='s2'
    - from_key='s2' to_key='s3'
    - from_key='s3' to_key='s4'
    - from_key='s4' to_key='s5'
  links:
    - name='Abcam Western Protocol' url='http://docs.abcam.com/pdf/protocols/general-western-blot-protocol.pdf'