Contents

Create a repeated treatment design with ISA descriptor

This example creates ISA study descriptor for study with sequential treatments organized in an arm. This shows how to use objects from the isatools.create component in a granular fashion. It creates each Element of the Study Arm at a time.

Finally, the study design plan is shown by serializing the ISA Study Design Model content as an ISA_design JSON document, which can be rendered in various ways (tables, figures).

Let’s load the tools

# If executing the notebooks on `Google Colab`,uncomment the following command 
# and run it to install the required python libraries. Also, make the test datasets available.

# !pip install -r requirements.txt
import datetime
from collections import OrderedDict
from isatools.model import (
    Investigation,
    Study,
    OntologyAnnotation,
    Sample,
    Characteristic,
    ProtocolParameter,
    ParameterValue,
    StudyFactor,
    FactorValue
)

from bokeh.io import output_file, show
from bokeh.plotting import figure
from bokeh.models import ColumnDataSource, Range1d, BoxAnnotation, Label, Legend, LegendItem, LabelSet
from bokeh.models.tools import HoverTool

import pandas as pd
import datetime as dt

import holoviews as hv
from holoviews import opts, dim
# hv.extension('bokeh')

Start by creating basic ISA Study metadata

investigation = Investigation()
study = Study(filename="s_study_xover.txt")
study.identifier = 'S-Xover-1'
study.title = 'My Simple ISA Study'
study.description = "We could alternataly use the class constructor's parameters to set some default " \
          "values at the time of creation, however we want to demonstrate how to use the " \
          "object's instance variables to set values."
study.submission_date = str(datetime.datetime.today())
study.public_release_date = str(datetime.datetime.today())
# study.sources = [Source(name="source1")]
# study.samples = [Sample(name="sample1")]
# study.protocols = [Protocol(name="sample collection")]
# study.process_sequence = [Process(executes_protocol=study.protocols[-1], inputs=[study.sources[-1]], outputs=[study.samples[-1]])]
investigation.studies = [study]
# investigation
# from isatools.isatab import dumps
# print(dumps(investigation))
import json
from isatools.isajson import ISAJSONEncoder
# print(json.dumps(investigation, cls=ISAJSONEncoder, sort_keys=True, indent=4, separators=(',', ': ')))

Let’s load the new ISA create module

from isatools.create.model import (
    Treatment,
    NonTreatment,
    StudyCell,
    StudyArm,
    ProductNode,
    ProtocolNode,
    AssayGraph,
    SampleAndAssayPlan,
    StudyDesign
)
from isatools.create.constants import (
    RUN_IN,
    WASHOUT,
    FOLLOW_UP,
    SAMPLE,
    EXTRACT,
    DATA_FILE
)

1. Creation of the first ISA Study Design Element and setting its type

nte1 = NonTreatment(element_type='screen', duration_unit=OntologyAnnotation(term="days"))
print(nte1)
NonTreatment(
            type='screen',
            duration=isatools.model.FactorValue(factor_name=isatools.model.StudyFactor(name='DURATION', factor_type=isatools.model.OntologyAnnotation(term='time', term_source=None, term_accession='', comments=[]), comments=[]), value=0.0, unit=isatools.model.OntologyAnnotation(term='days', term_source=None, term_accession='', comments=[]))
        )

2. Creation of another ISA Study Design Element, of type Treatment

te1 = Treatment()
te1.type='biological intervention'
print(te1)
"Treatment
        (type=biological intervention, 
        factor_values=[])
        

2.1 defining the first treatment as a vector of ISA factor values:

Under “ISA Study Design Create mode”, a Study Design Element of type Treatment needs to be defined by a vector of Factors and their respective associated Factor Values. This is done as follows:

f1 = StudyFactor(name='virus', factor_type=OntologyAnnotation(term="organism"))
f1v = FactorValue(factor_name=f1, value="hsv1")
f2 = StudyFactor(name='dose', factor_type=OntologyAnnotation(term="quantity"))
f2v = FactorValue(factor_name=f2, value='high dose')
f3 = StudyFactor(name='time post infection', factor_type=OntologyAnnotation(term="time"))
f3v = FactorValue(factor_name=f3, value=2, unit=OntologyAnnotation(term='hr'))
#assigning the factor values declared above to the ISA treatment element
te1.factor_values = [f1v,f2v,f3v]
print(te1)
"Treatment
        (type=biological intervention, 
        factor_values=[isatools.model.FactorValue(factor_name=isatools.model.StudyFactor(name='dose', factor_type=isatools.model.OntologyAnnotation(term='quantity', term_source=None, term_accession='', comments=[]), comments=[]), value='high dose', unit=None), isatools.model.FactorValue(factor_name=isatools.model.StudyFactor(name='time post infection', factor_type=isatools.model.OntologyAnnotation(term='time', term_source=None, term_accession='', comments=[]), comments=[]), value=2, unit=isatools.model.OntologyAnnotation(term='hr', term_source=None, term_accession='', comments=[])), isatools.model.FactorValue(factor_name=isatools.model.StudyFactor(name='virus', factor_type=isatools.model.OntologyAnnotation(term='organism', term_source=None, term_accession='', comments=[]), comments=[]), value='hsv1', unit=None)])
        

3. Creation of a second ISA Study Design Element, of type Treatment, following the same pattern.

te2 = Treatment()
te2.type = 'chemical intervention'
antivir = StudyFactor(name='antiviral', factor_type=OntologyAnnotation(term="chemical entity"))
antivirv = FactorValue(factor_name=antivir, value='hsvflumab')
intensity = StudyFactor(name='dose', factor_type=OntologyAnnotation(term="quantity"))
intensityv= FactorValue(factor_name=intensity, value = 10, unit=OntologyAnnotation(term='mg/kg/day'))
duration =  StudyFactor(name = 'treatment duration', factor_type=OntologyAnnotation(term="time"))
durationv = FactorValue(factor_name=duration, value=2, unit=OntologyAnnotation(term='weeks'))
te2.factor_values = [antivirv,intensityv,durationv]
print(te2)
                        
                        
"Treatment
        (type=chemical intervention, 
        factor_values=[isatools.model.FactorValue(factor_name=isatools.model.StudyFactor(name='antiviral', factor_type=isatools.model.OntologyAnnotation(term='chemical entity', term_source=None, term_accession='', comments=[]), comments=[]), value='hsvflumab', unit=None), isatools.model.FactorValue(factor_name=isatools.model.StudyFactor(name='dose', factor_type=isatools.model.OntologyAnnotation(term='quantity', term_source=None, term_accession='', comments=[]), comments=[]), value=10, unit=isatools.model.OntologyAnnotation(term='mg/kg/day', term_source=None, term_accession='', comments=[])), isatools.model.FactorValue(factor_name=isatools.model.StudyFactor(name='treatment duration', factor_type=isatools.model.OntologyAnnotation(term='time', term_source=None, term_accession='', comments=[]), comments=[]), value=2, unit=isatools.model.OntologyAnnotation(term='weeks', term_source=None, term_accession='', comments=[]))])
        
te3 = Treatment()
te3.type = 'radiological intervention'
rays = StudyFactor(name='radiation', factor_type=OntologyAnnotation(term="physical entity"))
raysv = FactorValue(factor_name=rays, value='neutron beam')
rays_intensity = StudyFactor(name='dose', factor_type=OntologyAnnotation(term="quantity"))
rays_intensityv= FactorValue(factor_name=rays_intensity, value = '10', unit=OntologyAnnotation(term='mSev'))
rays_duration =  StudyFactor(name = 'treatment duration', factor_type=OntologyAnnotation(term="time"))
rays_durationv = FactorValue(factor_name=rays_duration, value='30', unit=OntologyAnnotation(term='minutes'))
te3.factor_values = [raysv,rays_intensityv,rays_durationv]
print(te3)
                
