/******************************************************************************* * Copyright 2012 University of Southern California * * 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. * * This code was developed by the Information Integration Group as part * of the Karma project at the Information Sciences Institute of the * University of Southern California. For more information, publications, * and related projects, please see: http://www.isi.edu/integration ******************************************************************************/ package edu.isi.karma.modeling.alignment; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.text.DecimalFormat; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.jgrapht.DirectedGraph; import org.jgrapht.graph.DirectedWeightedMultigraph; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import edu.isi.karma.rep.alignment.ColumnNode; import edu.isi.karma.rep.alignment.DefaultLink; import edu.isi.karma.rep.alignment.LabeledLink; import edu.isi.karma.rep.alignment.LiteralNode; import edu.isi.karma.rep.alignment.Node; import edu.isi.karma.rep.alignment.SemanticType; public class GraphVizUtil { private static Logger logger = LoggerFactory.getLogger(GraphVizUtil.class); private GraphVizUtil() { } private static double roundDecimals(double d, int k) { String format = ""; for (int i = 0; i < k; i++) format += "#"; DecimalFormat DForm = new DecimalFormat("#." + format); return Double.valueOf(DForm.format(d)); } public static String getLocalName(String uri) { if (uri == null) return ""; String localName = uri; if (uri.contains("#") && !uri.endsWith("#")) localName = uri.substring(uri.lastIndexOf('#') + 1); else { if (uri.endsWith("/")) uri = uri.substring(0, uri.length() - 2); if (uri.contains("/")) localName = uri.substring(uri.lastIndexOf('/') + 1); } return localName; } // private static String getModelIds(Set<String> modelIds) { // String label = ""; // if (modelIds == null || modelIds.size() == 0) // return label; // label += "["; // for (String pId : modelIds) // label += pId + ","; // if (label.endsWith(",")) // label = label.substring(0, label.length() - 1); // label += "]"; // return label; // } private static org.kohsuke.graphviz.Graph convertToGraphviz( DirectedGraph<Node, DefaultLink> graph, Map<ColumnNode, ColumnNode> mappingToSourceColumns, boolean onlyAddPatterns, GraphVizLabelType nodeLabelType, GraphVizLabelType linkLabelType, boolean showNodeMetaData, boolean showLinkMetaData) { String metaDataSeparator = "\n"; org.kohsuke.graphviz.Graph gViz = new org.kohsuke.graphviz.Graph(); if (graph == null) return gViz; org.kohsuke.graphviz.Style internalNodeStyle = new org.kohsuke.graphviz.Style(); // internalNodeStyle.attr("shape", "circle"); internalNodeStyle.attr("style", "filled"); internalNodeStyle.attr("color", "white"); //internalNodeStyle.attr("fontsize", "10"); internalNodeStyle.attr("fillcolor", "lightgray"); // org.kohsuke.graphviz.Style inputNodeStyle = new org.kohsuke.graphviz.Style(); // inputNodeStyle.attr("shape", "plaintext"); // inputNodeStyle.attr("style", "filled"); // inputNodeStyle.attr("fillcolor", "#3CB371"); // // org.kohsuke.graphviz.Style outputNodeStyle = new org.kohsuke.graphviz.Style(); // outputNodeStyle.attr("shape", "plaintext"); // outputNodeStyle.attr("style", "filled"); // outputNodeStyle.attr("fillcolor", "gold"); org.kohsuke.graphviz.Style parameterNodeStyle = new org.kohsuke.graphviz.Style(); parameterNodeStyle.attr("shape", "plaintext"); parameterNodeStyle.attr("style", "filled"); parameterNodeStyle.attr("fillcolor", "gold"); org.kohsuke.graphviz.Style literalNodeStyle = new org.kohsuke.graphviz.Style(); literalNodeStyle.attr("shape", "plaintext"); literalNodeStyle.attr("style", "filled"); literalNodeStyle.attr("fillcolor", "#CC7799"); org.kohsuke.graphviz.Style edgeStyle = new org.kohsuke.graphviz.Style(); edgeStyle.attr("color", "brown"); //edgeStyle.attr("fontsize", "10"); edgeStyle.attr("fontcolor", "black"); HashMap<Node, org.kohsuke.graphviz.Node> nodeIndex = new HashMap<>(); for (DefaultLink e : graph.edgeSet()) { Set<String> modelIds = null; if (e instanceof LabeledLink) { modelIds = ((LabeledLink)e).getModelIds(); } if (onlyAddPatterns && (modelIds == null || modelIds.isEmpty())) continue; Node source = e.getSource(); Node target = e.getTarget(); org.kohsuke.graphviz.Node n = nodeIndex.get(source); String sourceId = source.getId(); String sourceUri = source.getUri(); String sourceLocalId, sourceLocalUri; String sourceLabel = ""; if (n == null) { n = new org.kohsuke.graphviz.Node(); // label = (uri == null || uri.trim().length() == 0?id:uri)); if (source instanceof ColumnNode) { ColumnNode mappedColumn = (mappingToSourceColumns == null) ? (ColumnNode)source : mappingToSourceColumns.get(source); sourceLabel = mappedColumn.getColumnName(); } else if(source instanceof LiteralNode) { sourceLabel = ((LiteralNode)source).getValue(); } else if (nodeLabelType == GraphVizLabelType.Id) sourceLabel = sourceId; else if (nodeLabelType == GraphVizLabelType.LocalId) sourceLabel = (sourceLocalId = getLocalName(sourceId)) == null ? sourceId : sourceLocalId; else if (nodeLabelType == GraphVizLabelType.Uri) sourceLabel = sourceUri; else if (nodeLabelType == GraphVizLabelType.LocalUri) sourceLabel = (sourceLocalUri = getLocalName(sourceUri)) == null ? sourceUri : sourceLocalUri; if (showNodeMetaData) { // sourceLabel += metaDataSeparator + getModelIds(source.getModelIds()); } n.attr("label", sourceLabel); nodeIndex.put(source, n); if (source instanceof ColumnNode) // attribute gViz.nodeWith(parameterNodeStyle); else if (source instanceof LiteralNode) // literal gViz.nodeWith(literalNodeStyle); else // internal node gViz.nodeWith(internalNodeStyle); gViz.node(n); } n = nodeIndex.get(target); String targetId = target.getId(); String targetUri = target.getUri(); String targetLocalId, targetLocalUri; String targetLabel = ""; if (n == null) { n = new org.kohsuke.graphviz.Node(); // label = (uri == null || uri.trim().length() == 0?id:uri)); if (target instanceof ColumnNode) { ColumnNode mappedColumn = (mappingToSourceColumns == null) ? (ColumnNode)target : mappingToSourceColumns.get(target); targetLabel = mappedColumn.getColumnName(); } else if(target instanceof LiteralNode) { targetLabel = ((LiteralNode)target).getValue(); } else if (nodeLabelType == GraphVizLabelType.Id) targetLabel = targetId; else if (nodeLabelType == GraphVizLabelType.LocalId) targetLabel = (targetLocalId = getLocalName(targetId)) == null ? targetId : targetLocalId; else if (nodeLabelType == GraphVizLabelType.Uri) targetLabel = targetUri; else if (nodeLabelType == GraphVizLabelType.LocalUri) targetLabel = (targetLocalUri = getLocalName(targetUri)) == null ? targetUri : targetLocalUri; if (showNodeMetaData) { // targetLabel += metaDataSeparator + getModelIds(target.getModelIds()); if (target instanceof ColumnNode) { ColumnNode mappedColumn = (mappingToSourceColumns == null) ? (ColumnNode)target : mappingToSourceColumns.get(target); List<SemanticType> suggestedTypes = mappedColumn.getTopKLearnedSemanticTypes(4); if (suggestedTypes != null) for (SemanticType st : suggestedTypes) targetLabel += "\n[" + getLocalName(st.getDomain().getUri()) + "," + getLocalName(st.getType().getUri()) + "," + roundDecimals(st.getConfidenceScore(),3) + "]"; } } n.attr("label", targetLabel); nodeIndex.put(target, n); if (target instanceof ColumnNode) // attribute gViz.nodeWith(parameterNodeStyle); else if (target instanceof LiteralNode) // literal gViz.nodeWith(literalNodeStyle); else // internal node gViz.nodeWith(internalNodeStyle); gViz.node(n); } org.kohsuke.graphviz.Edge edge = new org.kohsuke.graphviz.Edge(nodeIndex.get(source), nodeIndex.get(target)); String edgeId = e.getId(); String edgeUri = e.getUri(); String edgeLocalUri; String edgeLabel = ""; if (linkLabelType == GraphVizLabelType.Id) edgeLabel = edgeId; else if (linkLabelType == GraphVizLabelType.LocalId) edgeLabel = edgeId; else if (linkLabelType == GraphVizLabelType.Uri) edgeLabel = edgeUri; else if (linkLabelType == GraphVizLabelType.LocalUri) edgeLabel = (edgeLocalUri = getLocalName(edgeUri)) == null ? edgeUri : edgeLocalUri; if (showLinkMetaData) { edgeLabel += metaDataSeparator; edgeLabel += "w=" + roundDecimals(e.getWeight(), 6); // edgeLabel += metaDataSeparator; // edgeLabel += getModelIds(modelIds); } edge.attr("label", edgeLabel); gViz.edgeWith(edgeStyle); gViz.edge(edge); } return gViz; } public static void exportJGraphToGraphviz( DirectedWeightedMultigraph<Node, DefaultLink> graph, String label, boolean onlyAddPatterns, GraphVizLabelType nodeLabelType, GraphVizLabelType linkLabelType, boolean showNodeMetaData, boolean showLinkMetaData, String filename) throws IOException { logger.info("exporting the graph to graphviz ..."); org.kohsuke.graphviz.Graph graphViz = convertToGraphviz(graph, null, onlyAddPatterns, nodeLabelType, linkLabelType, showNodeMetaData, showLinkMetaData);; graphViz.attr("fontcolor", "blue"); graphViz.attr("remincross", "true"); graphViz.attr("label", label == null ? "" : label); OutputStream out = new FileOutputStream(filename); graphViz.writeTo(out); logger.info("export is done."); } public static void exportSemanticModelToGraphviz( SemanticModel model, GraphVizLabelType nodeLabelType, GraphVizLabelType linkLabelType, boolean showNodeMetaData, boolean showLinkMetaData, String filename) throws IOException { OutputStream out = new FileOutputStream(filename); org.kohsuke.graphviz.Graph graphViz = new org.kohsuke.graphviz.Graph(); graphViz.attr("fontcolor", "blue"); graphViz.attr("remincross", "true"); graphViz.attr("label", model.getName() == null ? "" : model.getName()); // graphViz.attr("page", "8.5,11"); org.kohsuke.graphviz.Graph gViz = convertToGraphviz(GraphUtil.asDefaultGraph(model.getGraph()), model.getMappingToSourceColumns(), false, nodeLabelType, linkLabelType, showNodeMetaData, showLinkMetaData); gViz.attr("label", "model"); gViz.id("cluster"); graphViz.subGraph(gViz); graphViz.writeTo(out); out.close(); } public static void exportSemanticModelsToGraphviz( Map<String, SemanticModel> models, String label, String filename, GraphVizLabelType nodeLabelType, GraphVizLabelType linkLabelType, boolean showNodeMetaData, boolean showLinkMetaData) throws IOException { org.kohsuke.graphviz.Graph graphViz = new org.kohsuke.graphviz.Graph(); graphViz.attr("fontcolor", "blue"); graphViz.attr("remincross", "true"); graphViz.attr("label", label == null ? "" : label); org.kohsuke.graphviz.Graph cluster = null; int counter = 0; if (models != null) { for(Entry<String,SemanticModel> entry : models.entrySet()) { if (entry.getKey() == "1-correct model") { cluster = GraphVizUtil.convertToGraphviz(GraphUtil.asDefaultGraph(entry.getValue().getGraph()), entry.getValue().getMappingToSourceColumns(), false, nodeLabelType, linkLabelType, false, false); } else { cluster = GraphVizUtil.convertToGraphviz(GraphUtil.asDefaultGraph(entry.getValue().getGraph()), entry.getValue().getMappingToSourceColumns(), false, nodeLabelType, linkLabelType, showNodeMetaData, showLinkMetaData); } cluster.id("cluster_" + counter); cluster.attr("label", entry.getKey()); graphViz.subGraph(cluster); counter++; } } OutputStream out = new FileOutputStream(filename); graphViz.writeTo(out); } }