private boolean isDiseaseObject(Renderable r, Set<Long> diseaseIds) { if (r instanceof FlowLine) { FlowLine fl = (FlowLine) r; return isFlowLineRelatedToSet(fl, diseaseIds); } // Assume normal objects only: this is a very strong assumption if (r.getReactomeId() == null) return false; // A PE may be represented multiple times in a pathway diagram. Some of them // are linked to normal reactions, and some linked to disease reactions. // Have to check these cases. if (r instanceof HyperEdge) return diseaseIds.contains(r.getReactomeId()); if (r instanceof Node) { Node node = (Node) r; List<HyperEdge> edges = node.getConnectedReactions(); boolean isDisease = false; for (HyperEdge edge : edges) { if (edge instanceof FlowLine) { isDisease = isFlowLineRelatedToSet((FlowLine) edge, diseaseIds); } else if (edge.getReactomeId() != null && diseaseIds.contains(edge.getReactomeId())) { isDisease = true; } if (isDisease) return true; } } return false; }
public void randomlyMapDiseaseNodesToNormalNodes( Map<Node, GKInstance> normalToDiseaseEntity, Collection<GKInstance> mapped, List<GKInstance> diseaseInputs, List<Node> normalNodes) { if (diseaseInputs != null && diseaseInputs.size() > 0) { normalNodes.removeAll(normalToDiseaseEntity.keySet()); if (normalNodes.size() > 0) { for (GKInstance input : diseaseInputs) { // if (mapped.contains(input)) if (contains(input, mapped)) continue; // it has been mapped already // Check if it has been used based on DB_ID Node matched = null; for (Node node : normalNodes) { if (node.getReactomeId().equals(input.getDBID())) { matched = node; break; } } if (matched == null) // Just pick up the first node matched = normalNodes.get(0); normalToDiseaseEntity.put(matched, input); normalNodes.remove(matched); if (normalNodes.size() == 0) break; } } } }
private boolean isNormalObject(Renderable r, Set<Long> normalIds) { if (r instanceof HyperEdge) { if (r instanceof FlowLine) return isFlowLineRelatedToSet((FlowLine) r, normalIds); // Most likely the following statements should not be reached. But place // here just in case. if (r.getReactomeId() == null) return true; if (normalIds.contains(r.getReactomeId())) return true; } else if (r instanceof Node) { if (r instanceof ProcessNode) return true; // Should be used only for normal pathway. if (r.getReactomeId() == null) return true; // Check if it is linked to another disease entities Node node = (Node) r; List<HyperEdge> edges = node.getConnectedReactions(); boolean isNormal = false; for (HyperEdge edge : edges) { if (edge instanceof FlowLine) isNormal = isFlowLineRelatedToSet((FlowLine) edge, normalIds); if (isNormal) return true; if (edge.getReactomeId() != null && normalIds.contains(edge.getReactomeId())) return true; // Some special cases that use links if (!(edge instanceof EntitySetAndEntitySetLink) && !(edge instanceof EntitySetAndMemberLink) && edge.getReactomeId() == null) return true; } } return false; }
/** * Overlay a single disease reaction onto a normal reaction. * * @param normalReaction * @param diseaseReaction * @param overlaidObjects */ private void overlayDiseaseReaction(HyperEdge normalReaction, GKInstance diseaseReaction) throws Exception { // Make a copy of the HyperEdge for future process that is related to Vertex and JSON generation HyperEdge reactionCopy = normalReaction.shallowCopy(); reactionCopy.setReactomeId(diseaseReaction.getDBID()); reactionCopy.setDisplayName(diseaseReaction.getDisplayName()); reactionCopy.setLineColor(DefaultRenderConstants.DEFAULT_DISEASE_BACKGROUND); displayedObject.addComponent(reactionCopy); overlaidObjects.add(reactionCopy); // Want to handle inputs, outputs and catalysts since regulators can // be ignored List<Node> nodes = new ArrayList<Node>(); nodes.addAll(normalReaction.getInputNodes()); nodes.addAll(normalReaction.getOutputNodes()); nodes.addAll(normalReaction.getHelperNodes()); // List objects not listed in the disease reaction as crossed objects Set<GKInstance> participants = InstanceUtilities.getReactionParticipants(diseaseReaction); Set<Long> diseaseIds = new HashSet<Long>(); for (GKInstance participant : participants) { diseaseIds.add(participant.getDBID()); if (participant.getSchemClass().isValidAttribute(ReactomeJavaConstants.hasMember)) { List<GKInstance> list = participant.getAttributeValuesList(ReactomeJavaConstants.hasMember); if (list != null && list.size() > 0) { for (GKInstance inst : list) diseaseIds.add(inst.getDBID()); } } if (participant.getSchemClass().isValidAttribute(ReactomeJavaConstants.hasCandidate)) { List<GKInstance> list = participant.getAttributeValuesList(ReactomeJavaConstants.hasCandidate); if (list != null && list.size() > 0) { for (GKInstance inst : list) diseaseIds.add(inst.getDBID()); } } } Set<GKInstance> lofInstances = new HashSet<GKInstance>(); Map<Node, GKInstance> normalToDiseaseEntity = mapMutatedToNormalNodes(diseaseReaction, normalReaction, nodes, lofInstances); for (Node node : nodes) { if (!diseaseIds.contains(node.getReactomeId())) { // Check if it should be mapped to a normal entity GKInstance diseaseEntity = normalToDiseaseEntity.get(node); if (diseaseEntity == null) crossedObjects.add(node); // Just crossed out else { Node diseaseNode = replaceNormalNode(node, diseaseEntity, contains(diseaseEntity, lofInstances)); if (diseaseNode == null) continue; // Just in case // Re-link to diseaseNode ConnectInfo connectInfo = reactionCopy.getConnectInfo(); List<?> widgets = connectInfo.getConnectWidgets(); for (Object obj : widgets) { ConnectWidget widget = (ConnectWidget) obj; if (widget.getConnectedNode() == node) widget.replaceConnectedNode(diseaseNode); } } } else overlaidObjects.add(node); } }
/** * Map mutated nodes in a disease reaction to displayed nodes in a normal reaction. The mapping is * based on sharing of referenceEntity. This may not be reliable! * * @param diseaseReaction * @param nodes * @throws InvalidAttributeException * @throws Exception @TODO: add a new attribute normalEntity in the PhysicalEntity class. */ private Map<Node, GKInstance> mapMutatedToNormalNodes( GKInstance diseaseReaction, HyperEdge normalReaction, List<Node> nodes, Set<GKInstance> lofInstances) throws InvalidAttributeException, Exception { List<GKInstance> efs = diseaseReaction.getAttributeValuesList(ReactomeJavaConstants.entityFunctionalStatus); // Map mutated entities to normal entities via ReferenceGeneProduct Map<Node, GKInstance> normalToDiseaseEntity = new HashMap<Node, GKInstance>(); if (efs == null) return normalToDiseaseEntity; for (GKInstance ef : efs) { GKInstance pe = (GKInstance) ef.getAttributeValue(ReactomeJavaConstants.physicalEntity); if (pe != null) { Set<GKInstance> refEntities = getReferenceEntity(pe); // want to find the matched node for (Node node : nodes) { if (node.getReactomeId() == null) continue; GKInstance nodeInst = adaptor.fetchInstance(node.getReactomeId()); Set<GKInstance> nodeRefEntities = getReferenceEntity(nodeInst); nodeRefEntities.retainAll(refEntities); if (nodeRefEntities.size() > 0) { normalToDiseaseEntity.put(node, pe); if (isLOFEntity(ef)) { lofInstances.add(pe); } break; } } } } // TODO: May have to consider stoichiometries too!!! // In gain of functions, some inputs or outputs may not be used by normal reactions. // This method will do its best to map these reaction participants Collection<GKInstance> mapped = normalToDiseaseEntity.values(); // First check inputs List<GKInstance> diseaseInputs = diseaseReaction.getAttributeValuesList(ReactomeJavaConstants.input); List<Node> normalNodes = normalReaction.getInputNodes(); randomlyMapDiseaseNodesToNormalNodes(normalToDiseaseEntity, mapped, diseaseInputs, normalNodes); // Check outputs List<GKInstance> diseaseOutputs = diseaseReaction.getAttributeValuesList(ReactomeJavaConstants.output); normalNodes = normalReaction.getOutputNodes(); randomlyMapDiseaseNodesToNormalNodes( normalToDiseaseEntity, mapped, diseaseOutputs, normalNodes); // Check helpers GKInstance ca = (GKInstance) diseaseReaction.getAttributeValue(ReactomeJavaConstants.catalystActivity); if (ca != null) { List<GKInstance> catalysts = ca.getAttributeValuesList(ReactomeJavaConstants.physicalEntity); normalNodes = normalReaction.getHelperNodes(); randomlyMapDiseaseNodesToNormalNodes(normalToDiseaseEntity, mapped, catalysts, normalNodes); } return normalToDiseaseEntity; }
/** * If a FlowLine connects two normal object, it should be a normal object. Otherwise, it should be * a disease object. * * @param flowLine * @param ids * @return */ private boolean isFlowLineRelatedToSet(FlowLine flowLine, Set<Long> ids) { Node input = flowLine.getInputNode(0); Node output = flowLine.getOutputNode(0); if (input != null && (ids.contains(input.getReactomeId()) || input instanceof ProcessNode) && // ProcessNode should be used in normal pathway only output != null && (ids.contains(output.getReactomeId()) || output instanceof ProcessNode)) return true; // if (output != null && normalIds.contains(output.getReactomeId())) // return true; return false; }
private void drawCrosses(Graphics g, List<Node> nodes, Rectangle clip) { Graphics2D g2 = (Graphics2D) g; Stroke oldStroke = g2.getStroke(); Stroke stroke = new BasicStroke(DefaultRenderConstants.DEFAULT_RED_CROSS_WIDTH); g2.setStroke(stroke); Paint oldPaint = g2.getPaint(); g2.setColor(Color.RED); for (Node node : nodes) { Rectangle r = node.getBounds(); if (!clip.intersects(r)) continue; g2.drawLine(r.x, r.y, r.x + r.width, r.y + r.height); g2.drawLine(r.x, r.y + r.height, r.x + r.width, r.y); } g2.setStroke(oldStroke); g2.setPaint(oldPaint); }
private Node replaceNormalNode( Node normalNode, GKInstance diseaseEntity, Boolean needDashedBorder) { Node diseaseNode = normalToDiseaseNode.get(normalNode); if (diseaseNode != null) return diseaseNode; try { // If a node exists already, it should use for (Renderable r : diseaseComps) { if (diseaseEntity.getDBID().equals(r.getReactomeId()) && r instanceof Node) { // This is rather arbitrary: if two nodes are very close, // use the existing one. int dx = Math.abs(r.getPosition().x - normalNode.getPosition().x); int dy = Math.abs(r.getPosition().y - normalNode.getPosition().y); if (dx < 10 && dy < 10) { // We don't need to create a new Node if it exists already normalToDiseaseNode.put(normalNode, (Node) r); overlaidObjects.add(r); // Add it to overlaid object to cover edges return (Node) r; } } } diseaseNode = normalNode.getClass().newInstance(); RenderUtility.copyRenderInfo(normalNode, diseaseNode); // The following should NOT be called since NodeAttachment is // related to disease entity only. // TODO: Need to support this. Currently it is not supported!!! See example // in PI3/AKT cancer pathway. // diseaseNode.setNodeAttachmentsLocally(node.getNodeAttachments()); diseaseNode.setDisplayName(diseaseEntity.getDisplayName()); diseaseNode.setReactomeId(diseaseEntity.getDBID()); diseaseNode.invalidateBounds(); diseaseNode.setRenderer(normalNode.getRenderer()); diseaseNode.setLineColor(DefaultRenderConstants.DEFAULT_DISEASE_BACKGROUND); diseaseNode.setNeedDashedBorder(needDashedBorder); RenderUtility.hideCompartmentInNodeName(diseaseNode); overlaidObjects.add(diseaseNode); displayedObject.addComponent(diseaseNode); normalToDiseaseNode.put(normalNode, diseaseNode); return diseaseNode; } catch (Exception e) { e.printStackTrace(); } return null; }
private void checkLossOfFunctionNodes() { try { lofNodes = new ArrayList<Node>(); List<Renderable> components = displayedObject.getComponents(); if (components == null || components.size() == 0) return; for (Renderable r : components) { if (r instanceof Node || r.getReactomeId() == null) continue; if (!diseaseIds.contains(r.getReactomeId())) continue; GKInstance inst = adaptor.fetchInstance(r.getReactomeId()); if (!inst.getSchemClass().isa(ReactomeJavaConstants.ReactionlikeEvent) || !inst.getSchemClass().isValidAttribute(ReactomeJavaConstants.entityFunctionalStatus)) continue; List<GKInstance> efs = inst.getAttributeValuesList(ReactomeJavaConstants.entityFunctionalStatus); Set<GKInstance> lofPEs = new HashSet<GKInstance>(); for (GKInstance ef : efs) { GKInstance pe = (GKInstance) ef.getAttributeValue(ReactomeJavaConstants.physicalEntity); if (isLOFEntity(ef)) lofPEs.add(pe); } List<Node> nodes = ((HyperEdge) r).getConnectedNodes(); for (Node node : nodes) { if (node.getReactomeId() == null) continue; GKInstance nodeInst = adaptor.fetchInstance(node.getReactomeId()); Set<GKInstance> nodeRefEntities = getReferenceEntity(nodeInst); for (GKInstance lofPE : lofPEs) { Set<GKInstance> lofRefEntities = getReferenceEntity(lofPE); lofRefEntities.retainAll(nodeRefEntities); if (lofRefEntities.size() > 0) { // A LOF node lofNodes.add(node); break; } } } } } catch (Exception e) { e.printStackTrace(); } }
private void drawComponents( Graphics g, List<Renderable> comps, Rectangle clip, boolean drawEdgeFirst) { List<HyperEdge> edges = new ArrayList<HyperEdge>(); for (Renderable obj : comps) { if (obj instanceof HyperEdge) edges.add((HyperEdge) obj); } if (drawEdgeFirst) { // Draw HyperEdges for (HyperEdge reaction : edges) { // Have to validate connect nodes first in case empty bounds List<Node> nodes = reaction.getConnectedNodes(); for (Node node : nodes) node.validateBounds(g); reaction.validateConnectInfo(); if (clip.intersects(reaction.getBounds())) reaction.render(g); } } // Draw complexes now drawComplexes(comps, clip, g); for (Renderable obj : comps) { if (obj instanceof RenderableCompartment || obj instanceof RenderableComplex || obj instanceof RenderablePathway) continue; // Escape it. It should be drawn earlier. if (obj instanceof Node) { Node node = (Node) obj; if (getHidePrivateNote() && (node instanceof Note) && ((Note) node).isPrivate()) continue; node.validateBounds(g); if (clip.intersects(node.getBounds())) node.render(g); } } if (!drawEdgeFirst) { // Draw HyperEdges for (HyperEdge reaction : edges) { reaction.validateConnectInfo(); if (clip.intersects(reaction.getBounds())) reaction.render(g); } } }
@Override public void paint(Graphics g) { // Clear the editor Graphics2D g2 = (Graphics2D) g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); // In case g is provided by other graphics context (e.g during exporting) g2.setFont(getFont()); g2.setBackground(background); Dimension size = getPreferredSize(); g2.clearRect(0, 0, size.width, size.height); // TODO: Delete the follow two statements. For test only // g2.setPaint(Color.yellow); // g2.fillRect(0, 0, size.width, size.height); // Enable zooming g2.scale(scaleX, scaleY); List comps = displayedObject.getComponents(); // Draw nodes first if (comps == null || comps.size() == 0) return; java.util.List edges = new ArrayList(); Rectangle clip = g.getClipBounds(); // Draw Compartments first List<RenderableCompartment> compartments = drawCompartments(g, comps, null, clip); drawComponents(g, normalComps, clip); if (isForNormal) { // Replace the original components with new set of Renderable objects for further processing RenderablePathway pathway = (RenderablePathway) displayedObject; List<Renderable> components = pathway.getComponents(); components.clear(); components.addAll(normalComps); components.addAll(compartments); // Don't forget them return; } // Draw a transparent background: light grey Color color = new Color(204, 204, 204, 175); g2.setPaint(color); // Dimension size = getPreferredSize(); // Preferred size has been scaled. Need to scale it back g2.fillRect(0, 0, (int) (size.width / scaleX + 1.0d), (int) (size.height / scaleY + 1.0d)); // Draw disease related objects for (Renderable r : diseaseComps) { if (lofNodes.contains(r)) ((Node) r).setNeedDashedBorder(true); } drawComponents(g, diseaseComps, clip); if (overlaidObjects.size() > 0) drawComponents( g, overlaidObjects, clip, true); // Want to draw edge first so that no validation is needed. if (crossedObjects.size() > 0) drawCrosses(g, crossedObjects, clip); RenderablePathway pathway = (RenderablePathway) displayedObject; pathway.setBgComponents(new ArrayList<Renderable>(normalComps)); List<Renderable> fgComps = new ArrayList<Renderable>(); fgComps.addAll(diseaseComps); fgComps.addAll(overlaidObjects); // Don't want to place compartments and pathway for (Iterator<Renderable> it = fgComps.iterator(); it.hasNext(); ) { Renderable r = it.next(); if (r instanceof RenderableCompartment || r instanceof RenderablePathway) it.remove(); } pathway.setFgComponents(fgComps); }