~duyi001/gephi/DSNI

« back to all changes in this revision

Viewing changes to StatisticsPlugin/src/org/gephi/statistics/plugin/DegreeDistribution.java

  • Committer: sunsnowad
  • Author(s): Yi Du
  • Date: 2011-09-08 16:36:59 UTC
  • mfrom: (1435.1.968 gephi)
  • Revision ID: sunsnowad@www-691ed046717-20110908163659-aorx14ylp8f9qwdx
1.merge with main branch
2.update twitter4j to version 2.2.4
3.fix an existing bug on "twitter user import"

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
Copyright 2008-2010 Gephi
3
 
Authors : Patick J. McSweeney <pjmcswee@syr.edu>, Sebastien Heymann <seb@gephi.org>
4
 
Website : http://www.gephi.org
5
 
 
6
 
This file is part of Gephi.
7
 
 
8
 
Gephi is free software: you can redistribute it and/or modify
9
 
it under the terms of the GNU Affero General Public License as
10
 
published by the Free Software Foundation, either version 3 of the
11
 
License, or (at your option) any later version.
12
 
 
13
 
Gephi is distributed in the hope that it will be useful,
14
 
but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 
GNU Affero General Public License for more details.
17
 
 
18
 
You should have received a copy of the GNU Affero General Public License
19
 
along with Gephi.  If not, see <http://www.gnu.org/licenses/>.
20
 
*/
21
 
package org.gephi.statistics.plugin;
22
 
 
23
 
import java.io.File;
24
 
import java.io.IOException;
25
 
import org.gephi.data.attributes.api.AttributeModel;
26
 
import org.gephi.statistics.spi.Statistics;
27
 
import org.gephi.graph.api.*;
28
 
import org.gephi.utils.TempDirUtils;
29
 
import org.gephi.utils.TempDirUtils.TempDir;
30
 
import org.gephi.utils.longtask.spi.LongTask;
31
 
import org.gephi.utils.progress.Progress;
32
 
import org.gephi.utils.progress.ProgressTicket;
33
 
import org.jfree.chart.ChartFactory;
34
 
import org.jfree.chart.ChartRenderingInfo;
35
 
import org.jfree.chart.ChartUtilities;
36
 
import org.jfree.chart.JFreeChart;
37
 
import org.jfree.chart.entity.StandardEntityCollection;
38
 
import org.jfree.chart.plot.PlotOrientation;
39
 
import org.jfree.chart.plot.XYPlot;
40
 
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
41
 
import org.jfree.data.xy.XYSeries;
42
 
import org.jfree.data.xy.XYSeriesCollection;
43
 
import org.openide.util.Exceptions;
44
 
import org.openide.util.Lookup;
45
 
 
46
 
/**
47
 
 * This class measures how closely the degree distribution of a
48
 
 * network follows a power-law scale.  An alpha value between 2 and 3
49
 
 * implies a power law.
50
 
 * @author pjmcswees
51
 
 */
52
 
public class DegreeDistribution implements Statistics, LongTask {
53
 
 
54
 
    /**  The combined In/Out-degree distribution. */
55
 
    private double[][] combinedDistribution;
56
 
    /** The In-degree distribution. */
57
 
    private double[][] inDistribution;
58
 
    /** The out-degree distribution. */
59
 
    private double[][] outDistribution;
60
 
    /** Remember if the metric has been canceled.  */
61
 
    private boolean isCanceled;
62
 
    /** The progress meter for this metric. */
63
 
    private ProgressTicket progress;
64
 
    /**  Indicates if this network should be directed or undirected.*/
65
 
    private boolean isDirected;
66
 
    /** The powerlaw value for the combined in/out-degree of this network. */
67
 
    private double combinedAlpha;
68
 
    /** The powerlaw value for the in-degree of this network. */
69
 
    private double inAlpha;
70
 
    /** The powerlaw value for the out-degree of this network. */
71
 
    private double outAlpha;
72
 
    /** The powerlaw value for the combined in/out-degree of this network. */
73
 
    private double combinedBeta;
74
 
    /** The powerlaw value for the in-degree of this network. */
75
 
    private double inBeta;
76
 
    /** The powerlaw value for the out-degree of this network. */
77
 
    private double outBeta;
78
 
 
79
 
    public DegreeDistribution() {
80
 
        GraphController graphController = Lookup.getDefault().lookup(GraphController.class);
81
 
        if (graphController != null && graphController.getModel() != null) {
82
 
            isDirected = graphController.getModel().isDirected();
83
 
        }
84
 
    }
85
 
 
86
 