"Treatment
        (type=radiological intervention, 
        factor_values=[isatools.model.FactorValue(factor_name=isatools.model.StudyFactor(name='dose', factor_type=isatools.model.OntologyAnnotation(term='quantity', term_source=None, term_accession='', comments=[]), comments=[]), value='10', unit=isatools.model.OntologyAnnotation(term='mSev', term_source=None, term_accession='', comments=[])), isatools.model.FactorValue(factor_name=isatools.model.StudyFactor(name='radiation', factor_type=isatools.model.OntologyAnnotation(term='physical entity', term_source=None, term_accession='', comments=[]), comments=[]), value='neutron beam', unit=None), isatools.model.FactorValue(factor_name=isatools.model.StudyFactor(name='treatment duration', factor_type=isatools.model.OntologyAnnotation(term='time', term_source=None, term_accession='', comments=[]), comments=[]), value='30', unit=isatools.model.OntologyAnnotation(term='minutes', term_source=None, term_accession='', comments=[]))])
        

4. Creation of ‘wash out’ period as an ISA Study Design Element.

# Creation of another ISA element, which is not a Treatment element, which is of type `screen` by default
nte2 = NonTreatment(duration_unit=OntologyAnnotation(term="days"))
print(nte2.type)
screen
# let's change it by setting its type by relying on the keys defined for the object
nte2.type=RUN_IN
print(nte2.type)
run-in
#let's change it again by direct use of the allowed strings (note: the string should match exactly the predefined values)
nte2.type = WASHOUT
print(nte2.type)
washout
# setting the factor values associated with 'default' DURATION Factor associated with such elements
nte2.duration.value=2
nte2.duration.unit=OntologyAnnotation(term="weeks")

5. Creation of ‘follow-up’ period as an ISA Study Design Element.

nte3 = NonTreatment(element_type=FOLLOW_UP, duration_value=4, duration_unit=OntologyAnnotation(term="month"))
# nte3.duration.value = 2
# nte3.duration.unit = 'months'
print(nte3)
NonTreatment(
            type='follow-up',
            duration=isatools.model.FactorValue(factor_name=isatools.model.StudyFactor(name='DURATION', factor_type=isatools.model.OntologyAnnotation(term='time', term_source=None, term_accession='', comments=[]), comments=[]), value=4, unit=isatools.model.OntologyAnnotation(term='month', term_source=None, term_accession='', comments=[]))
        )

6. Creation of the associated container, known as an ISA Cell for each ISA Element.

In this example, a single Element is hosted by a Cell, which must be named. In more complex designs (e.g. study designs with assymetric arms), a Cell may contain more than one Element, hence the list attribute.

st_cl1= StudyCell(name="st_cl1", elements=[nte1])
st_cl2= StudyCell(name="st_cl2", elements=[te1])
st_cl3= StudyCell(name="st_cl3", elements=[nte2])
st_cl4= StudyCell(name="st_cl4", elements=[te2])
st_cl6= StudyCell(name="st_cl6", elements=[nte2])
st_cl7= StudyCell(name="st_cl7", elements=[te3])
st_cl5= StudyCell(name="st_cl5", elements=[nte3])

7. Creation of an ISA Study Arm and setting the number of subjects associated to that unique sequence of ISA Cells.

arm1 = StudyArm(name='Arm 1', group_size=5, )
print(arm1)

genotype_cat = OntologyAnnotation(term="genotype")
genotype_value1 = OntologyAnnotation(term="control - normal")
genotype_value2 = OntologyAnnotation(term="mutant")

arm1 = StudyArm(
    name='Arm 1', 
    group_size=2, 
    source_type=Characteristic(
        category=genotype_cat,
        value=genotype_value1
    )
)
print(arm1)
"StudyArm(
               name=Arm 1,
               source_type=Characteristic(
    category=Study Subject
    value=Human
    unit=
    comments=0 Comment objects
),
               group_size=5, 
               no. cells=0,
               no. sample_assay_plans=0
               )
"StudyArm(
               name=Arm 1,
               source_type=Characteristic(
    category=genotype
    value=control - normal
    unit=
    comments=0 Comment objects
),
               group_size=2, 
               no. cells=0,
               no. sample_assay_plans=0
               )

8. Declaring an ISA Sample Assay Plan, defining which Sample are to be collected and which Assays to be used

input_material1=ProductNode(id_="MAT1", name="liver", node_type=SAMPLE,size=1,characteristics=[Characteristic(category=OntologyAnnotation(term='organism part'), value=OntologyAnnotation(term='liver'))])
input_material2=ProductNode(id_="MAT2", name="blood", node_type=SAMPLE,size=1,characteristics=[Characteristic(category=OntologyAnnotation(term='organism part'), value=OntologyAnnotation(term='blood'))])
input_material3=ProductNode(id_="MAT3", name="urine", node_type=SAMPLE,size=3,characteristics=[Characteristic(category=OntologyAnnotation(term='organism part'), value=OntologyAnnotation(term='urine'))])

9. Loading an isa assay definition in the form of an ordered dictionary.

  • It corresponds to an ISA configuration assay table but expressed in JSON.

  • In this NMR assay there is a sample extraction step, which produces “supernatant” and “pellet” extracts (1 of each per input sample).

  • IMPORTANT: Note how ISA OntologyAnnotation elements are used in this data structure

nmr_assay_dict = OrderedDict([
    ('measurement_type', OntologyAnnotation(term='metabolite profiling')),
    ('technology_type', OntologyAnnotation(term='nmr spectroscopy')),
            ('extraction', {}),
            ('extract', [
                {
                    'node_type': EXTRACT,
                    'characteristics_category': OntologyAnnotation(term='extract type'),
                    'characteristics_value': 'supernatant',
                    'size': 1,
                    'technical_replicates': None,
                    'is_input_to_next_protocols': True
                },
                {
                    'node_type': EXTRACT,
                    'characteristics_category': OntologyAnnotation(term='extract type'),
                    'characteristics_value': 'pellet',
                    'size': 1,
                    'technical_replicates': None,
                    'is_input_to_next_protocols': True
                }
            ]),
            ('nmr_spectroscopy', {
                OntologyAnnotation(term='instrument'): ['Bruker AvanceII 1 GHz'],
                OntologyAnnotation(term='acquisition_mode'): ['1D 13C NMR','1D 1H NMR','2D 13C-13C NMR'],
                OntologyAnnotation(term='pulse_sequence'): ['CPMG','TOCSY','HOESY','watergate']
            }),
            ('raw_spectral_data_file', [
                {
                    'node_type': DATA_FILE,
                    'size': 1,
                    'technical_replicates': 2,
                    'is_input_to_next_protocols': False
                }
            ])
        ])

10. We now show how to create an new AssayGraph structure from scratch, as if we were defining a completely new assay type.

new_assay_graph1=AssayGraph(
    id_="WB",
    measurement_type=OntologyAnnotation(term="protein profiling"),
    technology_type=OntologyAnnotation(term="Western blot")
)

11. We procede by assembling the Process graph:

protocol_node_protein = ProtocolNode(id_="P",name='Protein extraction')
protocol_node_data_acq = ProtocolNode(
    id_="DA",
    name='WB imaging',
    parameter_values=[
        ParameterValue(
            category=ProtocolParameter(parameter_name=OntologyAnnotation(term="channel")),
            value=OntologyAnnotation(term="360 nm")
        ),
        ParameterValue(
            category=ProtocolParameter(parameter_name=OntologyAnnotation(term='channel')),
            value=OntologyAnnotation(term="550 nm")
        )
    ]
)

protein_char = Characteristic(category=OntologyAnnotation(term='material type'), value='protein extract')
protein_sample_node = ProductNode(id_="SP", node_type=EXTRACT, size=1, characteristics=[protein_char])
wb_data_node = ProductNode(id_="WBD", node_type=DATA_FILE, size=1)


nodes = [protein_sample_node, wb_data_node, protocol_node_protein, protocol_node_data_acq]
links = [
    (protocol_node_protein, protein_sample_node),
    (protein_sample_node, protocol_node_data_acq),
    (protocol_node_data_acq, wb_data_node)
]

new_assay_graph1.add_nodes(nodes)
new_assay_graph1.add_links(links)

