From 47679cc55a6341c79c83691aecd421ef5240a6b4 Mon Sep 17 00:00:00 2001 From: Piotr Gawron <piotr.gawron@uni.lu> Date: Wed, 23 Oct 2019 13:28:26 +0200 Subject: [PATCH] import/export of new structural state implemented --- .../sbml/species/SbmlSpeciesExporter.java | 79 ++++++++++++++++++- .../model/sbml/species/SbmlSpeciesParser.java | 79 +++++++++++++++++-- .../model/sbml/SbmlExporterTest.java | 25 +++--- .../sbml/species/SbmlSpeciesExporterTest.java | 5 +- 4 files changed, 169 insertions(+), 19 deletions(-) diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesExporter.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesExporter.java index a7cf1fdfd1..3688c5e1e8 100644 --- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesExporter.java +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesExporter.java @@ -32,6 +32,7 @@ public class SbmlSpeciesExporter extends SbmlElementExporter<Species, org.sbml.j private SbmlCompartmentExporter compartmentExporter; private int modificationResidueCounter = 0; + private int structuralStateCounter = 0; private Map<String, String> modificationResidueIds = new HashMap<>(); public SbmlSpeciesExporter(Model sbmlModel, @@ -172,14 +173,15 @@ public class SbmlSpeciesExporter extends SbmlElementExporter<Species, org.sbml.j private void assignStructuralStateToMulti(Species element, MultiSpeciesPlugin multiExtension, MultiSpeciesType speciesType) { - String structuralState = null; + StructuralState structuralState = null; if (element instanceof Protein) { structuralState = ((Protein) element).getStructuralState(); } else if (element instanceof Complex) { structuralState = ((Complex) element).getStructuralState(); } if (structuralState != null) { - assignValueToFeature(element, multiExtension, speciesType, structuralState, BioEntityFeature.STRUCTURAL_STATE); + assignValueToFeature(element, multiExtension, speciesType, structuralState.getValue(), + BioEntityFeature.STRUCTURAL_STATE); } } @@ -374,13 +376,16 @@ public class SbmlSpeciesExporter extends SbmlElementExporter<Species, org.sbml.j String multiDistinguisher = null; if (isExtensionEnabled(SbmlExtension.MULTI)) { - String structuralState = null; + StructuralState structuralState = null; if (element instanceof Protein) { + structuralState = ((Protein) element).getStructuralState(); } else if (element instanceof Complex) { structuralState = ((Complex) element).getStructuralState(); } - multiDistinguisher = structuralState; + if (structuralState != null) { + multiDistinguisher = structuralState.getValue(); + } if (element instanceof SpeciesWithModificationResidue) { List<String> modifications = new ArrayList<>(); @@ -465,6 +470,9 @@ public class SbmlSpeciesExporter extends SbmlElementExporter<Species, org.sbml.j createModificationGlyph(mr, speciesGlyph); } } + if (element.getStructuralState() != null) { + createStructuralStateGlyph(element, speciesGlyph); + } } TextGlyph textGlyph = getLayout().createTextGlyph("text_" + element.getElementId(), element.getName()); textGlyph @@ -484,6 +492,44 @@ public class SbmlSpeciesExporter extends SbmlElementExporter<Species, org.sbml.j } + private void createStructuralStateGlyph(Species element, AbstractReferenceGlyph speciesGlyph) { + org.sbml.jsbml.Species sbmlSpecies = getSbmlModel().getSpecies(speciesGlyph.getReference()); + + MultiSpeciesPlugin speciesExtension = (MultiSpeciesPlugin) sbmlSpecies.getExtension("multi"); + + SpeciesFeatureType structuralStateFeature = getFeature(element.getClass(), getMultiSpeciesType(element), + BioEntityFeature.STRUCTURAL_STATE); + + PossibleSpeciesFeatureValue possibleSpeciesFeatureValue = getPosibleFeatureIdByName( + element.getStructuralState().getValue(), structuralStateFeature); + + SpeciesFeature feature = null; + for (SpeciesFeature existingFeature : speciesExtension.getListOfSpeciesFeatures()) { + if (existingFeature.getSpeciesFeatureType().equals(structuralStateFeature.getId())) { + feature = existingFeature; + } + } + + SpeciesFeatureValue modificationFeatureValue = null; + for (SpeciesFeatureValue featureValue : feature.getListOfSpeciesFeatureValues()) { + if (possibleSpeciesFeatureValue.getId().equals(featureValue.getValue())) { + modificationFeatureValue = featureValue; + } + } + + modificationFeatureValue.setId(getStructuralStateUniqueId(element.getStructuralState())); + + GeneralGlyph modificationGlyph = getLayout().createGeneralGlyph("structural_state_" + (idCounter++), + modificationFeatureValue.getId()); + ReferenceGlyph referenceGlyph = new ReferenceGlyph("structural_state_reference_" + (idCounter++)); + referenceGlyph.setGlyph(speciesGlyph.getId()); + referenceGlyph.setBoundingBox(createBoundingBoxForStructuralState(element.getStructuralState())); + + modificationGlyph.addReferenceGlyph(referenceGlyph); + modificationGlyph.setBoundingBox(createBoundingBoxForStructuralState(element.getStructuralState())); + + } + @SuppressWarnings("unchecked") private MultiSpeciesType createSpeciesTypeForClass(MultiModelPlugin multiPlugin, Class<? extends Element> clazz) { MultiSpeciesType speciesType = new MultiSpeciesType(); @@ -560,6 +606,20 @@ public class SbmlSpeciesExporter extends SbmlElementExporter<Species, org.sbml.j modificationGlyph.setBoundingBox(createBoundingBoxForModification(mr)); } + private BoundingBox createBoundingBoxForStructuralState(StructuralState structuralState) { + double width = structuralState.getWidth(); + double height = structuralState.getHeight(); + double x = structuralState.getPosition().getX(); + double y = structuralState.getPosition().getY(); + BoundingBox boundingBox = new BoundingBox(); + boundingBox.setPosition(new Point(x, y, structuralState.getSpecies().getZ() + 1)); + Dimensions dimensions = new Dimensions(); + dimensions.setWidth(width); + dimensions.setHeight(height); + boundingBox.setDimensions(dimensions); + return boundingBox; + } + private BoundingBox createBoundingBoxForModification(ModificationResidue mr) { double width, height; if (mr instanceof AbstractRegionModification) { @@ -592,4 +652,15 @@ public class SbmlSpeciesExporter extends SbmlElementExporter<Species, org.sbml.j return result; } + private String getStructuralStateUniqueId(StructuralState mr) { + String modificationId = "structural_state_" + getSbmlIdKey(mr.getSpecies()); + String result = modificationResidueIds.get(modificationId); + if (result == null) { + result = "structural_state_" + (structuralStateCounter++); + modificationResidueIds.put(modificationId, result); + } + return result; + + } + } diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesParser.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesParser.java index d6c62603e5..7a98e43eea 100644 --- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesParser.java +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesParser.java @@ -2,8 +2,7 @@ package lcsb.mapviewer.converter.model.sbml.species; import java.awt.geom.Point2D; import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.List; +import java.util.*; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -31,6 +30,8 @@ public class SbmlSpeciesParser extends SbmlElementParser<org.sbml.jsbml.Species> private static String ARTIFITIAL_SOURCE_ID = "sbml_artifitial_source"; Logger logger = LogManager.getLogger(SbmlSpeciesParser.class); + Map<String, String> structuralStateIdMap = new HashMap<>(); + public SbmlSpeciesParser(Model model, lcsb.mapviewer.model.map.model.Model minervaModel) { super(model, minervaModel); } @@ -65,13 +66,20 @@ public class SbmlSpeciesParser extends SbmlElementParser<org.sbml.jsbml.Species> String featureTypeString = feature.getSpeciesFeatureType(); List<String> featureValues = getFeatureValues(speciesType, feature); if (MultiPackageNamingUtils.isFeatureId(featureTypeString, BioEntityFeature.STRUCTURAL_STATE)) { + String structuralStateId = null; + for (SpeciesFeatureValue featureValue : feature.getListOfSpeciesFeatureValues()) { + if (featureValue.getId() != null) { + structuralStateId = featureValue.getId(); + } + } if (minervaElement instanceof Protein) { - ((Protein) minervaElement).setStructuralState(String.join("; ", featureValues)); + minervaElement.setStructuralState(createStructuralState(featureValues)); } else if (minervaElement instanceof Complex) { - ((Complex) minervaElement).setStructuralState(String.join("; ", featureValues)); + minervaElement.setStructuralState(createStructuralState(featureValues)); } else { logger.warn(warnPrefix + "Structural state not supported"); } + structuralStateIdMap.put(minervaElement.getElementId(), structuralStateId); } else if (MultiPackageNamingUtils.isFeatureId(featureTypeString, BioEntityFeature.POSITION_TO_COMPARTMENT)) { if (featureValues.size() != 1) { logger.warn(warnPrefix + "Position to compartment must have exactly one value"); @@ -161,6 +169,12 @@ public class SbmlSpeciesParser extends SbmlElementParser<org.sbml.jsbml.Species> } } + private StructuralState createStructuralState(List<String> featureValues) { + StructuralState structuralState = new StructuralState(); + structuralState.setValue(String.join("; ", featureValues)); + return structuralState; + } + private List<String> getFeatureValues(MultiSpeciesType speciesType, SpeciesFeature feature) { SpeciesFeatureType featureType = speciesType.getListOfSpeciesFeatureTypes().get(feature.getSpeciesFeatureType()); @@ -320,7 +334,29 @@ public class SbmlSpeciesParser extends SbmlElementParser<org.sbml.jsbml.Species> // find a reference to the alias in layout, so we know it's the proper value ReferenceGlyph referenceGlyph = ((GeneralGlyph) graphicalObject).getListOfReferenceGlyphs().get(0); if (Objects.equal(referenceGlyph.getGlyph(), mr.getSpecies().getElementId())) { -// if (referenceGlyph.getGlyph().equals(mr.getSpecies().getElementId())) { + // if (referenceGlyph.getGlyph().equals(mr.getSpecies().getElementId())) { + residueGlyph = (GeneralGlyph) graphicalObject; + } + } else { + residueGlyph = (GeneralGlyph) graphicalObject; + } + } + } + } + return residueGlyph; + } + + private GeneralGlyph getResidueGlyphForStructuralState(StructuralState mr) { + GeneralGlyph residueGlyph = null; + String structurlaStateId = structuralStateIdMap.get(mr.getSpecies().getElementId()); + for (GraphicalObject graphicalObject : getLayout().getListOfAdditionalGraphicalObjects()) { + if (graphicalObject instanceof GeneralGlyph) { + if (Objects.equal(((GeneralGlyph) graphicalObject).getReference(), structurlaStateId)) { + if (((GeneralGlyph) graphicalObject).getListOfReferenceGlyphs().size() > 0) { + // find a reference to the alias in layout, so we know it's the proper value + ReferenceGlyph referenceGlyph = ((GeneralGlyph) graphicalObject).getListOfReferenceGlyphs().get(0); + if (Objects.equal(referenceGlyph.getGlyph(), mr.getSpecies().getElementId())) { + // if (referenceGlyph.getGlyph().equals(mr.getSpecies().getElementId())) { residueGlyph = (GeneralGlyph) graphicalObject; } } else { @@ -366,21 +402,54 @@ public class SbmlSpeciesParser extends SbmlElementParser<org.sbml.jsbml.Species> for (Element element : result) { String compartmentId = null; + String speciesId = element.getElementId(); if (getLayout().getSpeciesGlyph(element.getElementId()) != null) { compartmentId = ((org.sbml.jsbml.Species) getLayout().getSpeciesGlyph(element.getElementId()) .getSpeciesInstance()).getCompartment(); + speciesId = ((org.sbml.jsbml.Species) getLayout().getSpeciesGlyph(element.getElementId()).getSpeciesInstance()) + .getId(); } else { if (!element.getElementId().equals(ARTIFITIAL_SINK_ID) && !element.getElementId().equals(ARTIFITIAL_SOURCE_ID)) { compartmentId = getSbmlModel().getSpecies(element.getElementId()).getCompartment(); } } + structuralStateIdMap.put(element.getElementId(), structuralStateIdMap.get(speciesId)); assignCompartment(element, compartmentId); assignModificationResiduesLayout(element); + assignStructuralStateLayout(element); } return result; } + private void assignStructuralStateLayout(Element element) { + if (element instanceof Protein || element instanceof Complex) { + StructuralState state = ((Species) element).getStructuralState(); + if (state != null) { + state.setFontSize(10); + state.setHeight(20); + state.setWidth(element.getWidth()); + state.setPosition(new Point2D.Double(element.getX(), element.getY() - 10)); + GeneralGlyph residueGlyph = getResidueGlyphForStructuralState(state); + if (residueGlyph != null) { + if (residueGlyph.getBoundingBox() == null || residueGlyph.getBoundingBox().getDimensions() == null) { + logger.warn( + new ElementUtils().getElementTag(element) + " Layout doesn't contain coordinates for structural state"); + } else { + double width = residueGlyph.getBoundingBox().getDimensions().getWidth(); + double height = residueGlyph.getBoundingBox().getDimensions().getHeight(); + double x = residueGlyph.getBoundingBox().getPosition().getX(); + double y = residueGlyph.getBoundingBox().getPosition().getY(); + state.setPosition(new Point2D.Double(x, y)); + state.setWidth(width); + state.setHeight(height); + } + } + + } + } + } + @Override protected void applyStyleToElement(Element elementWithLayout, LocalStyle style) { super.applyStyleToElement(elementWithLayout, style); diff --git a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlExporterTest.java b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlExporterTest.java index 145e36e21b..6a2c07c771 100644 --- a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlExporterTest.java +++ b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlExporterTest.java @@ -3,7 +3,6 @@ package lcsb.mapviewer.converter.model.sbml; import static org.junit.Assert.*; import java.awt.Color; -import java.awt.geom.Line2D; import java.awt.geom.Point2D; import java.io.File; import java.lang.reflect.Modifier; @@ -17,7 +16,6 @@ import org.sbml.jsbml.SBMLDocument; import org.sbml.jsbml.ext.multi.*; import lcsb.mapviewer.common.Configuration; -import lcsb.mapviewer.common.comparator.LineComparator; import lcsb.mapviewer.common.comparator.ListComparator; import lcsb.mapviewer.converter.ConverterParams; import lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser; @@ -397,7 +395,7 @@ public class SbmlExporterTest extends SbmlTestFunctions { public void testExportProteinState() throws Exception { Model model = createEmptyModel(); GenericProtein element = createProtein(); - element.setStructuralState("xxx"); + element.setStructuralState(createStructuralState(element)); model.addElement(element); Model deserializedModel = getModelAfterSerializing(model); @@ -430,9 +428,9 @@ public class SbmlExporterTest extends SbmlTestFunctions { @Test public void testMultiExtensionProteinStateInTypes() throws Exception { - String structuralState = "xxx"; Model model = createEmptyModel(); GenericProtein element = createProtein(); + StructuralState structuralState = createStructuralState(element); element.setStructuralState(structuralState); model.addElement(element); org.sbml.jsbml.Model sbmlModel = exporter.toSbmlDocument(model).getModel(); @@ -442,7 +440,7 @@ public class SbmlExporterTest extends SbmlTestFunctions { for (MultiSpeciesType speciesType : multiPlugin.getListOfSpeciesTypes()) { for (SpeciesFeatureType featureType : speciesType.getListOfSpeciesFeatureTypes()) { for (PossibleSpeciesFeatureValue featureValue : featureType.getListOfPossibleSpeciesFeatureValues()) { - if (featureValue.getName().equals(structuralState)) { + if (featureValue.getName().equals(structuralState.getValue())) { structuralStateValueFound = true; } } @@ -454,13 +452,12 @@ public class SbmlExporterTest extends SbmlTestFunctions { @Test public void testMultiExtensionProteinStateSuplicateInTypes() throws Exception { - String structuralState = "xxx"; Model model = createEmptyModel(); GenericProtein element = createProtein(); - element.setStructuralState(structuralState); + element.setStructuralState(createStructuralState(element)); model.addElement(element); element = createProtein(); - element.setStructuralState(structuralState); + element.setStructuralState(createStructuralState(element)); model.addElement(element); org.sbml.jsbml.Model sbmlModel = exporter.toSbmlDocument(model).getModel(); MultiModelPlugin multiPlugin = (MultiModelPlugin) sbmlModel.getExtension("multi"); @@ -498,9 +495,9 @@ public class SbmlExporterTest extends SbmlTestFunctions { @Test public void testMultiExtensionStructuralStateTypeDefinition() throws Exception { - String structuralState = "xxx"; Model model = createEmptyModel(); GenericProtein element = createProtein(); + StructuralState structuralState = createStructuralState(element); element.setStructuralState(structuralState); model.addElement(element); org.sbml.jsbml.Model sbmlModel = exporter.toSbmlDocument(model).getModel(); @@ -512,6 +509,16 @@ public class SbmlExporterTest extends SbmlTestFunctions { speciesExtension.getListOfSpeciesFeatures().size() > 0); } + private StructuralState createStructuralState(Element element) { + StructuralState structuralState = new StructuralState(); + structuralState.setValue("xxx"); + structuralState.setPosition(new Point2D.Double(element.getX(), element.getY() - 10)); + structuralState.setWidth(element.getWidth()); + structuralState.setHeight(20.0); + structuralState.setFontSize(10.0); + return structuralState; + } + @Test public void testExportResidue() throws Exception { Model model = createEmptyModel(); diff --git a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesExporterTest.java b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesExporterTest.java index 190972f434..caa0240f2b 100644 --- a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesExporterTest.java +++ b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/species/SbmlSpeciesExporterTest.java @@ -18,6 +18,7 @@ import lcsb.mapviewer.model.map.compartment.Compartment; import lcsb.mapviewer.model.map.model.Model; import lcsb.mapviewer.model.map.model.ModelFullIndexed; import lcsb.mapviewer.model.map.species.*; +import lcsb.mapviewer.model.map.species.field.StructuralState; public class SbmlSpeciesExporterTest extends SbmlTestFunctions { @@ -84,7 +85,9 @@ public class SbmlSpeciesExporterTest extends SbmlTestFunctions { public void testIdsOfSpeciesWithStructuralStates() throws InconsistentModelException { Species protein1 = createProtein(); Protein protein2 = createProtein(); - protein2.setStructuralState("X"); + StructuralState state = new StructuralState(); + state.setValue("X"); + protein2.setStructuralState(state); Model model = new ModelFullIndexed(null); model.addElement(protein1); model.addElement(protein2); -- GitLab