    /**
87
 
     * @param isDirected Indicates the metric's interpretation of this network.
88
 
     */
89
 
    public void setDirected(boolean isDirected) {
90
 
        this.isDirected = isDirected;
91
 
    }
92
 
 
93
 
    public boolean isDirected() {
94
 
        return isDirected;
95
 
    }
96
 
 
97
 
    /**
98
 
     * @return The combined in/out-degree power law value for this network.
99
 
     */
100
 
    public double getCombinedPowerLaw() {
101
 
        return this.combinedAlpha;
102
 
    }
103
 
 
104
 
    /**
105
 
     * @return The combined in/out-degree power law value for this network.
106
 
     */
107
 
    public double getInPowerLaw() {
108
 
        return this.inAlpha;
109
 
    }
110
 
 
111
 
    /**
112
 
     * @return The combined in/out-degree power law value for this network.
113
 
     */
114
 
    public double getOutPowerLaw() {
115
 
        return this.outAlpha;
116
 
    }
117
 
 
118
 
    /**
119
 
     * Calculates the degree distribution for this network.
120
 
     * Either a combined degree distribution or separate
121
 
     * in-degree distribution and out-degree distribution
122
 
     * is calculated based on the mDirected variable.
123
 
     *
124
 
     * @param graphModel
125
 
     */
126
 
    public void execute(GraphModel graphModel, AttributeModel attributeModel) {
127
 
        //Get the graph from the graphController, based
128
 
        //on the mDirected variable.
129
 
        HierarchicalGraph graph;
130
 
        if (isDirected) {
131
 
            graph = graphModel.getHierarchicalDirectedGraphVisible();
132
 
        } else {
133
 
            graph = graphModel.getHierarchicalUndirectedGraphVisible();
134
 
        }
135
 
        execute(graph, attributeModel);
136
 
    }
137
 
 
138
 
    public void execute(HierarchicalGraph graph, AttributeModel attributeModel) {
139
 
        //Mark this as not yet canceled.
140
 
        isCanceled = false;
141
 
 
142
 
        graph.readLock();
143
 
 
144
 
        //Start 
145
 
        Progress.start(progress, graph.getNodeCount());
146
 
 
147
 
 
148
 
        //Consider the in and out degree of every node
149
 
        if (isDirected) {
150
 
            inDistribution = new double[2][2 * graph.getNodeCount()];
151
 
            outDistribution = new double[2][2 * graph.getNodeCount()];
152
 
        } else {
153
 
            combinedDistribution = new double[2][2 * graph.getNodeCount()];
154
 
        }
155
 
 
156
 
 
157
 
        int nodeCount = 0;
158
 
        for (Node node : graph.getNodes()) {
159
 
            if (isDirected) {
160
 
                int inDegree = ((HierarchicalDirectedGraph) graph).getTotalInDegree(node);
161
 
                int outDegree = ((HierarchicalDirectedGraph) graph).getTotalOutDegree(node);
162
 
                inDistribution[1][inDegree]++;
163
 
                outDistribution[1][outDegree]++;
164
 
                inDistribution[0][inDegree] = inDegree;
165
 
                outDistribution[0][outDegree] = outDegree;
166
 
            } else {
167
 
                int combinedDegree = ((HierarchicalUndirectedGraph) graph).getTotalDegree(node);
168
 
                combinedDistribution[1][combinedDegree]++;
169
 
                combinedDistribution[0][combinedDegree] = combinedDegree;
170
 
            }
171
 
            Progress.progress(progress, nodeCount);
172
 
            nodeCount++;
173
 
            if (isCanceled) {
174
 
                graph.readUnlockAll();
175
 
                return;
176
 
            }
177
 
        }
178
 
 
179
 
        graph.readUnlock();
180
 
 
181
 
        if (isDirected) {
182
 
            double[] inFit = new double[2];
183
 
            double[] outFit = new double[2];
184
 
            leastSquares(inDistribution[1], inFit);
185
 
            leastSquares(outDistribution[1], outFit);
186
 
            inAlpha = inFit[1];
187
 
            inBeta = inFit[0];
188
 
            outAlpha = outFit[1];
189
 
            outBeta = outFit[0];
190
 
        } else {
191
 
            double[] fit = new double[2];
192
 
            leastSquares(combinedDistribution[1], fit);
193
 
            combinedAlpha = fit[1];
194
 
            combinedBeta = fit[0];
195
 
        }
196
 
    }
197
 
 
198
 
