umberto.WeightedClusterCoefficient.WeightedClusterCoefficient.java Source code

Java tutorial

Introduction

Here is the source code for umberto.WeightedClusterCoefficient.WeightedClusterCoefficient.java

Source

/*
 Authors : Umberto Griffo <umberto.griffo@gmail.com>
 Linkedin : it.linkedin.com/pub/umberto-griffo/31/768/99
 Twitter : @UmbertoGriffo
     
 DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    
 The contents of this file are subject to the terms of either the GNU
 General Public License Version 3 only ("GPL") or the Common
 Development and Distribution License("CDDL") (collectively, the
 "License"). You may not use this file except in compliance with the
 License. 
 You can obtain a copy of the License at http://www.gnu.org/licenses/gpl-3.0.txt.
    
 */
package umberto.WeightedClusterCoefficient;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.gephi.data.attributes.api.*;
import org.gephi.graph.api.*;
import org.gephi.statistics.spi.Statistics;
import org.gephi.utils.longtask.spi.LongTask;
import org.gephi.utils.progress.Progress;
import org.gephi.utils.progress.ProgressTicket;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.openide.util.Lookup;

/**
 * Calculates the Weighted Cluster Coefficient for every node and the average
 * value.
 *
 * @see WeightedClusterCoefficientBuilder
 * @see WeightedClusterCoefficientUI
 * @author Umberto Griffo
 */
public class WeightedClusterCoefficient implements Statistics, LongTask {
    //public cons for the result column name if reused by others

    public static final String AVG_WEIGHTED_CLUSTER_COEFFICIENT = "avg_weighted_cluster_coefficient";
    public static final String AVERAGE_WEIGHTED_CLUSTER_COEFFICIENT = "average_weighted_cluster_coefficient";
    private final static Logger LOGGER = Logger.getLogger("org.umberto.weighted_cluster_coefficient");
    private String report = "";
    /**
     * Remembers if the Cancel function has been called.
     */
    private boolean cancel;
    private ProgressTicket progressTicket;
    /**
     * Indicates should treat graph as undirected.
     */
    private boolean isDirected;
    /**
     * Keep track of the work done.
     */
    private int N;
    private double[] nodeClustering;
    private double avgClusteringCoeff;
    private double avgStrenght;
    private SortedMap<Float, Integer> strenght_distribution = new TreeMap<Float, Integer>();
    private SortedMap<Float, Float> cumulated_strenght_distribution = new TreeMap<Float, Float>();// to plot cumulate distribution
    private SortedMap<Float, Integer> cc_distribution = new TreeMap<Float, Integer>();

    public WeightedClusterCoefficient() {
        GraphController graphController = Lookup.getDefault().lookup(GraphController.class);
        if (graphController != null && graphController.getModel() != null) {
            isDirected = graphController.getModel().isDirected();
        }
    }

    @Override
    public void execute(GraphModel graphModel, AttributeModel attributeModel) {
        HierarchicalGraph hgraph = null;
        if (isDirected) {
            hgraph = graphModel.getHierarchicalDirectedGraphVisible();
        } else {
            hgraph = graphModel.getHierarchicalUndirectedGraphVisible();
        }

        execute(hgraph, attributeModel);
    }