The following step does 3 things:

  • generate an assay plan from the assay declaration data strucure

  • create a Sample and Assay Plan object holding a list of samples and the list of assay workflows which have been declared

  • create a Sample to Assay object, which details which sample will be input to a specific assay.

nmr_assay_graph = AssayGraph.generate_assay_plan_from_dict(nmr_assay_dict)

sap1 = SampleAndAssayPlan(
    name='sap1',
    sample_plan=[input_material1,input_material2,input_material3],
    assay_plan=[new_assay_graph1,nmr_assay_graph]
)

sample2assay_plan = {
    input_material3: [new_assay_graph1, nmr_assay_graph],
    input_material2: [nmr_assay_graph],
    input_material1: [nmr_assay_graph]
}

sap1.sample_to_assay_map = sample2assay_plan
# specifying which sample type (sometimes referred to as specimen)
# sap1.add_sample_type('liver')
# specifying how many times each specimen is supposed to be collected
# sap1.add_sample_plan_record('liver',3)
#### 9. Declaration of an ISA assay and linking specimen type and data acquisition plan for this assay
# # declare the type of `Assay` which will be performed
# assay_type1 = Assay(measurement_type='metabolite profiling', technology_type='mass spectrometry')
# # associate this assay type to the `SampleAssayPlan`
# sap1.add_assay_type(assay_type1)
# # specify which `sample type` will be used as input to the declare `Assay`
# sap1.add_assay_plan_record('liver',assay_type1)

11. Build an ISA Study Design Arm by adding the first set of ISA Cells and setting the Sample Assay Plan

arm1.add_item_to_arm_map(st_cl1,sap1)
print(arm1.name, arm1.source_type)
Arm 1 Characteristic(
    category=genotype
    value=control - normal
    unit=
    comments=0 Comment objects
)

12 Now expanding the Arm by adding a new Cell, which uses the same Sample Assay Plan as the one used in Cell #1.

Of course, the Sample Assay Plan for this new Cell could be different. It would have to be to built as shown before.

arm1.add_item_to_arm_map(st_cl2,sap1)
# Adding the last section of the Arm, with a cell which also uses the same sample assay plan.
arm1.add_item_to_arm_map(st_cl3,sap1)
arm1.add_item_to_arm_map(st_cl4,sap1)
arm1.add_item_to_arm_map(st_cl6,sap1)
arm1.add_item_to_arm_map(st_cl7,sap1)
arm1.add_item_to_arm_map(st_cl5,sap1)

13. Creation of additional ISA Study Arms and setting the number of subjects associated to that unique sequence of ISA Cells.

arm2 = StudyArm(
    name='Arm 2',
    source_type=Characteristic(
        category=genotype_cat,
        value=genotype_value1
    )
)
arm2.group_size=5
arm2.add_item_to_arm_map(st_cl1,sap1)
arm2.add_item_to_arm_map(st_cl4,sap1)
arm2.add_item_to_arm_map(st_cl3,sap1)
arm2.add_item_to_arm_map(st_cl2,sap1)
arm2.add_item_to_arm_map(st_cl6,sap1)
arm2.add_item_to_arm_map(st_cl7,sap1)
arm2.add_item_to_arm_map(st_cl5,sap1)
arm3 = StudyArm(
    name='Arm 3',
    source_type=Characteristic(
        category=genotype_cat,
        value=genotype_value1
    )
)
arm3.group_size=5
arm3.add_item_to_arm_map(st_cl1,sap1)
arm3.add_item_to_arm_map(st_cl7,sap1)
arm3.add_item_to_arm_map(st_cl3,sap1)
arm3.add_item_to_arm_map(st_cl4,sap1)
arm3.add_item_to_arm_map(st_cl6,sap1)
arm3.add_item_to_arm_map(st_cl2,sap1)
arm3.add_item_to_arm_map(st_cl5,sap1)

14. We can now create the ISA Study Design object, which will receive the Arms defined by the user.

study_design= StudyDesign(name='trial design #1')
# print(sd)
# Adding a study arm to the study design object.
study_design.add_study_arm(arm1)
study_design.add_study_arm(arm2)
study_design.add_study_arm(arm3)
# print(sd)
# Let's now serialize the ISA study design to JSON
import json
from isatools.isajson import ISAJSONEncoder
from isatools.create.model import StudyDesignEncoder

f=json.dumps(study_design, cls=StudyDesignEncoder, sort_keys=True, indent=4, separators=(',', ': '))

15. let’s produce a graphical overview of the study design arms and the associated sample assay plans

def get_treatment_factors(some_element):
    treat = ""
    for j in range(len(some_element['factorValues'])):
        if j < len(some_element['factorValues']) - 1:
            if 'unit' in some_element['factorValues'][j].keys():
                treat = treat + some_element['factorValues'][j]['factor']['name'].lower() + ": " \
                        + str(some_element['factorValues'][j]['value']) + " " \
                        + str(some_element['factorValues'][j]['unit']['term'].lower()) + ", "
            else:
                treat = treat + some_element['factorValues'][j]['factor']['name'].lower() + ": " \
                        + str(some_element['factorValues'][j]['value']) + ","
        else:
            if 'unit' in some_element['factorValues'][j].keys():
                treat = treat + some_element['factorValues'][j]['factor']['name'].lower() + ": " \
                        + str(some_element['factorValues'][j]['value']) + " " \
                        + str(some_element['factorValues'][j]['unit']['term'].lower())
            else:
                treat = treat + some_element['factorValues'][j]['factor']['name'].lower() + ": " \
                        + str(some_element['factorValues'][j]['value'])

    return treat
design = json.loads(json.dumps(study_design, cls=StudyDesignEncoder, sort_keys=True, indent=4, separators=(',', ': ')))
frames = []
Items = []

# defining a color pallet for the different element types:
element_colors = {"biological intervention": "rgb(253,232,37)",
                  "radiological intervention": "rgb(53, 155, 8)",
                  "dietary intervention": "rgb(53, 155, 8)",
                  "chemical intervention": "rgb(69, 13, 83)",
                  "washout": "rgb(45, 62, 120)",
                  "screen": "rgb(33, 144, 140)",
                  "run in": "rgb(43, 144, 180)",
                  "follow-up": "rgb(88, 189, 94)",
                  "concomitant treatment": "rgb(255, 255, 0)"}

# processing the study design arms and treatment plans:
for key in design["studyArms"].keys():
    DF = pd.DataFrame(columns=['Arm', 'Cell', 'Type', 'Start_date', 'End_date', 'Treatment', 'Color'])
    arm_name = key
    # print("arm: ", arm_name)
    size = design["studyArms"][key]["groupSize"]
    size_annotation = "n=" + str(size)

    cells_per_arm = design["studyArms"][key]["cells"]
    cell_counter = 0
    for cell in cells_per_arm:
        cell_name = cell['name']
        elements_per_cell = cell['elements']

        for element in elements_per_cell:
            treat = ""
            element_counter = 0                      
            if 'concomitantTreatments' in element.keys():
                element_counter = element_counter + 1
                treatments = []
                for item in element['concomitantTreatments']:
                    treatment = get_treatment_factors(item)
                    treatments.append(treatment)
                    
                concomitant = ','.join(treatments[0:-1])
                concomitant = concomitant + ' and ' + treatments[-1]
                array = [arm_name, cell_name, arm_name + ": [" + concomitant + "]_concomitant_" + str(cell_counter),
                     dt.datetime(cell_counter + 2000, 1, 1), dt.datetime(cell_counter + 2000 + 1, 1, 1),
                     str(element['factorValues']),
                     concomitant,
                     element_colors["concomitant treatment"]]
                Items.append(array)

            elif 'type' in element.keys():
                treatment = get_treatment_factors(element)
                element_counter = element_counter + 1
                array = [arm_name, cell_name, arm_name + ": [" + str(element['type']) + "]_" + str(cell_counter),
                         dt.datetime((cell_counter + 2000), 1, 1), dt.datetime((cell_counter + 2000 + 1), 1, 1),
                         # str(element['factorValues']),
                         str(treatment),
                         element_colors[element['type']]]
                Items.append(array)

            cell_counter = cell_counter + 1