    /**
199
 
     * Fits the logarithm distribution/degree to a straight line of the form:
200
 
     *  a + b *x which is then interpreted as a*x^y in the non-logarithmic scale
201
 
     *
202
 
     * @param dist The distribution of node degrees to fit to a logarithmized straight line
203
 
     *
204
 
     * @return An array of 2 doubles
205
 
     *                                  index 0: b
206
 
     *                                  index 1: a
207
 
     *
208
 
     *  For more see Wolfram Least Squares Fitting
209
 
     */
210
 
    public void leastSquares(double[] dist, double[] res) {
211
 
        //Vararibles to compute
212
 
        double SSxx = 0;
213
 
        double SSxy = 0;
214
 
        //double SSyy = 0;
215
 
 
216
 
        //Compute the average log(x) value when for positive (>0) values
217
 
        double avgX = 0;
218
 
        double avgY = 0;
219
 
        double nonZero = 0;
220
 
        for (int i = 1; i < dist.length; i++) {
221
 
            if (dist[i] > 0) {
222
 
                avgX += Math.log(i);
223
 
                avgY += Math.log(dist[i]);
224
 
                nonZero++;
225
 
            }
226
 
 
227
 
            if (isCanceled) {
228
 
                return;
229
 
            }
230
 
 
231
 
        }
232
 
        avgX /= nonZero;
233
 
        avgY /= nonZero;
234
 
 
235
 
        //compute the variance of log(x)
236
 
        for (int i = 1; i < dist.length; i++) {
237
 
            if (dist[i] > 0) {
238
 
                SSxx += Math.pow(Math.log(i) - avgX, 2);
239
 
                //SSyy += Math.pow(Math.log(dist[i]) - avgY, 2);
240
 
                SSxy += (Math.log(i) - avgX) * (Math.log(dist[i]) - avgY);
241
 
            }
242
 
        }
243
 
 
244
 
        //Compute and return the results
245
 
        res[0] = SSxy / SSxx;
246
 
        res[1] = avgY - res[0] * avgX;
247
 
    }
248
 
 
249
 
    /**
250
 
     * @return A String report based on the interpretation of the network.
251
 
     */
252
 
    public String getReport() {
253
 
        return (isDirected) ? getDirectedReport() : getUndirectedReport();
254
 
    }
255
 
 
256
 
    /**
257
 
     *
258
 
     * @return The directed version of the report.
259
 
     */
260
 
