source: trunk/autoquest-ui-swt/src/main/java/de/ugoe/cs/autoquest/ui/swt/TaskTreePlotUtils.java @ 2061

Last change on this file since 2061 was 2061, checked in by pharms, 8 years ago
File size: 19.7 KB
Line 
1//   Copyright 2012 Georg-August-Universität Göttingen, Germany
2//
3//   Licensed under the Apache License, Version 2.0 (the "License");
4//   you may not use this file except in compliance with the License.
5//   You may obtain a copy of the License at
6//
7//       http://www.apache.org/licenses/LICENSE-2.0
8//
9//   Unless required by applicable law or agreed to in writing, software
10//   distributed under the License is distributed on an "AS IS" BASIS,
11//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12//   See the License for the specific language governing permissions and
13//   limitations under the License.
14
15package de.ugoe.cs.autoquest.ui.swt;
16
17import java.awt.BasicStroke;
18import java.awt.Graphics2D;
19import java.awt.geom.Ellipse2D;
20import java.awt.geom.Rectangle2D;
21import java.io.BufferedOutputStream;
22import java.io.FileOutputStream;
23import java.text.DecimalFormat;
24import java.util.HashMap;
25import java.util.HashSet;
26import java.util.LinkedList;
27import java.util.List;
28import java.util.Map;
29import java.util.Set;
30import java.util.TreeMap;
31
32import org.jfree.chart.ChartFactory;
33import org.jfree.chart.JFreeChart;
34import org.jfree.chart.axis.AxisLocation;
35import org.jfree.chart.axis.LogarithmicAxis;
36import org.jfree.chart.axis.NumberAxis;
37import org.jfree.chart.plot.PlotOrientation;
38import org.jfree.chart.plot.ValueMarker;
39import org.jfree.chart.plot.XYPlot;
40import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
41import org.jfree.chart.title.TextTitle;
42import org.jfree.data.xy.DefaultTableXYDataset;
43import org.jfree.data.xy.XYDataset;
44import org.jfree.data.xy.XYSeries;
45import org.jfree.ui.RectangleAnchor;
46import org.jfree.ui.RectangleInsets;
47
48import com.lowagie.text.Rectangle;
49import com.lowagie.text.pdf.DefaultFontMapper;
50import com.lowagie.text.pdf.PdfContentByte;
51import com.lowagie.text.pdf.PdfTemplate;
52import com.lowagie.text.pdf.PdfWriter;
53
54import de.ugoe.cs.autoquest.tasktrees.treeifc.DefaultTaskInstanceTraversingVisitor;
55import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTask;
56import de.ugoe.cs.autoquest.tasktrees.treeifc.IEventTaskInstance;
57import de.ugoe.cs.autoquest.tasktrees.treeifc.ISequence;
58import de.ugoe.cs.autoquest.tasktrees.treeifc.ITask;
59import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInfo;
60import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskInstance;
61import de.ugoe.cs.autoquest.tasktrees.treeifc.ITaskModel;
62import de.ugoe.cs.autoquest.tasktrees.treeifc.TaskMetric;
63import de.ugoe.cs.autoquest.tasktrees.treeifc.TaskTreeUtils;
64
65/**
66 * <p>
67 * TODO comment
68 * </p>
69 *
70 * @author Patrick Harms
71 */
72public class TaskTreePlotUtils {
73   
74    /** name for visualizing a task count to event coverage plot */
75    public static final String TASK_COUNT__EVENT_COVERAGE_PLOT = "event coverage plot";
76   
77    /** name for visualizing the instance counts of tasks ordered by the event coverage */
78    public static final String ORDERED_TASK_COUNT_PLOT = "task instance count - coverage plot";
79   
80    /** name for visualizing a cumulative coverage of events by the tasks orded by their event
81     *  coverage */
82    public static final String CUMULATIVE_TASK_COVERAGE_PLOT = "cumulative task coverage plot";
83   
84    /** colors */
85    public static final java.awt.Color[] colors = new java.awt.Color[] {
86        java.awt.Color.BLACK, java.awt.Color.GRAY, java.awt.Color.RED, java.awt.Color.CYAN,
87        java.awt.Color.ORANGE, java.awt.Color.GREEN, java.awt.Color.MAGENTA, java.awt.Color.BLUE,
88        java.awt.Color.PINK, java.awt.Color.DARK_GRAY, java.awt.Color.LIGHT_GRAY,
89        java.awt.Color.YELLOW
90    };
91   
92    /**
93     *
94     */
95    public static JFreeChart createPlot(String           name,
96                                        List<ITaskModel> models,
97                                        List<String>     modelNames,
98                                        List<Integer>    groups)
99    {
100        JFreeChart chart = null;
101       
102        if (TASK_COUNT__EVENT_COVERAGE_PLOT.equals(name)) {
103            XYDataset dataset1 = createTaskCountEventCoveragePlotDataSet(models.get(0));
104           
105            chart = ChartFactory.createXYLineChart
106                (TASK_COUNT__EVENT_COVERAGE_PLOT, "task counts", "event coverage",
107                 dataset1, PlotOrientation.VERTICAL, models.size() > 1, false, false);
108           
109            for (int i = 1; i < models.size(); i++) {
110                chart.getXYPlot().setDataset
111                    (i, createTaskCountEventCoveragePlotDataSet(models.get(i)));
112            }
113           
114            XYPlot plot = chart.getXYPlot();
115            NumberAxis domainAxis = new LogarithmicAxis("task counts");
116            NumberAxis rangeAxis = new LogarithmicAxis("event coverage");
117            plot.setDomainAxis(domainAxis);
118            plot.setRangeAxis(rangeAxis);
119        }
120        else if (CUMULATIVE_TASK_COVERAGE_PLOT.equals(name)) {
121            Set<ISequence> mostProminent =
122                TaskTreeUtils.getMostProminentTasks(models.get(0), models.get(0).getTasks());
123           
124            XYDataset dataset = createCumulativeTaskCoveragePlotDataSet(models.get(0),
125                                                                        modelNames.get(0));
126            chart = ChartFactory.createXYLineChart
127                (CUMULATIVE_TASK_COVERAGE_PLOT,
128                 "Sequences ordered by coverage in % of sequences",
129                 "Cumulative action instance coverage in % of all recorded action instances",
130                 dataset, PlotOrientation.VERTICAL, models.size() > 1, false, false);
131           
132            final XYPlot plot = chart.getXYPlot();
133            plot.setBackgroundPaint(java.awt.Color.WHITE);
134            plot.setDomainAxisLocation(AxisLocation.BOTTOM_OR_RIGHT);
135           
136            double mpMarker = (double) 100 * mostProminent.size() / dataset.getItemCount(0);
137            ValueMarker marker = new ValueMarker(mpMarker);
138            marker.setLabel(new DecimalFormat("#0.0").format(mpMarker));
139            marker.setLabelAnchor(RectangleAnchor.BOTTOM);
140            marker.setLabelOffset(new RectangleInsets(0, -12, 10, 15));
141            plot.addDomainMarker(marker);
142           
143            double xLow = 0;
144            double yLow = 0;
145            double xHigh = 100;
146            double yHigh = 100;
147            double maxY = 0;
148            for (int i = 0; i < dataset.getItemCount(0); i++) {
149                double xValue = dataset.getXValue(0, i);
150                double yValue = dataset.getYValue(0, i);
151               
152                if ((xLow < xValue) && (xValue < mpMarker)) {
153                    xLow = xValue;
154                    yLow = yValue;
155                }
156                else if ((xHigh > xValue) && (xValue > mpMarker)) {
157                    xHigh = xValue;
158                    yHigh = yValue;
159                }
160               
161                maxY = Math.max(maxY, yValue);
162            }
163           
164            marker = new ValueMarker((yHigh + yLow) / 2);
165            marker.setLabel(new DecimalFormat("#0.0").format((yHigh + yLow) / 2));
166            marker.setLabelOffset(new RectangleInsets(5, 15, 0, 10));
167            plot.addRangeMarker(marker);
168            marker = new ValueMarker(maxY);
169            marker.setLabel(new DecimalFormat("#0.0").format(maxY));
170            marker.setLabelOffset(new RectangleInsets(5, 15, 0, 10));
171            plot.addRangeMarker(marker);
172           
173            plot.getRenderer(0).setSeriesPaint(0, colors[0]);
174            plot.getRenderer(0).setSeriesStroke(0, new BasicStroke(3.0f, BasicStroke.CAP_ROUND,
175                                                                   BasicStroke.JOIN_ROUND));
176           
177            for (int i = 1; i < models.size(); i++) {
178                plot.setDataset(i, createCumulativeTaskCoveragePlotDataSet(models.get(i),
179                                                                           modelNames.get(i)));
180               
181                plot.setRenderer(i, new XYLineAndShapeRenderer(true, false));
182                plot.getRenderer(i).setSeriesPaint(0, colors[groups.get(i)]);
183                plot.getRenderer(i).setSeriesStroke(0, new BasicStroke(1.0f, BasicStroke.CAP_ROUND,
184                                                                       BasicStroke.JOIN_ROUND));
185            }
186
187            NumberAxis domainAxis = new NumberAxis
188                ("Sequences ordered by coverage in % of sequences");
189           
190            domainAxis.setUpperBound(100);
191            plot.setDomainAxis(domainAxis);
192           
193            NumberAxis rangeAxis = new NumberAxis
194                ("Cumulative action instance coverage in % of all recorded action instances");
195           
196            rangeAxis.setUpperBound(100);
197            plot.setRangeAxis(rangeAxis);
198        }
199        else if (ORDERED_TASK_COUNT_PLOT.equals(name)) {
200            XYDataset dataset = createOrderedTaskCountPlotDataSet(models.get(0), modelNames.get(0));
201           
202            chart = ChartFactory.createXYLineChart
203                (ORDERED_TASK_COUNT_PLOT, "tasks ordered by coverage",
204                 "number of instances", dataset, PlotOrientation.VERTICAL, models.size() > 1,
205                 false, false);
206           
207            final XYPlot plot = chart.getXYPlot();
208            plot.setBackgroundPaint(java.awt.Color.WHITE);
209            plot.setDomainAxisLocation(AxisLocation.BOTTOM_OR_RIGHT);
210
211            XYLineAndShapeRenderer scatterRenderer = new XYLineAndShapeRenderer(false, true);
212            scatterRenderer.setSeriesShapesFilled(0, false);
213            scatterRenderer.setSeriesShape(0, new Ellipse2D.Float(-3.0f, -3.0f, 6.0f, 6.0f));
214            scatterRenderer.setSeriesPaint(0, colors[0]);
215            plot.setRenderer(0, scatterRenderer);
216
217            for (int i = 1; i < models.size(); i++) {
218                chart.getXYPlot().setDataset
219                    (i, createOrderedTaskCountPlotDataSet(models.get(i), modelNames.get(i)));
220               
221                scatterRenderer = new XYLineAndShapeRenderer(false, true);
222                scatterRenderer.setSeriesShapesFilled(0, false);
223                scatterRenderer.setSeriesShape(0, new Ellipse2D.Float(-3.0f, -3.0f, 6.0f, 6.0f));
224                scatterRenderer.setSeriesPaint(0, colors[i]);
225                plot.setRenderer(i, scatterRenderer);
226            }
227
228            NumberAxis domainAxis = new NumberAxis("sequences ordered by coverage");
229            domainAxis.setUpperBound(100);
230            plot.setDomainAxis(domainAxis);
231           
232            NumberAxis rangeAxis = new LogarithmicAxis("number of instances");
233            plot.setRangeAxis(rangeAxis);
234        }
235
236        return chart;
237    }
238   
239    /**
240     *
241     */
242    public static void saveChartToPDF(JFreeChart chart, String fileName, int width, int height)
243        throws Exception
244    {
245        if (chart != null) {
246            BufferedOutputStream out = null;
247            try {
248                out = new BufferedOutputStream(new FileOutputStream(fileName));
249                   
250                //convert chart to PDF with iText:
251                Rectangle pagesize = new Rectangle(width, height);
252                com.lowagie.text.Document document =
253                    new com.lowagie.text.Document(pagesize, 50, 50, 50, 50);
254               
255                try {
256                    PdfWriter writer = PdfWriter.getInstance(document, out);
257                    document.addAuthor("JFreeChart");
258                    document.open();
259           
260                    PdfContentByte cb = writer.getDirectContent();
261                    PdfTemplate tp = cb.createTemplate(width, height);
262                    Graphics2D g2 = tp.createGraphics(width, height, new DefaultFontMapper());
263           
264                    Rectangle2D r2D = new Rectangle2D.Double(0, 0, width, height);
265                    TextTitle title = chart.getTitle();
266                    chart.setTitle((TextTitle) null);
267                    chart.draw(g2, r2D, null);
268                    chart.setTitle(title);
269                    g2.dispose();
270                    cb.addTemplate(tp, 0, 0);
271                }
272                finally {
273                    document.close();
274                }
275            }
276            finally {
277                if (out != null) {
278                    out.close();
279                }
280            }
281        }
282    }
283
284    /**
285     *
286     */
287    private static XYDataset createTaskCountEventCoveragePlotDataSet(ITaskModel taskModel) {
288        // tree maps required to have sorted maps
289        TreeMap<Integer, Integer> minValues = new TreeMap<>();
290        TreeMap<Integer, List<Integer>> allValues = new TreeMap<>();
291        TreeMap<Integer, Integer> maxValues = new TreeMap<>();
292       
293        for (ITask task : taskModel.getTasks()) {
294            if (task instanceof ISequence) {
295                ITaskInfo info = taskModel.getTaskInfo(task);
296                int count = task.getInstances().size();
297                int eventCoverage = info.getMeasureValue(TaskMetric.EVENT_COVERAGE);
298
299                Integer minValue = minValues.get(count);
300
301                if ((minValue == null) || (minValue > eventCoverage)) {
302                    minValues.put(count, eventCoverage);
303                }
304
305                Integer maxValue = maxValues.get(count);
306
307                if ((maxValue == null) || (maxValue < eventCoverage)) {
308                    maxValues.put(count, eventCoverage);
309                }
310
311                List<Integer> values = allValues.get(count);
312
313                if (values == null) {
314                    values = new LinkedList<Integer>();
315                    allValues.put(count, values);
316                }
317
318                values.add(eventCoverage);
319            }
320        }
321       
322        DefaultTableXYDataset dataset = new DefaultTableXYDataset();
323        XYSeries minSeries = new XYSeries("min values", true, false);
324        XYSeries avgSeries = new XYSeries("avg values", true, false);
325        XYSeries maxSeries = new XYSeries("max values", true, false);
326       
327        // entries are correctly sorted due to the map
328        for (Map.Entry<Integer, List<Integer>> entry : allValues.entrySet()) {
329            int count = entry.getKey();
330
331            minSeries.add(count, minValues.get(count));
332            maxSeries.add(count, maxValues.get(count));
333           
334            avgSeries.add(count, getAverage(entry.getValue()));
335        }
336       
337        dataset.addSeries(minSeries);
338        dataset.addSeries(avgSeries);
339        dataset.addSeries(maxSeries);
340        return dataset;
341    }
342
343    /**
344     *
345     */
346    private static XYDataset createCumulativeTaskCoveragePlotDataSet(ITaskModel     taskModel,
347                                                                     String         taskModelName)
348    {
349        Map<Integer, List<ISequence>> coverageCounts = new HashMap<>();
350        Map<ISequence, Set<IEventTaskInstance>> coverages = new HashMap<>();
351        Set<IEventTaskInstance> allEvents = new HashSet<>();
352        int maxCoverage = 0;
353       
354        for (ITask task : taskModel.getTasks()) {
355            if (task instanceof ISequence) {
356                final Set<IEventTaskInstance> coveredEvents = new HashSet<>();
357               
358                for (ITaskInstance instance : task.getInstances()) {
359                    instance.accept(new DefaultTaskInstanceTraversingVisitor() {
360                        @Override
361                        public void visit(IEventTaskInstance eventTaskInstance) {
362                            coveredEvents.add(eventTaskInstance);
363                        }
364                    });
365                }
366               
367                coverages.put((ISequence) task, coveredEvents);
368               
369                List<ISequence> tasksWithSameCoverage = coverageCounts.get(coveredEvents.size());
370
371                if (tasksWithSameCoverage == null) {
372                    tasksWithSameCoverage = new LinkedList<>();
373                    coverageCounts.put(coveredEvents.size(), tasksWithSameCoverage);
374                }
375
376                tasksWithSameCoverage.add((ISequence) task);
377               
378                maxCoverage = Math.max(maxCoverage, coveredEvents.size());
379            }
380            else if (task instanceof IEventTask) {
381                for (ITaskInstance instance : task.getInstances()) {
382                    allEvents.add((IEventTaskInstance) instance);
383                }
384            }
385        }
386       
387        XYSeries cumulativeSeries = new XYSeries(taskModelName, true, false);
388        Set<IEventTaskInstance> cumulativeCoverage = new HashSet<>();
389       
390        // entries are correctly sorted due to the map
391        int sequenceIndex = 1;
392       
393        for (int i = maxCoverage; i > 0; i--) {
394            List<ISequence> sequencesWithSameCoverage = coverageCounts.get(i);
395
396            if (sequencesWithSameCoverage == null) {
397                continue;
398            }
399           
400            for (ISequence sequence : sequencesWithSameCoverage) {
401                cumulativeCoverage.addAll(coverages.get(sequence));
402                double xvalue = (double) 100 * sequenceIndex / coverages.size();
403                double yvalue = (double) 100 * cumulativeCoverage.size() / allEvents.size();
404                cumulativeSeries.add(xvalue, yvalue);
405                sequenceIndex++;
406            }
407        }
408       
409        DefaultTableXYDataset dataset = new DefaultTableXYDataset();
410        dataset.addSeries(cumulativeSeries);
411        return dataset;
412    }
413
414    /**
415     *
416     */
417    private static XYDataset createOrderedTaskCountPlotDataSet(ITaskModel taskModel,
418                                                               String     taskModelName)
419    {
420        Map<Integer, List<ISequence>> coverageCounts = new HashMap<>();
421        Map<ISequence, Set<IEventTaskInstance>> coverages = new HashMap<>();
422        int maxCoverage = 0;
423       
424        for (ITask task : taskModel.getTasks()) {
425            if (task instanceof ISequence) {
426                final Set<IEventTaskInstance> coveredEvents = new HashSet<>();
427               
428                for (ITaskInstance instance : task.getInstances()) {
429                    instance.accept(new DefaultTaskInstanceTraversingVisitor() {
430                        @Override
431                        public void visit(IEventTaskInstance eventTaskInstance) {
432                            coveredEvents.add(eventTaskInstance);
433                        }
434                    });
435                }
436               
437                coverages.put((ISequence) task, coveredEvents);
438               
439                List<ISequence> tasksWithSameCoverage = coverageCounts.get(coveredEvents.size());
440
441                if (tasksWithSameCoverage == null) {
442                    tasksWithSameCoverage = new LinkedList<>();
443                    coverageCounts.put(coveredEvents.size(), tasksWithSameCoverage);
444                }
445
446                tasksWithSameCoverage.add((ISequence) task);
447               
448                maxCoverage = Math.max(maxCoverage, coveredEvents.size());
449            }
450        }
451       
452        XYSeries counts = new XYSeries(taskModelName, true, false);
453       
454        // entries are correctly sorted due to the map
455        int sequenceIndex = 1;
456       
457        for (int i = maxCoverage; i > 0; i--) {
458            List<ISequence> sequencesWithSameCoverage = coverageCounts.get(i);
459
460            if (sequencesWithSameCoverage == null) {
461                continue;
462            }
463           
464            for (ISequence sequence : sequencesWithSameCoverage) {
465                double xvalue = (double) 100 * sequenceIndex / coverages.size();
466                counts.add(xvalue, sequence.getInstances().size());
467                sequenceIndex++;
468            }
469        }
470       
471        DefaultTableXYDataset dataset = new DefaultTableXYDataset();
472        dataset.addSeries(counts);
473        return dataset;
474    }
475
476
477    /**
478     *
479     */
480    private static double getAverage(List<Integer> values) {
481        int all = 0;
482       
483        for (Integer value : values) {
484            all += value;
485        }
486
487        return ((double) all) / values.size();
488    }
489}
Note: See TracBrowser for help on using the repository browser.