From c598a1df7ca003ae6fc298918b1ae50132835f30 Mon Sep 17 00:00:00 2001 From: Tim Angus Date: Wed, 16 Aug 2023 14:14:26 +0100 Subject: [PATCH] Add ImportAnnotationsCommand --- source/plugins/correlation/CMakeLists.txt | 2 + .../correlation/importannotationscommand.cpp | 147 ++++++++++++++++++ .../correlation/importannotationscommand.h | 68 ++++++++ 3 files changed, 217 insertions(+) create mode 100644 source/plugins/correlation/importannotationscommand.cpp create mode 100644 source/plugins/correlation/importannotationscommand.h diff --git a/source/plugins/correlation/CMakeLists.txt b/source/plugins/correlation/CMakeLists.txt index 7e8765176..17ab16573 100644 --- a/source/plugins/correlation/CMakeLists.txt +++ b/source/plugins/correlation/CMakeLists.txt @@ -23,6 +23,7 @@ list(APPEND HEADERS ${CMAKE_CURRENT_LIST_DIR}/featurescaling.h ${CMAKE_CURRENT_LIST_DIR}/graphsizeestimateplotitem.h ${CMAKE_CURRENT_LIST_DIR}/hierarchicalclusteringcommand.h + ${CMAKE_CURRENT_LIST_DIR}/importannotationscommand.h ${CMAKE_CURRENT_LIST_DIR}/knnprotograph.h ${CMAKE_CURRENT_LIST_DIR}/loading/correlationfileparser.h ${CMAKE_CURRENT_LIST_DIR}/normaliser.h @@ -47,6 +48,7 @@ list(APPEND SOURCES ${CMAKE_CURRENT_LIST_DIR}/featurescaling.cpp ${CMAKE_CURRENT_LIST_DIR}/graphsizeestimateplotitem.cpp ${CMAKE_CURRENT_LIST_DIR}/hierarchicalclusteringcommand.cpp + ${CMAKE_CURRENT_LIST_DIR}/importannotationscommand.cpp ${CMAKE_CURRENT_LIST_DIR}/loading/correlationfileparser.cpp ${CMAKE_CURRENT_LIST_DIR}/qcpcolumnannotations.cpp ${CMAKE_CURRENT_LIST_DIR}/quantilenormaliser.cpp diff --git a/source/plugins/correlation/importannotationscommand.cpp b/source/plugins/correlation/importannotationscommand.cpp new file mode 100644 index 000000000..7fd5f165e --- /dev/null +++ b/source/plugins/correlation/importannotationscommand.cpp @@ -0,0 +1,147 @@ +/* Copyright © 2013-2023 Graphia Technologies Ltd. + * + * This file is part of Graphia. + * + * Graphia is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Graphia is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Graphia. If not, see . + */ + +#include "importannotationscommand.h" + +#include "correlationplugin.h" + +#include "shared/utils/string.h" +#include "shared/loading/userelementdata.h" + +#include "../crashhandler.h" + +using namespace Qt::Literals::StringLiterals; + +ImportAnnotationsCommand::ImportAnnotationsCommand(CorrelationPluginInstance* plugin, + TabularData* data, int keyRowIndex, const std::vector& importRowIndices, bool replace) : + _plugin(plugin), _data(std::move(*data)), + _keyRowIndex(static_cast(keyRowIndex)), _importRowIndices(importRowIndices), + _replace(replace) +{} + +QString ImportAnnotationsCommand::firstAnnotationName() const +{ + if(!_createdAnnotationNames.empty()) + return _createdAnnotationNames.front(); + + if(!_replacedUserDataVectors.empty()) + return _replacedUserDataVectors.begin()->name(); + + return {}; +} + +QString ImportAnnotationsCommand::description() const +{ + return multipleAnnotations() ? QObject::tr("Import Column Annotations") : QObject::tr("Import Column Annotation"); +} + +QString ImportAnnotationsCommand::verb() const +{ + return multipleAnnotations() ? QObject::tr("Importing Column Annotations") : QObject::tr("Importing Column Annotation"); +} + +QString ImportAnnotationsCommand::pastParticiple() const +{ + return multipleAnnotations() ? + QObject::tr("%1 Annotations Imported").arg(numAnnotations()) : + QObject::tr("Annotation %1 Imported").arg(firstAnnotationName()); +} + +QString ImportAnnotationsCommand::debugDescription() const +{ + QString text = description(); + + return text; +} + +bool ImportAnnotationsCommand::execute() +{ + std::map map; + + for(size_t column = 0; column < _plugin->numColumns(); column++) + { + const auto& columnName = _plugin->columnName(column); + + for(size_t dataColumn = 1; dataColumn < _data.numColumns(); dataColumn++) + { + auto keyRowValue = _data.valueAt(dataColumn, _keyRowIndex); + + if(columnName == keyRowValue) + { + map[columnName] = dataColumn; + break; + } + } + + setProgress((static_cast(column) * 100) / + static_cast(_plugin->numColumns())); + } + + setProgress(-1); + + if(map.empty()) + return false; + + auto& userData = _plugin->userColumnData(); + + for(auto rowIndex : _importRowIndices) + { + auto annotationName = _data.valueAt(0, static_cast(rowIndex)); + auto* existingVector = userData.vector(annotationName); + + const bool replace = _replace && existingVector != nullptr && + existingVector->type() == _data.typeIdentity(static_cast(rowIndex)).type(); + + if(replace) + _replacedUserDataVectors.emplace_back(*existingVector); + else + { + annotationName = u::findUniqueName(userData.vectorNames(), annotationName); + _createdVectorNames.emplace(annotationName); + } + + for(size_t column = 0; column < _plugin->numColumns(); column++) + { + const auto& columnName = _plugin->columnName(column); + + auto value = map.contains(columnName) ? + _data.valueAt(map.at(columnName), static_cast(rowIndex)) : QString{}; + userData.setValue(column, annotationName, value); + } + } + + _plugin->rebuildColumnAnnotations(); + + return true; +} + +void ImportAnnotationsCommand::undo() +{ + auto& userData = _plugin->userColumnData(); + + for(const auto& vectorName : _createdVectorNames) + userData.remove(vectorName); + + for(auto&& vector : _replacedUserDataVectors) + userData.setVector(std::move(vector)); + + _createdVectorNames.clear(); + _replacedUserDataVectors.clear(); + + _plugin->rebuildColumnAnnotations(); +} diff --git a/source/plugins/correlation/importannotationscommand.h b/source/plugins/correlation/importannotationscommand.h new file mode 100644 index 000000000..d31ff9236 --- /dev/null +++ b/source/plugins/correlation/importannotationscommand.h @@ -0,0 +1,68 @@ +/* Copyright © 2013-2023 Graphia Technologies Ltd. + * + * This file is part of Graphia. + * + * Graphia is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Graphia is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Graphia. If not, see . + */ + +#ifndef IMPORTANNOTATIONSCOMMAND_H +#define IMPORTANNOTATIONSCOMMAND_H + +#include "shared/commands/icommand.h" + +#include "shared/loading/tabulardata.h" +#include "shared/loading/userdatavector.h" + +#include + +#include +#include + +class CorrelationPluginInstance; + +class ImportAnnotationsCommand : public ICommand +{ +private: + CorrelationPluginInstance* _plugin = nullptr; + + TabularData _data; + size_t _keyRowIndex; + std::vector _importRowIndices; + + bool _replace = false; + std::vector _replacedUserDataVectors; + + std::set _createdVectorNames; + std::vector _createdAnnotationNames; + + size_t numAnnotations() const { return _importRowIndices.size(); } + bool multipleAnnotations() const { return numAnnotations() > 1; } + QString firstAnnotationName() const; + +public: + ImportAnnotationsCommand(CorrelationPluginInstance* plugin, + TabularData* data, int keyRowIndex, const std::vector& importRowIndices, + bool replace); + + QString description() const override; + QString verb() const override; + QString pastParticiple() const override; + + QString debugDescription() const override; + + bool execute() override; + void undo() override; +}; + +#endif // IMPORTANNOTATIONSCOMMAND_H