for i, Dat in enumerate(Items):
    DF.loc[i] = Dat
#     print("setting:", DF.loc[i])

# providing the canvas for the figure
# print("THESE ARE THE TYPES_: ", DF.Type.tolist())
fig = figure(title='Study Design Treatment Plan',
             width=800,
             height=400,
             y_range=DF.Type.tolist(),
             x_range=Range1d(DF.Start_date.min(), DF.End_date.max()),
             tools='save')

# adding a tool tip
hover = HoverTool(tooltips="Task: @Type<br>\
Start: @Start_date<br>\
Cell_Name: @Cell<br>\
Treatment: @Treatment")
fig.add_tools(hover)

DF['ID'] = DF.index+0.8
# print("ID: ", DF['ID'])
DF['ID1'] = DF.index+1.2
# print("ID1: ", DF['ID1'])
CDS = ColumnDataSource(DF)
# , legend=str(size_annotation)
r = fig.quad(left='Start_date', right='End_date', bottom='ID', top='ID1', source=CDS, color="Color")
fig.xaxis.axis_label = 'Time'
fig.yaxis.axis_label = 'study arms'

# working at providing a background color change for every arm in the study design
counts = DF['Arm'].value_counts().tolist()
# print("total number of study arms:", len(counts), "| number of phases per arm:", counts)
# box = []
# for i, this_element in enumerate(DF['Arm']):
#     if i==0:
#         box[i] = BoxAnnotation(bottom=0,
#                              top=DF['Arm'].value_counts().tolist()[0],
#                              fill_color="blue")
#     elif i % 2 == 0:
#         box[i] = BoxAnnotation(bottom=DF['Arm'].value_counts().tolist()[0],
#                              top=DF['Arm'].value_counts().tolist()[0],
#                              fill_color="silver")
#     else:
#         box[i] = BoxAnnotation(bottom=DF['Arm'].value_counts().tolist()[0],
#                              top=DF['Arm'].value_counts().tolist()[0] + DF['Arm'].value_counts().tolist()[1],
#                              fill_color="grey",
#                              fill_alpha=0.1)
# # adding the background color for each arm:
# for element in box:
#     fig.add_layout(element)
# # fig.add_layout(box2)
# # fig.add_layout(legend,'right')

caption1 = Legend(items=[(str(size_annotation), [r])])
fig.add_layout(caption1, 'right')

citation = Label(x=10, y=-80, x_units='screen', y_units='screen',
                 text='repeated measure group design layout - isa-api 0.12', render_mode='css',
                 border_line_color='gray', border_line_alpha=0.4,
                 background_fill_color='white', background_fill_alpha=1.0)

fig.add_layout(citation)