    private String getDirectedReport() {
261
 
        double inMax = 0;
262
 
        XYSeries inSeries2 = new XYSeries("Series 2");
263
 
        for (int i = 1; i < inDistribution[1].length; i++) {
264
 
            if (inDistribution[1][i] > 0) {
265
 
                inSeries2.add((Math.log(inDistribution[0][i]) / Math.log(Math.E)), (Math.log(inDistribution[1][i]) / Math.log(Math.E)));
266
 
                inMax = (float) Math.max((Math.log(inDistribution[0][i]) / Math.log(Math.E)), inMax);
267
 
            }
268
 
        }
269
 
        double inA = inAlpha;
270
 
        double inB = inBeta;
271
 
 
272
 
        String inImageFile = "";
273
 
        String outImageFile = "";
274
 
        try {
275
 
 
276
 
            XYSeries inSeries1 = new XYSeries(inAlpha + " ");
277
 
            inSeries1.add(0, inA);
278
 
            inSeries1.add(inMax, inA + inB * inMax);
279
 
 
280
 
            XYSeriesCollection inDataset = new XYSeriesCollection();
281
 
            inDataset.addSeries(inSeries1);
282
 
            inDataset.addSeries(inSeries2);
283
 
 
284
 
            JFreeChart inChart = ChartFactory.createXYLineChart(
285
 
                    "In-Degree Distribution",
286
 
                    "In-Degree",
287
 
                    "Occurrence",
288
 
                    inDataset,
289
 
                    PlotOrientation.VERTICAL,
290
 
                    true,
291
 
                    false,
292
 
                    false);
293
 
            XYPlot inPlot = (XYPlot) inChart.getPlot();
294
 
            XYLineAndShapeRenderer inRenderer = new XYLineAndShapeRenderer();
295
 
            inRenderer.setSeriesLinesVisible(0, true);
296
 
            inRenderer.setSeriesShapesVisible(0, false);
297
 
            inRenderer.setSeriesLinesVisible(1, false);
298
 
            inRenderer.setSeriesShapesVisible(1, true);
299
 
            inRenderer.setSeriesShape(1, new java.awt.geom.Ellipse2D.Double(0, 0, 1, 1));
300
 
            inPlot.setBackgroundPaint(java.awt.Color.WHITE);
301
 
            inPlot.setDomainGridlinePaint(java.awt.Color.GRAY);
302
 
            inPlot.setRangeGridlinePaint(java.awt.Color.GRAY);
303
 
 
304
 
            inPlot.setRenderer(inRenderer);
305
 
 
306
 
            final ChartRenderingInfo info = new ChartRenderingInfo(new StandardEntityCollection());
307
 
 
308
 
 
309
 
            TempDir tempDir = TempDirUtils.createTempDir();
310
 
            final String fileName = "inDistribution.png";
311
 
            final File file1 = tempDir.createFile(fileName);
312
 
            inImageFile = "<IMG SRC=\"file:" + file1.getAbsolutePath() + "\" " + "WIDTH=\"600\" HEIGHT=\"400\" BORDER=\"0\" USEMAP=\"#chart\"></IMG>";
313
 
            ChartUtilities.saveChartAsPNG(file1, inChart, 600, 400, info);
314
 
 
315
 
 
316
 
            double outMax = 0;
317
 
            XYSeries outSeries2 = new XYSeries("Series 2");
318
 
            for (int i = 1; i < outDistribution[1].length; i++) {
319
 
                if (outDistribution[1][i] > 0) {
320
 
                    outSeries2.add((Math.log(outDistribution[0][i]) / Math.log(Math.E)), (Math.log(outDistribution[1][i]) / Math.log(Math.E)));
321
 
                    outMax = (float) Math.max((Math.log(outDistribution[0][i]) / Math.log(Math.E)), outMax);
322
 
                }
323
 
            }
324
 
            double outA = outAlpha;
325
 
            double outB = outBeta;
326
 
 
327
 
 
328
 
            XYSeries outSeries1 = new XYSeries(outAlpha + " ");
329
 
            outSeries1.add(0, outA);
330
 
            outSeries1.add(outMax, outA + outB * outMax);
331
 
 
332
 
            XYSeriesCollection outDataset = new XYSeriesCollection();
333
 
            outDataset.addSeries(outSeries1);
334
 
            outDataset.addSeries(outSeries2);
335
 
 
336
 
            JFreeChart outchart = ChartFactory.createXYLineChart(
337
 
                    "Out-Degree Distribution",
338
 
                    "Out-Degree",
339
 
                    "Occurrence",
340
 
                    outDataset,
341
 
                    PlotOrientation.VERTICAL,
342
 
                    true,
343
 
                    false,
344
 
                    false);
345
 
            XYPlot outPlot = (XYPlot) outchart.getPlot();
346
 
            XYLineAndShapeRenderer outRenderer = new XYLineAndShapeRenderer();
347
 
            outRenderer.setSeriesLinesVisible(0, true);
348
 
            outRenderer.setSeriesShapesVisible(0, false);
349
 
            outRenderer.setSeriesLinesVisible(1, false);
350
 
            outRenderer.setSeriesShapesVisible(1, true);
351
 
            outRenderer.setSeriesShape(1, new java.awt.geom.Ellipse2D.Double(0, 0, 1, 1));
352
 
            outPlot.setBackgroundPaint(java.awt.Color.WHITE);
353
 
            outPlot.setDomainGridlinePaint(java.awt.Color.GRAY);
354
 
            outPlot.setRangeGridlinePaint(java.awt.Color.GRAY);
355
 
 
356
 
            outPlot.setRenderer(outRenderer);
357
 
 
358
 
            final ChartRenderingInfo info2 = new ChartRenderingInfo(new StandardEntityCollection());
359
 
            final String fileName2 = "outDistribution.png";
360
 
            final File file2 = tempDir.createFile(fileName2);
361
 
            outImageFile = "<IMG SRC=\"file:" + file2.getAbsolutePath() + "\" " + "WIDTH=\"600\" HEIGHT=\"400\" BORDER=\"0\" USEMAP=\"#chart\"></IMG>";
362
 
            ChartUtilities.saveChartAsPNG(file2, outchart, 600, 400, info2);
363
 
        } catch (IOException e) {
364
 
            Exceptions.printStackTrace(e);
365
 
        }
366
 
 
367
 
 
368
 
 
369
 
 
370
 
        String report = "<HTML> <BODY> <h1>Degree Distribution Metric Report </h1> "
371
 
                + "<hr>"
372
 
                + "<br>"
373
 
                + "<h2> Parameters: </h2>"
374
 
                + "Network Interpretation:  " + (isDirected ? "directed" : "undirected") + "<br>"
375
 
                + "<br> <h2> Results: </h2>"
376
 
                + "In-Degree Power Law: -" + inAlpha + "\n <BR>"
377
 
                + inImageFile + "<br>Out-Degree Power Law: -" + outAlpha + "\n <BR>"
378
 
                + outImageFile + "</BODY> </HTML>";
379
 
 
380
 
 
381
 
        return report;
382
 
    }
383
 
 
384
 
