Page tree
Skip to end of metadata
Go to start of metadata

Dynamic Properties

Introduction

Dynamic Properties are one of two types of properties that use Jython scripts for providing special functionality to OpenBIS. To understand the basic concept read about Properties Handled By Scripts.

Defining dynamic properties

To create a dynamic property:

  • Define a property type with appropriate name and data type (Admin->Plugins→Add Plugin)

  • Choose Dynamic Property Evaluator from Plugin type dropdown list in the upper left corner.
  • You may evaluate script on chosen entity in Script Tester section.

Creating scripts

To edit existing dynamic property script, edit dynamic property (Admin→Plugins→(click on dynamic property)→Edit plugin)

The scripts should be written using standard Jython syntax. Unlike custom columns and filters (which also require Jython syntax), dynamic properties can have more than one line of code. If the Script contains only one line, it will be evaluated and used as the value of appropriate dynamic property. If on the other hand a multi line script is needed, the function named "calculate" will be expected and the the result will be used as property value.

To access the entity object from the script, use the following syntax:

entity.<requested method>

Currently available methods that can be called on all kinds of entities include:

  • code()
  • property(propertyTypeCode)
  • propertyValue(propertyTypeCode)
  • propertyRendered(propertyTypeCode)
  • properties()

For more details see IEntityAdaptor (interface implemented by entity) and IEntityPropertyAdaptor (interface implemented by each property).

It is also possible to acces the complete Java Object by calling "entityPE()" method, but this is appropach is not recomended, as the returned value is not a part of a well defined API and may change at any point. You may use it as a workaround, in case some data are not accessible via well defined API, but you should contact OpenBIS helpdesk and comunicate your needs, so the appropriate methods can be added to the official API.

You can test your script on selected entities (samples/experiments/materials/data sets) using the testing environment - part of Script Editor.

 

Simple Examples

  1. Show a value of a Sample property which is named 'Multiplicity'

 

entity.propertyValue('Multiplicity')

 

2. Takes an existing property and multiplies the value by 1.5

float(entity.propertyValue('CONCENTRATION_ORIGINAL_ILLUMINA'))*1.5

 

 

Advanced Examples

  1. Show all entity properties as one dynamic property:

 

def get_properties(e):  
    """Automatically creates entity description"""
    properties = e.properties()
    if properties is None:
        return "No properties defined"
    else:
        result = ""
        for p in properties:
            result = result + "\n" + p.propertyTypeCode() + ": " + p.renderedValue()
        return result
    
def calculate(): 
    """Main script function. The result will be used as the value of appropriate dynamic property."""
    return get_properties(entity) 

 

2. Calculate a new float value based some other values

 

import java.lang.String as String

def calculateValue():  
  nM = 0
  uLDNA = 0
  if entity.propertyValue('CONCENTRATION_PREPARED_ILLUMINA') != '' and \
     entity.propertyValue('FRAGMENT_SIZE_PREPARED_ILLUMINA') != '' :
    nM =  float(entity.propertyValue('CONCENTRATION_PREPARED_ILLUMINA')) /  \
           float(entity.propertyValue('FRAGMENT_SIZE_PREPARED_ILLUMINA')) *  \
           1000000 / 650
    if float(entity.propertyValue('UL_STOCK')) !='' :
      uLDNA =  float(entity.propertyValue('UL_STOCK')) * 2 / nM    
      uLEB = float(entity.propertyValue('UL_STOCK')) - uLDNA
      return String.format("%16.1f", uLEB)
  return 0
 
def calculate(): 
    """Main script function. The result will be used as the value of appropriate dynamic property."""
    return calculateValue()

 

3. Calculate a time difference between two time stamps:

 

from datetime import datetime
def dateTimeSplitter(openbisDate):
  dateAndTime, tz = openbisDate.rsplit(" ", 1)
  pythonDateTime = datetime.strptime(dateAndTime, "%Y-%m-%d %H:%M:%S")  
  return pythonDateTime
