package org.bridgedb.cytoscape.internal; /******************************************************************************* * Copyright 2010-2013 BridgeDb App developing team * * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. ******************************************************************************/ import org.bridgedb.cytoscape.internal.util.DataSourceWrapper; import org.bridgedb.cytoscape.internal.util.IDMapperWrapper; import org.bridgedb.cytoscape.internal.util.XrefWrapper; import org.cytoscape.model.CyColumn; import org.cytoscape.model.CyNetwork; import org.cytoscape.model.CyNode; import org.cytoscape.model.CyRow; import org.cytoscape.work.TaskMonitor; import org.cytoscape.model.CyTable; import java.util.*; public class AttributeBasedIDMappingImpl implements AttributeBasedIDMapping{ protected TaskMonitor taskMonitor; protected boolean interrupted; protected Map<String,Class<?>> attrNameType = null; protected IDMapperClientManager idMapperClientManager; protected IDMapperWrapper idMapperWrapper; protected String report; public AttributeBasedIDMappingImpl(TaskMonitor taskMonitor, IDMapperClientManager idMapperClientManager) { this.taskMonitor = taskMonitor; idMapperWrapper = new IDMapperWrapper(idMapperClientManager); } public void setTaskMonitor(TaskMonitor taskMonitor) { this.taskMonitor = taskMonitor; interrupted = false; } @Override public void interrupt() { interrupted = true; taskMonitor.showMessage(TaskMonitor.Level.ERROR, "ID mapping cancelled. Not all IDs were mapped."); } @Override public String getReport() { return report; } /** * Define target attributes. * Call this method first before mapping if necessary. * @param attrNameType */ private void defineTgtAttrs(CyNetwork network, Map<String,Class<?>> attrNameType) { this.attrNameType = attrNameType; CyTable cyTable = network.getDefaultNodeTable(); for (Map.Entry<String,Class<?>> entry : attrNameType.entrySet()) { String attrname = entry.getKey(); Class<?> attrtype = entry.getValue(); if (null != cyTable.getColumn(attrname)) { cyTable.deleteColumn(attrname); } // if not exist if (attrtype == List.class) { cyTable.createListColumn(attrname, String.class, false); } else { cyTable.createColumn(attrname, attrtype, false); } } } /** * {@inheritDoc} */ public void map(CyNetwork network, Map<String,Set<DataSourceWrapper>> mapSrcAttrIDTypes, Map<String, DataSourceWrapper> mapTgtAttrNameIDType, Map<String,Class<?>> attrNameType, int srcXrefsPerBatch) { // prepare source xrefs List<CyNode> nodes = network.getNodeList(); CyTable table = network.getDefaultNodeTable(); updateTaskMonitor("Preparing source cross references...", -1.0); Map<CyNode,Set<XrefWrapper>> mapNodeSrcXrefs = prepareNodeSrcXrefs(table, nodes, mapSrcAttrIDTypes); List<XrefWrapper> srcXrefs = srcXrefUnion(mapNodeSrcXrefs); // target id types Set<DataSourceWrapper> tgtTypes = new HashSet(mapTgtAttrNameIDType.values()); // id mapping String msg = attributesSelected(mapSrcAttrIDTypes) ? "This may take minutes or longer to finish since attributes were selected as source type. Mapping IDs...\n" : "Mapping IDs... "; Map<XrefWrapper, Set<XrefWrapper>> mapping; if (srcXrefsPerBatch==-1) { mapping = idMapperWrapper.mapID(srcXrefs, tgtTypes); } else { mapping = new HashMap<XrefWrapper, Set<XrefWrapper>>(); int batches = (int)Math.ceil(1.0*srcXrefs.size()/srcXrefsPerBatch); for (int batch=0; batch<batches; batch++) { int start = batch*srcXrefsPerBatch; int end = batch==batches-1 ? srcXrefs.size() : (batch+1)*srcXrefsPerBatch; updateTaskMonitor(msg + (start+1) + "/" +srcXrefs.size() + " source identifiers", 1.0*(start+1)/srcXrefs.size()); mapping.putAll(idMapperWrapper.mapID(srcXrefs.subList(start, end), tgtTypes)); if (interrupted) { break; } } } // define target attributes defineTgtAttrs(network, attrNameType); // set target attribute updateTaskMonitor("Set target column...", -1.0); Map<CyNode,Set<XrefWrapper>> mapNodeTgtXrefs = getNodeTgtXrefs(mapNodeSrcXrefs, mapping); setTgtAttribute(table, mapNodeTgtXrefs, mapTgtAttrNameIDType); if (mapNodeTgtXrefs.isEmpty() && !nodes.isEmpty()) { report = "No IDs were mapped. Please make sure you seleceted the corrected ID mapping resources and source ID types."; updateTaskMonitor(report, 1.0, true); } else { report = "Identifiers mapped for "+mapNodeTgtXrefs.size()+" nodes (out of "+nodes.size()+")."; updateTaskMonitor(report,1.0); } } private boolean attributesSelected(Map<String,Set<DataSourceWrapper>> mapSrcAttrIDTypes) { for (Set<DataSourceWrapper> dsws : mapSrcAttrIDTypes.values()) { for (DataSourceWrapper dsw : dsws) { if (dsw.getDsAttr() == DataSourceWrapper.DsAttr.ATTRIBUTE) { return true; } } } return false; } private Map<CyNode,Set<XrefWrapper>> prepareNodeSrcXrefs(CyTable nodeTable, Collection<CyNode> nodes, Map<String,Set<DataSourceWrapper>> mapSrcAttrIDTypes) { Map<CyNode,Set<XrefWrapper>> ret = new HashMap(); // int nNode = nodes.size(); // int i=0; for (CyNode node : nodes) { // if (interrupted) return null; // updateTaskMonitor("Preparing cross reference for nodes...\n"+i+"/"+nNode,(i+1)*100/nNode); // i++; Set<XrefWrapper> xrefs = new HashSet(); ret.put(node, xrefs); CyRow cyRow = nodeTable.getRow(node.getSUID()); for (Map.Entry<String,Set<DataSourceWrapper>> entryAttrIDTypes : mapSrcAttrIDTypes.entrySet()) { String attrName = entryAttrIDTypes.getKey(); Set<DataSourceWrapper> dss = entryAttrIDTypes.getValue(); CyColumn cyColumn = nodeTable.getColumn(attrName); if (cyColumn.getType() == List.class) { List attr = cyRow.get(cyColumn.getName(), List.class); if (attr!=null) { for (Object obj : attr) { String str = obj.toString(); for (DataSourceWrapper ds : dss) { xrefs.add(new XrefWrapper(str, ds)); } } } } else { Object obj = cyRow.get(cyColumn.getName(), cyColumn.getType()); if (obj!=null) { String str = obj.toString(); if (str.length()>0) { for (DataSourceWrapper ds : dss) { xrefs.add(new XrefWrapper(str, ds)); } } } } } } return ret; } private List<XrefWrapper> srcXrefUnion(Map<CyNode,Set<XrefWrapper>> mapNodeSrcXrefs) { Set<XrefWrapper> ret = new HashSet(); for (Set<XrefWrapper> xrefs : mapNodeSrcXrefs.values()) { ret.addAll(xrefs); } return new ArrayList<XrefWrapper>(ret); } private Map<CyNode,Set<XrefWrapper>> getNodeTgtXrefs (Map<CyNode,Set<XrefWrapper>> mapNodeSrcXrefs, Map<XrefWrapper, Set<XrefWrapper>> idMapping) { Map<CyNode,Set<XrefWrapper>> mapNodeTgtXrefs = new HashMap(); for (Map.Entry<CyNode,Set<XrefWrapper>> entryNodeXrefs : mapNodeSrcXrefs.entrySet()) { CyNode node = entryNodeXrefs.getKey(); Set<XrefWrapper> tgtXrefs = new HashSet(); Set<XrefWrapper> srcXrefs = entryNodeXrefs.getValue(); //TODO: deal with ambiguity--same node, same attribute, different data source for (XrefWrapper srcXref : srcXrefs) { Set<XrefWrapper> xrefs = idMapping.get(srcXref); if (xrefs!=null) { tgtXrefs.addAll(xrefs); } } if (!tgtXrefs.isEmpty()) mapNodeTgtXrefs.put(node, tgtXrefs); } return mapNodeTgtXrefs; } private void setTgtAttribute(CyTable nodeTable, Map<CyNode,Set<XrefWrapper>> mapNodeTgtXrefs, Map<String, DataSourceWrapper> mapTgtAttrNameIDType) { Map<DataSourceWrapper, Set<String>> mapIDTypeAttrName = new HashMap(); for (String attrName : mapTgtAttrNameIDType.keySet()) { DataSourceWrapper idType = mapTgtAttrNameIDType.get(attrName); Set<String> names = mapIDTypeAttrName.get(idType); if (names==null) { names = new HashSet(); mapIDTypeAttrName.put(idType, names); } names.add(attrName); } // int i = 0; for (Map.Entry<CyNode,Set<XrefWrapper>> entryNodeXrefs : mapNodeTgtXrefs.entrySet()) { // if (interrupted) return; // if (++i%100==0) { // updateTaskMonitor("Preparing cross reference for nodes...\n"+i+"/"+nNode,(i+1)*100/nNode); // } // type wise Map<DataSourceWrapper, Set<String>> mapDsIds = new HashMap(); Set<XrefWrapper> tgtXrefs = entryNodeXrefs.getValue(); for (XrefWrapper xref : tgtXrefs) { DataSourceWrapper ds = xref.getDataSource(); Set<String> ids = mapDsIds.get(ds); if (ids==null) { ids = new TreeSet(); // alphabetically mapDsIds.put(ds, ids); } ids.add(xref.getValue()); } // set attribute CyNode node = entryNodeXrefs.getKey(); CyRow cyRow = nodeTable.getRow(node.getSUID()); for (Map.Entry<DataSourceWrapper, Set<String>> entryDsIds : mapDsIds.entrySet()) { DataSourceWrapper ds = entryDsIds.getKey(); Set<String> attrNames = mapIDTypeAttrName.get(ds); if (attrNames==null) { // TODO: what happened? continue; } for (String attrName : attrNames) { Class attrType = nodeTable.getColumn(attrName).getType(); Set<String> ids = entryDsIds.getValue(); if (attrType==List.class) { List<String> values = new ArrayList(ids); cyRow.set(attrName, values); } else if (attrType==String.class) { // only returns the first ID //TODO: is that a way to get the "best" one? if (!ids.isEmpty()) { cyRow.set(attrName, ids.iterator().next()); } } } } } } private void updateTaskMonitor(String status, double percentage) { updateTaskMonitor(status, percentage, false); } private void updateTaskMonitor(String status, double percentage, boolean error) { if (this.taskMonitor!=null) { if (error) { taskMonitor.showMessage(TaskMonitor.Level.ERROR, status); } else { taskMonitor.setStatusMessage(status); } taskMonitor.setProgress(percentage); } } }