Warning

This page is a work in progress that is mostly incomplete!

Entering Data

First, we create the nodes themselves. Second, we create a Sample and attribute the nodes to it. Finally, we add the Sample to our database using the SampleView.

Creating Nodes

The construction of each node type follows mostly the same process. There are a few required properties for each node.

Common Properties

The properties common to all nodes are:

  • name (string, required): the name of the node. This does not need to be unique. In some cases it may even be desirable to have multiple nodes with the same name (ie all Action nodes that describe procurement of reagents could be named “Procurement”)

  • tags (list[string], optional): strings by which to tag the node. This could be useful for searching for nodes with a particular tag. For example, all nodes that describe procurement of reagents could be tagged “procurement”.

Node-Specific Properties

Some nodes require additional default properties. Below, we show the minimum set of information required to add nodes into the database.

Material Nodes

Material nodes do not require additional properties – a name will suffice, though in practice you will probably want to add more information/metadata to describe your material. This will be covered in the next section.

1from labgraph import Material
2
3material_node = Material(
4    name="Titanium Dioxide" #required argument
5    tags=["reagent"], #optional argument
6)

Action Nodes

In addition to the common properties, Action nodes require the following:
  • an associated Actor that is performing this Action

  • when appropriate, a list of Ingredients that are acted upon by this Action

An Actor is an entity that can perform one or more Actions. An Actor could be an instrument within your lab, a person, or a set of tools that are always used together. In the example below, the “grinding” Action is performed using the “mortar and pestle” Actor. Once added to the database, the Actor can and should be reused in other Actions. This is particularly useful when a single Action can be performed by multiple Actors. For example, the “grinding” Action could also be performed using a “ball mill” Actor, or a “heating” action could be performed by one of four “furnace_a”, “furnace_b”…”furnace_d” Actors within the lab.

Most Actions will take some Material(s) as an input, like a “dissolve” action will have incoming edges from solute and solvent Material nodes to generate a “solution” Material node. In this situation, one needs to track not only which Materials are inputs to the Action, but _how much_ of each Material is used and, optionally, the role of the Material in the Action. This is achieved by the Ingredient class, which is a wrapper around a Material node that provides additional information (quantity, the unit of said quantity, and an option “name” field that can be used to describe the role of the Material in the Action). In the example below, the “grinding” Action takes one Material as an input, and the Ingredient class is used to specify that the Material is used in a quantity of 1 gram.

 1from labgraph import Action, Ingredient, Actor
 2from labgraph.views import ActorView
 3
 4actor_view = ActorView()
 5mortar_and_pestle = Actor(
 6    name="Mortar and Pestle" #required argument
 7    description="A mortar and pestle is a device used since ancient times to prepare ingredients or substances by crushing and grinding them into a fine paste or powder." #optional argument
 8    tags = ["hand tools", "morphology"]
 9)
10actor_view.add(mortar_and_pestle)
11
12action_node = Action(
13    name="Grinding" #required argument
14    ingredients = [
15        Ingredient(
16            material = material_node, #required argument
17            quantity = 1, #required argument
18            unit = "g" #required argument
19        )
20    ],
21    actor = mortar_and_pestle
22)

Measurement Nodes

 1from labgraph import Measurement, Actor
 2from labgraph.views import ActorView
 3
 4actor_view = ActorView()
 5xrd_instrument = Actor(
 6    name="Bruker D8 Advance" #required argument
 7    description="The Bruker D8 Advance is a high-resolution X-ray diffractometer that can be used to determine the crystal structure of a material." #optional argument
 8    tags = ["XRD", "crystal structure"]
 9)
10actor_view.add(xrd_instrument)
11
12measurement_node = Measurement(
13    name="XRD" #required argument
14    material=material_node, #required argument
15    actor=xrd_instrument #required argument
16)

Analysis Nodes

 1from labgraph import Analysis, Actor
 2from labgraph.views import AnalysisMethodView
 3
 4analysismethod_view = AnalysisMethodView()
 5phase_identification_method = AnalysisMethod(
 6    name="Phase Identification", #required argument
 7    description="Phase identification is the process of determining the phases present in a material.", #optional argument
 8    tags = ["XRD", "crystal structure"],
 9    version = "1.0.0",
10    github_link = "https://github.com/myrepo/phase_identification"
11)
12analysismethod_view.add(phase_identification_method)
13
14phase_identification_method = analysismethod_view.get("Phase Identification") #in case method was already in your database
15
16analysis_node = Analysis(
17    name="XRD" #required argument
18    material=material_node, #required argument
19    analysis_method=phase_identification_method #required argument
20)

Adding your data to nodes

All the examples above show the minimum information required to create a node. However, you probably want to add your own metadata to these nodes too! This is really easy – just pass them as keyword arguments to the node constructor. For example, if you wanted to add a description to your material node, you could do:

1material_node = Material(
2    name="Titanium Dioxide" #required argument
3    tags=["reagent"], #optional argument
4    description="Titanium dioxide is a white solid that is insoluble in water. It is commonly used as a pigment in paints, inks, plastics, paper, sunscreen, food coloring, and cosmetics." #your own extra field!
5)

Other common examples include adding process parameters to an Action node:

 1action_node = Action(
 2    name="Annealing" #required argument
 3    ingredients = [
 4        Ingredient(
 5            material = material_node, #required argument
 6            quantity = 1, #required argument
 7            unit = "g" #required argument
 8        )
 9    ],
10    actor = furnace,
11    temperature_celsius = 1500, #your own extra field!
12    duration_minutes = 240 #your own extra field!
13)

and, of course, adding raw data to a Measurement node:

1measurement_node = Measurement(
2    name="XRD" #required argument
3    material=material_node, #required argument
4    actor=xrd_instrument #required argument
5    data = {
6        "2theta": [10, 20, 30, 40, 50],
7        "intensity": [0, 17.5, 12.1, 1.3, 0]
8    } #your own extra field!
9)

Note

Whatever data you put in your nodes will eventually be encoded as BSON to be stored in MongoDB. This means that you can’t use any data types that BSON doesn’t support. For example, you can’t use a numpy array as a value in your data dictionary. You can, however, use a list. If you want to use a numpy array, you should convert it to a list first.