    public void execute(HierarchicalGraph hgraph, AttributeModel attributeModel) {
        cancel = false;
        //The atrributes computed by the statistics
        AttributeTable nodeTable = attributeModel.getNodeTable();
        AttributeColumn clusteringCol = nodeTable.getColumn("weightedclustering");
        if (clusteringCol == null) {
            clusteringCol = nodeTable.addColumn("weightedclustering", "Weighted Clustering Coefficient",
                    AttributeType.DOUBLE, AttributeOrigin.COMPUTED, new Double(0));
        }
        AttributeColumn strenghtCol = nodeTable.getColumn("strenght");
        if (strenghtCol == null) {
            strenghtCol = nodeTable.addColumn("strenght", "Strenght", AttributeType.DOUBLE,
                    AttributeOrigin.COMPUTED, new Double(0));
        }
        float totalCC = 0;
        float totalStrenght = 0;

        hgraph.readLock();

        N = hgraph.getNodeCount();
        nodeClustering = new double[N];
        Progress.start(progressTicket, N);

        int node_count = 0;

        for (Node node : hgraph.getNodes()) {
            float strenght = 0;
            float nodeCC = 0;
            float cc = 0;
            int degree = hgraph.getDegree(node);
            //Calculate the node strenght
            if (isDirected) {
                float totalInWeight = 0;
                float totalOutWeight = 0;
                for (Iterator it = ((HierarchicalDirectedGraph) hgraph).getEdgesAndMetaEdges(node).iterator(); it
                        .hasNext();) {
                    Edge e = (Edge) it.next();
                    if (e.getSource().equals(node)) {
                        totalOutWeight += (float) e.getWeight();
                    }
                    if (e.getTarget().equals(node)) {
                        totalInWeight += (float) e.getWeight();
                    }
                }
                strenght = totalInWeight + totalOutWeight;
                //populate strenght distribution
                int count = strenght_distribution.containsKey(strenght) ? strenght_distribution.get(strenght) : 0;
                strenght_distribution.put(strenght, count + 1);

            } else {
                for (Iterator it = hgraph.getEdgesAndMetaEdges(node).iterator(); it.hasNext();) {
                    Edge e = (Edge) it.next();
                    strenght += (float) e.getWeight();
                }
                //populate strenght distribution
                int count = strenght_distribution.containsKey(strenght) ? strenght_distribution.get(strenght) : 0;
                strenght_distribution.put(strenght, count + 1);
            }
            //if a node have degree < 2 means that this node can't form a triangle.
            if (degree < 2) {
                cc = 0;
            } else {
                //Search Triangle
                NodeIterable neighbors1 = hgraph.getNeighbors(node);
                //browse the pairs of neighbors
                for (Node neighbor1 : neighbors1) {
                    NodeIterable neighbors2 = hgraph.getNeighbors(node);
                    for (Node neighbor2 : neighbors2) {
                        if (neighbor1 == neighbor2) {
                            continue;
                        }
                        if (isDirected) {
                            float w1 = 0;
                            float w2 = 0;
                            //find a triangle
                            if (((HierarchicalDirectedGraph) hgraph).getEdge(neighbor1, neighbor2) != null) {
                                if (((HierarchicalDirectedGraph) hgraph).getEdge(node, neighbor1) != null) {
                                    w1 = hgraph.getEdge(node, neighbor1).getWeight();
                                } else if (((HierarchicalDirectedGraph) hgraph).getEdge(neighbor1, node) != null) {
                                    w1 = hgraph.getEdge(neighbor1, node).getWeight();
                                }
                                if (((HierarchicalDirectedGraph) hgraph).getEdge(node, neighbor2) != null) {
                                    w2 = hgraph.getEdge(node, neighbor2).getWeight();
                                } else if (((HierarchicalDirectedGraph) hgraph).getEdge(neighbor2, node) != null) {
                                    w2 = hgraph.getEdge(neighbor2, node).getWeight();
                                }
                                nodeCC += (w1 + w2) / 2;
                            }
                            //find a triangle
                            if (((HierarchicalDirectedGraph) hgraph).getEdge(neighbor2, neighbor1) != null) {
                                if (((HierarchicalDirectedGraph) hgraph).getEdge(node, neighbor1) != null) {
                                    w1 = hgraph.getEdge(node, neighbor1).getWeight();
                                } else if (((HierarchicalDirectedGraph) hgraph).getEdge(neighbor1, node) != null) {
                                    w1 = hgraph.getEdge(neighbor1, node).getWeight();
                                }
                                if (((HierarchicalDirectedGraph) hgraph).getEdge(node, neighbor2) != null) {
                                    w2 = hgraph.getEdge(node, neighbor2).getWeight();
                                } else if (((HierarchicalDirectedGraph) hgraph).getEdge(neighbor2, node) != null) {
                                    w2 = hgraph.getEdge(neighbor2, node).getWeight();
                                }
                                nodeCC += (w1 + w2) / 2;
                            }
                        } else {
                            //find a triangle
                            if (hgraph.isAdjacent(neighbor1, neighbor2)) {
                                nodeCC += (hgraph.getEdge(node, neighbor1).getWeight()
                                        + hgraph.getEdge(node, neighbor2).getWeight()) / 2;
                            }
                        }
                    }
                }
                nodeCC /= 2.0;//because a triangle is seen 2 times
                //Calculate local cluster coefficient
                cc = (2 / (strenght * (degree - 1))) * nodeCC;
                if (isDirected) {
                    cc = (1 / (strenght * (degree - 1))) * nodeCC;
                }
            }

            nodeClustering[node_count] = cc;
            //populate cc distribution
            int count = cc_distribution.containsKey(cc) ? cc_distribution.get(cc) : 0;
            cc_distribution.put(cc, count + 1);
            //Save the node values
            AttributeRow row = (AttributeRow) node.getNodeData().getAttributes();
            row.setValue(clusteringCol, cc);
            row.setValue(strenghtCol, strenght);

            totalCC += cc;
            totalStrenght += strenght;
            if (cancel) {
                break;
            }
            node_count++;
            Progress.progress(progressTicket, node_count);
        }
        avgClusteringCoeff = totalCC / hgraph.getNodeCount();
        avgStrenght = totalStrenght / hgraph.getNodeCount();
        hgraph.readUnlockAll();
    }

