From 0d76c71916788db9533468791a88ce840017f100 Mon Sep 17 00:00:00 2001 From: Peter Schubert <Peter.Schubert@hhu.de> Date: Fri, 23 Dec 2022 10:48:31 +0100 Subject: [PATCH] import from df implemented --- rbaxdf/model/rba_densities.py | 16 +++- rbaxdf/model/rba_enzymes.py | 6 +- rbaxdf/model/rba_macromolecules.py | 35 ++++++++ rbaxdf/model/rba_metabolism.py | 65 ++++++++++----- rbaxdf/model/rba_model.py | 32 ++++---- rbaxdf/model/rba_parameters.py | 46 ++++++++--- rbaxdf/model/rba_processes.py | 126 ++++++++++++++++++++--------- rbaxdf/model/rba_target_value.py | 21 +++-- rbaxdf/model/rba_targets.py | 36 +++++++-- rbaxdf/utils/et_utils.py | 33 -------- rbaxdf/utils/utils.py | 78 ++++++++++++++++++ 11 files changed, 356 insertions(+), 138 deletions(-) delete mode 100644 rbaxdf/utils/et_utils.py create mode 100644 rbaxdf/utils/utils.py diff --git a/rbaxdf/model/rba_densities.py b/rbaxdf/model/rba_densities.py index 3d236ff..48ca99c 100644 --- a/rbaxdf/model/rba_densities.py +++ b/rbaxdf/model/rba_densities.py @@ -8,6 +8,7 @@ import pandas as pd from xml.etree.ElementTree import parse, ElementTree, Element, SubElement, indent from .rba_target_value import RbaTargetValue +from rbaxdf.utils.utils import extract_params class RbaDensities: @@ -26,6 +27,9 @@ class RbaDensities: assert root.tag == 'RBADensity' self.densities = RbaDensity.import_xml(root.find('listOfTargetDensities')) + def from_df(self, df): + self.densities = RbaDensity.from_df(df) + def export_xml(self, model_dir): file_name = os.path.join(model_dir, 'density.xml') @@ -72,7 +76,17 @@ class RbaDensity: for target_density in target_densities.findall('targetDensity'): cid = target_density.attrib['compartment'] rba_density = RbaDensity(cid) - rba_density.target_value = RbaTargetValue(target_density) + rba_density.target_value = RbaTargetValue.from_dict(target_density.attrib) + data[cid] = rba_density + return data + + @staticmethod + def from_df(df): + data = {} + for cid, row in df.iterrows(): + rba_density = RbaDensity(cid) + target_value = extract_params(row['targetValue']) + rba_density.target_value = RbaTargetValue.from_dict(target_value) data[cid] = rba_density return data diff --git a/rbaxdf/model/rba_enzymes.py b/rbaxdf/model/rba_enzymes.py index b1f4965..ec7eaf2 100644 --- a/rbaxdf/model/rba_enzymes.py +++ b/rbaxdf/model/rba_enzymes.py @@ -8,7 +8,7 @@ import os import pandas as pd from xml.etree.ElementTree import parse, ElementTree, Element, SubElement, indent -from rbaxdf.utils.et_utils import get_species_refs +from rbaxdf.utils.utils import get_species_refs_from_xml class RbaEnzymes: @@ -102,8 +102,8 @@ class RbaEnzyme: machinery_composition = enzyme.find('machineryComposition') if machinery_composition is not None: - rba_enzyme.mach_reactants = get_species_refs(machinery_composition.find('listOfReactants')) - rba_enzyme.mach_products = get_species_refs(machinery_composition.find('listOfProducts')) + rba_enzyme.mach_reactants = get_species_refs_from_xml(machinery_composition.find('listOfReactants')) + rba_enzyme.mach_products = get_species_refs_from_xml(machinery_composition.find('listOfProducts')) data[eid] = rba_enzyme return data diff --git a/rbaxdf/model/rba_macromolecules.py b/rbaxdf/model/rba_macromolecules.py index b4fc92c..663b7c5 100644 --- a/rbaxdf/model/rba_macromolecules.py +++ b/rbaxdf/model/rba_macromolecules.py @@ -32,6 +32,10 @@ class RbaMacromolecules: self.components = RbaComponent.import_xml(root.find('listOfComponents')) self.macromolecules = RbaMacromolecule.import_xml(root.find('listOfMacromolecules')) + def from_df(self, df): + self.components = RbaComponent.from_df(df) + self.macromolecules = RbaMacromolecule.from_df(df) + def export_xml(self, model_dir): file_name = os.path.join(model_dir, self.type + '.xml') root = Element(type2tag[self.type]) @@ -58,6 +62,9 @@ class RbaMacromolecules: df.index.name = self.type return df + def validate(self, component_ids): + return True + class RbaComponent: @@ -79,6 +86,18 @@ class RbaComponent: data[cid] = rba_component return data + @staticmethod + def from_df(df): + data = {} + components = [col for col in df.columns if col != 'compartment'] + for cid in components: + rba_component = RbaComponent(cid) + rba_component.name = df.at['name', cid] + rba_component.type = df.at['type', cid] + rba_component.weight = df.at['weight', cid] + data[cid] = rba_component + return data + def export_xml(self): attribs = {'id': self.id, 'name': self.name, 'type': self.type, 'weight': str(self.weight)} return Element('component', attribs) @@ -111,6 +130,22 @@ class RbaMacromolecule: data[mmid] = rba_macromolecule return data + @staticmethod + def from_df(df): + data = {} + components = [col for col in df.columns if col != 'compartment'] + macromolecules = [idx for idx in df.index if idx not in ['name', 'type', 'weight']] + for mmid in macromolecules: + rba_macromolecule = RbaMacromolecule(mmid) + rba_macromolecule.compartment = df.at[mmid, 'compartment'] + for component in components: + stoic = df.at[mmid, component] + if np.isfinite(stoic) and stoic > 0.0: + rba_macromolecule.composition[component] = stoic + data[mmid] = rba_macromolecule + + return data + def export_xml(self): attribs = {'id': self.id, 'compartment': self.compartment} macromolecule = Element('macromolecule', attribs) diff --git a/rbaxdf/model/rba_metabolism.py b/rbaxdf/model/rba_metabolism.py index 4760c43..30f7a1d 100644 --- a/rbaxdf/model/rba_metabolism.py +++ b/rbaxdf/model/rba_metabolism.py @@ -7,7 +7,7 @@ import os import pandas as pd from xml.etree.ElementTree import parse, ElementTree, Element, SubElement, indent -from rbaxdf.utils.et_utils import get_species_refs +from rbaxdf.utils.utils import get_species_refs_from_xml, get_species_refs_from_str class RbaMetabolism: @@ -32,6 +32,11 @@ class RbaMetabolism: self.species = RbaSpecies.import_xml(root.find('listOfSpecies')) self.reactions = RbaReaction.import_xml(root.find('listOfReactions')) + def from_df(self, df_c, df_s, df_r): + self.compartments = RbaCompartment.from_df(df_c) + self.species = RbaSpecies.from_df(df_s) + self.reactions = RbaReaction.from_df(df_r) + def export_xml(self, model_dir): file_name = os.path.join(model_dir, 'metabolism.xml') root = Element('RBAMetabolism') @@ -52,23 +57,14 @@ class RbaMetabolism: indent(tree) tree.write(file_name) - def to_df(self, m_type): - df = None - if m_type == 'compartments': - df = pd.DataFrame([item.to_dict() for item in self.compartments.values()]) - df.index.name = 'index' - - elif m_type == 'species': - df = pd.DataFrame([item.to_dict() for item in self.species.values()]) - df.set_index('species', inplace=True) - - elif m_type == 'reactions': - df = pd.DataFrame([item.to_dict() for item in self.reactions.values()]) - df.set_index('reaction', inplace=True) - - else: - print(f'wrong metabolism type: {m_type}') - return df + def to_df(self): + df_c = pd.DataFrame([item.to_dict() for item in self.compartments.values()]) + df_c.index.name = 'index' + df_s = pd.DataFrame([item.to_dict() for item in self.species.values()]) + df_s.set_index('species', inplace=True) + df_r = pd.DataFrame([item.to_dict() for item in self.reactions.values()]) + df_r.set_index('reaction', inplace=True) + return df_c, df_s, df_r def validate(self, component_ids): valid = True @@ -100,6 +96,15 @@ class RbaCompartment: data[cid] = rba_compartment return data + @staticmethod + def from_df(df): + data = {} + for _, row in df.iterrows(): + cid = row['compartment'] + rba_compartment = RbaCompartment(cid) + data[cid] = rba_compartment + return data + def export_xml(self): return Element('compartment', {'id': self.id}) @@ -125,6 +130,15 @@ class RbaSpecies: data[sid] = rba_species return data + @staticmethod + def from_df(df): + data = {} + for sid, row in df.iterrows(): + rba_species = RbaSpecies(sid) + rba_species.boundary_condition = row['boundaryCondition'] + data[sid] = rba_species + return data + def export_xml(self): attribs = {'id': self.id, 'boundaryCondition': str(self.boundary_condition).lower()} return Element('species', attribs) @@ -150,8 +164,19 @@ class RbaReaction: rba_reaction = RbaReaction(rid) if reaction.attrib['reversible'].lower() == 'false': rba_reaction.reversible = False - rba_reaction.reactants = get_species_refs(reaction.find('listOfReactants')) - rba_reaction.products = get_species_refs(reaction.find('listOfProducts')) + rba_reaction.reactants = get_species_refs_from_xml(reaction.find('listOfReactants')) + rba_reaction.products = get_species_refs_from_xml(reaction.find('listOfProducts')) + data[rid] = rba_reaction + return data + + @staticmethod + def from_df(df): + data = {} + for rid, row in df.iterrows(): + rba_reaction = RbaReaction(rid) + rba_reaction.reversible = row['reversible'] + rba_reaction.reactants = get_species_refs_from_str(row['reactants']) + rba_reaction.products = get_species_refs_from_str(row['products']) data[rid] = rba_reaction return data diff --git a/rbaxdf/model/rba_model.py b/rbaxdf/model/rba_model.py index 205d192..cc206dc 100644 --- a/rbaxdf/model/rba_model.py +++ b/rbaxdf/model/rba_model.py @@ -63,22 +63,27 @@ class RbaModel: def to_df(self): m_dict = {} if self.is_model is True: - m_dict['rnas'] = self.rnas.to_df() + m_dict['compartments'], m_dict['species'], m_dict['reactions'] = self.metabolism.to_df() m_dict['dna'] = self.dna.to_df() + m_dict['rnas'] = self.rnas.to_df() m_dict['proteins'] = self.proteins.to_df() m_dict['enzymes'] = self.enzymes.to_df() m_dict['densities'] = self.densities.to_df() m_dict['targets'] = self.targets.to_df() - m_dict['compartments'] = self.metabolism.to_df('compartments') - m_dict['species'] = self.metabolism.to_df('species') - m_dict['reactions'] = self.metabolism.to_df('reactions') - m_dict['functions'] = self.parameters.to_df('functions') - m_dict['aggregates'] = self.parameters.to_df('aggregates') - m_dict['processes'] = self.processes.to_df('processes') - m_dict['processing_maps'] = self.processes.to_df('processingMaps') - + m_dict['functions'], m_dict['aggregates'] = self.parameters.to_df() + m_dict['processes'], m_dict['processing_maps'] = self.processes.to_df() return m_dict + def from_df(self, m_dict): + self.metabolism.from_df(m_dict['compartments'], m_dict['species'], m_dict['reactions']) + self.dna.from_df(m_dict['dna']) + self.rnas.from_df(m_dict['rnas']) + self.proteins.from_df(m_dict['proteins']) + self.densities.from_df(m_dict['densities']) + self.targets.from_df(m_dict['targets']) + self.parameters.from_df(m_dict['functions'], m_dict['aggregates']) + self.processes.from_df(m_dict['processes'], m_dict['processing_maps']) + def to_excel(self): xlsx_name = os.path.join(self.model_dir, 'model') + '.xlsx' m_dict = self.to_df() @@ -100,8 +105,7 @@ class RbaModel: with pd.ExcelWriter(xlsx_name) as writer: for name, df in m_dict.items(): - keep_index = False if df.index.name == 'index' else True - df.to_excel(writer, sheet_name=name, index=keep_index) + df.to_excel(writer, sheet_name=name) print(f'model exported to {xlsx_name}') def validate(self): @@ -113,8 +117,6 @@ class RbaModel: 'aggregates': set(self.parameters.aggregates)} valid = True - components = {'parameters', 'metabolism', - 'processes', 'enzymes', 'densities', 'targets'} for component in components: valid = valid and getattr(self, component).validate(component_ids) print(f'model valid status: {valid}') @@ -140,7 +142,6 @@ class RbaModel: unused_parameters = parameters.difference(ref_parameters) unused_molecules = molecules.difference(ref_molecules) - unused = 0 if len(unused_parameters) > 0: print(f'{len(unused_parameters)} unused parameters:', unused_parameters) @@ -151,8 +152,5 @@ class RbaModel: if unused == 0: print('no unused parameters/molecules') - def from_df(self): - pass - def from_excel(self): pass diff --git a/rbaxdf/model/rba_parameters.py b/rbaxdf/model/rba_parameters.py index 1a6f35e..629fb16 100644 --- a/rbaxdf/model/rba_parameters.py +++ b/rbaxdf/model/rba_parameters.py @@ -7,6 +7,8 @@ import os import pandas as pd from xml.etree.ElementTree import parse, ElementTree, Element, SubElement, indent +from rbaxdf.utils.utils import extract_params + class RbaParameters: @@ -26,6 +28,10 @@ class RbaParameters: self.functions = RbaFunction.import_xml(root.find('listOfFunctions')) self.aggregates = RbaAggregate.import_xml(root.find('listOfAggregates')) + def from_df(self, df_f, df_a): + self.functions = RbaFunction.from_df(df_f) + self.aggregates = RbaAggregate.from_df(df_a) + def export_xml(self, model_dir): file_name = os.path.join(model_dir, 'parameters.xml') @@ -50,17 +56,12 @@ class RbaParameters: value_info = self.aggregates[value].value_info return value_info - def to_df(self, p_type): - df = None - if p_type == 'functions': - df = pd.DataFrame([item.to_dict() for item in self.functions.values()]) - df.set_index('function', inplace=True) - elif p_type == 'aggregates': - df = pd.DataFrame([item.to_dict() for item in self.aggregates.values()]) - df.set_index('aggregate', inplace=True) - else: - print(f'wrong parameter type: {p_type}') - return df + def to_df(self): + df_f = pd.DataFrame([item.to_dict() for item in self.functions.values()]) + df_f.set_index('function', inplace=True) + df_a = pd.DataFrame([item.to_dict() for item in self.aggregates.values()]) + df_a.set_index('aggregate', inplace=True) + return df_f, df_a def validate(self, component_ids): valid = True @@ -107,6 +108,18 @@ class RbaFunction: data[fid] = rba_function return data + @staticmethod + def from_df(df): + data = {} + for fid, row in df.iterrows(): + rba_function = RbaFunction(fid) + rba_function.type = row['type'] + rba_function.variable = row['variable'] + rba_function.parameters = extract_params(row['parameters']) + rba_function.set_value_info() + data[fid] = rba_function + return data + def export_xml(self): attribs = {'id': self.id, 'type': self.type, 'variable': self.variable} function = Element('function', attribs) @@ -164,6 +177,17 @@ class RbaAggregate: data[aid] = rba_aggregate return data + @staticmethod + def from_df(df): + data = {} + for aid, row in df.iterrows(): + rba_aggregate = RbaAggregate(aid) + rba_aggregate.type = row['type'] + rba_aggregate.functions = [item.strip() for item in row['functions'].split(',')] + rba_aggregate.set_value_info() + data[aid] = rba_aggregate + return data + def export_xml(self): attribs = {'id': self.id, 'type': self.type} aggregate = Element('aggregate', attribs) diff --git a/rbaxdf/model/rba_processes.py b/rbaxdf/model/rba_processes.py index c193228..83c2f8a 100644 --- a/rbaxdf/model/rba_processes.py +++ b/rbaxdf/model/rba_processes.py @@ -9,7 +9,7 @@ import pandas as pd from xml.etree.ElementTree import parse, ElementTree, Element, SubElement, indent from .rba_target_value import RbaTargetValue -from rbaxdf.utils.et_utils import get_species_refs +from rbaxdf.utils.utils import get_species_refs_from_xml, get_species_refs_from_str, extract_params class RbaProcesses: @@ -31,6 +31,10 @@ class RbaProcesses: self.processes = RbaProcess.import_xml(root.find('listOfProcesses')) self.processing_maps = RbaProcessingMap.import_xml(root.find('listOfProcessingMaps')) + def from_df(self, df_p, df_pm): + self.processes = RbaProcess.from_df(df_p) + self.processing_maps = RbaProcessingMap.from_df(df_pm) + def export_xml(self, model_dir): file_name = os.path.join(model_dir, 'processes.xml') @@ -48,29 +52,25 @@ class RbaProcesses: indent(tree) tree.write(file_name) - def to_df(self, p_type): - df = None - if p_type == 'processes': - df = pd.DataFrame([item.to_dict() for item in self.processes.values()]) - df.set_index('process', inplace=True) - elif p_type == 'processingMaps': - data = [] - for pmid, pmap in self.processing_maps.items(): - pm_dict = pmap.to_dict() - if ((len(pm_dict['constantProcessing'].get('reactants', {})) > 0) or - (len(pm_dict['constantProcessing'].get('products', {})) > 0)): - data.append([pmid, 'constantProcessing', np.nan, pm_dict['constantProcessing']['reactants'], - pm_dict['constantProcessing']['products']]) - for component, comp_proc in pm_dict['componentProcessings'].items(): - data.append([pmid, component, comp_proc['machineryCost'], comp_proc['reactants'], - comp_proc['products']]) - - df = pd.DataFrame(data, columns=['processingMap', 'component', 'machineryCost', - 'reactants', 'products']) - df.set_index('processingMap', inplace=True) - else: - print(f'wrong parameter type: {p_type}') - return df + def to_df(self): + df_p = pd.DataFrame([item.to_dict() for item in self.processes.values()]) + df_p.set_index('process', inplace=True) + data = [] + for pmid, pmap in self.processing_maps.items(): + pm_dict = pmap.to_dict() + if ((len(pm_dict['constantProcessing'].get('reactants', {})) > 0) or + (len(pm_dict['constantProcessing'].get('products', {})) > 0)): + data.append([pmid, 'constantProcessing', np.nan, pm_dict['constantProcessing']['reactants'], + pm_dict['constantProcessing']['products']]) + for component, comp_proc in pm_dict['componentProcessings'].items(): + data.append([pmid, component, comp_proc['machineryCost'], comp_proc['reactants'], + comp_proc['products']]) + + df_pm = pd.DataFrame(data, columns=['processingMap', 'component', 'machineryCost', + 'reactants', 'products']) + df_pm.set_index('processingMap', inplace=True) + + return df_p, df_pm def validate(self, component_ids): valid = True @@ -161,9 +161,9 @@ class RbaProcess: machinery = process.find('machinery') if machinery is not None: composition = machinery.find('machineryComposition') - reactants = get_species_refs(composition.find('listOfReactants')) - products = get_species_refs(composition.find('listOfProducts')) - capacity = RbaTargetValue(machinery.find('capacity')) + reactants = get_species_refs_from_xml(composition.find('listOfReactants')) + products = get_species_refs_from_xml(composition.find('listOfProducts')) + capacity = RbaTargetValue.from_dict(machinery.find('capacity').attrib) rba_process.machinery = {'capacity': capacity, 'reactants': reactants, 'products': products} processings = process.find('processings') @@ -172,18 +172,46 @@ class RbaProcess: if productions is not None: processing = productions.find('processing') processing_map = processing.attrib['processingMap'] - p_set = processing.attrib['set'] - inputs = processing.find('listOfInputs') - p_inputs = [sref.attrib['species'] for sref in inputs.findall('speciesReference')] - rba_process.productions = {'processingMap': processing_map, 'set': p_set, 'inputs': p_inputs} + set_type = processing.attrib['set'] + lo_inputs = processing.find('listOfInputs') + inputs = [sref.attrib['species'] for sref in lo_inputs.findall('speciesReference')] + rba_process.productions = {'processingMap': processing_map, 'set': set_type, 'inputs': inputs} degradations = processings.find('listOfDegradations') if degradations is not None: processing = degradations.find('processing') processing_map = processing.attrib['processingMap'] - p_set = processing.attrib['set'] - inputs = processing.find('listOfInputs') - p_inputs = [sref.attrib['species'] for sref in inputs.findall('speciesReference')] - rba_process.degradations = {'processingMap': processing_map, 'set': p_set, 'inputs': p_inputs} + set_type = processing.attrib['set'] + lo_inputs = processing.find('listOfInputs') + inputs = [sref.attrib['species'] for sref in lo_inputs.findall('speciesReference')] + rba_process.degradations = {'processingMap': processing_map, 'set': set_type, 'inputs': inputs} + + data[pid] = rba_process + return data + + @staticmethod + def from_df(df): + data = {} + for pid, row in df.iterrows(): + rba_process = RbaProcess(pid) + rba_process.name = row['name'] + capacity_dict = extract_params(row['machineryCapacity']) + capacity = RbaTargetValue.from_dict(capacity_dict) + reactants = get_species_refs_from_str(row['machineryReactants']) + products = get_species_refs_from_str(row['machineryProducts']) + rba_process.machinery = {'capacity': capacity, 'reactants': reactants, + 'products': products} + + processing_map = row['productionProcessingMap'] + set_type = row['productionSet'] + inputs = [item.strip() for item in row['productionInputs'].split(',')] + if type(processing_map) is str and len(processing_map) > 0: + rba_process.productions = {'processingMap': processing_map, 'set': set_type, 'inputs': inputs} + + processing_map = row['degradationProcessingMap'] + set_type = row['degradationSet'] + inputs = [item.strip() for item in row['degradationInputs'].split(',')] + if type(processing_map) is str and len(processing_map) > 0: + rba_process.degradations = {'processingMap': processing_map, 'set': set_type, 'inputs': inputs} data[pid] = rba_process return data @@ -274,16 +302,36 @@ class RbaProcessingMap: const_proc = processing_map.find('constantProcessing') if const_proc is not None: - rba_pmap.constant_processing['reactants'] = get_species_refs(const_proc.find('listOfReactants')) - rba_pmap.constant_processing['products'] = get_species_refs(const_proc.find('listOfProducts')) + rba_pmap.constant_processing['reactants'] = get_species_refs_from_xml( + const_proc.find('listOfReactants')) + rba_pmap.constant_processing['products'] = get_species_refs_from_xml(const_proc.find('listOfProducts')) comp_procs = processing_map.find('listOfComponentProcessings') if comp_procs is not None: for comp_proc in comp_procs.findall('componentProcessing'): component = comp_proc.attrib['component'] cost = float(comp_proc.get('machineryCost', '0')) - reactants = get_species_refs(comp_proc.find('listOfReactants')) - products = get_species_refs(comp_proc.find('listOfProducts')) + reactants = get_species_refs_from_xml(comp_proc.find('listOfReactants')) + products = get_species_refs_from_xml(comp_proc.find('listOfProducts')) + rba_pmap.component_processings[component] = {'cost': cost, 'reactants': reactants, + 'products': products} + data[pmid] = rba_pmap + return data + + @staticmethod + def from_df(df): + data = {} + for pmid, group in df.groupby('processingMap'): + rba_pmap = RbaProcessingMap(pmid) + for _, row in group.iterrows(): + component = row['component'] + reactants = get_species_refs_from_str(row['reactants']) + products = get_species_refs_from_str(row['products']) + if component == 'constantProcessing': + rba_pmap.constant_processing['reactants'] = reactants + rba_pmap.constant_processing['products'] = products + else: + cost = row['machineryCost'] rba_pmap.component_processings[component] = {'cost': cost, 'reactants': reactants, 'products': products} data[pmid] = rba_pmap diff --git a/rbaxdf/model/rba_target_value.py b/rbaxdf/model/rba_target_value.py index e5ee386..8b470f1 100644 --- a/rbaxdf/model/rba_target_value.py +++ b/rbaxdf/model/rba_target_value.py @@ -6,13 +6,20 @@ Peter Schubert, CCB, HHU Duesseldorf, December 2022 class RbaTargetValue: - def __init__(self, target): - self.lower_bound = target.attrib.get('lowerBound') - self.upper_bound = target.attrib.get('upperBound') - self.value = target.attrib.get('value') - if self.value is not None: - self.lower_bound = None - self.upper_bound = None + def __init__(self): + self.lower_bound = None + self.upper_bound = None + self.value = None + + @staticmethod + def from_dict(value_dict): + target_value = RbaTargetValue() + if 'value' in value_dict: + target_value.value = value_dict['value'] + else: + target_value.lower_bound = value_dict.get('lowerBound') + target_value.upper_bound = value_dict.get('upperBound') + return target_value def to_dict(self): target_values = {} diff --git a/rbaxdf/model/rba_targets.py b/rbaxdf/model/rba_targets.py index fadf2e7..4778076 100644 --- a/rbaxdf/model/rba_targets.py +++ b/rbaxdf/model/rba_targets.py @@ -7,7 +7,8 @@ import os import pandas as pd from xml.etree.ElementTree import parse, ElementTree, Element, SubElement, indent -from rbaxdf.utils.et_utils import get_target_species, get_target_reactions +from rbaxdf.utils.utils import get_target_species_from_xml, get_target_reactions_from_xml, extract_params +from .rba_target_value import RbaTargetValue class RbaTargets: @@ -27,6 +28,9 @@ class RbaTargets: self.target_groups = RbaTargetGroup.import_xml(root.find('listOfTargetGroups')) + def from_df(self, df): + self.target_groups = RbaTargetGroup.from_df(df) + def export_xml(self, model_dir): file_name = os.path.join(model_dir, 'targets.xml') root = Element('RBATargets') @@ -98,12 +102,30 @@ class RbaTargetGroup: data = {} for target_group in target_groups.findall('targetGroup'): tgid = target_group.attrib.get('id', '') - rba_target = RbaTargetGroup(tgid) - rba_target.concentrations = get_target_species(target_group.find('listOfConcentrations')) - rba_target.production_fluxes = get_target_species(target_group.find('listOfProductionFluxes')) - rba_target.degradation_fluxes = get_target_species(target_group.find('listOfDegradationFluxes')) - rba_target.reaction_fluxes = get_target_reactions(target_group.find('listOfReactionFluxes')) - data[tgid] = rba_target + rba_tg = RbaTargetGroup(tgid) + rba_tg.concentrations = get_target_species_from_xml(target_group.find('listOfConcentrations')) + rba_tg.production_fluxes = get_target_species_from_xml(target_group.find('listOfProductionFluxes')) + rba_tg.degradation_fluxes = get_target_species_from_xml(target_group.find('listOfDegradationFluxes')) + rba_tg.reaction_fluxes = get_target_reactions_from_xml(target_group.find('listOfReactionFluxes')) + data[tgid] = rba_tg + return data + + @staticmethod + def from_df(df): + data = {} + for tgid, group in df.groupby('targetGroup'): + rba_tg = RbaTargetGroup(tgid) + for _, row in group.iterrows(): + target_value = extract_params(row['targetValue']) + if row['targetType'] == 'concentrations': + rba_tg.concentrations[row['target']] = RbaTargetValue.from_dict(target_value) + if row['targetType'] == 'productionFluxes': + rba_tg.production_fluxes[row['target']] = RbaTargetValue.from_dict(target_value) + if row['targetType'] == 'degradationFluxes': + rba_tg.degradation_fluxes[row['target']] = RbaTargetValue.from_dict(target_value) + if row['targetType'] == 'reactionFluxes': + rba_tg.reaction_fluxes[row['target']] = RbaTargetValue.from_dict(target_value) + data[tgid] = rba_tg return data def export_xml(self): diff --git a/rbaxdf/utils/et_utils.py b/rbaxdf/utils/et_utils.py deleted file mode 100644 index b364f88..0000000 --- a/rbaxdf/utils/et_utils.py +++ /dev/null @@ -1,33 +0,0 @@ - - -from rbaxdf.model.rba_target_value import RbaTargetValue - - -def get_target_species(ts_parent): - data = {} - if ts_parent is not None: - for target in ts_parent.findall('targetSpecies'): - species = target.attrib['species'] - target_value = RbaTargetValue(target) - data[species] = target_value - return data - - -def get_target_reactions(tr_parent): - data = {} - if tr_parent is not None: - for target in tr_parent.findall('targetReaction'): - reaction = target.attrib['reaction'] - target_values = RbaTargetValue(target) - data[reaction] = target_values - return data - - -def get_species_refs(srefs_parent): - srefs = {} - if srefs_parent is not None: - for sref in srefs_parent.findall('speciesReference'): - sid = sref.attrib['species'] - stoic = float(sref.attrib['stoichiometry']) - srefs[sid] = stoic - return srefs diff --git a/rbaxdf/utils/utils.py b/rbaxdf/utils/utils.py new file mode 100644 index 0000000..2c90795 --- /dev/null +++ b/rbaxdf/utils/utils.py @@ -0,0 +1,78 @@ + + +from rbaxdf.model.rba_target_value import RbaTargetValue + + +def get_target_species_from_xml(ts_parent): + data = {} + if ts_parent is not None: + for target in ts_parent.findall('targetSpecies'): + species = target.attrib['species'] + target_value = RbaTargetValue.from_dict(target.attrib) + data[species] = target_value + return data + + +def get_target_reactions_from_xml(tr_parent): + data = {} + if tr_parent is not None: + for target in tr_parent.findall('targetReaction'): + reaction = target.attrib['reaction'] + target_values = RbaTargetValue.from_dict(target.attrib) + data[reaction] = target_values + return data + + +def get_species_refs_from_xml(srefs_parent): + srefs = {} + if srefs_parent is not None: + for sref in srefs_parent.findall('speciesReference'): + sid = sref.attrib['species'] + stoic = float(sref.attrib['stoichiometry']) + srefs[sid] = stoic + return srefs + + +def get_species_refs_from_str(srefs_str): + srefs = {} + for sref in srefs_str.split(';'): + params = extract_params(sref) + if 'species' in params and 'stoic' in params: + srefs[params['species']] = float(params['stoic']) + return srefs + + +def extract_params(record): + """Extract parameters from a record. + + A single record consists of comma separated key-value pairs. + Example: 'key1=val1, key2=val2, ...' is converted to + {key1: val1, key2: val2, ...} + + :param record: key '=' value pairs separated by "," + :type record: str + :returns: key-values pairs extracted from record + :rtype: dict + """ + params = {} + for kv_pair in record_generator(record, sep=','): + if '=' in kv_pair: + k, v = kv_pair.split('=') + params[k.strip()] = v.strip() + return params + + +def record_generator(records_str, sep=';'): + """Generator to extract individual records from a string of records. + + :param records_str: containing records separated by sep + :type records_str: str + :param sep: seperator used to separate records + :type sep: str (default: ';') + :returns: key-values pairs extracted from record + :rtype: dict + """ + if type(records_str) == str: + for record in records_str.split(sep): + if len(record.strip()) > 0: + yield record.strip() -- GitLab