show(fig)
# This statement will take some time to execute. Be patients
study = study_design.generate_isa_study()
len(study.assays)
2
investigation.studies=[study]
# print(investigation.studies[0].assays[1])
print(investigation.studies[0].assays[0])
Assay(
    measurement_type=protein profiling
    technology_type=Western blot
    technology_platform=
    filename=a_WB_protein-profiling_Western-blot.txt
    data_files=252 DataFile objects
    samples=0 Sample objects
    process_sequence=504 Process objects
    other_material=252 Material objects
    characteristic_categories=0 OntologyAnnots
    comments=0 Comment objects
    units=0 Unit objects
)
# WRITING ISA-JSON document to string
isa_json = json.dumps(investigation, cls=ISAJSONEncoder, sort_keys=True, indent=4, separators=(',', ': '))
# from isatools.isatab import dump_tables_to_dataframes as dumpdf
# dataframes = dumpdf(investigation)
# dataframes.keys()
2021-07-21 18:16:26,476 [INFO]: isatab.py(_all_end_to_end_paths:1131) >> [0, 1, 2]
2021-07-21 18:16:26,735 [WARNING]: isatab.py(write_study_table_files:1195) >> [4, 3, 0, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 16, 15, 18, 17, 20, 19, 22, 21, 24, 23, 26, 25, 28, 27, 30, 29, 32, 31, 34, 33, 36, 35, 38, 37, 40, 39, 42, 41, 44, 43, 46, 45, 48, 47, 50, 49, 52, 51, 54, 53, 56, 55, 58, 57, 60, 59, 62, 61, 64, 63, 66, 65, 68, 67, 70, 69, 72, 71, 74, 73, 76, 75, 78, 77, 80, 79, 82, 81, 84, 83, 86, 85, 88, 87, 90, 89, 92, 91, 94, 93, 96, 95, 98, 97, 100, 99, 102, 101, 104, 103, 106, 105, 108, 107, 110, 109, 112, 111, 114, 113, 116, 115, 118, 117, 120, 119, 122, 121, 124, 123, 126, 125, 128, 127, 130, 129, 132, 131, 134, 133, 136, 135, 138, 137, 140, 139, 142, 141, 144, 143, 1, 146, 145, 148, 147, 150, 149, 152, 151, 154, 153, 156, 155, 158, 157, 160, 159, 162, 161, 164, 163, 166, 165, 168, 167, 170, 169, 172, 171, 174, 173, 176, 175, 178, 177, 180, 179, 182, 181, 184, 183, 186, 185, 188, 187, 190, 189, 192, 191, 194, 193, 196, 195, 198, 197, 200, 199, 202, 201, 204, 203, 206, 205, 208, 207, 210, 209, 212, 211, 214, 213, 216, 215, 218, 217, 220, 219, 222, 221, 224, 223, 226, 225, 228, 227, 230, 229, 232, 231, 234, 233, 236, 235, 238, 237, 240, 239, 242, 241, 244, 243, 246, 245, 248, 247, 250, 249, 252, 251, 254, 253, 256, 255, 258, 257, 260, 259, 262, 261, 264, 263, 266, 265, 268, 267, 270, 269, 272, 271, 274, 273, 276, 275, 278, 277, 280, 279, 282, 281, 284, 283, 286, 285, 288, 287, 290, 289, 292, 291, 294, 293, 296, 295, 298, 297, 300, 299, 302, 301, 304, 303, 306, 305, 308, 307, 310, 309, 312, 311, 314, 313, 316, 315, 318, 317, 320, 319, 322, 321, 324, 323, 326, 325, 328, 327, 330, 329, 332, 331, 334, 333, 336, 335, 338, 337, 340, 339, 342, 341, 344, 343, 346, 345, 348, 347, 350, 349, 352, 351, 354, 353, 356, 355, 358, 357, 360, 359, 362, 361, 364, 363, 366, 365, 368, 367, 370, 369, 372, 371, 374, 373, 376, 375, 378, 377, 380, 379, 382, 381, 384, 383, 386, 385, 388, 387, 390, 389, 392, 391, 394, 393, 396, 395, 398, 397, 400, 399, 402, 401, 404, 403, 406, 405, 408, 407, 410, 409, 412, 411, 414, 413, 416, 415, 418, 417, 420, 419, 422, 421, 424, 423, 426, 425, 428, 427, 430, 429, 432, 431, 434, 433, 436, 435, 438, 437, 440, 439, 442, 441, 444, 443, 446, 445, 448, 447, 450, 449, 452, 451, 454, 453, 456, 455, 458, 457, 460, 459, 462, 461, 464, 463, 466, 465, 468, 467, 470, 469, 472, 471, 474, 473, 476, 475, 478, 477, 480, 479, 482, 481, 484, 483, 486, 485, 488, 487, 490, 489, 492, 491, 494, 493, 2, 496, 495, 498, 497, 500, 499, 502, 501, 504, 503, 506, 505, 508, 507, 510, 509, 512, 511, 514, 513, 516, 515, 518, 517, 520, 519, 522, 521, 524, 523, 526, 525, 528, 527, 530, 529, 532, 531, 534, 533, 536, 535, 538, 537, 540, 539, 542, 541, 544, 543, 546, 545, 548, 547, 550, 549, 552, 551, 554, 553, 556, 555, 558, 557, 560, 559, 562, 561, 564, 563, 566, 565, 568, 567, 570, 569, 572, 571, 574, 573, 576, 575, 578, 577, 580, 579, 582, 581, 584, 583, 586, 585, 588, 587, 590, 589, 592, 591, 594, 593, 596, 595, 598, 597, 600, 599, 602, 601, 604, 603, 606, 605, 608, 607, 610, 609, 612, 611, 614, 613, 616, 615, 618, 617, 620, 619, 622, 621, 624, 623, 626, 625, 628, 627, 630, 629, 632, 631, 634, 633, 636, 635, 638, 637, 640, 639, 642, 641, 644, 643, 646, 645, 648, 647, 650, 649, 652, 651, 654, 653, 656, 655, 658, 657, 660, 659, 662, 661, 664, 663, 666, 665, 668, 667, 670, 669, 672, 671, 674, 673, 676, 675, 678, 677, 680, 679, 682, 681, 684, 683, 686, 685, 688, 687, 690, 689, 692, 691, 694, 693, 696, 695, 698, 697, 700, 699, 702, 701, 704, 703, 706, 705, 708, 707, 710, 709, 712, 711, 714, 713, 716, 715, 718, 717, 720, 719, 722, 721, 724, 723, 726, 725, 728, 727, 730, 729, 732, 731, 734, 733, 736, 735, 738, 737, 740, 739, 742, 741, 744, 743, 746, 745, 748, 747, 750, 749, 752, 751, 754, 753, 756, 755, 758, 757, 760, 759, 762, 761, 764, 763, 766, 765, 768, 767, 770, 769, 772, 771, 774, 773, 776, 775, 778, 777, 780, 779, 782, 781, 784, 783, 786, 785, 788, 787, 790, 789, 792, 791, 794, 793, 796, 795, 798, 797, 800, 799, 802, 801, 804, 803, 806, 805, 808, 807, 810, 809, 812, 811, 814, 813, 816, 815, 818, 817, 820, 819, 822, 821, 824, 823, 826, 825, 828, 827, 830, 829, 832, 831, 834, 833, 836, 835, 838, 837, 840, 839, 842, 841]
2021-07-21 18:16:26,736 [INFO]: isatab.py(_longest_path_and_attrs:1091) >> [[0, 4, 3], [0, 6, 5], [0, 8, 7], [0, 10, 9], [0, 12, 11], [0, 14, 13], [0, 16, 15], [0, 18, 17], [0, 20, 19], [0, 22, 21], [0, 24, 23], [0, 26, 25], [0, 28, 27], [0, 30, 29], [0, 32, 31], [0, 34, 33], [0, 36, 35], [0, 38, 37], [0, 40, 39], [0, 42, 41], [0, 44, 43], [0, 46, 45], [0, 48, 47], [0, 50, 49], [0, 52, 51], [0, 54, 53], [0, 56, 55], [0, 58, 57], [0, 60, 59], [0, 62, 61], [0, 64, 63], [0, 66, 65], [0, 68, 67], [0, 70, 69], [0, 72, 71], [0, 74, 73], [0, 76, 75], [0, 78, 77], [0, 80, 79], [0, 82, 81], [0, 84, 83], [0, 86, 85], [0, 88, 87], [0, 90, 89], [0, 92, 91], [0, 94, 93], [0, 96, 95], [0, 98, 97], [0, 100, 99], [0, 102, 101], [0, 104, 103], [0, 106, 105], [0, 108, 107], [0, 110, 109], [0, 112, 111], [0, 114, 113], [0, 116, 115], [0, 118, 117], [0, 120, 119], [0, 122, 121], [0, 124, 123], [0, 126, 125], [0, 128, 127], [0, 130, 129], [0, 132, 131], [0, 134, 133], [0, 136, 135], [0, 138, 137], [0, 140, 139], [0, 142, 141], [1, 144, 143], [1, 146, 145], [1, 148, 147], [1, 150, 149], [1, 152, 151], [1, 154, 153], [1, 156, 155], [1, 158, 157], [1, 160, 159], [1, 162, 161], [1, 164, 163], [1, 166, 165], [1, 168, 167], [1, 170, 169], [1, 172, 171], [1, 174, 173], [1, 176, 175], [1, 178, 177], [1, 180, 179], [1, 182, 181], [1, 184, 183], [1, 186, 185], [1, 188, 187], [1, 190, 189], [1, 192, 191], [1, 194, 193], [1, 196, 195], [1, 198, 197], [1, 200, 199], [1, 202, 201], [1, 204, 203], [1, 206, 205], [1, 208, 207], [1, 210, 209], [1, 212, 211], [1, 214, 213], [1, 216, 215], [1, 218, 217], [1, 220, 219], [1, 222, 221], [1, 224, 223], [1, 226, 225], [1, 228, 227], [1, 230, 229], [1, 232, 231], [1, 234, 233], [1, 236, 235], [1, 238, 237], [1, 240, 239], [1, 242, 241], [1, 244, 243], [1, 246, 245], [1, 248, 247], [1, 250, 249], [1, 252, 251], [1, 254, 253], [1, 256, 255], [1, 258, 257], [1, 260, 259], [1, 262, 261], [1, 264, 263], [1, 266, 265], [1, 268, 267], [1, 270, 269], [1, 272, 271], [1, 274, 273], [1, 276, 275], [1, 278, 277], [1, 280, 279], [1, 282, 281], [1, 284, 283], [1, 286, 285], [1, 288, 287], [1, 290, 289], [1, 292, 291], [1, 294, 293], [1, 296, 295], [1, 298, 297], [1, 300, 299], [1, 302, 301], [1, 304, 303], [1, 306, 305], [1, 308, 307], [1, 310, 309], [1, 312, 311], [1, 314, 313], [1, 316, 315], [1, 318, 317], [1, 320, 319], [1, 322, 321], [1, 324, 323], [1, 326, 325], [1, 328, 327], [1, 330, 329], [1, 332, 331], [1, 334, 333], [1, 336, 335], [1, 338, 337], [1, 340, 339], [1, 342, 341], [1, 344, 343], [1, 346, 345], [1, 348, 347], [1, 350, 349], [1, 352, 351], [1, 354, 353], [1, 356, 355], [1, 358, 357], [1, 360, 359], [1, 362, 361], [1, 364, 363], [1, 366, 365], [1, 368, 367], [1, 370, 369], [1, 372, 371], [1, 374, 373], [1, 376, 375], [1, 378, 377], [1, 380, 379], [1, 382, 381], [1, 384, 383], [1, 386, 385], [1, 388, 387], [1, 390, 389], [1, 392, 391], [1, 394, 393], [1, 396, 395], [1, 398, 397], [1, 400, 399], [1, 402, 401], [1, 404, 403], [1, 406, 405], [1, 408, 407], [1, 410, 409], [1, 412, 411], [1, 414, 413], [1, 416, 415], [1, 418, 417], [1, 420, 419], [1, 422, 421], [1, 424, 423], [1, 426, 425], [1, 428, 427], [1, 430, 429], [1, 432, 431], [1, 434, 433], [1, 436, 435], [1, 438, 437], [1, 440, 439], [1, 442, 441], [1, 444, 443], [1, 446, 445], [1, 448, 447], [1, 450, 449], [1, 452, 451], [1, 454, 453], [1, 456, 455], [1, 458, 457], [1, 460, 459], [1, 462, 461], [1, 464, 463], [1, 466, 465], [1, 468, 467], [1, 470, 469], [1, 472, 471], [1, 474, 473], [1, 476, 475], [1, 478, 477], [1, 480, 479], [1, 482, 481], [1, 484, 483], [1, 486, 485], [1, 488, 487], [1, 490, 489], [1, 492, 491], [2, 494, 493], [2, 496, 495], [2, 498, 497], [2, 500, 499], [2, 502, 501], [2, 504, 503], [2, 506, 505], [2, 508, 507], [2, 510, 509], [2, 512, 511], [2, 514, 513], [2, 516, 515], [2, 518, 517], [2, 520, 519], [2, 522, 521], [2, 524, 523], [2, 526, 525], [2, 528, 527], [2, 530, 529], [2, 532, 531], [2, 534, 533], [2, 536, 535], [2, 538, 537], [2, 540, 539], [2, 542, 541], [2, 544, 543], [2, 546, 545], [2, 548, 547], [2, 550, 549], [2, 552, 551], [2, 554, 553], [2, 556, 555], [2, 558, 557], [2, 560, 559], [2, 562, 561], [2, 564, 563], [2, 566, 565], [2, 568, 567], [2, 570, 569], [2, 572, 571], [2, 574, 573], [2, 576, 575], [2, 578, 577], [2, 580, 579], [2, 582, 581], [2, 584, 583], [2, 586, 585], [2, 588, 587], [2, 590, 589], [2, 592, 591], [2, 594, 593], [2, 596, 595], [2, 598, 597], [2, 600, 599], [2, 602, 601], [2, 604, 603], [2, 606, 605], [2, 608, 607], [2, 610, 609], [2, 612, 611], [2, 614, 613], [2, 616, 615], [2, 618, 617], [2, 620, 619], [2, 622, 621], [2, 624, 623], [2, 626, 625], [2, 628, 627], [2, 630, 629], [2, 632, 631], [2, 634, 633], [2, 636, 635], [2, 638, 637], [2, 640, 639], [2, 642, 641], [2, 644, 643], [2, 646, 645], [2, 648, 647], [2, 650, 649], [2, 652, 651], [2, 654, 653], [2, 656, 655], [2, 658, 657], [2, 660, 659], [2, 662, 661], [2, 664, 663], [2, 666, 665], [2, 668, 667], [2, 670, 669], [2, 672, 671], [2, 674, 673], [2, 676, 675], [2, 678, 677], [2, 680, 679], [2, 682, 681], [2, 684, 683], [2, 686, 685], [2, 688, 687], [2, 690, 689], [2, 692, 691], [2, 694, 693], [2, 696, 695], [2, 698, 697], [2, 700, 699], [2, 702, 701], [2, 704, 703], [2, 706, 705], [2, 708, 707], [2, 710, 709], [2, 712, 711], [2, 714, 713], [2, 716, 715], [2, 718, 717], [2, 720, 719], [2, 722, 721], [2, 724, 723], [2, 726, 725], [2, 728, 727], [2, 730, 729], [2, 732, 731], [2, 734, 733], [2, 736, 735], [2, 738, 737], [2, 740, 739], [2, 742, 741], [2, 744, 743], [2, 746, 745], [2, 748, 747], [2, 750, 749], [2, 752, 751], [2, 754, 753], [2, 756, 755], [2, 758, 757], [2, 760, 759], [2, 762, 761], [2, 764, 763], [2, 766, 765], [2, 768, 767], [2, 770, 769], [2, 772, 771], [2, 774, 773], [2, 776, 775], [2, 778, 777], [2, 780, 779], [2, 782, 781], [2, 784, 783], [2, 786, 785], [2, 788, 787], [2, 790, 789], [2, 792, 791], [2, 794, 793], [2, 796, 795], [2, 798, 797], [2, 800, 799], [2, 802, 801], [2, 804, 803], [2, 806, 805], [2, 808, 807], [2, 810, 809], [2, 812, 811], [2, 814, 813], [2, 816, 815], [2, 818, 817], [2, 820, 819], [2, 822, 821], [2, 824, 823], [2, 826, 825], [2, 828, 827], [2, 830, 829], [2, 832, 831], [2, 834, 833], [2, 836, 835], [2, 838, 837], [2, 840, 839], [2, 842, 841]]
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
/var/folders/5n/rl6lqnks4rqb59pbtpvvntqw0000gr/T/ipykernel_18651/1244306393.py in <module>
      1 from isatools.isatab import dump_tables_to_dataframes as dumpdf
