#include "pch.h" #include "metavis.h" #include "SettingDialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "DockableGraphView.h" #include #include "RangeSlider.h" #include "tsneIteractive.h" #include "util.h" metavis::metavis(QWidget* parent) : QMainWindow(parent) { ui.setupUi(this); /* create settings object*/ //settings = new QSettings(QSettings::IniFormat, QSettings::UserScope, "TK", "metavis", this); settings = new QSettings("settings.ini", QSettings::IniFormat, this); //settings = new QSettings(QCoreApplication::applicationDirPath()+ "hatschi.ini", QSettings::IniFormat); setStyleSheet(styleSheet() + "QMainWindow::separator {background: rgb(200, 200, 200);width: 1px;height: 1px;}"); setStyleSheet(styleSheet() + "QTabBar::tab:selected {color: rgb(0, 122, 204);}"); setStyleSheet(styleSheet() + "QTabWidget::pane {border-top: 0px solid #C2C7CB;margin: -9px -9px -13px -9px;}"); this->setDockNestingEnabled(true); option = dockOption::right; createBitInSpector(); QDockWidget* saveForTabPad = lastDocked; option = dockOption::splitTop; createProjectManager(); option = dockOption::splitLeft; createBitFieldV2(); QDockWidget* saveForTabTsne = lastDocked; initPlotter(); createScratchpad(saveForTabPad); createTSNE(saveForTabTsne); readMainWindowSettings(); ui.actionOpen->setShortcut(QKeySequence(Qt::CTRL + Qt::Key::Key_O)); QMenu* viewMenu = createPopupMenu(); viewMenu->setTitle("View"); ui.menuBar->insertMenu(manager->projectMenu->menuAction(), viewMenu); this->setCentralWidget(nullptr); } void metavis::openSetting() { SettingDialog settingDialog(settings, this); /* Blocking operation */ settingDialog.exec(); } metavis::~metavis() { writeActualMainWindowSettings(); } void metavis::selectRunData(RunData* data) { selectedBestGraph->removeAll(); selectedBestGraph->setDisplayLabel(QString::fromStdString(data->name)); for (SingleRun& run : data->singleRunList) { selectedBestGraph->addSeries(&run.bestMaxSolutionFoundPerIteration, data->name, QString::fromStdString(run.name), QColor(12, 116, 137, 200), GraphPlottSeries::SeriesType::Line); } selectedBestGraph->addSeries(&data->bestAverageMaxSolutionFoundPerIteration, data->name, "average best from " + QString::fromStdString(data->name), QColor(255, 0, 0), GraphPlottSeries::SeriesType::Line); selectedBestGraph->getSeriesVector().back().lineWidth = 3; selectedBestGraph->frameGraphInView(); } void metavis::selectSingleRun(SingleRun* run) { selectedBestAverageGraph->removeAll(); selectedBestAverageGraph->setDisplayLabel(QString::fromStdString(run->name)); selectedBestAverageGraph->addSeries(&run->bestMaxSolutionFoundPerIteration, run->runDataName, "best", QColor(255, 0, 0), GraphPlottSeries::SeriesType::Line); selectedBestAverageGraph->addSeries(&run->averageSolutionPerItertion, run->runDataName, "average", QColor(0, 0, 255), GraphPlottSeries::SeriesType::Line); selectedBestAverageGraph->frameGraphInView(); selectedMinMaxGraph->removeAll(); selectedMinMaxGraph->setDisplayLabel(QString::fromStdString(run->name)); selectedMinMaxGraph->addSeries(&run->dotsForDistribution, run->runDataName,"distribution", QColor(255, 165, 0, 100), GraphPlottSeries::SeriesType::Dot); selectedMinMaxGraph->addSeries(&run->minSolutionPerItertion, run->runDataName,"min", QColor(255, 0, 0), GraphPlottSeries::SeriesType::Line); selectedMinMaxGraph->addSeries(&run->maxSolutionPerItertion, run->runDataName,"max" , QColor(0, 0, 255), GraphPlottSeries::SeriesType::Line); selectedMinMaxGraph->frameGraphInView(); selectedMeanHammingDistanceGraph->removeAll(); selectedMeanHammingDistanceGraph->setDisplayLabel(QString::fromStdString(run->name)); selectedMeanHammingDistanceGraph->addSeries(&run->meanHammingDistancePerIteration, run->runDataName, "mean Hamming Distance", QColor(255, 0, 0), GraphPlottSeries::SeriesType::Line); selectedMeanHammingDistanceGraph->frameGraphInView(); bitfieldPanel->field->setDisplayLabel(QString::fromStdString(run->name)); bitfieldPanel->displaySingleRun(run); bitfieldPanel->update(); inspectorPanel->inspector->updateData(run->begin, run->end); inspectorPanel->setRunName(run->name); tsnePanel->assignData(run->begin, run->end, QString::fromStdString(run->name)); } void metavis::removeRunDataFromAllViews(RunData* data) { selectedBestAverageGraph->removeRunData(data); selectedBestAverageGraph->update(); selectedMinMaxGraph->removeRunData(data); selectedMinMaxGraph->update(); selectedMeanHammingDistanceGraph->removeRunData(data); selectedMeanHammingDistanceGraph->update(); selectedBestGraph->removeRunData(data); selectedBestGraph->update(); bitfieldPanel->clearRun(); bitfieldPanel->update(); inspectorPanel->removeRun(); tsnePanel->clear(); } void metavis::dockWidget(QDockWidget* dock) { switch (option) { case left: addDockWidget(Qt::LeftDockWidgetArea, dock); break; case right: addDockWidget(Qt::RightDockWidgetArea, dock); break; case top: addDockWidget(Qt::TopDockWidgetArea, dock); break; case bottom: addDockWidget(Qt::BottomDockWidgetArea, dock); break; case splitLeft: this->splitDockWidget(lastDocked, dock, Qt::Orientation::Horizontal); this->splitDockWidget(dock, lastDocked, Qt::Orientation::Horizontal); break; case splitRight: this->splitDockWidget(lastDocked, dock, Qt::Orientation::Horizontal); break; case splitBottom: this->splitDockWidget(lastDocked, dock, Qt::Orientation::Vertical); break; case splitTop: this->splitDockWidget(lastDocked, dock, Qt::Orientation::Vertical); this->splitDockWidget(dock, lastDocked, Qt::Orientation::Vertical); break; case tab: tabifyDockWidget(lastDocked, dock); break; default: addDockWidget(Qt::LeftDockWidgetArea, dock); break; } lastDocked = dock; } GraphView* metavis::createCustomWidget(QString titleString, bool tabToLast) { DockableGraphView* dock = new DockableGraphView(this, titleString); qDebug() << titleString; dockWidget(dock); return dock->view; } void metavis::createBitFieldV2() { QDockWidget* dock = new QDockWidget(this); bitfieldPanel = new BitfieldControlPanel(this); bitfieldPanel->field->setScratchpad(pad); bitfieldPanel->field->setInformation("

