- added multiple format support for input data (now supports csv, tabs, ; and spaces)
[mldemos:baraks-mldemos.git] / Core / expose.cpp
1 #include <public.h>
2 #include <mymaths.h>
3 #include "expose.h"
4 #include "ui_expose.h"
5 #include <QClipboard>
6 #include <QBitmap>
7 #include <QDebug>
8
9 using namespace std;
10
11 Expose::Expose(Canvas *canvas, QWidget *parent) :
12     QWidget(parent),
13     ui(new Ui::Expose),
14     canvas(canvas)
15 {
16     ui->setupUi(this);
17     connect(ui->typeCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(Repaint()));
18     connect(ui->clipboardButton, SIGNAL(clicked()), this, SLOT(Clipboard()));
19     this->setWindowTitle("Multivariate Visualisation");
20 }
21
22 Expose::~Expose()
23 {
24     delete ui;
25 }
26
27 void Expose::DrawData(QPixmap& pixmap, std::vector<fvec> samples, ivec labels, int type, bool bProjected)
28 {
29     if(!samples.size() || !labels.size()) return;
30     vector<QColor> sampleColors(labels.size());
31     FOR(i, labels.size())
32     {
33         QColor color = SampleColor[labels[i]%SampleColorCnt];
34         sampleColors[i] = color;
35     }
36     DrawData(pixmap, samples, sampleColors, type, bProjected);
37 }
38
39 void Expose::DrawData(QPixmap& pixmap, std::vector<fvec> samples, std::vector<QColor> sampleColors, int type, bool bProjected, bool bLearned)
40 {
41     if(!samples.size()) return;
42     int w = pixmap.width(), h = pixmap.height();
43
44     int dim = samples[0].size();
45     int gridX = dim;
46     int gridY = dim;
47
48         fvec mins(dim, FLT_MAX), maxes(dim, -FLT_MIN), diffs(dim, 0);
49     FOR(d, dim)
50     {
51         FOR(i, samples.size())
52         {
53             mins[d] = min(mins[d], samples[i][d]);
54             maxes[d] = max(maxes[d], samples[i][d]);
55         }
56         }
57         FOR(d, dim)
58         {
59                 diffs[d] = maxes[d] - mins[d];
60         }
61
62     int pad = 20;
63     int mapW = w - pad*2, mapH = h - pad*2;
64     QPainter painter(&pixmap);
65     painter.setRenderHint(QPainter::Antialiasing);
66
67     switch(type)
68     {
69     case 0: // scatterplots
70     {
71         mapW = w/gridX - pad*2;
72         mapH = h/gridX - pad*2;
73         int radiusBase = max(5.f, 5 * sqrtf(mapW / 200.f));
74
75         QList<QPixmap> maps;
76         FOR(index0, dim)
77         {
78             FOR(index1, dim)
79                         {
80                 QPixmap map(mapW + 2*pad,mapH + 2*pad);
81                 int smallW = map.width() - 2*pad, smallH = map.height() - 2*pad;
82                 if(!bLearned) map.fill(Qt::white);
83                 else
84                 {
85                     QBitmap bitmap(map.size());
86                     bitmap.clear();
87                     map.setMask(bitmap);
88                     map.fill(Qt::transparent);
89                 }
90                 QPainter painter(&map);
91                 painter.setRenderHint(QPainter::Antialiasing);
92
93                                 if(diffs[index0] != 0.f && diffs[index1] != 0.f)
94                                 {
95                                         FOR(i, samples.size())
96                                         {
97                                                 float x = samples[i][index0];
98                                                 float y = samples[i][index1];
99                                                 x = (x-mins[index0])/diffs[index0];
100                                                 y = (y-mins[index1])/diffs[index1];
101                                                 QPointF point(y*smallW + pad, x*smallH + pad);
102                         float radius = radiusBase;
103                         if(bLearned)
104                         {
105                             radius = radiusBase + radiusBase/2;
106                             if(i < sampleColors.size()) painter.setPen(QPen(sampleColors[i], radiusBase/2));
107                             painter.setBrush(Qt::NoBrush);
108                             painter.drawEllipse(QRectF(point.x()-radius/2.,point.y()-radius/2.,radius,radius));
109                             radius += radiusBase/2-1;
110                             painter.setPen(QPen(Qt::black, 0.5));
111                             painter.drawEllipse(QRectF(point.x()-radius/2.,point.y()-radius/2.,radius,radius));
112                         }
113                         else
114                         {
115                             if(i < sampleColors.size()) painter.setBrush(sampleColors[i]);
116                             painter.setPen(Qt::black);
117                             painter.drawEllipse(QRectF(point.x()-radius/2.,point.y()-radius/2.,radius,radius));
118                         }
119                                         }
120                                 }
121                 painter.setBrush(Qt::NoBrush);
122                 painter.setPen(Qt::black);
123                 painter.setRenderHint(QPainter::Antialiasing, false);
124                 painter.drawRect(pad/2,pad/2,smallW+pad, smallH+pad);
125                 QString text =  QString("x%1  x%2").arg(index1+1).arg(index0+1);
126                 if(bProjected) text = QString("e%1  e%2").arg(index1+1).arg(index0+1);
127                 painter.drawText(pad/2+1, map.height()-pad/2-1,text);
128                 maps.push_back(map);
129             }
130         }
131
132         FOR(i, maps.size())
133         {
134             int xIndex = i%gridX;
135             int yIndex = i/gridX;
136             painter.drawPixmap(QPoint(xIndex*w/gridX, yIndex*h/gridY), maps[i]);
137         }
138     }
139         break;
140     case 1: // parallel coordinates
141     {
142         painter.setRenderHint(QPainter::Antialiasing, false);
143         FOR(d, dim)
144         {
145             float x = d*mapW/(float)(dim-1) + pad;
146             painter.setPen(Qt::black);
147             painter.drawLine(x, pad, x, mapH+pad);
148             QString text =  QString("x%1").arg(d+1);
149             if(bProjected) text = QString("e%1").arg(d+1);
150             painter.drawText(x-10, mapH+2*pad-4, text);
151         }
152
153         painter.setRenderHint(QPainter::Antialiasing);
154         FOR(i, samples.size())
155         {
156             QPointF old;
157                         FOR(d, dim)
158             {
159                                 if(diffs[d] == 0.f) continue;
160                                 float x = d*mapW/(float)(dim-1) + pad;
161                 float y = samples[i][d];
162                 y = (y-mins[d])/(maxes[d] - mins[d]);
163                 QPointF point(x,pad + y*mapH);
164                 float radius = 7;
165                 QColor color = Qt::black;
166                 if(i < sampleColors.size()) color = sampleColors[i];
167                 painter.setBrush(color);
168                 painter.setPen(Qt::black);
169                 painter.drawEllipse(QRectF(point.x()-radius/2.,point.y()-radius/2.,radius,radius));
170                 if(color == Qt::white) color = Qt::black;
171                 painter.setPen(color);
172                 if(d) painter.drawLine(point, old);
173                 old = point;
174             }
175         }
176     }
177         break;
178     case 2: // radial graphs
179     {
180         float radius = min(mapW, mapH)/3.f;
181         QPointF center(mapW*0.5f, mapH*0.5f);
182         QPointF old;
183         painter.setPen(Qt::black);
184         painter.setBrush(Qt::NoBrush);
185         painter.drawEllipse(center, radius, radius);
186         FOR(d, dim)
187         {
188                         float theta = d/(float)(dim)*2*M_PI;
189             QPointF point = QPointF(cos(theta), sin(theta))*radius;
190             painter.setBrush(Qt::white);
191             painter.drawEllipse(center+point, 4, 4);
192             QString text =  QString("x%1").arg(d+1);
193             if(bProjected) text = QString("e%1").arg(d+1);
194             painter.drawText(center + point*1.1, text);
195             old = point;
196         }
197
198         painter.setPen(Qt::black);
199         FOR(i, samples.size())
200         {
201             QPointF samplePoint;
202             float dimSum = 0;
203             FOR(d, dim)
204             {
205                                 if(diffs[d] == 0.f) continue;
206                                 float theta = d/(float)(dim)*2*M_PI;
207                 QPointF point = QPointF(cos(theta), sin(theta))*radius;
208                 float value = (samples[i][d]-mins[d])/(maxes[d]-mins[d]);
209                 samplePoint += point*value;
210                 dimSum += value;
211             }
212             samplePoint /= dimSum;
213             float drawRadius = 7;
214             QPointF point = center + samplePoint;
215             QColor color = Qt::black;
216             if(i < sampleColors.size()) color = sampleColors[i];
217             painter.setBrush(color);
218             painter.drawEllipse(QRectF(point.x()-drawRadius/2.,point.y()-drawRadius/2.,drawRadius,drawRadius));
219         }
220     }
221         break;
222     case 3: // andrews plots
223     {
224         float radius = min(mapW, mapH)/3.f;
225         QPointF center(mapW*0.5f, mapH*0.5f);
226         painter.setPen(Qt::black);
227
228         // f(t) = x0/sqrt(2) + x1*sin(t) + x2*cos(t) + x3*sin(2t) + x4*cos(2t) + x5*sin(3t) + x6*cos(3t) + x7*sin(4t)
229         vector<fvec> values(samples.size());
230         const int steps = 200;
231         float minv=FLT_MAX, maxv=-FLT_MAX;
232         FOR(i, samples.size())
233         {
234             values[i].resize(steps);
235             FOR(j, steps)
236             {
237                 float t = j/(float)steps*(M_PI*2) - M_PI;
238                 float value = 0;
239                 FOR(d, dim)
240                 {
241                                         if(diffs[d] == 0.f) continue;
242                                         float v = (samples[i][d]-mins[d])/(maxes[d]-mins[d]);
243                     if(!d) value += v*sqrtf(2.f);
244                     else
245                     {
246
247                         value += v * (d%2 ? sin(t*((d+1)/2)) : cos(t*((d+1)/2)));
248                     }
249                 }
250                 values[i][j] = value;
251                 minv = min(minv, value);
252                 maxv = max(maxv, value);
253             }
254         }
255
256         painter.setRenderHint(QPainter::Antialiasing, false);
257         painter.setPen(Qt::black);
258         painter.drawLine(pad, mapH-10+pad, mapW+pad, mapH-10+pad);
259         QFont font = painter.font();
260         font.setPointSize(9);
261         painter.setFont(font);
262         QStringList ticks;
263         ticks << "-pi" << "-pi/2" << "0" << "pi/2" << "pi";
264         FOR(i, 5)
265         {
266             int x = i*mapW/(4);
267             painter.setRenderHint(QPainter::Antialiasing, false);
268             painter.drawLine(pad + x, mapH-10 - 4 + pad, pad + x, mapH-10 + 4 + pad);
269             painter.setRenderHint(QPainter::Antialiasing);
270             painter.drawText(pad + x-25,mapH-10 + 4 + pad, 50, 20, Qt::AlignCenter, ticks[i]);
271         }
272
273         painter.setRenderHint(QPainter::Antialiasing);
274         FOR(i, values.size())
275         {
276             QColor color = Qt::black;
277             if(i < sampleColors.size()) color = sampleColors[i];
278             if(color == Qt::white) color = Qt::black;
279             painter.setPen(QPen(color,0.5));
280
281             QPointF old;
282             FOR(j, values[i].size())
283             {
284                 float value = (values[i][j]-minv)/(maxv-minv);
285                 QPointF point = QPointF(j*pixmap.width()/steps, value*mapH + pad);
286                 if(j) painter.drawLine(point, old);
287                 old = point;
288             }
289         }
290     }
291         break;
292     }
293 }
294
295 void Expose::DrawVariableData(QPixmap& pixmap, std::vector<fvec> samples, ivec labels, int type, fvec params, bool bProjected)
296 {
297     if(!samples.size() || !labels.size()) return;
298     vector<QColor> sampleColors(labels.size());
299     FOR(i, labels.size())
300     {
301         QColor color = SampleColor[labels[i]%SampleColorCnt];
302         sampleColors[i] = color;
303     }
304     DrawVariableData(pixmap, samples, sampleColors, type, params, bProjected);
305 }
306
307 void Expose::DrawVariableData(QPixmap& pixmap, std::vector<fvec> samples, std::vector<QColor> sampleColors, int type, fvec params, bool bProjected, bool bLearned)
308 {
309     if(!samples.size()) return;
310     int w = pixmap.width(), h = pixmap.height();
311
312     int dim = samples[0].size();
313     int gridX = dim;
314     int gridY = dim;
315
316     fvec mins(dim, FLT_MAX), maxes(dim, -FLT_MIN), diffs(dim, 0);
317     FOR(d, dim)
318     {
319         FOR(i, samples.size())
320         {
321             mins[d] = min(mins[d], samples[i][d]);
322             maxes[d] = max(maxes[d], samples[i][d]);
323         }
324     }
325     FOR(d, dim)
326     {
327         diffs[d] = maxes[d] - mins[d];
328     }
329
330     int pad = 20;
331     int mapW = w - pad*2, mapH = h - pad*2;
332     QPainter painter(&pixmap);
333     painter.setRenderHint(QPainter::Antialiasing);
334
335     painter.setPen(Qt::black);
336     switch(type)
337     {
338     case 0: // bubble graph
339     {
340         painter.setRenderHint(QPainter::Antialiasing, false);
341         painter.drawLine(pad, mapH+pad, mapW+pad, mapH+pad);
342         painter.drawLine(pad, pad, pad, mapH+pad);
343
344         int xIndex = params[0];
345         int yIndex = params[1];
346         int sIndex = params[2];
347         if(sIndex == -1)
348         {
349             srand48(0);
350             srand(0);
351         }
352         painter.setRenderHint(QPainter::Antialiasing);
353         FOR(i, samples.size())
354         {
355             float x = (samples[i][xIndex]-mins[xIndex])/(diffs[xIndex]);
356             float y = (samples[i][yIndex]-mins[yIndex])/(diffs[yIndex]);
357             QPointF point(x*mapW + pad,y*mapH + pad);
358
359             float radius = 10;
360             if(sIndex != -1)
361             {
362                 radius = (samples[i][sIndex]-mins[sIndex])/(diffs[sIndex]);
363                 radius = radius*60 + 3;
364             }
365             else
366             {
367                 radius = drand48()*40 + 3;
368             }
369
370             QColor color = Qt::black;
371             if(i < sampleColors.size()) color = sampleColors[i];
372             painter.setBrush(color);
373             painter.setPen(Qt::black);
374             painter.setOpacity(0.5f);
375             painter.drawEllipse(QRectF(point.x()-radius/2.,point.y()-radius/2.,radius,radius));
376         }
377     }
378     break;
379     }
380 }
381 void Expose::GenerateAndrewsPlots()
382 {
383     std::vector<fvec> samples = canvas->data->GetSamples();
384     ivec labels = canvas->data->GetLabels();
385     if(!samples.size()) return;
386     int dim = samples[0].size();
387
388     fvec mins(dim, FLT_MAX), maxes(dim, -FLT_MIN);
389     FOR(d, dim)
390     {
391         FOR(i, samples.size())
392         {
393             mins[d] = min(mins[d], samples[i][d]);
394             maxes[d] = max(maxes[d], samples[i][d]);
395         }
396     }
397
398     int pad = 20;
399     int mapW = (ui->scrollArea->width()-12) - pad*2, mapH = (ui->scrollArea->height()-12) - pad*2;
400
401     ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
402     ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
403     pixmap = QPixmap(ui->scrollArea->width(), ui->scrollArea->height());
404     pixmap.fill(Qt::white);
405     QPainter painter(&pixmap);
406     painter.setRenderHint(QPainter::Antialiasing);
407     float radius = min(mapW, mapH)/3.f;
408     QPointF center(mapW*0.5f, mapH*0.5f);
409     QPointF old;
410     painter.setPen(Qt::black);
411
412     // f(t) = x0/sqrt(2) + x1*sin(t) + x2*cos(t) + x3*sin(2t) + x4*cos(2t) + x5*sin(3t) + x6*cos(3t) + x7*sin(4t)
413     vector<fvec> values(samples.size());
414     const int steps = 200;
415     float minv=FLT_MAX, maxv=-FLT_MAX;
416     FOR(i, samples.size())
417     {
418         values[i].resize(steps);
419         FOR(j, steps)
420         {
421             float t = j/(float)steps*(M_PI*2) - M_PI;
422             float value = 0;
423             FOR(d, dim)
424             {
425                 float v = (samples[i][d]-mins[d])/(maxes[d]-mins[d]);
426                 if(!d) value += v*sqrtf(2.f);
427                 else
428                 {
429
430                     value += v * (d%2 ? sin(t*((d+1)/2)) : cos(t*((d+1)/2)));
431                 }
432             }
433             values[i][j] = value;
434             minv = min(minv, value);
435             maxv = max(maxv, value);
436         }
437     }
438
439     FOR(i, values.size())
440     {
441         FOR(j, values[i].size())
442         {
443             float value = (values[i][j]-minv)/(maxv-minv);
444             QPointF point = QPointF(j*pixmap.width()/steps, value*mapH + pad);
445             QColor color = SampleColor[labels[i]%SampleColorCnt];
446                         painter.setPen(QPen(color,0.5));
447                         if(j) painter.drawLine(point, old);
448             old = point;
449         }
450     }
451
452     ui->display->setPixmap(pixmap);
453     ui->display->repaint();
454 }
455
456
457 void Expose::GenerateRadialGraph()
458 {
459     std::vector<fvec> samples = canvas->data->GetSamples();
460     ivec labels = canvas->data->GetLabels();
461     if(!samples.size()) return;
462     int dim = samples[0].size();
463
464     fvec mins(dim, FLT_MAX), maxes(dim, -FLT_MIN);
465     FOR(d, dim)
466     {
467         FOR(i, samples.size())
468         {
469             mins[d] = min(mins[d], samples[i][d]);
470             maxes[d] = max(maxes[d], samples[i][d]);
471         }
472     }
473
474     int pad = 20;
475     int mapW = (ui->scrollArea->width()-12) - pad*2, mapH = (ui->scrollArea->height()-12) - pad*2;
476
477     ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
478     ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
479     pixmap = QPixmap(ui->scrollArea->width(), ui->scrollArea->height());
480     pixmap.fill(Qt::white);
481     QPainter painter(&pixmap);
482     painter.setRenderHint(QPainter::Antialiasing);
483     float radius = min(mapW, mapH)/3.f;
484     QPointF center(mapW*0.5f, mapH*0.5f);
485     QPointF old;
486     painter.setPen(Qt::black);
487     FOR(d, dim)
488     {
489         float theta = d/(float)(dim)*2*M_PI;
490         QPointF point = QPointF(cos(theta), sin(theta))*radius;
491         if(d) painter.drawLine(center + point, center + old);
492         painter.drawText(center + point*1.1, QString("e%1").arg(d+1));
493         old = point;
494     }
495     painter.drawLine(center + QPointF(1.f, 0.f)*radius, center + old);
496
497     painter.setRenderHint(QPainter::Antialiasing);
498     FOR(i, samples.size())
499     {
500         QPointF samplePoint;
501         float dimSum = 0;
502         FOR(d, dim)
503         {
504             float theta = d/(float)(dim)*2*M_PI;
505             QPointF point = QPointF(cos(theta), sin(theta))*radius;
506             float value = (samples[i][d]-mins[d])/(maxes[d]-mins[d]);
507             samplePoint += point*value;
508             dimSum += value;
509         }
510         samplePoint /= dimSum;
511         float drawRadius = 7;
512         Canvas::drawSample(painter, center + samplePoint, drawRadius, labels[i]);
513         QColor color = SampleColor[labels[i]%SampleColorCnt];
514         painter.setPen(color);
515     }
516
517     ui->display->setPixmap(pixmap);
518     ui->display->repaint();
519 }
520
521 void Expose::GenerateParallelCoords()
522 {
523     std::vector<fvec> samples = canvas->data->GetSamples();
524     ivec labels = canvas->data->GetLabels();
525     if(!samples.size()) return;
526     int dim = samples[0].size();
527
528     fvec mins(dim, FLT_MAX), maxes(dim, -FLT_MIN);
529     FOR(d, dim)
530     {
531         FOR(i, samples.size())
532         {
533             mins[d] = min(mins[d], samples[i][d]);
534             maxes[d] = max(maxes[d], samples[i][d]);
535         }
536     }
537
538     int pad = 20;
539     int mapW = (ui->scrollArea->width()-12) - pad*2, mapH = (ui->scrollArea->height()-12) - pad*2;
540
541     ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
542     ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
543     pixmap = QPixmap(ui->scrollArea->width(), ui->scrollArea->height());
544     pixmap.fill(Qt::white);
545     QPainter painter(&pixmap);
546     FOR(d, dim)
547     {
548         float x = d*mapW/(float)(dim-1) + pad;
549         painter.setPen(Qt::black);
550         painter.drawLine(x, pad, x, mapH+pad);
551         painter.drawText(x-10, mapH+2*pad-4, QString("e%1").arg(d+1));
552     }
553
554     painter.setRenderHint(QPainter::Antialiasing);
555     FOR(i, samples.size())
556     {
557         QPointF old;
558         FOR(d, dim)
559         {
560             float x = d*mapW/(float)(dim-1) + pad;
561             float y = samples[i][d];
562             y = (y-mins[d])/(maxes[d] - mins[d]);
563             QPointF point(x,pad + y*mapH);
564             float radius = 7;
565             Canvas::drawSample(painter, point, radius, labels[i]);
566             QColor color = SampleColor[labels[i]%SampleColorCnt];
567             painter.setPen(color);
568             if(d) painter.drawLine(point, old);
569             old = point;
570         }
571     }
572
573     ui->display->setPixmap(pixmap);
574     ui->display->repaint();
575 }
576
577 void Expose::GenerateScatterPlot(bool bCheckOnly)
578 {
579     std::vector<fvec> samples = canvas->data->GetSamples();
580     ivec labels = canvas->data->GetLabels();
581     if(!samples.size()) return;
582     int dim = samples[0].size();
583     bool bEvenCount = dim%2 == 1;
584     int gridX = dim;
585     int gridY = dim;
586
587     fvec mins(dim, FLT_MAX), maxes(dim, -FLT_MIN);
588     FOR(d, dim)
589     {
590         FOR(i, samples.size())
591         {
592             mins[d] = min(mins[d], samples[i][d]);
593             maxes[d] = max(maxes[d], samples[i][d]);
594         }
595     }
596
597     int pad = 20;
598     int mapW = (ui->scrollArea->width()-12)/gridX - pad*2;
599     int mapH = (ui->scrollArea->height()-12)/gridX - pad*2;
600
601     bool bScroll = false;
602     if(mapW < 100 || mapH < 100)
603     {
604         bScroll = true;
605         mapW = max(mapW, 100);
606         mapH = max(mapH, 100);
607     }
608     if(bScroll && bCheckOnly) return;
609
610     QList<QPixmap> maps;
611     FOR(index0, dim)
612     {
613         FOR(index1, dim)
614         {
615             QPixmap map(mapW + 2*pad,mapH + 2*pad);
616             int w = map.width() - 2*pad, h = map.height() - 2*pad;
617             map.fill(Qt::white);
618             QPainter painter(&map);
619             painter.setRenderHint(QPainter::Antialiasing);
620
621             FOR(i, samples.size())
622             {
623                 float x = samples[i][index0];
624                 float y = samples[i][index1];
625                 x = (x-mins[index0])/(maxes[index0] - mins[index0]);
626                 y = (y-mins[index1])/(maxes[index1] - mins[index1]);
627                 QPointF point(y*w + pad, x*h + pad);
628                 float radius = 5;
629                 Canvas::drawSample(painter, point, radius, labels[i]);
630             }
631             painter.setBrush(Qt::NoBrush);
632             painter.setPen(Qt::black);
633             painter.setRenderHint(QPainter::Antialiasing, false);
634             painter.drawRect(pad/2,pad/2,w+pad, h+pad);
635             painter.drawText(pad/2+1, map.height()-pad/2-1, QString("e%1 x e%2").arg(index1+1).arg(index0+1));
636             maps.push_back(map);
637         }
638     }
639
640     if(bScroll)
641     {
642         pixmap = QPixmap((mapW+2*pad)*gridX, (mapH+2*pad)*gridY);
643         ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
644         ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
645     }
646     else
647     {
648         pixmap = QPixmap(ui->scrollArea->width(), ui->scrollArea->height());
649         ui->scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
650         ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
651     }
652     pixmap.fill(Qt::white);
653     QPainter painter(&pixmap);
654     FOR(i, maps.size())
655     {
656         int xIndex = i%gridX;
657         int yIndex = i/gridX;
658         painter.drawPixmap(QPoint(xIndex*pixmap.width()/gridX, yIndex*pixmap.height()/gridY), maps[i]);
659     }
660     ui->display->setPixmap(pixmap);
661     ui->display->repaint();
662 }
663
664 void Expose::resizeEvent( QResizeEvent *event )
665 {
666     if(ui->typeCombo->currentIndex() == 0 && ui->scrollArea->horizontalScrollBarPolicy() == Qt::ScrollBarAlwaysOn)
667     {
668         GenerateScatterPlot(true);
669     }
670     else Repaint();
671     repaint();
672 }
673
674 void Expose::Repaint()
675 {
676     switch(ui->typeCombo->currentIndex())
677     {
678     case 0:
679         GenerateScatterPlot();
680         break;
681     case 1:
682         GenerateParallelCoords();
683         break;
684     case 2:
685         GenerateRadialGraph();
686         break;
687     case 3:
688         GenerateAndrewsPlots();
689         break;
690     }
691     repaint();
692 }
693
694 void Expose::Clipboard()
695 {
696     QImage image = ui->display->pixmap()->toImage();
697     QClipboard *clipboard = QApplication::clipboard();
698     clipboard->setImage(image);
699 }
700
701 void Expose::paintEvent(QPaintEvent *event)
702 {
703     QWidget::paintEvent(event);
704     if(!canvas) return;
705     if(pixmap.isNull()) Repaint();
706 }