----> 2 dataframes = dumpdf(investigation)
      3 dataframes.keys()

~/.pyenv/versions/3.9.0/envs/isa-api-py39/src/isatools/isatools/isatab.py in dump_tables_to_dataframes(isa_obj)
   4578     try:
   4579         tmp = tempfile.mkdtemp()
-> 4580         dump(isa_obj=isa_obj, output_path=tmp, skip_dump_tables=False)
   4581         for s_file in glob.iglob(os.path.join(tmp, 's_*')):
   4582             output[os.path.basename(s_file)] = read_tfile(s_file)

~/.pyenv/versions/3.9.0/envs/isa-api-py39/src/isatools/isatools/isatab.py in dump(isa_obj, output_path, i_file_name, skip_dump_tables, write_factor_values_in_assay_table)
   1047         pass
   1048     else:
-> 1049         write_study_table_files(investigation, output_path)
   1050         write_assay_table_files(
   1051             investigation, output_path, write_factor_values_in_assay_table)

~/.pyenv/versions/3.9.0/envs/isa-api-py39/src/isatools/isatools/isatab.py in write_study_table_files(inv_obj, output_dir)
   1296                         fvlabel = "{0}.Factor Value[{1}]".format(
   1297                             olabel, fv.factor_name.name)
-> 1298                         write_value_columns(df_dict, fvlabel, fv)
   1299         """if isinstance(pbar, ProgressBar):
   1300             pbar.finish()"""

~/.pyenv/versions/3.9.0/envs/isa-api-py39/src/isatools/isatools/isatab.py in write_value_columns(df_dict, label, x)
   1717     if isinstance(x.value, (int, float)) and x.unit:
   1718         if isinstance(x.unit, OntologyAnnotation):
-> 1719             df_dict[label][-1] = x.value
   1720             df_dict[label + ".Unit"][-1] = x.unit.term
   1721             df_dict[label + ".Unit.Term Source REF"][-1] = \