Bitfield

This search space visualization displays all found solution of a single run.
Hover over a dot to see its bitstring.
The color represents the objective function.
Gray patterned area: Represents the area where no solution can be generated.
Y Axis: Represents the amount of set bits of a solution.
X Axis: The x axis represents the position of the solution which is concluded by collapsing
all solutions of a Y Value and spreading these between 0 and 1. The solutions are sorted descendingly based on their value.
Example with a four long bitstring and two set bits. For two set bits, there are six different solutions:
1100 1010 1001 0110 0101 0011
The solution 0101 is the 5th possible solution and gets the position value \'0.8\'.

Tipp: Select an interesting area and add the points to the scratchpad for fast comparison.

Options

The Transparency slider handles the transparency of the dots.
The Size slider handles the radius of the dots.
Tipp: Make the dots big and the transparency low the see clustering.
Under \'More Options\' the color for the objective function and the displayed itertion can be controlled."); dock->setWindowTitle("Bitfield"); dock->setObjectName("Bitfield"); dock->setWidget(bitfieldPanel); dockWidget(dock); } void metavis::createProjectManager() { QDockWidget* dock= new QDockWidget(this); manager = new ProjectManager(this); dock->setWindowTitle("Project Manager"); dock->setObjectName("Project Manager"); dock->setWidget(manager); connect(ui.actionOpen, &QAction::triggered, manager, &ProjectManager::openFileDialog); dockWidget(dock); manager->projectMenu->setTitle("Project"); ui.menuBar->addMenu(manager->projectMenu); } void metavis::createTSNE(QDockWidget* dockto) { QDockWidget* dock = new QDockWidget(this); tsnePanel = new TsneControlPanel(this); connect(tsnePanel, &TsneControlPanel::started, this, [this]() {this->showStatusBarMessage("T-SNE calculating...");}); connect(tsnePanel, &TsneControlPanel::finished, this, &metavis::clearStatusBar); tsnePanel->plott->setScratchpad(pad); tsnePanel->plott->setInformation("

T-SNE

This search space evaluation uses a gradient descent method and has to be calculated first via the \"Start\" button.
This search space visualization display all found solutions of a single run.
Hover over a dot to see its bitstring.
The color represents the objective function.
The axes have no special meaning besides indicating the distance between solutions.
Start Button: Starts the tsne methods. This may take a while.
Pause Button: Pauses the tsne methods.