def calculate():
  
  try:
    start = entity.propertyValue('FLOW_CELL_SEQUENCED_ON')
    end = entity.propertyValue('SEQUENCER_FINISHED')
    s = dateTimeSplitter(start)
    e = dateTimeSplitter(end)
    diffTime = e-s
    return str(diffTime)
  except:
    return "N/A"

 

4. Illumina NGS Low Plexity Pooling Checker: checks if the complexity of a pooled sample is good enough for a successful run:

def checkBarcodes():
  '''
  'parents' are a HashSet of SamplePropertyPE
  ''' 
  VOCABULARY_INDEX1 = 'BARCODE'
  VOCABULARY_INDEX2 = 'INDEX2'
  RED = set(['A','C'])
  GREEN = set(['T', 'G'])
  SUCCESS_MESSAGE="OK"
  NO_INDEX = "No Index"
  
  listofIndices = []
  boolList = []
  positionList = []
  returnString = " "
  for e in entity.entityPE().parents:
    for s in e.properties:
      if s.entityTypePropertyType.propertyType.simpleCode == VOCABULARY_INDEX1:
        index = s.getVocabularyTerm().code
        if len(listofIndices) > 0:
          for n in range(0,len(index)-1):
            listofIndices[n].append(index[n])
        else:
          for n in range(0,len(index)-1):
            listofIndices.append([index[n]])
       
      # remove any duplicates   
      setofIndices=[set(list) for list in listofIndices]    
 
      # Test whether every element in the set 's' is in the RED set
      boolList=[setofNuc.issubset(RED) for setofNuc in setofIndices]
  if boolList:
    for b in boolList:
      if b:
        positionList.append(boolList.index(b)+1)
        # set the value to False, because 'index' returns only the first occurrence
        boolList[boolList.index(b)]=False
  else:
   return NO_INDEX
    #  if s.entityTypePropertyType.propertyType.simpleCode == VOCABULARY_INDEX2:
    #   pass 
  if positionList:
    for pos in positionList:
      returnString += "WARNING! Base position " + str(pos) + " of " + \
                         VOCABULARY_INDEX1 + \
                         " does not contain both color channels" + \
                         "\n" 
  else:
    returnString = SUCCESS_MESSAGE
  return returnString
def calculate(): 
    """Main script function. The result will be used as the value of appropriate dynamic property."""
    return checkBarcodes() 

 

 

Data Types

Any data type that can be used by openBIS properties is supported by dynamic properties. The script always returns just a string representation of a property value. The value is then validated and in special cases converted before being saved. The string formats and validation rules are the same as in batch import/update of samples/experiments/data sets/materials.

The non-trivial cases are properties with data type:

  • CONTROLLED VOCABULARY - use code of vocabulary term as string representation,
  • MATERIAL - use function material(code, typeCode) to create the string representation.

Creating and Deploying Java Plugins

To create valid Java plugin for Dynamic Properties, one should create a class that is implementing ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.calculator.api.IDynamicPropertyCalculatorHotDeployPlugin interface. The class should be annotated with  ch.ethz.cisd.hotdeploy.PluginInfo annotation specifying the name of the plugin, and ch.systemsx.cisd.openbis.generic.server.dataaccess.dynamic_property.calculator.api.IDynamicPropertyCalculatorHotDeployPlugin class as a plugin type.

Such a plugin should be exported to a jar file and put into <<openBIS installation directory>>/servers/entity-related-plugins/dynamic-properties directory. The plugin will be detected automatically and will be automatically available to openBIS. No restart is needed.

Dynamic properties evaluator

Evaluation of dynamic properties may be very time consuming, therefore it is not done automatically after each metadata update. To make sure that the potential inconsistencies are repaired, the maintenance task can be defined (service.properties), that runs in specified intervals:

maintenance-plugins = dynamic-property-evaluator

dynamic-property-evaluator.class = ch.systemsx.cisd.openbis.generic.server.task.DynamicPropertyEvaluationMaintenanceTask
# run daily at midnight  
dynamic-property-evaluator.interval = 86400
dynamic-property-evaluator.start = 00:00

If the value of a dynamic property has not yet been calculated, it will be shown as (pending evaluation).

  • No labels