    /**
385
 
     *
386
 
     * @return The undirected version of this report.
387
 
     */
388
 
    private String getUndirectedReport() {
389
 
        double max = 0;
390
 
        XYSeries series2 = new XYSeries("Series 2");
391
 
        for (int i = 1; i < combinedDistribution[1].length; i++) {
392
 
            if (combinedDistribution[1][i] > 0) {
393
 
                series2.add((Math.log(combinedDistribution[0][i]) / Math.log(Math.E)), (Math.log(combinedDistribution[1][i]) / Math.log(Math.E)));
394
 
                max = (float) Math.max((Math.log(combinedDistribution[0][i]) / Math.log(Math.E)), max);
395
 
            }
396
 
        }
397
 
        double a = combinedAlpha;
398
 
        double b = combinedBeta;
399
 
 
400
 
 
401
 
        XYSeries series1 = new XYSeries(combinedAlpha + " ");
402
 
        series1.add(0, a);
403
 
        series1.add(max, a + b * max);
404
 
 
405
 
        XYSeriesCollection dataset = new XYSeriesCollection();
406
 
        dataset.addSeries(series1);
407
 
        dataset.addSeries(series2);
408
 
 
409
 
        JFreeChart chart = ChartFactory.createXYLineChart(
410
 
                "Degree Distribution",
411
 
                "Degree",
412
 
                "Occurrence",
413
 
                dataset,
414
 
                PlotOrientation.VERTICAL,
415
 
                true,
416
 
                false,
417
 
                false);
418
 
        XYPlot plot = (XYPlot) chart.getPlot();
419
 
        XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
420
 
        renderer.setSeriesLinesVisible(0, true);
421
 
        renderer.setSeriesShapesVisible(0, false);
422
 
        renderer.setSeriesLinesVisible(1, false);
423
 
        renderer.setSeriesShapesVisible(1, true);
424
 
        renderer.setSeriesShape(1, new java.awt.geom.Ellipse2D.Double(0, 0, 1, 1));
425
 
        plot.setBackgroundPaint(java.awt.Color.WHITE);
426
 
        plot.setDomainGridlinePaint(java.awt.Color.GRAY);
427
 
        plot.setRangeGridlinePaint(java.awt.Color.GRAY);
428
 
 
429
 
        plot.setRenderer(renderer);
430
 
 
431
 
 
432
 
        String imageFile = "";
433
 
        try {
434
 
            final ChartRenderingInfo info = new ChartRenderingInfo(new StandardEntityCollection());
435
 
            TempDir tempDir = TempDirUtils.createTempDir();
436
 
            final String fileName = "distribution.png";
437
 
            final File file1 = tempDir.createFile(fileName);
438
 
            imageFile = "<IMG SRC=\"file:" + file1.getAbsolutePath() + "\" " + "WIDTH=\"600\" HEIGHT=\"400\" BORDER=\"0\" USEMAP=\"#chart\"></IMG>";
439
 
            ChartUtilities.saveChartAsPNG(file1, chart, 600, 400, info);
440
 
 
441
 
        } catch (IOException e) {
442
 
            System.out.println(e.toString());
443
 
        }
444
 
 
445
 
 
446
 
        String report = "<HTML> <BODY> <h1>Degree Distribution Metric Report </h1> "
447
 
                + "<hr>"
448
 
                + "<br>"
449
 
                + "<h2> Parameters: </h2>"
450
 
                + "Network Interpretation:  " + (isDirected ? "directed" : "undirected") + "<br>"
451
 
                + "<br> <h2> Results: </h2>"
452
 
                + "Degree Power Law: -" + combinedAlpha + "\n <BR>"
453
 
                + imageFile + "</BODY> </HTML>";
454
 
        return report;
455
 
    }
456
 
 
457
 
    /**
458
 
     * @return Indicates that the metric canceled flag was set.
459
 
     */
460
 
    public boolean cancel() {
461
 
        isCanceled = true;
462
 
        return true;
463
 
    }
464
 
 
465
 
    /**
466
 
     * @param progressTicket Sets the progress meter for the metric.
467
 
     */
468
 
    public void setProgressTicket(ProgressTicket pProgressTicket) {
469
 
        progress = pProgressTicket;
470
 
    }
471
 
}