Tipp select a interesting area and add the points to the scratchpad for fast comparison.

Options

Transparency slider handles the transparency of the dots.
Size slider handles the radius of the dots.
Tipp make the dots big and the transparency low the see clustering.
Under \'More Options\' the color for the objective function and the displayed itertion can be controlled.
Also to important parameter for T-SNE can be controlled via slider or textfield.
Perplexity is a parameter that should indicate how many neighbors a solution have.
Learnrate: is a parameter that determine how fast the gradient descent methods make updates."); dock->setWindowTitle("T-SNE"); dock->setObjectName("T-SNE"); dock->setWidget(tsnePanel); this->tabifyDockWidget(dockto, dock); dockto->raise(); } GraphPlott* metavis::initGraphPlott(QString title, QString YAxisLegend, QString XAxisLegend) { QDockWidget* dock = new QDockWidget(this); GraphPlott* graphplott = new GraphPlott(this); graphplott->setDefaultVisibleWindow(0, 100, 30, 110); dock->setWidget(graphplott); dock->setWindowTitle(title); dock->setObjectName(title); graphplott->setAxisLegend(XAxisLegend, YAxisLegend); dockWidget(dock); return graphplott; } void metavis::initPlotter() { option = splitLeft; selectedBestGraph = initGraphPlott("Best Overview"); selectedBestGraph->setScratchpad(pad); selectedBestGraph->setInformation("

Best Overview

Shows all best graphs in gray for comparison.
The red line shows the average best over all repetition.
By hovering over a line the repetition name is shown.

Objective Function: Describes how good the solution is, it depends on the problem if a low or high value is desired."); option = splitTop; selectedBestAverageGraph = initGraphPlott("Best Average"); selectedBestAverageGraph->setScratchpad(pad); selectedBestAverageGraph->setInformation("

Best Average

The red line shows the best graph that presents the best objective function value found for each iteration of a single repetition.
The blue line shows the average graph that presents the average objective function value in the popullation for each iteration of a single repetition.

Objective Function: Describes how good the solution is. It depends on the problem if a low or high value is desired."); //GraphPlott* selectedParticleGraph = initGraphPlott("Best Vs Average"); option = tab; selectedMinMaxGraph = initGraphPlott("Min Max Distribution"); selectedMinMaxGraph->setInformation("

Min Max Distribution

The blue line shows the max graph that presents the maximum objective function value in the popullation for each iteration of a single round.
The red line shows the minimum objective function value in the popullation for each iteration of a single round.
The orange dots show all objective function values in the population for each iteration of a single repetition.

Objective Function: Describes how good the solution is. It depends on the problem if a low or high value is desired."); selectedMinMaxGraph->setScratchpad(pad); option = tab; selectedMeanHammingDistanceGraph = initGraphPlott("Mean Hamming Distance", "Mean Hamming Distance"); selectedMeanHammingDistanceGraph->setInformation("

Mean Hamming Distance

The red line shows the mean hamming distance for each solution to each solution from the population for each iteration of a single repetition.

