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

Last change on this file since 2168 was 2168, checked in by pharms, 7 years ago
  • changes for first VR oriented usability evaluation
File size: 20.9 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 yMP = dataset.getYValue(0, mostProminent.size() - 1);
171            double maxY = dataset.getYValue(0, dataset.getItemCount(0) - 1);
172           
173            marker = new ValueMarker(yMP);
174            marker.setLabel(new DecimalFormat("#0.0").format(yMP));
175            marker.setLabelOffset(new RectangleInsets(5, 15, 0, 10));
176            plot.addRangeMarker(marker);
177            marker = new ValueMarker(maxY);
178            marker.setLabel(new DecimalFormat("#0.0").format(maxY));
179            marker.setLabelOffset(new RectangleInsets(5, 15, 0, 10));
180            plot.addRangeMarker(marker);
181           
182            plot.getRenderer(0).setSeriesPaint(0, colors[0]);
183            plot.getRenderer(0).setSeriesStroke(0, new BasicStroke(3.0f, BasicStroke.CAP_ROUND,
184                                                                   BasicStroke.JOIN_ROUND));
185           
186            for (int i = 1; i < models.size(); i++) {
187                plot.setDataset(i, createCumulativeTaskCoveragePlotDataSet(models.get(i),
188                                                                           modelNames.get(i)));
189               
190                plot.setRenderer(i, new XYLineAndShapeRenderer(true, false));
191                plot.getRenderer(i).setSeriesPaint(0, colors[groups.get(i)]);
192                plot.getRenderer(i).setSeriesStroke(0, new BasicStroke(1.0f, BasicStroke.CAP_ROUND,
193                                                                       BasicStroke.JOIN_ROUND));
194            }
195
196            NumberAxis domainAxis = new NumberAxis
197                ("Sequences ordered by coverage in % of sequences");
198           
199            domainAxis.setUpperBound(100);
200            plot.setDomainAxis(domainAxis);
201           
202            NumberAxis rangeAxis = new NumberAxis
203                ("Cumulative action instance coverage in % of all recorded action instances");
204           
205            rangeAxis.setUpperBound(100);
206            plot.setRangeAxis(rangeAxis);
207        }
208        else if (ORDERED_TASK_COUNT_PLOT.equals(name)) {
209            XYDataset dataset = createOrderedTaskCountPlotDataSet(models.get(0), modelNames.get(0));
210           
211            chart = ChartFactory.createXYLineChart
212                (ORDERED_TASK_COUNT_PLOT, "tasks ordered by coverage",
213                 "number of instances", dataset, PlotOrientation.VERTICAL, models.size() > 1,
214                 false, false);
215           
216            final XYPlot plot = chart.getXYPlot();
217            plot.setBackgroundPaint(java.awt.Color.WHITE);
218            plot.setDomainAxisLocation(AxisLocation.BOTTOM_OR_RIGHT);
219
220            XYLineAndShapeRenderer scatterRenderer = new XYLineAndShapeRenderer(false, true);
221            scatterRenderer.setSeriesShapesFilled(0, false);
222            scatterRenderer.setSeriesShape(0, new Ellipse2D.Float(-3.0f, -3.0f, 6.0f, 6.0f));
223            scatterRenderer.setSeriesPaint(0, colors[0]);
224            plot.setRenderer(0, scatterRenderer);
225
226            for (int i = 1; i < models.size(); i++) {
227                chart.getXYPlot().setDataset
228                    (i, createOrderedTaskCountPlotDataSet(models.get(i), modelNames.get(i)));
229               
230                scatterRenderer = new XYLineAndShapeRenderer(false, true);
231                scatterRenderer.setSeriesShapesFilled(0, false);
232                scatterRenderer.setSeriesShape(0, new Ellipse2D.Float(-3.0f, -3.0f, 6.0f, 6.0f));
233                scatterRenderer.setSeriesPaint(0, colors[i]);
234                plot.setRenderer(i, scatterRenderer);
235            }
236
237            NumberAxis domainAxis = new NumberAxis("sequences ordered by coverage");
238            domainAxis.setUpperBound(100);
239            plot.setDomainAxis(domainAxis);
240           
241            NumberAxis rangeAxis = new LogarithmicAxis("number of instances");
242            plot.setRangeAxis(rangeAxis);
243        }
244
245        return chart;
246    }
247   
248    /**
249     *
250     */
251    public static void saveChartToPDF(JFreeChart chart, String fileName, int width, int height)
252        throws Exception
253    {
254        if (chart != null) {
255            BufferedOutputStream out = null;
256            try {
257                out = new BufferedOutputStream(new FileOutputStream(fileName));
258                   
259                //convert chart to PDF with iText:
260                Rectangle pagesize = new Rectangle(width, height);
261                com.lowagie.text.Document document =
262                    new com.lowagie.text.Document(pagesize, 50, 50, 50, 50);
263               
264                try {
265                    PdfWriter writer = PdfWriter.getInstance(document, out);
266                    document.addAuthor("JFreeChart");
267                    document.open();
268           
269                    PdfContentByte cb = writer.getDirectContent();
270                    PdfTemplate tp = cb.createTemplate(width, height);
271                    Graphics2D g2 = tp.createGraphics(width, height, new DefaultFontMapper());
272           
273                    Rectangle2D r2D = new Rectangle2D.Double(0, 0, width, height);
274                    TextTitle title = chart.getTitle();
275                    chart.setTitle((TextTitle) null);
276                    chart.draw(g2, r2D, null);
277                    chart.setTitle(title);
278                    g2.dispose();
279                    cb.addTemplate(tp, 0, 0);
280                }
281                finally {
282                    document.close();
283                }
284            }
285            finally {
286                if (out != null) {
287                    out.close();
288                }
289            }
290        }
291    }
292
293    /**
294     *
295     */
296    private static XYDataset createTaskCountEventCoveragePlotDataSet(ITaskModel taskModel,
297                                                                     String     taskModelName)
298    {
299        Map<Integer, List<ISequence>> coverageCounts = new HashMap<>();
300        Map<ISequence, Set<IEventTaskInstance>> coverages = new HashMap<>();
301        Set<IEventTaskInstance> allEvents = new HashSet<>();
302        int maxCoverage = 0;
303       
304        for (ITask task : taskModel.getTasks()) {
305            if (task instanceof ISequence) {
306                final Set<IEventTaskInstance> coveredEvents = new HashSet<>();
307               
308                for (ITaskInstance instance : task.getInstances()) {
309                    instance.accept(new DefaultTaskInstanceTraversingVisitor() {
310                        @Override
311                        public void visit(IEventTaskInstance eventTaskInstance) {
312                            coveredEvents.add(eventTaskInstance);
313                        }
314                    });
315                }
316               
317                coverages.put((ISequence) task, coveredEvents);
318               
319                List<ISequence> tasksWithSameCoverage = coverageCounts.get(coveredEvents.size());
320
321                if (tasksWithSameCoverage == null) {
322                    tasksWithSameCoverage = new LinkedList<>();
323                    coverageCounts.put(coveredEvents.size(), tasksWithSameCoverage);
324                }
325
326                tasksWithSameCoverage.add((ISequence) task);
327               
328                maxCoverage = Math.max(maxCoverage, coveredEvents.size());
329            }
330            else if (task instanceof IEventTask) {
331                for (ITaskInstance instance : task.getInstances()) {
332                    allEvents.add((IEventTaskInstance) instance);
333                }
334            }
335        }
336       
337        XYSeries countSeries = new XYSeries(taskModelName, true, false);
338       
339        // entries are correctly sorted due to the map
340        int sequenceIndex = 1;
341       
342        for (int i = maxCoverage; i > 0; i--) {
343            List<ISequence> sequencesWithSameCoverage = coverageCounts.get(i);
344
345            if (sequencesWithSameCoverage == null) {
346                continue;
347            }
348           
349            for (ISequence sequence : sequencesWithSameCoverage) {
350                double xvalue = (double) 100 * sequenceIndex / coverages.size();
351                double yvalue = (double) 100 * coverages.get(sequence).size() / allEvents.size();
352                countSeries.add(xvalue, yvalue);
353                sequenceIndex++;
354            }
355        }
356       
357        DefaultTableXYDataset dataset = new DefaultTableXYDataset();
358        dataset.addSeries(countSeries);
359        return dataset;
360    }
361
362    /**
363     *
364     */
365    private static XYDataset createCumulativeTaskCoveragePlotDataSet(ITaskModel     taskModel,
366                                                                     String         taskModelName)
367    {
368        Map<Integer, List<ISequence>> coverageCounts = new HashMap<>();
369        Map<ISequence, Set<IEventTaskInstance>> coverages = new HashMap<>();
370        Set<IEventTaskInstance> allEvents = new HashSet<>();
371        int maxCoverage = 0;
372       
373        for (ITask task : taskModel.getTasks()) {
374            if (task instanceof ISequence) {
375                final Set<IEventTaskInstance> coveredEvents = new HashSet<>();
376               
377                for (ITaskInstance instance : task.getInstances()) {
378                    instance.accept(new DefaultTaskInstanceTraversingVisitor() {
379                        @Override
380                        public void visit(IEventTaskInstance eventTaskInstance) {
381                            coveredEvents.add(eventTaskInstance);
382                        }
383                    });
384                }
385               
386                coverages.put((ISequence) task, coveredEvents);
387               
388                List<ISequence> tasksWithSameCoverage = coverageCounts.get(coveredEvents.size());
389
390                if (tasksWithSameCoverage == null) {
391                    tasksWithSameCoverage = new LinkedList<>();
392                    coverageCounts.put(coveredEvents.size(), tasksWithSameCoverage);
393                }
394
395                tasksWithSameCoverage.add((ISequence) task);
396               
397                maxCoverage = Math.max(maxCoverage, coveredEvents.size());
398            }
399            else if (task instanceof IEventTask) {
400                for (ITaskInstance instance : task.getInstances()) {
401                    allEvents.add((IEventTaskInstance) instance);
402                }
403            }
404        }
405       
406        XYSeries cumulativeSeries = new XYSeries(taskModelName, true, false);
407        Set<IEventTaskInstance> cumulativeCoverage = new HashSet<>();
408       
409        // entries are correctly sorted due to the map
410        int sequenceIndex = 1;
411       
412        for (int i = maxCoverage; i > 0; i--) {
413            List<ISequence> sequencesWithSameCoverage = coverageCounts.get(i);
414
415            if (sequencesWithSameCoverage == null) {
416                continue;
417            }
418           
419            for (ISequence sequence : sequencesWithSameCoverage) {
420                cumulativeCoverage.addAll(coverages.get(sequence));
421                double xvalue = (double) 100 * sequenceIndex / coverages.size();
422                double yvalue = (double) 100 * cumulativeCoverage.size() / allEvents.size();
423                cumulativeSeries.add(xvalue, yvalue);
424                sequenceIndex++;
425            }
426        }
427       
428        DefaultTableXYDataset dataset = new DefaultTableXYDataset();
429        dataset.addSeries(cumulativeSeries);
430        return dataset;
431    }
432
433    /**
434     *
435     */
436    private static XYDataset createOrderedTaskCountPlotDataSet(ITaskModel taskModel,
437                                                               String     taskModelName)
438    {
439        Map<Integer, List<ISequence>> coverageCounts = new HashMap<>();
440        Map<ISequence, Set<IEventTaskInstance>> coverages = new HashMap<>();
441        int maxCoverage = 0;
442       
443        for (ITask task : taskModel.getTasks()) {
444            if (task instanceof ISequence) {
445                final Set<IEventTaskInstance> coveredEvents = new HashSet<>();
446               
447                for (ITaskInstance instance : task.getInstances()) {
448                    instance.accept(new DefaultTaskInstanceTraversingVisitor() {
449                        @Override
450                        public void visit(IEventTaskInstance eventTaskInstance) {
451                            coveredEvents.add(eventTaskInstance);
452                        }
453                    });
454                }
455               
456                coverages.put((ISequence) task, coveredEvents);
457               
458                List<ISequence> tasksWithSameCoverage = coverageCounts.get(coveredEvents.size());
459
460                if (tasksWithSameCoverage == null) {
461                    tasksWithSameCoverage = new LinkedList<>();
462                    coverageCounts.put(coveredEvents.size(), tasksWithSameCoverage);
463                }
464
465                tasksWithSameCoverage.add((ISequence) task);
466               
467                maxCoverage = Math.max(maxCoverage, coveredEvents.size());
468            }
469        }
470       
471        XYSeries counts = new XYSeries(taskModelName, true, false);
472       
473        // entries are correctly sorted due to the map
474        int sequenceIndex = 1;
475       
476        for (int i = maxCoverage; i > 0; i--) {
477            List<ISequence> sequencesWithSameCoverage = coverageCounts.get(i);
478
479            if (sequencesWithSameCoverage == null) {
480                continue;
481            }
482           
483            for (ISequence sequence : sequencesWithSameCoverage) {
484                double xvalue = (double) 100 * sequenceIndex / coverages.size();
485                counts.add(xvalue, sequence.getInstances().size());
486                sequenceIndex++;
487            }
488        }
489       
490        DefaultTableXYDataset dataset = new DefaultTableXYDataset();
491        dataset.addSeries(counts);
492        return dataset;
493    }
494
495}
Note: See TracBrowser for help on using the repository browser.