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