KeyError: 'Sample Name.0.Factor Value[DURATION]'
# Alternatevely, if you want to save the ISA-TAB files to a specific directory, you can run:
from isatools import isatab
# import os
# os.makedirs('/notebook-output/isa-repeated-measure-crossover-design', exist_ok = True)
isatab.dump(investigation, './notebook-output/isa-repeated-measure-crossover-design')
2021-08-09 18:51:57,184 [INFO]: isatab.py(_all_end_to_end_paths:1131) >> [0, 1, 2]
2021-08-09 18:51:57,468 [WARNING]: isatab.py(write_study_table_files:1194) >> [4, 3, 0, 6, 5, 8, 7, 10, 9, 12, 11, 14, 13, 16, 15, 18, 17, 20, 19, 22, 21, 24, 23, 26, 25, 28, 27, 30, 29, 32, 31, 34, 33, 36, 35, 38, 37, 40, 39, 42, 41, 44, 43, 46, 45, 48, 47, 50, 49, 52, 51, 54, 53, 56, 55, 58, 57, 60, 59, 62, 61, 64, 63, 66, 65, 68, 67, 70, 69, 72, 71, 74, 73, 76, 75, 78, 77, 80, 79, 82, 81, 84, 83, 86, 85, 88, 87, 90, 89, 92, 91, 94, 93, 96, 95, 98, 97, 100, 99, 102, 101, 104, 103, 106, 105, 108, 107, 110, 109, 112, 111, 114, 113, 116, 115, 118, 117, 120, 119, 122, 121, 124, 123, 126, 125, 128, 127, 130, 129, 132, 131, 134, 133, 136, 135, 138, 137, 140, 139, 142, 141, 144, 143, 1, 146, 145, 148, 147, 150, 149, 152, 151, 154, 153, 156, 155, 158, 157, 160, 159, 162, 161, 164, 163, 166, 165, 168, 167, 170, 169, 172, 171, 174, 173, 176, 175, 178, 177, 180, 179, 182, 181, 184, 183, 186, 185, 188, 187, 190, 189, 192, 191, 194, 193, 196, 195, 198, 197, 200, 199, 202, 201, 204, 203, 206, 205, 208, 207, 210, 209, 212, 211, 214, 213, 216, 215, 218, 217, 220, 219, 222, 221, 224, 223, 226, 225, 228, 227, 230, 229, 232, 231, 234, 233, 236, 235, 238, 237, 240, 239, 242, 241, 244, 243, 246, 245, 248, 247, 250, 249, 252, 251, 254, 253, 256, 255, 258, 257, 260, 259, 262, 261, 264, 263, 266, 265, 268, 267, 270, 269, 272, 271, 274, 273, 276, 275, 278, 277, 280, 279, 282, 281, 284, 283, 286, 285, 288, 287, 290, 289, 292, 291, 294, 293, 296, 295, 298, 297, 300, 299, 302, 301, 304, 303, 306, 305, 308, 307, 310, 309, 312, 311, 314, 313, 316, 315, 318, 317, 320, 319, 322, 321, 324, 323, 326, 325, 328, 327, 330, 329, 332, 331, 334, 333, 336, 335, 338, 337, 340, 339, 342, 341, 344, 343, 346, 345, 348, 347, 350, 349, 352, 351, 354, 353, 356, 355, 358, 357, 360, 359, 362, 361, 364, 363, 366, 365, 368, 367, 370, 369, 372, 371, 374, 373, 376, 375, 378, 377, 380, 379, 382, 381, 384, 383, 386, 385, 388, 387, 390, 389, 392, 391, 394, 393, 396, 395, 398, 397, 400, 399, 402, 401, 404, 403, 406, 405, 408, 407, 410, 409, 412, 411, 414, 413, 416, 415, 418, 417, 420, 419, 422, 421, 424, 423, 426, 425, 428, 427, 430, 429, 432, 431, 434, 433, 436, 435, 438, 437, 440, 439, 442, 441, 444, 443, 446, 445, 448, 447, 450, 449, 452, 451, 454, 453, 456, 455, 458, 457, 460, 459, 462, 461, 464, 463, 466, 465, 468, 467, 470, 469, 472, 471, 474, 473, 476, 475, 478, 477, 480, 479, 482, 481, 484, 483, 486, 485, 488, 487, 490, 489, 492, 491, 494, 493, 2, 496, 495, 498, 497, 500, 499, 502, 501, 504, 503, 506, 505, 508, 507, 510, 509, 512, 511, 514, 513, 516, 515, 518, 517, 520, 519, 522, 521, 524, 523, 526, 525, 528, 527, 530, 529, 532, 531, 534, 533, 536, 535, 538, 537, 540, 539, 542, 541, 544, 543, 546, 545, 548, 547, 550, 549, 552, 551, 554, 553, 556, 555, 558, 557, 560, 559, 562, 561, 564, 563, 566, 565, 568, 567, 570, 569, 572, 571, 574, 573, 576, 575, 578, 577, 580, 579, 582, 581, 584, 583, 586, 585, 588, 587, 590, 589, 592, 591, 594, 593, 596, 595, 598, 597, 600, 599, 602, 601, 604, 603, 606, 605, 608, 607, 610, 609, 612, 611, 614, 613, 616, 615, 618, 617, 620, 619, 622, 621, 624, 623, 626, 625, 628, 627, 630, 629, 632, 631, 634, 633, 636, 635, 638, 637, 640, 639, 642, 641, 644, 643, 646, 645, 648, 647, 650, 649, 652, 651, 654, 653, 656, 655, 658, 657, 660, 659, 662, 661, 664, 663, 666, 665, 668, 667, 670, 669, 672, 671, 674, 673, 676, 675, 678, 677, 680, 679, 682, 681, 684, 683, 686, 685, 688, 687, 690, 689, 692, 691, 694, 693, 696, 695, 698, 697, 700, 699, 702, 701, 704, 703, 706, 705, 708, 707, 710, 709, 712, 711, 714, 713, 716, 715, 718, 717, 720, 719, 722, 721, 724, 723, 726, 725, 728, 727, 730, 729, 732, 731, 734, 733, 736, 735, 738, 737, 740, 739, 742, 741, 744, 743, 746, 745, 748, 747, 750, 749, 752, 751, 754, 753, 756, 755, 758, 757, 760, 759, 762, 761, 764, 763, 766, 765, 768, 767, 770, 769, 772, 771, 774, 773, 776, 775, 778, 777, 780, 779, 782, 781, 784, 783, 786, 785, 788, 787, 790, 789, 792, 791, 794, 793, 796, 795, 798, 797, 800, 799, 802, 801, 804, 803, 806, 805, 808, 807, 810, 809, 812, 811, 814, 813, 816, 815, 818, 817, 820, 819, 822, 821, 824, 823, 826, 825, 828, 827, 830, 829, 832, 831, 834, 833, 836, 835, 838, 837, 840, 839, 842, 841]
2021-08-09 18:51:57,471 [INFO]: isatab.py(_longest_path_and_attrs:1091) >> [[0, 4, 3], [0, 6, 5], [0, 8, 7], [0, 10, 9], [0, 12, 11], [0, 14, 13], [0, 16, 15], [0, 18, 17], [0, 20, 19], [0, 22, 21], [0, 24, 23], [0, 26, 25], [0, 28, 27], [0, 30, 29], [0, 32, 31], [0, 34, 33], [0, 36, 35], [0, 38, 37], [0, 40, 39], [0, 42, 41], [0, 44, 43], [0, 46, 45], [0, 48, 47], [0, 50, 49], [0, 52, 51], [0, 54, 53], [0, 56, 55], [0, 58, 57], [0, 60, 59], [0, 62, 61], [0, 64, 63], [0, 66, 65], [0, 68, 67], [0, 70, 69], [0, 72, 71], [0, 74, 73], [0, 76, 75], [0, 78, 77], [0, 80, 79], [0, 82, 81], [0, 84, 83], [0, 86, 85], [0, 88, 87], [0, 90, 89], [0, 92, 91], [0, 94, 93], [0, 96, 95], [0, 98, 97], [0, 100, 99], [0, 102, 101], [0, 104, 103], [0, 106, 105], [0, 108, 107], [0, 110, 109], [0, 112, 111], [0, 114, 113], [0, 116, 115], [0, 118, 117], [0, 120, 119], [0, 122, 121], [0, 124, 123], [0, 126, 125], [0, 128, 127], [0, 130, 129], [0, 132, 131], [0, 134, 133], [0, 136, 135], [0, 138, 137], [0, 140, 139], [0, 142, 141], [1, 144, 143], [1, 146, 145], [1, 148, 147], [1, 150, 149], [1, 152, 151], [1, 154, 153], [1, 156, 155], [1, 158, 157], [1, 160, 159], [1, 162, 161], [1, 164, 163], [1, 166, 165], [1, 168, 167], [1, 170, 169], [1, 172, 171], [1, 174, 173], [1, 176, 175], [1, 178, 177], [1, 180, 179], [1, 182, 181], [1, 184, 183], [1, 186, 185], [1, 188, 187], [1, 190, 189], [1, 192, 191], [1, 194, 193], [1, 196, 195], [1, 198, 197], [1, 200, 199], [1, 202, 201], [1, 204, 203], [1, 206, 205], [1, 208, 207], [1, 210, 209], [1, 212, 211], [1, 214, 213], [1, 216, 215], [1, 218, 217], [1, 220, 219], [1, 222, 221], [1, 224, 223], [1, 226, 225], [1, 228, 227], [1, 230, 229], [1, 232, 231], [1, 234, 233], [1, 236, 235], [1, 238, 237], [1, 240, 239], [1, 242, 241], [1, 244, 243], [1, 246, 245], [1, 248, 247], [1, 250, 249], [1, 252, 251], [1, 254, 253], [1, 256, 255], [1, 258, 257], [1, 260, 259], [1, 262, 261], [1, 264, 263], [1, 266, 265], [1, 268, 267], [1, 270, 269], [1, 272, 271], [1, 274, 273], [1, 276, 275], [1, 278, 277], [1, 280, 279], [1, 282, 281], [1, 284, 283], [1, 286, 285], [1, 288, 287], [1, 290, 289], [1, 292, 291], [1, 294, 293], [1, 296, 295], [1, 298, 297], [1, 300, 299], [1, 302, 301], [1, 304, 303], [1, 306, 305], [1, 308, 307], [1, 310, 309], [1, 312, 311], [1, 314, 313], [1, 316, 315], [1, 318, 317], [1, 320, 319], [1, 322, 321], [1, 324, 323], [1, 326, 325], [1, 328, 327], [1, 330, 329], [1, 332, 331], [1, 334, 333], [1, 336, 335], [1, 338, 337], [1, 340, 339], [1, 342, 341], [1, 344, 343], [1, 346, 345], [1, 348, 347], [1, 350, 349], [1, 352, 351], [1, 354, 353], [1, 356, 355], [1, 358, 357], [1, 360, 359], [1, 362, 361], [1, 364, 363], [1, 366, 365], [1, 368, 367], [1, 370, 369], [1, 372, 371], [1, 374, 373], [1, 376, 375], [1, 378, 377], [1, 380, 379], [1, 382, 381], [1, 384, 383], [1, 386, 385], [1, 388, 387], [1, 390, 389], [1, 392, 391], [1, 394, 393], [1, 396, 395], [1, 398, 397], [1, 400, 399], [1, 402, 401], [1, 404, 403], [1, 406, 405], [1, 408, 407], [1, 410, 409], [1, 412, 411], [1, 414, 413], [1, 416, 415], [1, 418, 417], [1, 420, 419], [1, 422, 421], [1, 424, 423], [1, 426, 425], [1, 428, 427], [1, 430, 429], [1, 432, 431], [1, 434, 433], [1, 436, 435], [1, 438, 437], [1, 440, 439], [1, 442, 441], [1, 444, 443], [1, 446, 445], [1, 448, 447], [1, 450, 449], [1, 452, 451], [1, 454, 453], [1, 456, 455], [1, 458, 457], [1, 460, 459], [1, 462, 461], [1, 464, 463], [1, 466, 465], [1, 468, 467], [1, 470, 469], [1, 472, 471], [1, 474, 473], [1, 476, 475], [1, 478, 477], [1, 480, 479], [1, 482, 481], [1, 484, 483], [1, 486, 485], [1, 488, 487], [1, 490, 489], [1, 492, 491], [2, 494, 493], [2, 496, 495], [2, 498, 497], [2, 500, 499], [2, 502, 501], [2, 504, 503], [2, 506, 505], [2, 508, 507], [2, 510, 509], [2, 512, 511], [2, 514, 513], [2, 516, 515], [2, 518, 517], [2, 520, 519], [2, 522, 521], [2, 524, 523], [2, 526, 525], [2, 528, 527], [2, 530, 529], [2, 532, 531], [2, 534, 533], [2, 536, 535], [2, 538, 537], [2, 540, 539], [2, 542, 541], [2, 544, 543], [2, 546, 545], [2, 548, 547], [2, 550, 549], [2, 552, 551], [2, 554, 553], [2, 556, 555], [2, 558, 557], [2, 560, 559], [2, 562, 561], [2, 564, 563], [2, 566, 565], [2, 568, 567], [2, 570, 569], [2, 572, 571], [2, 574, 573], [2, 576, 575], [2, 578, 577], [2, 580, 579], [2, 582, 581], [2, 584, 583], [2, 586, 585], [2, 588, 587], [2, 590, 589], [2, 592, 591], [2, 594, 593], [2, 596, 595], [2, 598, 597], [2, 600, 599], [2, 602, 601], [2, 604, 603], [2, 606, 605], [2, 608, 607], [2, 610, 609], [2, 612, 611], [2, 614, 613], [2, 616, 615], [2, 618, 617], [2, 620, 619], [2, 622, 621], [2, 624, 623], [2, 626, 625], [2, 628, 627], [2, 630, 629], [2, 632, 631], [2, 634, 633], [2, 636, 635], [2, 638, 637], [2, 640, 639], [2, 642, 641], [2, 644, 643], [2, 646, 645], [2, 648, 647], [2, 650, 649], [2, 652, 651], [2, 654, 653], [2, 656, 655], [2, 658, 657], [2, 660, 659], [2, 662, 661], [2, 664, 663], [2, 666, 665], [2, 668, 667], [2, 670, 669], [2, 672, 671], [2, 674, 673], [2, 676, 675], [2, 678, 677], [2, 680, 679], [2, 682, 681], [2, 684, 683], [2, 686, 685], [2, 688, 687], [2, 690, 689], [2, 692, 691], [2, 694, 693], [2, 696, 695], [2, 698, 697], [2, 700, 699], [2, 702, 701], [2, 704, 703], [2, 706, 705], [2, 708, 707], [2, 710, 709], [2, 712, 711], [2, 714, 713], [2, 716, 715], [2, 718, 717], [2, 720, 719], [2, 722, 721], [2, 724, 723], [2, 726, 725], [2, 728, 727], [2, 730, 729], [2, 732, 731], [2, 734, 733], [2, 736, 735], [2, 738, 737], [2, 740, 739], [2, 742, 741], [2, 744, 743], [2, 746, 745], [2, 748, 747], [2, 750, 749], [2, 752, 751], [2, 754, 753], [2, 756, 755], [2, 758, 757], [2, 760, 759], [2, 762, 761], [2, 764, 763], [2, 766, 765], [2, 768, 767], [2, 770, 769], [2, 772, 771], [2, 774, 773], [2, 776, 775], [2, 778, 777], [2, 780, 779], [2, 782, 781], [2, 784, 783], [2, 786, 785], [2, 788, 787], [2, 790, 789], [2, 792, 791], [2, 794, 793], [2, 796, 795], [2, 798, 797], [2, 800, 799], [2, 802, 801], [2, 804, 803], [2, 806, 805], [2, 808, 807], [2, 810, 809], [2, 812, 811], [2, 814, 813], [2, 816, 815], [2, 818, 817], [2, 820, 819], [2, 822, 821], [2, 824, 823], [2, 826, 825], [2, 828, 827], [2, 830, 829], [2, 832, 831], [2, 834, 833], [2, 836, 835], [2, 838, 837], [2, 840, 839], [2, 842, 841]]
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
/var/folders/5n/rl6lqnks4rqb59pbtpvvntqw0000gr/T/ipykernel_54507/4200718032.py in <module>
      3 # import os
      4 # os.makedirs('/notebook-output/isa-repeated-measure-crossover-design', exist_ok = True)