Hamming Distance: Describes the distance between to bitstrings by calculating the amount of different bits, e.g. 00110 and 11100 have a hamming distance of 3."); multiBestGraph; multiAvgGraph; multiMinGraph; multiMaxGraph; multiMeanHammingDistanceGraph; } void metavis::createBitInSpector() { QDockWidget* dock = new QDockWidget(this); inspectorPanel = new BitInspectorPanel(this); dock->setWidget(inspectorPanel); dock->setWindowTitle("Inspector"); dock->setObjectName("Inspector"); dockWidget(dock); } void metavis::createScratchpad(QDockWidget* dockto) { QDockWidget* dock = new QDockWidget(this); dock->setWidget(pad); dock->setWindowTitle("Scratchpad"); dock->setObjectName("Scratchpad"); this->tabifyDockWidget(dockto, dock); dockto->raise(); } void metavis::writeActualMainWindowSettings() { settings->beginGroup("MainWindow"); settings->setValue("maximized", isMaximized()); if (!isMaximized()) { /* position and size of the window if not maximized */ settings->setValue("pos", pos()); settings->setValue("size", size()); settings->setValue("screenCount", QApplication::desktop()->screenCount()); } settings->setValue("geometry", saveGeometry()); settings->setValue("windowState", saveState()); settings->endGroup(); } void metavis::readMainWindowSettings() { settings->beginGroup("MainWindow"); if (QApplication::desktop()->screenCount() == settings->value("screenCount", 1)) { //Only when same screeenCount move the window; move(settings->value("pos", QPoint(360, 200)).toPoint()); } resize(settings->value("size", QSize(1200, 675)).toSize()); if (settings->value("maximized", false).toBool()) { showMaximized(); } this->restoreGeometry(settings->value("geometry").toByteArray()); this->restoreState(settings->value("windowState").toByteArray()); settings->endGroup(); } void metavis::openFile() { //int oldIndex = runVec.size(); /*int size = runList.size(); for (int i = 0; i < pathList.size(); i++) { qDebug() << "file:" << pathList[i]; runList.push_back(RunData(pathList[i].toStdString())); }*/ /*for (std::list::iterator iter = std::next(runList.begin(), size); iter != runList.end(); iter++) { QColor runColor = multiBestGraph->generateNextColorForGraph(); multiBestGraph->addLine(&iter->bestMinSolutionFoundPerIteration, &*iter, runColor); multiAvgGraph->addLine(&iter->averageSolutionPerItertion, &*iter, runColor); multiMaxGraph->addLine(&iter->maxSolutionPerItertion, &*iter, runColor); multiMinGraph->addLine(&iter->minSolutionPerItertion, &*iter, runColor); multiMeanHammingDistanceGraph->addLine(&iter->meanHammingDistancePerIteration, &*iter, runColor); }*/ /* for (int i = 0; i < runList.size(); i++) { QColor runColor = multiBestGraph->generateNextColorForGraph(); multiBestGraph->addLine(&runList[i].bestSolutionPerIteration, &runList[i], runColor); multiAvgGraph->addLine(&runList[i].averageSolutionPerItertion, &runList[i], runColor); multiMaxGraph->addLine(&runList[i].maxSolutionPerItertion, &runList[i], runColor); multiMinGraph->addLine(&runList[i].minSolutionPerItertion, &runList[i], runColor); //multiMeanHammingDistanceGraph->addLine(&runVec[i].meanHammingDistancePerIteration, &runVec[i], runColor); }*/ /*std::vector::iterator end = runVec.end(); for (int i = 0; i < pathList.size(); i++) { qDebug() << "file:" << pathList[i]; runVec.push_back(RunData(pathList[i].toStdString())); } for (std::vector::iterator iter = end; iter != runVec.end(); iter++) { QColor runColor = multiBestGraph->generateNextColorForGraph(); multiBestGraph->addLine(&iter->bestSolutionPerIteration, &*iter, runColor); multiAvgGraph->addLine(&iter->averageSolutionPerItertion, &*iter, runColor); multiMaxGraph->addLine(&iter->maxSolutionPerItertion, &*iter, runColor); multiMinGraph->addLine(&iter->minSolutionPerItertion, &*iter, runColor); multiMeanHammingDistanceGraph->addLine(&iter->meanHammingDistancePerIteration, &*iter, runColor); }*/ //actualBestAverageGraph->addLine(runVec[0].bestSolutionPerIteration, QColor(255, 0, 0)); //actualBestAverageGraph->addLine(runVec[0].averageSolutionPerItertion, QColor(0, 0, 255)); //actualMinMaxGraph->addLine(runVec[0].minSolutionPerItertion, QColor(255, 0, 0)); //actualMinMaxGraph->addLine(runVec[0].maxSolutionPerItertion, QColor(0, 0, 255)); //actualMinMaxGraph->addDots(runVec[0].dotsForDistribution, QColor(255, 165, 0, 100)); //for (auto iter = runVec[0].particleMap.begin(); iter != runVec[0].particleMap.end(); iter++) { // actualParticleGraph->addLine(iter->second); //} ////Test /*RunData* rundata = &runList.back(); bitField->addDots(&rundata->dotsForBitField, rundata, QColor(255, 165, 0, 100)); updateBitFieldColors(); bitField->graphSeriesVec.back().useDataPointColor = true; tsneWidget->assignRunData(&runList.back()); inspector->addData(&runList.back().solutionVec); plottTest->addSeries(&rundata->bestMaxSolutionFoundPerIteration, rundata, QColor(255, 165, 0, 100), GraphPlottSeries::SeriesType::Line);*/ //actualMeanHmmingDistanceGraph->addLine(runVec[0].meanHammingDistancePerIteration, QColor(255, 0, 0)); } void metavis::showStatusBarLoading() { ui.statusBar->showMessage("Loading..."); ui.statusBar->setStyleSheet("background-color: rgb(247, 197, 72);"); } void metavis::showStatusBarMessage(QString message) { ui.statusBar->showMessage(message); ui.statusBar->setStyleSheet("background-color: rgb(247, 197, 72);"); } void metavis::clearStatusBar() { ui.statusBar->clearMessage(); ui.statusBar->setStyleSheet("background-color: rgb(240, 240, 240);"); }