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

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