----> 5 isatab.dump(investigation, './notebook-output/isa-repeated-measure-crossover-design')

~/.pyenv/versions/3.9.0/envs/isa-api-py39/src/isatools/isatools/isatab.py in dump(isa_obj, output_path, i_file_name, skip_dump_tables, write_factor_values_in_assay_table)
   1047         pass
   1048     else:
-> 1049         write_study_table_files(investigation, output_path)
   1050         write_assay_table_files(
   1051             investigation, output_path, write_factor_values_in_assay_table)

~/.pyenv/versions/3.9.0/envs/isa-api-py39/src/isatools/isatools/isatab.py in write_study_table_files(inv_obj, output_dir)
   1295                         fvlabel = "{0}.Factor Value[{1}]".format(
   1296                             olabel, fv.factor_name.name)
-> 1297                         write_value_columns(df_dict, fvlabel, fv)
   1298         """if isinstance(pbar, ProgressBar):
   1299             pbar.finish()"""

~/.pyenv/versions/3.9.0/envs/isa-api-py39/src/isatools/isatools/isatab.py in write_value_columns(df_dict, label, x)
   1715     if isinstance(x.value, (int, float)) and x.unit:
   1716         if isinstance(x.unit, OntologyAnnotation):
-> 1717             df_dict[label][-1] = x.value
   1718             df_dict[label + ".Unit"][-1] = x.unit.term
   1719             df_dict[label + ".Unit.Term Source REF"][-1] = \

KeyError: 'Sample Name.0.Factor Value[DURATION]'
len(dataframes.keys())
len(dataframes.keys())
dataframes[list(dataframes.keys())[1]]
[x for x in study.assays[0].graph.nodes() if isinstance(x, Sample)]
len([x for x in study.assays[0].graph.nodes() if isinstance(x, Sample)])
[getattr(x, 'name', None) for x in study.assays[0].graph.nodes()]