    public double getAverageWeightedClusteringCoefficient() {
        return avgClusteringCoeff;
    }

    public double getAverageNodeStrenght() {
        return avgStrenght;
    }

    @Override
    public String getReport() {
        /*
         * SAVE IN FILE FOR MULTIPLE PLOT
         */
        //current directory
        boolean success;
        String currentDir = System.getProperty("user.dir");
        String saveDir = currentDir + "\\savedata";
        boolean exist = (new File(saveDir)).exists();
        if (!exist) {
            success = (new File(saveDir)).mkdir();
        } else {
            success = true;
        }
        Set<SortedMap.Entry<Float, Integer>> set_strenght2 = strenght_distribution.entrySet();
        for (SortedMap.Entry<Float, Integer> element : set_strenght2) {
            float cumulated = 0;
            for (SortedMap.Entry<Float, Integer> element2 : set_strenght2) {
                //F(s) = nodes fraction with (strenght/strenght max) >= s
                if (element2.getKey() >= element.getKey()) {
                    cumulated += element2.getValue();
                }
            }
            cumulated_strenght_distribution.put(element.getKey(), (cumulated / strenght_distribution.lastKey()));
        }
        System.out.println(strenght_distribution);
        System.out.println(cumulated_strenght_distribution);

        //Transform to Map
        Map<Float, Float> strenght_distribution_map = new HashMap<Float, Float>();
        Set<SortedMap.Entry<Float, Float>> set_strenght = cumulated_strenght_distribution.entrySet();
        for (SortedMap.Entry<Float, Float> element : set_strenght) {
            Float num_occorrenze = element.getValue();
            Float strenght = element.getKey();
            strenght_distribution_map.put(strenght, num_occorrenze);
        }

        System.out.println(cc_distribution);

        Map<Float, Integer> cc_distribution_map = new HashMap<Float, Integer>();

        Set<SortedMap.Entry<Float, Integer>> set_cc = cc_distribution.entrySet();
        for (SortedMap.Entry<Float, Integer> element : set_cc) {
            Integer num_occorrenze = element.getValue();
            Float cc = element.getKey();
            //double prob = (double) num_occorrenze / N;
            cc_distribution_map.put(cc, num_occorrenze);
        }
        //Save file
        if (success) {
            String completeDirIntra = saveDir + "\\StrengthDistribution.txt";
            String finalDir = completeDirIntra.replace("\\", "\\\\");
            LOGGER.log(Level.INFO, "Intra path: {0}", new Object[] { finalDir });
            generateSaveFile(finalDir, strenght_distribution_map);
        } else {
            LOGGER.log(Level.INFO, "Don't create a new directory");
        }
        System.out.println(strenght_distribution_map);
        System.out.println(cc_distribution_map);
        //Distribution series
        XYSeries strenghtSeries = ChartUtils.createXYSeries(strenght_distribution_map, "Strength Distribution");
        XYSeries ccSeries = ChartUtils.createXYSeries(cc_distribution_map,
                "Weighted cluster coefficient Distribution");

        XYSeriesCollection dataset1 = new XYSeriesCollection();
        dataset1.addSeries(strenghtSeries);

        XYSeriesCollection dataset2 = new XYSeriesCollection();
        dataset2.addSeries(ccSeries);

        JFreeChart chart1 = ChartFactory.createXYLineChart("Strenght Distribution", "Strength", "F(Strength)",
                dataset1, PlotOrientation.VERTICAL, true, false, false);
        ChartUtils.decorateChart(chart1);
        ChartUtils.scaleLogChart(chart1, strenghtSeries, false);
        String strenghtImageFile = ChartUtils.renderChart(chart1, "Strength-distribution.png");

        JFreeChart chart2 = ChartFactory.createXYLineChart("Weighted Cluster Coefficient Distribution",
                "Weighted Cluster Coefficient", "# Nodes", dataset2, PlotOrientation.VERTICAL, true, false, false);

        ChartUtils.decorateChart(chart2);
        ChartUtils.scaleChart(chart2, ccSeries, false);
        String ccImageFile = ChartUtils.renderChart(chart2, "ccdistribution.png");

        NumberFormat f = new DecimalFormat("#0.000");

        return "<HTML> <BODY> <h1> Weighted Clustering Coefficient Metric Report </h1> " + "<hr>" + "<br />"
                + "<h2> Parameters: </h2>" + "Network Interpretation:  " + (isDirected ? "directed" : "undirected")
                + "<br />" + "<br>" + "<h2> Results: </h2>" + "Average Clustering Coefficient: "
                + f.format(avgClusteringCoeff) + "<br />"
                + "The Average Clustering Coefficient is the mean value of individual coefficients.<br /><br />"
                + ccImageFile + "<br /><br />" + "Average Node Strength: " + f.format(avgStrenght) + "<br />"
                + "The Average Node Strength is the mean value of individual node Strength.<br /><br />"
                + strenghtImageFile + "<br /><br />"
                + "Where F(Strength) = fraction of nodes with (Strength/Max Strength)>= Strength" + "<br />"
                + "<h2> Algorithm: </h2>" + "Simple and slow brute force.<br />"
                + "Reference: \"A. Barrat and M. Barthelemy and R. Pastor-Satorras and A. Vespignani (2004). \"The architecture of complex weighted networks\". Proceedings of the National Academy of Sciences 101 (11): 37473752."
                + "</BODY> </HTML>";
    }

    @Override
    public boolean cancel() {
        this.cancel = true;
        return true;
    }

    @Override
    public void setProgressTicket(ProgressTicket progressTicket) {
        this.progressTicket = progressTicket;
    }

    public void setDirected(boolean isDirected) {
        this.isDirected = isDirected;
    }

    public boolean isDirected() {
        return isDirected;
    }

    /**
     * Generate distribution file.
     *
     * @param sFileName file path.
     */
    public void generateSaveFile(String sFileName, Map<Float, Float> map) {
        try {
            FileWriter writer = new FileWriter(sFileName);
            Set<Map.Entry<Float, Float>> set = map.entrySet();
            int k = 0;
            for (Map.Entry<Float, Float> element : set) {
                writer.append(element.getKey().toString());
                writer.append(' ');
                writer.append(element.getValue().toString());
                k = k + 1;
                if (k != map.size()) {
                    writer.append('\n');
                }
            }
            writer.flush();
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}