From 1282ff92d5b33508400385dca3a8f8ebdbff6a73 Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Sun, 12 Jun 2022 13:37:24 +0200 Subject: [PATCH 1/6] Simplify --- graph/graphicsitemnode.cpp | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/graph/graphicsitemnode.cpp b/graph/graphicsitemnode.cpp index 5a5e84a1..8b4d064c 100644 --- a/graph/graphicsitemnode.cpp +++ b/graph/graphicsitemnode.cpp @@ -287,25 +287,16 @@ void GraphicsItemNode::setNodeColour() g_settings->randomColourNegativeLightness); negColour.setAlpha(g_settings->randomColourNegativeOpacity); - QColor colour1, colour2; - if (m_deBruijnNode->isPositiveNode()) - { - colour1 = posColour; - colour2 = negColour; - } - else - { - colour1 = negColour; - colour2 = posColour; - } + if (!m_deBruijnNode->isPositiveNode()) + std::swap(posColour, negColour); - m_colour = colour1; + m_colour = posColour; DeBruijnNode * revCompNode = m_deBruijnNode->getReverseComplement(); if (revCompNode != nullptr) { GraphicsItemNode * revCompGraphNode = revCompNode->getGraphicsItemNode(); if (revCompGraphNode != nullptr) - revCompGraphNode->m_colour = colour2; + revCompGraphNode->m_colour = negColour; } break; } From 316acd3fc1e14e6920e94c243c3885536d7abdc1 Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Sun, 12 Jun 2022 17:14:30 +0200 Subject: [PATCH 2/6] Refactor node coloring: - Factor out all logic into a separate class - Lots of cleanup here and there --- CMakeLists.txt | 2 +- command_line/commoncommandlinefunctions.cpp | 6 +- command_line/commoncommandlinefunctions.h | 2 +- command_line/image.cpp | 2 +- graph/assemblygraph.cpp | 74 +++---- graph/assemblygraph.h | 2 - graph/graphicsitemnode.cpp | 203 +++-------------- graph/graphicsitemnode.h | 18 +- graph/nodecolorer.cpp | 228 ++++++++++++++++++++ graph/nodecolorer.h | 54 +++++ program/globals.h | 4 +- program/main.cpp | 13 +- program/settings.cpp | 9 +- program/settings.h | 19 +- tests/bandagetests.cpp | 6 +- ui/mainwindow.cpp | 199 ++++++----------- ui/mainwindow.h | 8 +- ui/settingsdialog.cpp | 7 +- 18 files changed, 468 insertions(+), 388 deletions(-) create mode 100644 graph/nodecolorer.cpp create mode 100644 graph/nodecolorer.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 24e57e58..814604cc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,7 +71,7 @@ set(LIB_SOURCES ui/tablewidgetitemname.cpp ui/tablewidgetitemshown.cpp ui/verticallabel.cpp - ui/verticalscrollarea.cpp) + ui/verticalscrollarea.cpp graph/nodecolorer.cpp graph/nodecolorer.h) set(FORMS ui/aboutdialog.ui diff --git a/command_line/commoncommandlinefunctions.cpp b/command_line/commoncommandlinefunctions.cpp index c5925d8b..536c27c7 100644 --- a/command_line/commoncommandlinefunctions.cpp +++ b/command_line/commoncommandlinefunctions.cpp @@ -501,7 +501,7 @@ void parseSettings(QStringList arguments) } } - g_settings->nodeColourScheme = getColourSchemeOption("--colour", &arguments); + g_settings->initializeColorer(getColourSchemeOption("--colour", &arguments)); // For backward compatibility we allow setting blast annotation view to show from "--colour" option. // To be removed when we can set up annotations from CLI. @@ -1038,9 +1038,9 @@ SciNot getSciNotOption(const QString& option, QStringList * arguments) return {arguments->at(sciNotIndex)}; } -NodeColourScheme getColourSchemeOption(const QString& option, QStringList * arguments) +NodeColorScheme getColourSchemeOption(const QString& option, QStringList * arguments) { - NodeColourScheme defaultScheme = RANDOM_COLOURS; + NodeColorScheme defaultScheme = RANDOM_COLOURS; int optionIndex = arguments->indexOf(option); if (optionIndex == -1) diff --git a/command_line/commoncommandlinefunctions.h b/command_line/commoncommandlinefunctions.h index dac22c14..f73d2b7c 100644 --- a/command_line/commoncommandlinefunctions.h +++ b/command_line/commoncommandlinefunctions.h @@ -59,7 +59,7 @@ int getIntOption(const QString& option, QStringList * arguments); double getFloatOption(const QString& option, QStringList * arguments); SciNot getSciNotOption(const QString& option, QStringList * arguments); QColor getColourOption(const QString& option, QStringList * arguments); -NodeColourScheme getColourSchemeOption(const QString& option, QStringList * arguments); +NodeColorScheme getColourSchemeOption(const QString& option, QStringList * arguments); std::set getBlastAnnotationViews(const QString& option, QStringList * arguments); GraphScope getGraphScopeOption(const QString& option, QStringList * arguments); QString getStringOption(const QString& option, QStringList * arguments); diff --git a/command_line/image.cpp b/command_line/image.cpp index 94f2f1dd..5103607d 100644 --- a/command_line/image.cpp +++ b/command_line/image.cpp @@ -151,7 +151,7 @@ int bandageImage(QStringList arguments) err << csvPath << " didn't contain color" << Qt::endl; return 1; } - g_settings->nodeColourScheme = CUSTOM_COLOURS; + g_settings->initializeColorer(CUSTOM_COLOURS); } if (errorMessage != "") diff --git a/graph/assemblygraph.cpp b/graph/assemblygraph.cpp index 09cf5b34..e4a1dfaf 100644 --- a/graph/assemblygraph.cpp +++ b/graph/assemblygraph.cpp @@ -314,22 +314,11 @@ double AssemblyGraph::getMeanDepth(const QList& nodes) } -void AssemblyGraph::resetNodeContiguityStatus() -{ +void AssemblyGraph::resetNodeContiguityStatus() { for (auto &entry : m_deBruijnGraphNodes) { entry->resetContiguityStatus(); } m_contiguitySearchDone = false; - - resetAllNodeColours(); -} - -void AssemblyGraph::resetAllNodeColours() -{ - for (auto &entry : m_deBruijnGraphNodes) { - if (entry->getGraphicsItemNode() != nullptr) - entry->getGraphicsItemNode()->setNodeColour(); - } } void AssemblyGraph::determineGraphInfo() @@ -790,32 +779,37 @@ void AssemblyGraph::addGraphicsItemsToScene(MyGraphicsScene * scene) double meanDrawnDepth = getMeanDepth(true); - //First make the GraphicsItemNode objects - for (auto &entry : m_deBruijnGraphNodes) { - DeBruijnNode * node = entry; + // First make the GraphicsItemNode objects + for (auto *node : m_deBruijnGraphNodes) { + if (!node->isDrawn()) + continue; - if (node->isDrawn()) - { - if (meanDrawnDepth == 0) - node->setDepthRelativeToMeanDrawnDepth(1.0); - else - node->setDepthRelativeToMeanDrawnDepth(node->getDepth() / meanDrawnDepth); - auto * graphicsItemNode = new GraphicsItemNode(node, m_graphAttributes); - node->setGraphicsItemNode(graphicsItemNode); - graphicsItemNode->setFlag(QGraphicsItem::ItemIsSelectable); - graphicsItemNode->setFlag(QGraphicsItem::ItemIsMovable); + node->setDepthRelativeToMeanDrawnDepth(meanDrawnDepth== 0 ? + 1.0 : node->getDepth() / meanDrawnDepth); + auto *graphicsItemNode = new GraphicsItemNode(node, m_graphAttributes); + node->setGraphicsItemNode(graphicsItemNode); + graphicsItemNode->setFlag(QGraphicsItem::ItemIsSelectable); + graphicsItemNode->setFlag(QGraphicsItem::ItemIsMovable); + + bool colSet = false; + if (auto *rcNode = node->getReverseComplement()) { + if (auto *revCompGraphNode = rcNode->getGraphicsItemNode()) { + auto colPair = g_settings->nodeColorer->get(graphicsItemNode, revCompGraphNode); + graphicsItemNode->setNodeColour(colPair.first); + revCompGraphNode->setNodeColour(colPair.second); + colSet = true; + } } + if (!colSet) + graphicsItemNode->setNodeColour(g_settings->nodeColorer->get(graphicsItemNode)); } - resetAllNodeColours(); - - //Then make the GraphicsItemEdge objects and add them to the scene first - //so they are drawn underneath + // Then make the GraphicsItemEdge objects and add them to the scene first, + // so they are drawn underneath for (auto &entry : m_deBruijnGraphEdges) { DeBruijnEdge * edge = entry.second; - if (edge->isDrawn()) - { + if (edge->isDrawn()) { auto * graphicsItemEdge = new GraphicsItemEdge(edge); edge->setGraphicsItemEdge(graphicsItemEdge); graphicsItemEdge->setFlag(QGraphicsItem::ItemIsSelectable); @@ -823,12 +817,12 @@ void AssemblyGraph::addGraphicsItemsToScene(MyGraphicsScene * scene) } } - //Now add the GraphicsItemNode objects to the scene so they are drawn - //on top - for (auto &entry : m_deBruijnGraphNodes) { - DeBruijnNode * node = entry; - if (node->hasGraphicsItem()) - scene->addItem(node->getGraphicsItemNode()); + // Now add the GraphicsItemNode objects to the scene, so they are drawn + // on top + for (auto *node : m_deBruijnGraphNodes) { + if (!node->hasGraphicsItem()) + continue; + scene->addItem(node->getGraphicsItemNode()); } } @@ -1568,8 +1562,7 @@ void AssemblyGraph::duplicateGraphicsNode(DeBruijnNode * originalNode, DeBruijnN newGraphicsItemNode->shiftPointsRight(); originalGraphicsItemNode->fixEdgePaths(); - originalGraphicsItemNode->setNodeColour(); - newGraphicsItemNode->setNodeColour(); + newGraphicsItemNode->setNodeColour(originalGraphicsItemNode->m_colour); originalGraphicsItemNode->setWidth(); @@ -1825,8 +1818,7 @@ bool AssemblyGraph::mergeGraphicsNodes2(QList * originalNodes, newNode->setGraphicsItemNode(newGraphicsItemNode); newGraphicsItemNode->setFlag(QGraphicsItem::ItemIsSelectable); newGraphicsItemNode->setFlag(QGraphicsItem::ItemIsMovable); - - newGraphicsItemNode->setNodeColour(); + newGraphicsItemNode->setNodeColour(g_settings->nodeColorer->get(newGraphicsItemNode)); scene->addItem(newGraphicsItemNode); diff --git a/graph/assemblygraph.h b/graph/assemblygraph.h index f5d21055..bf7db9c8 100644 --- a/graph/assemblygraph.h +++ b/graph/assemblygraph.h @@ -111,8 +111,6 @@ class AssemblyGraph : public QObject static double getMeanDepth(std::vector nodes); static double getMeanDepth(const QList& nodes); void resetNodeContiguityStatus(); - void resetAllNodeColours(); - void clearAllBlastHitPointers(); void determineGraphInfo(); void clearGraphInfo(); void recalculateAllDepthsRelativeToDrawnMean(); diff --git a/graph/graphicsitemnode.cpp b/graph/graphicsitemnode.cpp index 8b4d064c..a1a83b0b 100644 --- a/graph/graphicsitemnode.cpp +++ b/graph/graphicsitemnode.cpp @@ -17,28 +17,33 @@ #include "graphicsitemnode.h" +#include "graphicsitemedge.h" #include "debruijnnode.h" +#include "debruijnedge.h" #include "ogdfnode.h" -#include +#include "assemblygraph.h" +#include "annotationsmanager.hpp" + #include "program/globals.h" +#include "program/memory.h" + +#include "ui/mygraphicsscene.h" +#include "ui/mygraphicsview.h" + +#include "ogdf/basic/GraphAttributes.h" + +#include +#include #include #include #include -#include "debruijnedge.h" -#include "graphicsitemedge.h" -#include "ogdf/basic/GraphAttributes.h" -#include #include #include -#include -#include "ui/mygraphicsscene.h" + #include -#include "ui/mygraphicsview.h" -#include -#include "blast/blasthitpart.h" -#include "assemblygraph.h" -#include "program/memory.h" -#include "annotationsmanager.hpp" + +#include +#include GraphicsItemNode::GraphicsItemNode(DeBruijnNode * deBruijnNode, ogdf::GraphAttributes * graphAttributes, QGraphicsItem * parent) : @@ -51,7 +56,7 @@ GraphicsItemNode::GraphicsItemNode(DeBruijnNode * deBruijnNode, OgdfNode * pathOgdfNode = deBruijnNode->getOgdfNode(); if (pathOgdfNode != nullptr) { - for (auto ogdfNode : pathOgdfNode->m_ogdfNodes) + for (auto *ogdfNode : pathOgdfNode->m_ogdfNodes) { QPointF point(graphAttributes->x(ogdfNode), graphAttributes->y(ogdfNode)); m_linePoints.push_back(point); @@ -255,108 +260,9 @@ void GraphicsItemNode::drawTextPathAtLocation(QPainter * painter, const QPainter painter->translate(-centre); } - - -void GraphicsItemNode::setNodeColour() -{ - switch (g_settings->nodeColourScheme) - { - case UNIFORM_COLOURS: - if (m_deBruijnNode->isSpecialNode()) - m_colour = g_settings->uniformNodeSpecialColour; - else if (usePositiveNodeColour()) - m_colour = g_settings->uniformPositiveNodeColour; - else - m_colour = g_settings->uniformNegativeNodeColour; - break; - - case RANDOM_COLOURS: - { - //Make a colour with a random hue. Assign a colour to both this node and - //its complement so their hue matches. - int hue = rand() % 360; - QColor posColour; - posColour.setHsl(hue, - g_settings->randomColourPositiveSaturation, - g_settings->randomColourPositiveLightness); - posColour.setAlpha(g_settings->randomColourPositiveOpacity); - - QColor negColour; - negColour.setHsl(hue, - g_settings->randomColourNegativeSaturation, - g_settings->randomColourNegativeLightness); - negColour.setAlpha(g_settings->randomColourNegativeOpacity); - - if (!m_deBruijnNode->isPositiveNode()) - std::swap(posColour, negColour); - - m_colour = posColour; - DeBruijnNode * revCompNode = m_deBruijnNode->getReverseComplement(); - if (revCompNode != nullptr) - { - GraphicsItemNode * revCompGraphNode = revCompNode->getGraphicsItemNode(); - if (revCompGraphNode != nullptr) - revCompGraphNode->m_colour = negColour; - } - break; - } - - case DEPTH_COLOUR: - { - m_colour = getDepthColour(); - break; - } - - case GRAY_COLOR: - { - m_colour = g_settings->grayColor; - break; - } - - case CUSTOM_COLOURS: - { - m_colour = g_assemblyGraph->getCustomColourForDisplay(m_deBruijnNode); - break; - } - - default: //CONTIGUITY COLOUR - { - //For single nodes, display the colour of whichever of the - //twin nodes has the greatest contiguity status. - ContiguityStatus contiguityStatus = m_deBruijnNode->getContiguityStatus(); - if (!m_hasArrow) - { - ContiguityStatus twinContiguityStatus = m_deBruijnNode->getReverseComplement()->getContiguityStatus(); - if (twinContiguityStatus < contiguityStatus) - contiguityStatus = twinContiguityStatus; - } - - switch (contiguityStatus) - { - case STARTING: - m_colour = g_settings->contiguityStartingColour; - break; - case CONTIGUOUS_STRAND_SPECIFIC: - m_colour = g_settings->contiguousStrandSpecificColour; - break; - case CONTIGUOUS_EITHER_STRAND: - m_colour = g_settings->contiguousEitherStrandColour; - break; - case MAYBE_CONTIGUOUS: - m_colour = g_settings->maybeContiguousColour; - break; - default: //NOT_CONTIGUOUS - m_colour = g_settings->notContiguousColour; - break; - } - } - } -} - - QPainterPath GraphicsItemNode::shape() const { - //If there is only one segment and it is shorter than half its + //If there is only one segment, and it is shorter than half its //width, then the arrow head will not be made with 45 degree //angles, but rather whatever angle is made by going from the //end to the back corners (the final node will be a triangle). @@ -390,9 +296,9 @@ QPainterPath GraphicsItemNode::shape() const //NOTE: THIS APPROACH CAN LEAD TO WEIRD EFFECTS WHEN THE NODE'S //POINTY END OVERLAPS WITH ANOTHER PART OF THE NODE. PERHAPS THERE //IS A BETTER WAY TO MAKE ARROWHEADS? - QLineF frontline = QLineF(getLast(), getSecondLast()).normalVector(); - frontline.setLength(m_width / 2.0); - QPointF frontVector = frontline.p2() - frontline.p1(); + QLineF frontLine = QLineF(getLast(), getSecondLast()).normalVector(); + frontLine.setLength(m_width / 2.0); + QPointF frontVector = frontLine.p2() - frontLine.p1(); QLineF arrowheadLine(getLast(), getSecondLast()); arrowheadLine.setLength(1.42 * (m_width / 2.0)); arrowheadLine.setAngle(arrowheadLine.angle() + 45.0); @@ -412,18 +318,18 @@ QPainterPath GraphicsItemNode::shape() const QPainterPath mainNodePathTmp = mainNodePath.subtracted(subtractionPath); - QLineF backline = QLineF(getFirst(), getSecond()).normalVector(); - backline.setLength(m_width / 2.0); - QPointF backVector = backline.p2() - backline.p1(); - QLineF arrowbackLine(getSecond(), getFirst()); - arrowbackLine.setLength(m_width / 2.0); - QPointF arrowbackVector = arrowbackLine.p2() - arrowbackLine.p1(); + QLineF backLine = QLineF(getFirst(), getSecond()).normalVector(); + backLine.setLength(m_width / 2.0); + QPointF backVector = backLine.p2() - backLine.p1(); + QLineF arrowBackLine(getSecond(), getFirst()); + arrowBackLine.setLength(m_width / 2.0); + QPointF arrowBackVector = arrowBackLine.p2() - arrowBackLine.p1(); QPainterPath addedPath; addedPath.moveTo(getFirst()); - addedPath.lineTo(getFirst() + backVector + arrowbackVector); + addedPath.lineTo(getFirst() + backVector + arrowBackVector); addedPath.lineTo(getFirst() + backVector); addedPath.lineTo(getFirst() - backVector); - addedPath.lineTo(getFirst() - backVector + arrowbackVector); + addedPath.lineTo(getFirst() - backVector + arrowBackVector); addedPath.lineTo(getFirst()); mainNodePathTmp.addPath(addedPath); @@ -497,7 +403,7 @@ void GraphicsItemNode::fixEdgePaths(std::vector * nodes) con } } - for (auto deBruijnEdge : edgesToFix) + for (auto *deBruijnEdge : edgesToFix) { GraphicsItemEdge * graphicsItemEdge = deBruijnEdge->getGraphicsItemEdge(); @@ -505,9 +411,9 @@ void GraphicsItemNode::fixEdgePaths(std::vector * nodes) con if (graphicsItemEdge != nullptr) graphicsItemEdge->calculateAndSetPath(); - //If this edge does not have a graphics item, then perhaps its - //reverse complment does. Only do this check if the graph was drawn - //on single mode. + // If this edge does not have a graphics item, then perhaps its + // reverse complement does. Only do this check if the graph was drawn + // on single mode. else if (!g_settings->doubleMode) { graphicsItemEdge = deBruijnEdge->getReverseComplement()->getGraphicsItemEdge(); @@ -807,45 +713,6 @@ QSize GraphicsItemNode::getNodeTextSize(const QString& text) return fontMetrics.size(0, text); } - -QColor GraphicsItemNode::getDepthColour() const -{ - double depth = m_deBruijnNode->getDepth(); - double lowValue; - double highValue; - if (g_settings->autoDepthValue) - { - lowValue = g_assemblyGraph->m_firstQuartileDepth; - highValue = g_assemblyGraph->m_thirdQuartileDepth; - } - else - { - lowValue = g_settings->lowDepthValue; - highValue = g_settings->highDepthValue; - } - - if (depth <= lowValue) - return g_settings->lowDepthColour; - if (depth >= highValue) - return g_settings->highDepthColour; - - double fraction = (depth - lowValue) / (highValue - lowValue); - - int redDifference = g_settings->highDepthColour.red() - g_settings->lowDepthColour.red(); - int greenDifference = g_settings->highDepthColour.green() - g_settings->lowDepthColour.green(); - int blueDifference = g_settings->highDepthColour.blue() - g_settings->lowDepthColour.blue(); - int alphaDifference = g_settings->highDepthColour.alpha() - g_settings->lowDepthColour.alpha(); - - int red = int(g_settings->lowDepthColour.red() + (fraction * redDifference) + 0.5); - int green = int(g_settings->lowDepthColour.green() + (fraction * greenDifference) + 0.5); - int blue = int(g_settings->lowDepthColour.blue() + (fraction * blueDifference) + 0.5); - int alpha = int(g_settings->lowDepthColour.alpha() + (fraction * alphaDifference) + 0.5); - - return {red, green, blue, alpha}; -} - - - void GraphicsItemNode::setWidth() { m_width = getNodeWidth(m_deBruijnNode->getDepthRelativeToMeanDrawnDepth(), g_settings->depthPower, diff --git a/graph/graphicsitemnode.h b/graph/graphicsitemnode.h index 3a612096..9b93b965 100644 --- a/graph/graphicsitemnode.h +++ b/graph/graphicsitemnode.h @@ -16,19 +16,20 @@ //along with Bandage. If not, see . -#ifndef GRAPHICSITEMNODE_H -#define GRAPHICSITEMNODE_H +#pragma once -#include -#include #include "ogdf/basic/GraphAttributes.h" -#include + #include #include #include #include #include #include +#include +#include + +#include class DeBruijnNode; class Path; @@ -77,9 +78,8 @@ class GraphicsItemNode : public QGraphicsItem QPointF getSecondLast() const {return m_linePoints[m_linePoints.size()-2];} std::vector getCentres() const; QPointF getCentre(std::vector linePoints) const; - void setNodeColour(); + void setNodeColour(QColor color) { m_colour = color; } QStringList getNodeText() const; - QColor getDepthColour() const; void setWidth(); QPainterPath makePartialPath(double startFraction, double endFraction); double getNodePathLength(); @@ -99,6 +99,4 @@ class GraphicsItemNode : public QGraphicsItem void pathHighlightNode2(QPainter * painter, DeBruijnNode * node, bool reverse, Path * path); QPainterPath buildPartialHighlightPath(double startFraction, double endFraction, bool reverse); void shiftPointSideways(bool left); -}; - -#endif // GRAPHICSITEMNODE_H +}; \ No newline at end of file diff --git a/graph/nodecolorer.cpp b/graph/nodecolorer.cpp new file mode 100644 index 00000000..de2cb5fe --- /dev/null +++ b/graph/nodecolorer.cpp @@ -0,0 +1,228 @@ +// Copyright 2022 Anton Korobeynikov + +// This file is part of Bandage + +// Bandage 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. + +// Bandage 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 Bandage. If not, see . + +#include "nodecolorer.h" +#include "assemblygraph.h" +#include "debruijnnode.h" +#include "program/globals.h" + +INodeColorer::INodeColorer(NodeColorScheme scheme) + : m_graph(g_assemblyGraph), m_scheme(scheme) {} + + +std::pair INodeColorer::get(const GraphicsItemNode *node, + const GraphicsItemNode *rcNode) { + QColor posColor = this->get(node); + QColor negColor = rcNode ? this->get(rcNode) : posColor; + + return { posColor, negColor }; +} + +class DepthNodeColorer : public INodeColorer { +public: + using INodeColorer::INodeColorer; + + QColor get(const GraphicsItemNode *node) override; + [[nodiscard]] const char* name() const override { return "Color by depth"; }; +}; + +class UniformNodeColorer : public INodeColorer { +public: + using INodeColorer::INodeColorer; + + QColor get(const GraphicsItemNode *node) override; + [[nodiscard]] const char* name() const override { return "Uniform color"; }; +}; + +class RandomNodeColorer : public INodeColorer { +public: + using INodeColorer::INodeColorer; + + QColor get(const GraphicsItemNode *node) override; + [[nodiscard]] std::pair get(const GraphicsItemNode *node, + const GraphicsItemNode *rcNode) override; + [[nodiscard]] const char* name() const override { return "Random colors"; }; +}; + +class GrayNodeColorer : public INodeColorer { +public: + using INodeColorer::INodeColorer; + + QColor get(const GraphicsItemNode *node) override; + [[nodiscard]] const char* name() const override { return "Gray colors"; }; +}; + +class CustomNodeColorer : public INodeColorer { +public: + using INodeColorer::INodeColorer; + + QColor get(const GraphicsItemNode *node) override; + [[nodiscard]] const char* name() const override { return "Custom colors"; }; +}; + +class ContiguityNodeColorer : public INodeColorer { +public: + using INodeColorer::INodeColorer; + + QColor get(const GraphicsItemNode *node) override; + [[nodiscard]] const char* name() const override { return "Color by contiguity"; }; +}; + +std::unique_ptr INodeColorer::create(NodeColorScheme scheme) { + switch (scheme) { + case UNIFORM_COLOURS: + return std::make_unique(scheme); + case RANDOM_COLOURS: + return std::make_unique(scheme); + case DEPTH_COLOUR: + return std::make_unique(scheme); + case CONTIGUITY_COLOUR: + return std::make_unique(scheme); + case CUSTOM_COLOURS: + return std::make_unique(scheme); + case GRAY_COLOR: + return std::make_unique(scheme); + } + + return nullptr; +} + +static QColor interpolateRgb(QColor from, QColor to, float fraction) { + float rDiff = to.redF() - from.redF(); + float gDiff = to.greenF() - from.greenF(); + float bDiff = to.blueF() - from.blueF(); + float aDiff = to.alphaF() - from.alphaF(); + + return QColor::fromRgbF(from.redF() + rDiff * fraction, + from.greenF() + gDiff * fraction, + from.blueF() + bDiff * fraction, + from.alphaF() + aDiff * fraction); +} + +QColor DepthNodeColorer::get(const GraphicsItemNode *node) { + const DeBruijnNode *deBruijnNode = node->m_deBruijnNode; + double depth = deBruijnNode->getDepth(); + double lowValue; + double highValue; + if (g_settings->autoDepthValue) { + lowValue = m_graph->m_firstQuartileDepth; + highValue = m_graph->m_thirdQuartileDepth; + } else { + lowValue = g_settings->lowDepthValue; + highValue = g_settings->highDepthValue; + } + + if (depth <= lowValue) + return g_settings->lowDepthColour; + if (depth >= highValue) + return g_settings->highDepthColour; + + float fraction = (depth - lowValue) / (highValue - lowValue); + return interpolateRgb(g_settings->lowDepthColour, g_settings->highDepthColour, fraction); +} + +QColor UniformNodeColorer::get(const GraphicsItemNode *node) { + const DeBruijnNode *deBruijnNode = node->m_deBruijnNode; + + if (deBruijnNode->isSpecialNode()) + return g_settings->uniformNodeSpecialColour; + else if (node->usePositiveNodeColour()) + return g_settings->uniformPositiveNodeColour; + else + return g_settings->uniformNegativeNodeColour; +} + +QColor RandomNodeColorer::get(const GraphicsItemNode *node) { + const DeBruijnNode *deBruijnNode = node->m_deBruijnNode; + + // Make a colour with a random hue. + int hue = rand() % 360; + QColor posColour; + posColour.setHsl(hue, + g_settings->randomColourPositiveSaturation, + g_settings->randomColourPositiveLightness); + posColour.setAlpha(g_settings->randomColourPositiveOpacity); + + QColor negColour; + negColour.setHsl(hue, + g_settings->randomColourNegativeSaturation, + g_settings->randomColourNegativeLightness); + negColour.setAlpha(g_settings->randomColourNegativeOpacity); + + if (!deBruijnNode->isPositiveNode()) + std::swap(posColour, negColour); + + return posColour; +} + +std::pair RandomNodeColorer::get(const GraphicsItemNode *node, const GraphicsItemNode *rcNode) { + const DeBruijnNode *deBruijnNode = node->m_deBruijnNode; + + // Make a colour with a random hue. Assign a colour to both this node and + // its complement so their hue matches. + int hue = rand() % 360; + QColor posColour; + posColour.setHsl(hue, + g_settings->randomColourPositiveSaturation, + g_settings->randomColourPositiveLightness); + posColour.setAlpha(g_settings->randomColourPositiveOpacity); + + QColor negColour; + negColour.setHsl(hue, + g_settings->randomColourNegativeSaturation, + g_settings->randomColourNegativeLightness); + negColour.setAlpha(g_settings->randomColourNegativeOpacity); + + if (!deBruijnNode->isPositiveNode()) + std::swap(posColour, negColour); + + return { posColour, negColour }; +} + +QColor GrayNodeColorer::get(const GraphicsItemNode *node) { + return g_settings->grayColor; +} + +QColor CustomNodeColorer::get(const GraphicsItemNode *node) { + return m_graph->getCustomColourForDisplay(node->m_deBruijnNode);; +} + +QColor ContiguityNodeColorer::get(const GraphicsItemNode *node) { + const DeBruijnNode *deBruijnNode = node->m_deBruijnNode; + + // For single nodes, display the colour of whichever of the + // twin nodes has the greatest contiguity status. + ContiguityStatus contiguityStatus = deBruijnNode->getContiguityStatus(); + if (!node->m_hasArrow) { + ContiguityStatus twinContiguityStatus = deBruijnNode->getReverseComplement()->getContiguityStatus(); + if (twinContiguityStatus < contiguityStatus) + contiguityStatus = twinContiguityStatus; + } + + switch (contiguityStatus) { + case STARTING: + return g_settings->contiguityStartingColour; + case CONTIGUOUS_STRAND_SPECIFIC: + return g_settings->contiguousStrandSpecificColour; + case CONTIGUOUS_EITHER_STRAND: + return g_settings->contiguousEitherStrandColour; + case MAYBE_CONTIGUOUS: + return g_settings->maybeContiguousColour; + default: //NOT_CONTIGUOUS + return g_settings->notContiguousColour; + } +} \ No newline at end of file diff --git a/graph/nodecolorer.h b/graph/nodecolorer.h new file mode 100644 index 00000000..93cb41da --- /dev/null +++ b/graph/nodecolorer.h @@ -0,0 +1,54 @@ +// Copyright 2022 Anton Korobeynikov + +// This file is part of Bandage + +// Bandage 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. + +// Bandage 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 Bandage. If not, see . + +#pragma once + +#include +#include + +class AssemblyGraph; +class GraphicsItemNode; + +// This needs to be synchronizes with selection combo box! +enum NodeColorScheme : int { + GRAY_COLOR = 0, + RANDOM_COLOURS = 1, + UNIFORM_COLOURS = 2, + DEPTH_COLOUR = 3, + CONTIGUITY_COLOUR = 4, + CUSTOM_COLOURS = 5, + LAST_SCHEME = CUSTOM_COLOURS +}; + +class INodeColorer { +public: + explicit INodeColorer(NodeColorScheme scheme); + virtual ~INodeColorer() = default; + + [[nodiscard]] virtual QColor get(const GraphicsItemNode *node) = 0; + [[nodiscard]] virtual std::pair get(const GraphicsItemNode *node, + const GraphicsItemNode *rcNode); + virtual void reset() {}; + [[nodiscard]] virtual const char* name() const = 0; + + static std::unique_ptr create(NodeColorScheme scheme); + + [[nodiscard]] NodeColorScheme scheme() const { return m_scheme; } +protected: + NodeColorScheme m_scheme; + QSharedPointer m_graph; +}; \ No newline at end of file diff --git a/program/globals.h b/program/globals.h index 9f768cfd..22fe9402 100644 --- a/program/globals.h +++ b/program/globals.h @@ -32,8 +32,6 @@ class BlastSearch; class AssemblyGraph; class AnnotationsManager; -enum NodeColourScheme {UNIFORM_COLOURS, RANDOM_COLOURS, DEPTH_COLOUR, - CONTIGUITY_COLOUR, CUSTOM_COLOURS, GRAY_COLOR}; enum GraphScope {WHOLE_GRAPH, AROUND_NODE, AROUND_PATHS, AROUND_BLAST_HITS, DEPTH_RANGE}; enum ContiguityStatus {STARTING, CONTIGUOUS_STRAND_SPECIFIC, CONTIGUOUS_EITHER_STRAND, MAYBE_CONTIGUOUS, @@ -63,7 +61,7 @@ using AnnotationGroupId = int; using ViewId = int; -//Some of the program's common components are made global so they don't have +//Some of the program's common components are made global, so they don't have //to be passed around as parameters. extern QSharedPointer g_settings; extern QSharedPointer g_memory; diff --git a/program/main.cpp b/program/main.cpp index 69007c30..6850bcef 100644 --- a/program/main.cpp +++ b/program/main.cpp @@ -20,19 +20,13 @@ #include "graph/debruijnnode.h" #include "graph/debruijnedge.h" - - -#include -#include -#include -#include - #include "command_line/load.h" #include "command_line/info.h" #include "command_line/image.h" #include "command_line/querypaths.h" #include "command_line/reduce.h" #include "command_line/commoncommandlinefunctions.h" + #include "program/settings.h" #include "program/memory.h" #include "program/globals.h" @@ -42,6 +36,11 @@ #include "graph/annotationsmanager.hpp" #include "ui/mygraphicsview.h" +#include +#include +#include +#include + #ifndef Q_OS_WIN32 #include #endif //Q_OS_WIN32 diff --git a/program/settings.cpp b/program/settings.cpp index 22d10a0d..c9cfc9af 100644 --- a/program/settings.cpp +++ b/program/settings.cpp @@ -17,6 +17,7 @@ #include "settings.h" +#include "graph/nodecolorer.h" #include Settings::Settings() @@ -43,7 +44,6 @@ Settings::Settings() edgeWidth = FloatSetting(1.5, 0.1, 100); outlineThickness = FloatSetting(0.0, 0.0, 100.0); selectionThickness = 1.0; - arrowheadSize = 0.01; arrowheadsInSingleMode = true; textOutlineThickness = FloatSetting(1.5, 0.0, 10.0); @@ -78,7 +78,7 @@ Settings::Settings() nodeDragging = NEARBY_PIECES; - nodeColourScheme = RANDOM_COLOURS; + initializeColorer(RANDOM_COLOURS); uniformPositiveNodeColour = QColor(178, 34, 34); uniformNegativeNodeColour = QColor(128, 0, 0); uniformNodeSpecialColour = QColor(0, 128, 0); @@ -145,3 +145,8 @@ Settings::Settings() annotationsSettings = {}; } + + +void Settings::initializeColorer(NodeColorScheme scheme) { + nodeColorer = INodeColorer::create(scheme); +} diff --git a/program/settings.h b/program/settings.h index dd655978..d90d7265 100644 --- a/program/settings.h +++ b/program/settings.h @@ -19,18 +19,18 @@ #ifndef SETTINGS_H #define SETTINGS_H +#include "globals.h" +#include "scinot.h" +// FIXME: This needs to be properly factored out +#include "graph/nodecolorer.h" + #include #include -#include "globals.h" #include #include #include -#include "graph/path.h" -#include "scinot.h" - -class DeBruijnNode; - +class INodeColorer; class IntSetting { @@ -105,7 +105,6 @@ class Settings FloatSetting edgeWidth; FloatSetting outlineThickness; double selectionThickness; - double arrowheadSize; bool arrowheadsInSingleMode; FloatSetting textOutlineThickness; @@ -149,7 +148,9 @@ class Settings QColor textColour; QColor textOutlineColour; - NodeColourScheme nodeColourScheme; + // FIXME: This does not belong here! + void initializeColorer(NodeColorScheme scheme); + std::shared_ptr nodeColorer; QColor uniformPositiveNodeColour; QColor uniformNegativeNodeColour; QColor uniformNodeSpecialColour; @@ -204,7 +205,7 @@ class Settings //running a BLAST search. QString blastSearchParameters; - //These are the optional BLAST hit filters: whether or not they are used and + //These are the optional BLAST hit filters: whether they are used and //what their values are. IntSetting blastAlignmentLengthFilter; FloatSetting blastQueryCoverageFilter; diff --git a/tests/bandagetests.cpp b/tests/bandagetests.cpp index 7fc156c8..9a3c8cf6 100644 --- a/tests/bandagetests.cpp +++ b/tests/bandagetests.cpp @@ -879,15 +879,15 @@ void BandageTests::commandLineSettings() commandLineSettings = QString("--colour random").split(" "); parseSettings(commandLineSettings); - QCOMPARE(g_settings->nodeColourScheme, RANDOM_COLOURS); + QCOMPARE(g_settings->nodeColorer->scheme(), RANDOM_COLOURS); commandLineSettings = QString("--colour uniform").split(" "); parseSettings(commandLineSettings); - QCOMPARE(g_settings->nodeColourScheme, UNIFORM_COLOURS); + QCOMPARE(g_settings->nodeColorer->scheme(), UNIFORM_COLOURS); commandLineSettings = QString("--colour depth").split(" "); parseSettings(commandLineSettings); - QCOMPARE(g_settings->nodeColourScheme, DEPTH_COLOUR); + QCOMPARE(g_settings->nodeColorer->scheme(), DEPTH_COLOUR); commandLineSettings = QString("--ransatpos 12").split(" "); parseSettings(commandLineSettings); diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index 970ebbea..902b35f4 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -66,6 +66,7 @@ #include "graphinfodialog.h" #include "graph/sequenceutils.hpp" #include "graph/assemblygraphbuilder.h" +#include "graph/nodecolorer.h" MainWindow::MainWindow(QString fileToLoadOnStartup, bool drawGraphAfterLoad) : QMainWindow(nullptr), @@ -1117,71 +1118,49 @@ void MainWindow::saveSelectedPathToFile() } +void MainWindow::resetAllNodeColours() { + for (auto &entry : g_assemblyGraph->m_deBruijnGraphNodes) { + auto *graphicsItemNode = entry->getGraphicsItemNode(); + if (!graphicsItemNode) + continue; + + graphicsItemNode->setNodeColour(g_settings->nodeColorer->get(graphicsItemNode)); + } + g_graphicsView->viewport()->update(); +} void MainWindow::switchColourScheme() { - switch (ui->coloursComboBox->currentIndex()) - { - case 0: - g_settings->nodeColourScheme = GRAY_COLOR; - ui->contiguityButton->setVisible(false); - ui->contiguityInfoText->setVisible(false); - break; - case 1: - g_settings->nodeColourScheme = RANDOM_COLOURS; - ui->contiguityButton->setVisible(false); - ui->contiguityInfoText->setVisible(false); - break; - case 2: - g_settings->nodeColourScheme = UNIFORM_COLOURS; - ui->contiguityButton->setVisible(false); - ui->contiguityInfoText->setVisible(false); - break; - case 3: - g_settings->nodeColourScheme = DEPTH_COLOUR; - ui->contiguityButton->setVisible(false); - ui->contiguityInfoText->setVisible(false); - break; - case 4: - g_settings->nodeColourScheme = CONTIGUITY_COLOUR; - ui->contiguityButton->setVisible(true); - ui->contiguityInfoText->setVisible(true); - break; - case 5: - g_settings->nodeColourScheme = CUSTOM_COLOURS; - ui->contiguityButton->setVisible(false); - ui->contiguityInfoText->setVisible(false); - break; - } + NodeColorScheme scheme = (NodeColorScheme)ui->coloursComboBox->currentIndex(); + g_settings->initializeColorer(scheme); + ui->contiguityButton->setVisible(scheme == CONTIGUITY_COLOUR); + ui->contiguityInfoText->setVisible(scheme == CONTIGUITY_COLOUR); - g_assemblyGraph->resetAllNodeColours(); - g_graphicsView->viewport()->update(); + resetAllNodeColours(); } -void MainWindow::determineContiguityFromSelectedNode() -{ +void MainWindow::determineContiguityFromSelectedNode() { g_assemblyGraph->resetNodeContiguityStatus(); std::vector selectedNodes = m_scene->getSelectedNodes(); - if (!selectedNodes.empty()) - { - MyProgressDialog progress(this, "Determining contiguity...", false); - progress.setWindowModality(Qt::WindowModal); - progress.show(); - - for (auto & selectedNode : selectedNodes) - selectedNode->determineContiguity(); - - g_assemblyGraph->m_contiguitySearchDone = true; - g_assemblyGraph->resetAllNodeColours(); - g_graphicsView->viewport()->update(); - } - else + if (selectedNodes.empty()) { QMessageBox::information(this, "No nodes selected", "Please select one or more nodes for which " "contiguity is to be determined."); + return; + } + + MyProgressDialog progress(this, "Determining contiguity...", false); + progress.setWindowModality(Qt::WindowModal); + progress.show(); + + for (auto *selectedNode : selectedNodes) + selectedNode->determineContiguity(); + + g_assemblyGraph->m_contiguitySearchDone = true; + resetAllNodeColours(); } @@ -1393,8 +1372,7 @@ void MainWindow::fontButtonPressed() -void MainWindow::setNodeCustomColour() -{ +void MainWindow::setNodeCustomColour() { std::vector selectedNodes = m_scene->getSelectedNodes(); if (selectedNodes.empty()) return; @@ -1404,26 +1382,25 @@ void MainWindow::setNodeCustomColour() dialogTitle += "s"; QColor newColour = QColorDialog::getColor(g_assemblyGraph->getCustomColourForDisplay(selectedNodes[0]), this, dialogTitle); - if (newColour.isValid()) - { - //If we are in single mode, apply the custom colour to both nodes in - //each complementary pair. - if (!g_settings->doubleMode) - selectedNodes = addComplementaryNodes(selectedNodes); + if (!newColour.isValid()) + return; - //If the colouring scheme is not currently custom, change it to custom now - if (g_settings->nodeColourScheme != CUSTOM_COLOURS) - setNodeColourSchemeComboBox(CUSTOM_COLOURS); + // If we are in single mode, apply the custom colour to both nodes in + // each complementary pair. + if (!g_settings->doubleMode) + selectedNodes = addComplementaryNodes(selectedNodes); - for (auto & selectedNode : selectedNodes) - { - g_assemblyGraph->setCustomColour(selectedNode, newColour); - if (selectedNode->getGraphicsItemNode() != nullptr) - selectedNode->getGraphicsItemNode()->setNodeColour(); + // If the colouring scheme is not currently custom, change it to custom now + g_settings->initializeColorer(CUSTOM_COLOURS); + ui->coloursComboBox->setCurrentIndex(g_settings->nodeColorer->scheme()); - } - g_graphicsView->viewport()->update(); + for (auto & selectedNode : selectedNodes) { + g_assemblyGraph->setCustomColour(selectedNode, newColour); + if (selectedNode->getGraphicsItemNode() != nullptr) + selectedNode->getGraphicsItemNode()->setNodeColour(newColour); } + + g_graphicsView->viewport()->update(); } void MainWindow::setNodeCustomLabel() @@ -1464,51 +1441,19 @@ std::vector MainWindow::addComplementaryNodes(std::vectordepthEffectOnWidth || - settingsBefore.depthPower != g_settings->depthPower) - g_assemblyGraph->recalculateAllNodeWidths(); - - //If any of the colours changed, reset the node colours now. - if (settingsBefore.uniformPositiveNodeColour != g_settings->uniformPositiveNodeColour || - settingsBefore.uniformNegativeNodeColour != g_settings->uniformNegativeNodeColour || - settingsBefore.uniformNodeSpecialColour != g_settings->uniformNodeSpecialColour || - settingsBefore.autoDepthValue != g_settings->autoDepthValue || - settingsBefore.lowDepthColour != g_settings->lowDepthColour || - settingsBefore.highDepthColour != g_settings->highDepthColour || - settingsBefore.lowDepthValue != g_settings->lowDepthValue || - settingsBefore.highDepthValue != g_settings->highDepthValue || - settingsBefore.grayColor != g_settings->grayColor || - settingsBefore.contiguousStrandSpecificColour != g_settings->contiguousStrandSpecificColour || - settingsBefore.contiguousEitherStrandColour != g_settings->contiguousEitherStrandColour || - settingsBefore.notContiguousColour != g_settings->notContiguousColour || - settingsBefore.maybeContiguousColour != g_settings->maybeContiguousColour || - settingsBefore.contiguityStartingColour != g_settings->contiguityStartingColour || - settingsBefore.randomColourPositiveOpacity != g_settings->randomColourPositiveOpacity || - settingsBefore.randomColourNegativeOpacity != g_settings->randomColourNegativeOpacity || - settingsBefore.randomColourPositiveSaturation != g_settings->randomColourPositiveSaturation || - settingsBefore.randomColourNegativeSaturation != g_settings->randomColourNegativeSaturation || - settingsBefore.randomColourPositiveLightness != g_settings->randomColourPositiveLightness || - settingsBefore.randomColourNegativeLightness != g_settings->randomColourNegativeLightness) - { - g_assemblyGraph->resetAllNodeColours(); - } + if (!settingsDialog.exec()) //The user clicked OK + return; - g_graphicsView->setAntialiasing(g_settings->antialiasing); - g_graphicsView->viewport()->update(); - } + settingsDialog.setSettingsFromWidgets(); + + g_assemblyGraph->recalculateAllNodeWidths(); + g_graphicsView->setAntialiasing(g_settings->antialiasing); + + resetAllNodeColours(); } void MainWindow::doSelectNodes(const std::vector &nodesToSelect, @@ -2186,7 +2131,7 @@ void MainWindow::setWidgetsFromSettings() ui->startingNodesExactMatchRadioButton->setChecked(g_settings->startingNodesExactMatch); ui->startingNodesPartialMatchRadioButton->setChecked(!g_settings->startingNodesExactMatch); - setNodeColourSchemeComboBox(g_settings->nodeColourScheme); + ui->coloursComboBox->setCurrentIndex(g_settings->nodeColorer->scheme()); setGraphScopeComboBox(g_settings->graphScope); ui->nodeDistanceSpinBox->setValue(g_settings->nodeDistance); @@ -2196,21 +2141,6 @@ void MainWindow::setWidgetsFromSettings() ui->maxDepthSpinBox->setValue(g_settings->maxDepthRange); } - - -void MainWindow::setNodeColourSchemeComboBox(NodeColourScheme nodeColourScheme) -{ - switch (nodeColourScheme) - { - case GRAY_COLOR: ui->coloursComboBox->setCurrentIndex(0); break; - case RANDOM_COLOURS: ui->coloursComboBox->setCurrentIndex(1); break; - case UNIFORM_COLOURS: ui->coloursComboBox->setCurrentIndex(2); break; - case DEPTH_COLOUR: ui->coloursComboBox->setCurrentIndex(3); break; - case CONTIGUITY_COLOUR: ui->coloursComboBox->setCurrentIndex(4); break; - case CUSTOM_COLOURS: ui->coloursComboBox->setCurrentIndex(5); break; - } -} - void MainWindow::setGraphScopeComboBox(GraphScope graphScope) { switch (graphScope) @@ -2438,10 +2368,12 @@ void MainWindow::removeSelection() g_assemblyGraph->determineGraphInfo(); displayGraphDetails(); - //Now that the graph has changed, we have to reset BLAST and contiguity - //stuff, as they may no longer apply. + // Now that the graph has changed, we have to reset BLAST and contiguity + // stuff, as they may no longer apply. cleanUpAllBlast(); + g_assemblyGraph->resetNodeContiguityStatus(); + resetAllNodeColours(); } @@ -2472,10 +2404,11 @@ void MainWindow::duplicateSelectedNodes() g_assemblyGraph->determineGraphInfo(); displayGraphDetails(); - //Now that the graph has changed, we have to reset BLAST and contiguity - //stuff, as they may no longer apply. + // Now that the graph has changed, we have to reset BLAST and contiguity + // stuff, as they may no longer apply. cleanUpAllBlast(); g_assemblyGraph->resetNodeContiguityStatus(); + resetAllNodeColours(); } void MainWindow::mergeSelectedNodes() @@ -2516,10 +2449,11 @@ void MainWindow::mergeSelectedNodes() g_assemblyGraph->determineGraphInfo(); displayGraphDetails(); - //Now that the graph has changed, we have to reset BLAST and contiguity - //stuff, as they may no longer apply. + // Now that the graph has changed, we have to reset BLAST and contiguity + // stuff, as they may no longer apply. cleanUpAllBlast(); g_assemblyGraph->resetNodeContiguityStatus(); + resetAllNodeColours(); } void MainWindow::mergeAllPossible() @@ -2552,6 +2486,7 @@ void MainWindow::mergeAllPossible() //stuff, as they may no longer apply. cleanUpAllBlast(); g_assemblyGraph->resetNodeContiguityStatus(); + resetAllNodeColours(); } else QMessageBox::information(this, "No possible merges", "The graph contains no nodes that can be merged."); diff --git a/ui/mainwindow.h b/ui/mainwindow.h index ef123ac1..bf3108e2 100644 --- a/ui/mainwindow.h +++ b/ui/mainwindow.h @@ -19,6 +19,10 @@ #ifndef MAINWINDOW_H #define MAINWINDOW_H +#include "program/globals.h" +#include "graph/nodecolorer.h" +#include "ogdf/energybased/FMMMLayout.h" + #include #include #include @@ -26,9 +30,7 @@ #include #include #include -#include "program/globals.h" #include -#include "ogdf/energybased/FMMMLayout.h" Q_MOC_INCLUDE("graph/debruijnnode.h") @@ -69,6 +71,7 @@ class MainWindow : public QMainWindow void displayGraphDetails(); void clearGraphDetails(); void resetScene(); + void resetAllNodeColours(); void layoutGraph(); void zoomToFitRect(QRectF rect); void zoomToFitScene(); @@ -83,7 +86,6 @@ class MainWindow : public QMainWindow void selectBasedOnContiguity(ContiguityStatus contiguityStatus); void setWidgetsFromSettings(); QString getDefaultImageFileName(); - void setNodeColourSchemeComboBox(NodeColourScheme nodeColourScheme); void setGraphScopeComboBox(GraphScope graphScope); void setupBlastQueryComboBox(); void setupPathSelectionLineEdit(QLineEdit *lineEdit); diff --git a/ui/settingsdialog.cpp b/ui/settingsdialog.cpp index 27a1e35f..7dd148c5 100644 --- a/ui/settingsdialog.cpp +++ b/ui/settingsdialog.cpp @@ -17,10 +17,13 @@ #include "settingsdialog.h" -#include "program/settings.h" + #include "colourbutton.h" -#include "graph/assemblygraph.h" #include "program/scinot.h" +#include "program/settings.h" + +#include "graph/assemblygraph.h" +#include "graph/nodecolorer.h" #include #include "ui_settingsdialog.h" From 82e40f7a42093223edaa5b322852ab29d21e0a80 Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Sun, 12 Jun 2022 18:03:08 +0200 Subject: [PATCH 3/6] Add "color by GC" settings --- graph/assemblygraph.cpp | 2 +- graph/assemblygraph.h | 2 +- graph/debruijnnode.cpp | 10 ++++++++++ graph/debruijnnode.h | 3 ++- graph/nodecolorer.cpp | 25 ++++++++++++++++++++++++- graph/nodecolorer.h | 3 ++- ui/mainwindow.cpp | 3 +++ ui/mainwindow.ui | 5 +++++ 8 files changed, 48 insertions(+), 5 deletions(-) diff --git a/graph/assemblygraph.cpp b/graph/assemblygraph.cpp index e4a1dfaf..e62b19c4 100644 --- a/graph/assemblygraph.cpp +++ b/graph/assemblygraph.cpp @@ -261,7 +261,7 @@ double AssemblyGraph::getMeanDepth(bool drawnNodesOnly) } -double AssemblyGraph::getMeanDepth(std::vector nodes) +double AssemblyGraph::getMeanDepth(const std::vector &nodes) { if (nodes.empty()) return 0.0; diff --git a/graph/assemblygraph.h b/graph/assemblygraph.h index bf7db9c8..0dd8b73a 100644 --- a/graph/assemblygraph.h +++ b/graph/assemblygraph.h @@ -108,7 +108,7 @@ class AssemblyGraph : public QObject static QByteArray getReverseComplement(const QByteArray& forwardSequence); void resetEdges(); double getMeanDepth(bool drawnNodesOnly = false); - static double getMeanDepth(std::vector nodes); + static double getMeanDepth(const std::vector &nodes); static double getMeanDepth(const QList& nodes); void resetNodeContiguityStatus(); void determineGraphInfo(); diff --git a/graph/debruijnnode.cpp b/graph/debruijnnode.cpp index 0fd99721..9b7a37c6 100644 --- a/graph/debruijnnode.cpp +++ b/graph/debruijnnode.cpp @@ -709,3 +709,13 @@ std::vector DeBruijnNode::getAllConnectedPositiveNodes() const return connectedPositiveNodesVector; } + +float DeBruijnNode::getGC() const { + size_t gc = 0; + for (size_t i = 0; i < m_sequence.size(); ++i) { + char c = m_sequence[i]; + gc += (c == 'G' || c == 'C'); + } + + return float(gc) / float(m_sequence.size()); +} diff --git a/graph/debruijnnode.h b/graph/debruijnnode.h index 7a522fc4..dfd3d5b6 100644 --- a/graph/debruijnnode.h +++ b/graph/debruijnnode.h @@ -54,6 +54,8 @@ class DeBruijnNode double getDepth() const {return m_depth;} double getDepthRelativeToMeanDrawnDepth() const {return m_depthRelativeToMeanDrawnDepth;} + float getGC() const; + const Sequence &getSequence() const; Sequence &getSequence(); @@ -67,7 +69,6 @@ class DeBruijnNode DeBruijnNode * getReverseComplement() const {return m_reverseComplement;} OgdfNode * getOgdfNode() const {return m_ogdfNode;} GraphicsItemNode * getGraphicsItemNode() const {return m_graphicsItemNode;} - bool thisOrReverseComplementHasGraphicsItemNode() const {return (m_graphicsItemNode != nullptr || getReverseComplement()->m_graphicsItemNode != nullptr);} bool hasGraphicsItem() const {return m_graphicsItemNode != nullptr;} auto edgeBegin() { return m_edges.begin(); } diff --git a/graph/nodecolorer.cpp b/graph/nodecolorer.cpp index de2cb5fe..d86df20a 100644 --- a/graph/nodecolorer.cpp +++ b/graph/nodecolorer.cpp @@ -82,6 +82,14 @@ class ContiguityNodeColorer : public INodeColorer { [[nodiscard]] const char* name() const override { return "Color by contiguity"; }; }; +class GCNodeColorer : public INodeColorer { +public: + using INodeColorer::INodeColorer; + + QColor get(const GraphicsItemNode *node) override; + [[nodiscard]] const char* name() const override { return "Color by GC content"; }; +}; + std::unique_ptr INodeColorer::create(NodeColorScheme scheme) { switch (scheme) { case UNIFORM_COLOURS: @@ -96,6 +104,8 @@ std::unique_ptr INodeColorer::create(NodeColorScheme scheme) { return std::make_unique(scheme); case GRAY_COLOR: return std::make_unique(scheme); + case GC_CONTENT: + return std::make_unique(scheme); } return nullptr; @@ -225,4 +235,17 @@ QColor ContiguityNodeColorer::get(const GraphicsItemNode *node) { default: //NOT_CONTIGUOUS return g_settings->notContiguousColour; } -} \ No newline at end of file +} + +QColor GCNodeColorer::get(const GraphicsItemNode *node) { + const DeBruijnNode *deBruijnNode = node->m_deBruijnNode; + + float lowValue = 0.2, highValue = 0.8, value = deBruijnNode->getGC(); + if (value > highValue) + return g_settings->highDepthColour; + else if (value < lowValue) + return g_settings->lowDepthColour; + + float fraction = (value - lowValue) / (highValue - lowValue); + return interpolateRgb(g_settings->lowDepthColour, g_settings->highDepthColour, fraction); +} diff --git a/graph/nodecolorer.h b/graph/nodecolorer.h index 93cb41da..f0dd036e 100644 --- a/graph/nodecolorer.h +++ b/graph/nodecolorer.h @@ -31,7 +31,8 @@ enum NodeColorScheme : int { DEPTH_COLOUR = 3, CONTIGUITY_COLOUR = 4, CUSTOM_COLOURS = 5, - LAST_SCHEME = CUSTOM_COLOURS + GC_CONTENT = 6, + LAST_SCHEME = GC_CONTENT }; class INodeColorer { diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index 902b35f4..0db5e1d2 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -542,6 +542,9 @@ void MainWindow::getSelectedNodeInfo(int & selectedNodeCount, QString & selected selectedNodeDepthText = formatDepthForDisplay(g_assemblyGraph->getMeanDepth(selectedNodes)); if (selectedNodeCount == 1) { + // FIXME: Hack! + selectedNodeDepthText += " GC: " + formatDoubleForDisplay(100 * selectedNodes[0]->getGC(), 1) + "%"; + auto tags = g_assemblyGraph->m_nodeTags.find(selectedNodes.front()); if (tags != g_assemblyGraph->m_nodeTags.end()) { std::stringstream txt; diff --git a/ui/mainwindow.ui b/ui/mainwindow.ui index fa1df844..04cafe2b 100644 --- a/ui/mainwindow.ui +++ b/ui/mainwindow.ui @@ -991,6 +991,11 @@ Custom colours + + + GC content + + From 187789b6a5594ba0ef27f37cf6eaf3bb375feafc Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Sun, 12 Jun 2022 18:33:04 +0200 Subject: [PATCH 4/6] Switch to better colormap --- graph/nodecolorer.cpp | 11 +- thirdparty/colormap/LICENSE | 21 + thirdparty/colormap/tinycolormap.hpp | 2466 ++++++++++++++++++++++++++ 3 files changed, 2491 insertions(+), 7 deletions(-) create mode 100644 thirdparty/colormap/LICENSE create mode 100644 thirdparty/colormap/tinycolormap.hpp diff --git a/graph/nodecolorer.cpp b/graph/nodecolorer.cpp index d86df20a..8fd02e1b 100644 --- a/graph/nodecolorer.cpp +++ b/graph/nodecolorer.cpp @@ -20,6 +20,9 @@ #include "debruijnnode.h" #include "program/globals.h" +#define TINYCOLORMAP_WITH_QT5 +#include + INodeColorer::INodeColorer(NodeColorScheme scheme) : m_graph(g_assemblyGraph), m_scheme(scheme) {} @@ -239,13 +242,7 @@ QColor ContiguityNodeColorer::get(const GraphicsItemNode *node) { QColor GCNodeColorer::get(const GraphicsItemNode *node) { const DeBruijnNode *deBruijnNode = node->m_deBruijnNode; - float lowValue = 0.2, highValue = 0.8, value = deBruijnNode->getGC(); - if (value > highValue) - return g_settings->highDepthColour; - else if (value < lowValue) - return g_settings->lowDepthColour; - float fraction = (value - lowValue) / (highValue - lowValue); - return interpolateRgb(g_settings->lowDepthColour, g_settings->highDepthColour, fraction); + return tinycolormap::GetColor(fraction).ConvertToQColor(); } diff --git a/thirdparty/colormap/LICENSE b/thirdparty/colormap/LICENSE new file mode 100644 index 00000000..3b51a1d0 --- /dev/null +++ b/thirdparty/colormap/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Yuki Koyama + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/thirdparty/colormap/tinycolormap.hpp b/thirdparty/colormap/tinycolormap.hpp new file mode 100644 index 00000000..bed482f5 --- /dev/null +++ b/thirdparty/colormap/tinycolormap.hpp @@ -0,0 +1,2466 @@ +/* + MIT License + + Copyright (c) 2018-2020 Yuki Koyama + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + + ------------------------------------------------------------------------------- + + The lookup table for Turbo is derived by Shot511 in his PR, + https://github.com/yuki-koyama/tinycolormap/pull/27 , from + https://gist.github.com/mikhailov-work/6a308c20e494d9e0ccc29036b28faa7a , which + is released by Anton Mikhailov, copyrighted by Google LLC, and licensed under + the Apache 2.0 license. To the best of our knowledge, the Apache 2.0 license is + compatible with the MIT license, and thus we release the merged entire code + under the MIT license. The license notice for Anton's code is posted here: + + Copyright 2019 Google LLC. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ + +#ifndef TINYCOLORMAP_HPP_ +#define TINYCOLORMAP_HPP_ + +#include +#include +#include + +#if defined(TINYCOLORMAP_WITH_EIGEN) +#include +#endif + +#if defined(TINYCOLORMAP_WITH_QT5) +#include +#endif + +#if defined(TINYCOLORMAP_WITH_QT5) && defined(TINYCOLORMAP_WITH_EIGEN) +#include +#include +#endif + +#if defined(TINYCOLORMAP_WITH_GLM) +#include +#endif + +namespace tinycolormap +{ + ////////////////////////////////////////////////////////////////////////////////// + // Interface + ////////////////////////////////////////////////////////////////////////////////// + + enum class ColormapType + { + Parula, Heat, Jet, Turbo, Hot, Gray, Magma, Inferno, Plasma, Viridis, Cividis, Github, Cubehelix + }; + + struct Color + { + explicit constexpr Color(double gray) noexcept : data{ gray, gray, gray } {} + constexpr Color(double r, double g, double b) noexcept : data{ r, g, b } {} + + double data[3]; + + double& r() noexcept { return data[0]; } + double& g() noexcept { return data[1]; } + double& b() noexcept { return data[2]; } + constexpr double r() const noexcept { return data[0]; } + constexpr double g() const noexcept { return data[1]; } + constexpr double b() const noexcept { return data[2]; } + + constexpr uint8_t ri() const noexcept { return static_cast(data[0] * 255.0); } + constexpr uint8_t gi() const noexcept { return static_cast(data[1] * 255.0); } + constexpr uint8_t bi() const noexcept { return static_cast(data[2] * 255.0); } + + double& operator[](std::size_t n) noexcept { return data[n]; } + constexpr double operator[](std::size_t n) const noexcept { return data[n]; } + double& operator()(std::size_t n) noexcept { return data[n]; } + constexpr double operator()(std::size_t n) const noexcept { return data[n]; } + + friend constexpr Color operator+(const Color& c0, const Color& c1) noexcept + { + return { c0.r() + c1.r(), c0.g() + c1.g(), c0.b() + c1.b() }; + } + + friend constexpr Color operator*(double s, const Color& c) noexcept + { + return { s * c.r(), s * c.g(), s * c.b() }; + } + +#if defined(TINYCOLORMAP_WITH_QT5) + QColor ConvertToQColor() const { return QColor(data[0] * 255.0, data[1] * 255.0, data[2] * 255.0); } +#endif +#if defined(TINYCOLORMAP_WITH_EIGEN) + Eigen::Vector3d ConvertToEigen() const { return Eigen::Vector3d(data[0], data[1], data[2]); } +#endif +#if defined(TINYCOLORMAP_WITH_GLM) + glm::vec3 ConvertToGLM() const { return glm::vec3(data[0], data[1], data[2]); } +#endif + }; + + inline Color GetColor(double x, ColormapType type = ColormapType::Viridis); + inline Color GetQuantizedColor(double x, unsigned int num_levels, ColormapType type = ColormapType::Viridis); + inline Color GetParulaColor(double x); + inline Color GetHeatColor(double x); + inline Color GetJetColor(double x); + inline Color GetTurboColor(double x); + inline Color GetHotColor(double x); + inline constexpr Color GetGrayColor(double x) noexcept; + inline Color GetMagmaColor(double x); + inline Color GetInfernoColor(double x); + inline Color GetPlasmaColor(double x); + inline Color GetViridisColor(double x); + inline Color GetCividisColor(double x); + inline Color GetGithubColor(double x); + inline Color GetCubehelixColor(double x); + +#if defined(TINYCOLORMAP_WITH_QT5) && defined(TINYCOLORMAP_WITH_EIGEN) + inline QImage CreateMatrixVisualization(const Eigen::MatrixXd& matrix); + inline void ExportMatrixVisualization(const Eigen::MatrixXd& matrix, const std::string& path); +#endif + + ////////////////////////////////////////////////////////////////////////////////// + // Private Implementation - public usage is not intended + ////////////////////////////////////////////////////////////////////////////////// + + namespace internal + { + inline constexpr double Clamp01(double x) noexcept + { + return (x < 0.0) ? 0.0 : (x > 1.0) ? 1.0 : x; + } + + // A helper function to calculate linear interpolation + template + Color CalcLerp(double x, const Color (&data)[N]) + { + const double a = Clamp01(x) * (N - 1); + const double i = std::floor(a); + const double t = a - i; + const Color& c0 = data[static_cast(i)]; + const Color& c1 = data[static_cast(std::ceil(a))]; + + return (1.0 - t) * c0 + t * c1; + } + + inline double QuantizeArgument(double x, unsigned int num_levels) + { + // Clamp num_classes to range [1, 255]. + num_levels = (std::max)(1u, (std::min)(num_levels, 255u)); + + const double interval_length = 255.0 / num_levels; + + // Calculate index of the interval to which the given x belongs to. + // Substracting eps prevents getting out of bounds index. + constexpr double eps = 0.0005; + const unsigned int index = static_cast((x * 255.0 - eps) / interval_length); + + // Calculate upper and lower bounds of the given interval. + const unsigned int upper_boundary = static_cast(index * interval_length + interval_length); + const unsigned int lower_boundary = static_cast(upper_boundary - interval_length); + + // Get middle "coordinate" of the given interval and move it back to [0.0, 1.0] interval. + const double xx = static_cast(upper_boundary + lower_boundary) * 0.5 / 255.0; + + return xx; + } + } + + ////////////////////////////////////////////////////////////////////////////////// + // Public Implementation + ////////////////////////////////////////////////////////////////////////////////// + + inline Color GetColor(double x, ColormapType type) + { + switch (type) + { + case ColormapType::Parula: + return GetParulaColor(x); + case ColormapType::Heat: + return GetHeatColor(x); + case ColormapType::Jet: + return GetJetColor(x); + case ColormapType::Turbo: + return GetTurboColor(x); + case ColormapType::Hot: + return GetHotColor(x); + case ColormapType::Gray: + return GetGrayColor(x); + case ColormapType::Magma: + return GetMagmaColor(x); + case ColormapType::Inferno: + return GetInfernoColor(x); + case ColormapType::Plasma: + return GetPlasmaColor(x); + case ColormapType::Viridis: + return GetViridisColor(x); + case ColormapType::Cividis: + return GetCividisColor(x); + case ColormapType::Github: + return GetGithubColor(x); + case ColormapType::Cubehelix: + return GetCubehelixColor(x); + default: + break; + } + + return GetViridisColor(x); + } + + inline Color GetQuantizedColor(double x, unsigned int num_levels, ColormapType type) + { + return GetColor(internal::QuantizeArgument(x, num_levels), type); + } + + inline Color GetParulaColor(double x) + { + constexpr Color data[] = + { + { 0.2081, 0.1663, 0.5292 }, + { 0.2091, 0.1721, 0.5411 }, + { 0.2101, 0.1779, 0.553 }, + { 0.2109, 0.1837, 0.565 }, + { 0.2116, 0.1895, 0.5771 }, + { 0.2121, 0.1954, 0.5892 }, + { 0.2124, 0.2013, 0.6013 }, + { 0.2125, 0.2072, 0.6135 }, + { 0.2123, 0.2132, 0.6258 }, + { 0.2118, 0.2192, 0.6381 }, + { 0.2111, 0.2253, 0.6505 }, + { 0.2099, 0.2315, 0.6629 }, + { 0.2084, 0.2377, 0.6753 }, + { 0.2063, 0.244, 0.6878 }, + { 0.2038, 0.2503, 0.7003 }, + { 0.2006, 0.2568, 0.7129 }, + { 0.1968, 0.2632, 0.7255 }, + { 0.1921, 0.2698, 0.7381 }, + { 0.1867, 0.2764, 0.7507 }, + { 0.1802, 0.2832, 0.7634 }, + { 0.1728, 0.2902, 0.7762 }, + { 0.1641, 0.2975, 0.789 }, + { 0.1541, 0.3052, 0.8017 }, + { 0.1427, 0.3132, 0.8145 }, + { 0.1295, 0.3217, 0.8269 }, + { 0.1147, 0.3306, 0.8387 }, + { 0.0986, 0.3397, 0.8495 }, + { 0.0816, 0.3486, 0.8588 }, + { 0.0646, 0.3572, 0.8664 }, + { 0.0482, 0.3651, 0.8722 }, + { 0.0329, 0.3724, 0.8765 }, + { 0.0213, 0.3792, 0.8796 }, + { 0.0136, 0.3853, 0.8815 }, + { 0.0086, 0.3911, 0.8827 }, + { 0.006, 0.3965, 0.8833 }, + { 0.0051, 0.4017, 0.8834 }, + { 0.0054, 0.4066, 0.8831 }, + { 0.0067, 0.4113, 0.8825 }, + { 0.0089, 0.4159, 0.8816 }, + { 0.0116, 0.4203, 0.8805 }, + { 0.0148, 0.4246, 0.8793 }, + { 0.0184, 0.4288, 0.8779 }, + { 0.0223, 0.4329, 0.8763 }, + { 0.0264, 0.437, 0.8747 }, + { 0.0306, 0.441, 0.8729 }, + { 0.0349, 0.4449, 0.8711 }, + { 0.0394, 0.4488, 0.8692 }, + { 0.0437, 0.4526, 0.8672 }, + { 0.0477, 0.4564, 0.8652 }, + { 0.0514, 0.4602, 0.8632 }, + { 0.0549, 0.464, 0.8611 }, + { 0.0582, 0.4677, 0.8589 }, + { 0.0612, 0.4714, 0.8568 }, + { 0.064, 0.4751, 0.8546 }, + { 0.0666, 0.4788, 0.8525 }, + { 0.0689, 0.4825, 0.8503 }, + { 0.071, 0.4862, 0.8481 }, + { 0.0729, 0.4899, 0.846 }, + { 0.0746, 0.4937, 0.8439 }, + { 0.0761, 0.4974, 0.8418 }, + { 0.0773, 0.5012, 0.8398 }, + { 0.0782, 0.5051, 0.8378 }, + { 0.0789, 0.5089, 0.8359 }, + { 0.0794, 0.5129, 0.8341 }, + { 0.0795, 0.5169, 0.8324 }, + { 0.0793, 0.521, 0.8308 }, + { 0.0788, 0.5251, 0.8293 }, + { 0.0778, 0.5295, 0.828 }, + { 0.0764, 0.5339, 0.827 }, + { 0.0746, 0.5384, 0.8261 }, + { 0.0724, 0.5431, 0.8253 }, + { 0.0698, 0.5479, 0.8247 }, + { 0.0668, 0.5527, 0.8243 }, + { 0.0636, 0.5577, 0.8239 }, + { 0.06, 0.5627, 0.8237 }, + { 0.0562, 0.5677, 0.8234 }, + { 0.0523, 0.5727, 0.8231 }, + { 0.0484, 0.5777, 0.8228 }, + { 0.0445, 0.5826, 0.8223 }, + { 0.0408, 0.5874, 0.8217 }, + { 0.0372, 0.5922, 0.8209 }, + { 0.0342, 0.5968, 0.8198 }, + { 0.0317, 0.6012, 0.8186 }, + { 0.0296, 0.6055, 0.8171 }, + { 0.0279, 0.6097, 0.8154 }, + { 0.0265, 0.6137, 0.8135 }, + { 0.0255, 0.6176, 0.8114 }, + { 0.0248, 0.6214, 0.8091 }, + { 0.0243, 0.625, 0.8066 }, + { 0.0239, 0.6285, 0.8039 }, + { 0.0237, 0.6319, 0.801 }, + { 0.0235, 0.6352, 0.798 }, + { 0.0233, 0.6384, 0.7948 }, + { 0.0231, 0.6415, 0.7916 }, + { 0.023, 0.6445, 0.7881 }, + { 0.0229, 0.6474, 0.7846 }, + { 0.0227, 0.6503, 0.781, }, + { 0.0227, 0.6531, 0.7773 }, + { 0.0232, 0.6558, 0.7735 }, + { 0.0238, 0.6585, 0.7696 }, + { 0.0246, 0.6611, 0.7656 }, + { 0.0263, 0.6637, 0.7615 }, + { 0.0282, 0.6663, 0.7574 }, + { 0.0306, 0.6688, 0.7532 }, + { 0.0338, 0.6712, 0.749 }, + { 0.0373, 0.6737, 0.7446 }, + { 0.0418, 0.6761, 0.7402 }, + { 0.0467, 0.6784, 0.7358 }, + { 0.0516, 0.6808, 0.7313 }, + { 0.0574, 0.6831, 0.7267 }, + { 0.0629, 0.6854, 0.7221 }, + { 0.0692, 0.6877, 0.7173 }, + { 0.0755, 0.6899, 0.7126 }, + { 0.082, 0.6921, 0.7078 }, + { 0.0889, 0.6943, 0.7029 }, + { 0.0956, 0.6965, 0.6979 }, + { 0.1031, 0.6986, 0.6929 }, + { 0.1104, 0.7007, 0.6878 }, + { 0.118, 0.7028, 0.6827 }, + { 0.1258, 0.7049, 0.6775 }, + { 0.1335, 0.7069, 0.6723 }, + { 0.1418, 0.7089, 0.6669 }, + { 0.1499, 0.7109, 0.6616 }, + { 0.1585, 0.7129, 0.6561 }, + { 0.1671, 0.7148, 0.6507 }, + { 0.1758, 0.7168, 0.6451 }, + { 0.1849, 0.7186, 0.6395 }, + { 0.1938, 0.7205, 0.6338 }, + { 0.2033, 0.7223, 0.6281 }, + { 0.2128, 0.7241, 0.6223 }, + { 0.2224, 0.7259, 0.6165 }, + { 0.2324, 0.7275, 0.6107 }, + { 0.2423, 0.7292, 0.6048 }, + { 0.2527, 0.7308, 0.5988 }, + { 0.2631, 0.7324, 0.5929 }, + { 0.2735, 0.7339, 0.5869 }, + { 0.2845, 0.7354, 0.5809 }, + { 0.2953, 0.7368, 0.5749 }, + { 0.3064, 0.7381, 0.5689 }, + { 0.3177, 0.7394, 0.563 }, + { 0.3289, 0.7406, 0.557 }, + { 0.3405, 0.7417, 0.5512 }, + { 0.352, 0.7428, 0.5453 }, + { 0.3635, 0.7438, 0.5396 }, + { 0.3753, 0.7446, 0.5339 }, + { 0.3869, 0.7454, 0.5283 }, + { 0.3986, 0.7461, 0.5229 }, + { 0.4103, 0.7467, 0.5175 }, + { 0.4218, 0.7473, 0.5123 }, + { 0.4334, 0.7477, 0.5072 }, + { 0.4447, 0.7482, 0.5021 }, + { 0.4561, 0.7485, 0.4972 }, + { 0.4672, 0.7487, 0.4924 }, + { 0.4783, 0.7489, 0.4877 }, + { 0.4892, 0.7491, 0.4831 }, + { 0.5, 0.7491, 0.4786 }, + { 0.5106, 0.7492, 0.4741 }, + { 0.5212, 0.7492, 0.4698 }, + { 0.5315, 0.7491, 0.4655 }, + { 0.5418, 0.749, 0.4613 }, + { 0.5519, 0.7489, 0.4571 }, + { 0.5619, 0.7487, 0.4531 }, + { 0.5718, 0.7485, 0.449 }, + { 0.5816, 0.7482, 0.4451 }, + { 0.5913, 0.7479, 0.4412 }, + { 0.6009, 0.7476, 0.4374 }, + { 0.6103, 0.7473, 0.4335 }, + { 0.6197, 0.7469, 0.4298 }, + { 0.629, 0.7465, 0.4261 }, + { 0.6382, 0.746, 0.4224 }, + { 0.6473, 0.7456, 0.4188 }, + { 0.6564, 0.7451, 0.4152 }, + { 0.6653, 0.7446, 0.4116 }, + { 0.6742, 0.7441, 0.4081 }, + { 0.683, 0.7435, 0.4046 }, + { 0.6918, 0.743, 0.4011 }, + { 0.7004, 0.7424, 0.3976 }, + { 0.7091, 0.7418, 0.3942 }, + { 0.7176, 0.7412, 0.3908 }, + { 0.7261, 0.7405, 0.3874 }, + { 0.7346, 0.7399, 0.384 }, + { 0.743, 0.7392, 0.3806 }, + { 0.7513, 0.7385, 0.3773 }, + { 0.7596, 0.7378, 0.3739 }, + { 0.7679, 0.7372, 0.3706 }, + { 0.7761, 0.7364, 0.3673 }, + { 0.7843, 0.7357, 0.3639 }, + { 0.7924, 0.735, 0.3606 }, + { 0.8005, 0.7343, 0.3573 }, + { 0.8085, 0.7336, 0.3539 }, + { 0.8166, 0.7329, 0.3506 }, + { 0.8246, 0.7322, 0.3472 }, + { 0.8325, 0.7315, 0.3438 }, + { 0.8405, 0.7308, 0.3404 }, + { 0.8484, 0.7301, 0.337 }, + { 0.8563, 0.7294, 0.3336 }, + { 0.8642, 0.7288, 0.33 }, + { 0.872, 0.7282, 0.3265 }, + { 0.8798, 0.7276, 0.3229 }, + { 0.8877, 0.7271, 0.3193 }, + { 0.8954, 0.7266, 0.3156 }, + { 0.9032, 0.7262, 0.3117 }, + { 0.911, 0.7259, 0.3078 }, + { 0.9187, 0.7256, 0.3038 }, + { 0.9264, 0.7256, 0.2996 }, + { 0.9341, 0.7256, 0.2953 }, + { 0.9417, 0.7259, 0.2907 }, + { 0.9493, 0.7264, 0.2859 }, + { 0.9567, 0.7273, 0.2808 }, + { 0.9639, 0.7285, 0.2754 }, + { 0.9708, 0.7303, 0.2696 }, + { 0.9773, 0.7326, 0.2634 }, + { 0.9831, 0.7355, 0.257 }, + { 0.9882, 0.739, 0.2504 }, + { 0.9922, 0.7431, 0.2437 }, + { 0.9952, 0.7476, 0.2373 }, + { 0.9973, 0.7524, 0.231 }, + { 0.9986, 0.7573, 0.2251 }, + { 0.9991, 0.7624, 0.2195 }, + { 0.999, 0.7675, 0.2141 }, + { 0.9985, 0.7726, 0.209 }, + { 0.9976, 0.7778, 0.2042 }, + { 0.9964, 0.7829, 0.1995 }, + { 0.995, 0.788, 0.1949 }, + { 0.9933, 0.7931, 0.1905 }, + { 0.9914, 0.7981, 0.1863 }, + { 0.9894, 0.8032, 0.1821 }, + { 0.9873, 0.8083, 0.178 }, + { 0.9851, 0.8133, 0.174 }, + { 0.9828, 0.8184, 0.17 }, + { 0.9805, 0.8235, 0.1661 }, + { 0.9782, 0.8286, 0.1622 }, + { 0.9759, 0.8337, 0.1583 }, + { 0.9736, 0.8389, 0.1544 }, + { 0.9713, 0.8441, 0.1505 }, + { 0.9692, 0.8494, 0.1465 }, + { 0.9672, 0.8548, 0.1425 }, + { 0.9654, 0.8603, 0.1385 }, + { 0.9638, 0.8659, 0.1343 }, + { 0.9623, 0.8716, 0.1301 }, + { 0.9611, 0.8774, 0.1258 }, + { 0.96, 0.8834, 0.1215 }, + { 0.9593, 0.8895, 0.1171 }, + { 0.9588, 0.8958, 0.1126 }, + { 0.9586, 0.9022, 0.1082 }, + { 0.9587, 0.9088, 0.1036 }, + { 0.9591, 0.9155, 0.099 }, + { 0.9599, 0.9225, 0.0944 }, + { 0.961, 0.9296, 0.0897 }, + { 0.9624, 0.9368, 0.085 }, + { 0.9641, 0.9443, 0.0802 }, + { 0.9662, 0.9518, 0.0753 }, + { 0.9685, 0.9595, 0.0703 }, + { 0.971, 0.9673, 0.0651 }, + { 0.9736, 0.9752, 0.0597 }, + { 0.9763, 0.9831, 0.0538 } + }; + + return internal::CalcLerp(x, data); + } + + inline Color GetHeatColor(double x) + { + constexpr Color data[] = + { + { 0.0, 0.0, 1.0 }, + { 0.0, 1.0, 1.0 }, + { 0.0, 1.0, 0.0 }, + { 1.0, 1.0, 0.0 }, + { 1.0, 0.0, 0.0 } + }; + + return internal::CalcLerp(x, data); + } + + inline Color GetJetColor(double x) + { + constexpr Color data[] = + { + { 0.0, 0.0, 0.5 }, + { 0.0, 0.0, 1.0 }, + { 0.0, 0.5, 1.0 }, + { 0.0, 1.0, 1.0 }, + { 0.5, 1.0, 0.5 }, + { 1.0, 1.0, 0.0 }, + { 1.0, 0.5, 0.0 }, + { 1.0, 0.0, 0.0 }, + { 0.5, 0.0, 0.0 } + }; + + return internal::CalcLerp(x, data); + } + + inline Color GetTurboColor(double x) + { + constexpr Color data[] = + { + { 0.18995, 0.07176, 0.23217 }, + { 0.19483, 0.08339, 0.26149 }, + { 0.19956, 0.09498, 0.29024 }, + { 0.20415, 0.10652, 0.31844 }, + { 0.20860, 0.11802, 0.34607 }, + { 0.21291, 0.12947, 0.37314 }, + { 0.21708, 0.14087, 0.39964 }, + { 0.22111, 0.15223, 0.42558 }, + { 0.22500, 0.16354, 0.45096 }, + { 0.22875, 0.17481, 0.47578 }, + { 0.23236, 0.18603, 0.50004 }, + { 0.23582, 0.19720, 0.52373 }, + { 0.23915, 0.20833, 0.54686 }, + { 0.24234, 0.21941, 0.56942 }, + { 0.24539, 0.23044, 0.59142 }, + { 0.24830, 0.24143, 0.61286 }, + { 0.25107, 0.25237, 0.63374 }, + { 0.25369, 0.26327, 0.65406 }, + { 0.25618, 0.27412, 0.67381 }, + { 0.25853, 0.28492, 0.69300 }, + { 0.26074, 0.29568, 0.71162 }, + { 0.26280, 0.30639, 0.72968 }, + { 0.26473, 0.31706, 0.74718 }, + { 0.26652, 0.32768, 0.76412 }, + { 0.26816, 0.33825, 0.78050 }, + { 0.26967, 0.34878, 0.79631 }, + { 0.27103, 0.35926, 0.81156 }, + { 0.27226, 0.36970, 0.82624 }, + { 0.27334, 0.38008, 0.84037 }, + { 0.27429, 0.39043, 0.85393 }, + { 0.27509, 0.40072, 0.86692 }, + { 0.27576, 0.41097, 0.87936 }, + { 0.27628, 0.42118, 0.89123 }, + { 0.27667, 0.43134, 0.90254 }, + { 0.27691, 0.44145, 0.91328 }, + { 0.27701, 0.45152, 0.92347 }, + { 0.27698, 0.46153, 0.93309 }, + { 0.27680, 0.47151, 0.94214 }, + { 0.27648, 0.48144, 0.95064 }, + { 0.27603, 0.49132, 0.95857 }, + { 0.27543, 0.50115, 0.96594 }, + { 0.27469, 0.51094, 0.97275 }, + { 0.27381, 0.52069, 0.97899 }, + { 0.27273, 0.53040, 0.98461 }, + { 0.27106, 0.54015, 0.98930 }, + { 0.26878, 0.54995, 0.99303 }, + { 0.26592, 0.55979, 0.99583 }, + { 0.26252, 0.56967, 0.99773 }, + { 0.25862, 0.57958, 0.99876 }, + { 0.25425, 0.58950, 0.99896 }, + { 0.24946, 0.59943, 0.99835 }, + { 0.24427, 0.60937, 0.99697 }, + { 0.23874, 0.61931, 0.99485 }, + { 0.23288, 0.62923, 0.99202 }, + { 0.22676, 0.63913, 0.98851 }, + { 0.22039, 0.64901, 0.98436 }, + { 0.21382, 0.65886, 0.97959 }, + { 0.20708, 0.66866, 0.97423 }, + { 0.20021, 0.67842, 0.96833 }, + { 0.19326, 0.68812, 0.96190 }, + { 0.18625, 0.69775, 0.95498 }, + { 0.17923, 0.70732, 0.94761 }, + { 0.17223, 0.71680, 0.93981 }, + { 0.16529, 0.72620, 0.93161 }, + { 0.15844, 0.73551, 0.92305 }, + { 0.15173, 0.74472, 0.91416 }, + { 0.14519, 0.75381, 0.90496 }, + { 0.13886, 0.76279, 0.89550 }, + { 0.13278, 0.77165, 0.88580 }, + { 0.12698, 0.78037, 0.87590 }, + { 0.12151, 0.78896, 0.86581 }, + { 0.11639, 0.79740, 0.85559 }, + { 0.11167, 0.80569, 0.84525 }, + { 0.10738, 0.81381, 0.83484 }, + { 0.10357, 0.82177, 0.82437 }, + { 0.10026, 0.82955, 0.81389 }, + { 0.09750, 0.83714, 0.80342 }, + { 0.09532, 0.84455, 0.79299 }, + { 0.09377, 0.85175, 0.78264 }, + { 0.09287, 0.85875, 0.77240 }, + { 0.09267, 0.86554, 0.76230 }, + { 0.09320, 0.87211, 0.75237 }, + { 0.09451, 0.87844, 0.74265 }, + { 0.09662, 0.88454, 0.73316 }, + { 0.09958, 0.89040, 0.72393 }, + { 0.10342, 0.89600, 0.71500 }, + { 0.10815, 0.90142, 0.70599 }, + { 0.11374, 0.90673, 0.69651 }, + { 0.12014, 0.91193, 0.68660 }, + { 0.12733, 0.91701, 0.67627 }, + { 0.13526, 0.92197, 0.66556 }, + { 0.14391, 0.92680, 0.65448 }, + { 0.15323, 0.93151, 0.64308 }, + { 0.16319, 0.93609, 0.63137 }, + { 0.17377, 0.94053, 0.61938 }, + { 0.18491, 0.94484, 0.60713 }, + { 0.19659, 0.94901, 0.59466 }, + { 0.20877, 0.95304, 0.58199 }, + { 0.22142, 0.95692, 0.56914 }, + { 0.23449, 0.96065, 0.55614 }, + { 0.24797, 0.96423, 0.54303 }, + { 0.26180, 0.96765, 0.52981 }, + { 0.27597, 0.97092, 0.51653 }, + { 0.29042, 0.97403, 0.50321 }, + { 0.30513, 0.97697, 0.48987 }, + { 0.32006, 0.97974, 0.47654 }, + { 0.33517, 0.98234, 0.46325 }, + { 0.35043, 0.98477, 0.45002 }, + { 0.36581, 0.98702, 0.43688 }, + { 0.38127, 0.98909, 0.42386 }, + { 0.39678, 0.99098, 0.41098 }, + { 0.41229, 0.99268, 0.39826 }, + { 0.42778, 0.99419, 0.38575 }, + { 0.44321, 0.99551, 0.37345 }, + { 0.45854, 0.99663, 0.36140 }, + { 0.47375, 0.99755, 0.34963 }, + { 0.48879, 0.99828, 0.33816 }, + { 0.50362, 0.99879, 0.32701 }, + { 0.51822, 0.99910, 0.31622 }, + { 0.53255, 0.99919, 0.30581 }, + { 0.54658, 0.99907, 0.29581 }, + { 0.56026, 0.99873, 0.28623 }, + { 0.57357, 0.99817, 0.27712 }, + { 0.58646, 0.99739, 0.26849 }, + { 0.59891, 0.99638, 0.26038 }, + { 0.61088, 0.99514, 0.25280 }, + { 0.62233, 0.99366, 0.24579 }, + { 0.63323, 0.99195, 0.23937 }, + { 0.64362, 0.98999, 0.23356 }, + { 0.65394, 0.98775, 0.22835 }, + { 0.66428, 0.98524, 0.22370 }, + { 0.67462, 0.98246, 0.21960 }, + { 0.68494, 0.97941, 0.21602 }, + { 0.69525, 0.97610, 0.21294 }, + { 0.70553, 0.97255, 0.21032 }, + { 0.71577, 0.96875, 0.20815 }, + { 0.72596, 0.96470, 0.20640 }, + { 0.73610, 0.96043, 0.20504 }, + { 0.74617, 0.95593, 0.20406 }, + { 0.75617, 0.95121, 0.20343 }, + { 0.76608, 0.94627, 0.20311 }, + { 0.77591, 0.94113, 0.20310 }, + { 0.78563, 0.93579, 0.20336 }, + { 0.79524, 0.93025, 0.20386 }, + { 0.80473, 0.92452, 0.20459 }, + { 0.81410, 0.91861, 0.20552 }, + { 0.82333, 0.91253, 0.20663 }, + { 0.83241, 0.90627, 0.20788 }, + { 0.84133, 0.89986, 0.20926 }, + { 0.85010, 0.89328, 0.21074 }, + { 0.85868, 0.88655, 0.21230 }, + { 0.86709, 0.87968, 0.21391 }, + { 0.87530, 0.87267, 0.21555 }, + { 0.88331, 0.86553, 0.21719 }, + { 0.89112, 0.85826, 0.21880 }, + { 0.89870, 0.85087, 0.22038 }, + { 0.90605, 0.84337, 0.22188 }, + { 0.91317, 0.83576, 0.22328 }, + { 0.92004, 0.82806, 0.22456 }, + { 0.92666, 0.82025, 0.22570 }, + { 0.93301, 0.81236, 0.22667 }, + { 0.93909, 0.80439, 0.22744 }, + { 0.94489, 0.79634, 0.22800 }, + { 0.95039, 0.78823, 0.22831 }, + { 0.95560, 0.78005, 0.22836 }, + { 0.96049, 0.77181, 0.22811 }, + { 0.96507, 0.76352, 0.22754 }, + { 0.96931, 0.75519, 0.22663 }, + { 0.97323, 0.74682, 0.22536 }, + { 0.97679, 0.73842, 0.22369 }, + { 0.98000, 0.73000, 0.22161 }, + { 0.98289, 0.72140, 0.21918 }, + { 0.98549, 0.71250, 0.21650 }, + { 0.98781, 0.70330, 0.21358 }, + { 0.98986, 0.69382, 0.21043 }, + { 0.99163, 0.68408, 0.20706 }, + { 0.99314, 0.67408, 0.20348 }, + { 0.99438, 0.66386, 0.19971 }, + { 0.99535, 0.65341, 0.19577 }, + { 0.99607, 0.64277, 0.19165 }, + { 0.99654, 0.63193, 0.18738 }, + { 0.99675, 0.62093, 0.18297 }, + { 0.99672, 0.60977, 0.17842 }, + { 0.99644, 0.59846, 0.17376 }, + { 0.99593, 0.58703, 0.16899 }, + { 0.99517, 0.57549, 0.16412 }, + { 0.99419, 0.56386, 0.15918 }, + { 0.99297, 0.55214, 0.15417 }, + { 0.99153, 0.54036, 0.14910 }, + { 0.98987, 0.52854, 0.14398 }, + { 0.98799, 0.51667, 0.13883 }, + { 0.98590, 0.50479, 0.13367 }, + { 0.98360, 0.49291, 0.12849 }, + { 0.98108, 0.48104, 0.12332 }, + { 0.97837, 0.46920, 0.11817 }, + { 0.97545, 0.45740, 0.11305 }, + { 0.97234, 0.44565, 0.10797 }, + { 0.96904, 0.43399, 0.10294 }, + { 0.96555, 0.42241, 0.09798 }, + { 0.96187, 0.41093, 0.09310 }, + { 0.95801, 0.39958, 0.08831 }, + { 0.95398, 0.38836, 0.08362 }, + { 0.94977, 0.37729, 0.07905 }, + { 0.94538, 0.36638, 0.07461 }, + { 0.94084, 0.35566, 0.07031 }, + { 0.93612, 0.34513, 0.06616 }, + { 0.93125, 0.33482, 0.06218 }, + { 0.92623, 0.32473, 0.05837 }, + { 0.92105, 0.31489, 0.05475 }, + { 0.91572, 0.30530, 0.05134 }, + { 0.91024, 0.29599, 0.04814 }, + { 0.90463, 0.28696, 0.04516 }, + { 0.89888, 0.27824, 0.04243 }, + { 0.89298, 0.26981, 0.03993 }, + { 0.88691, 0.26152, 0.03753 }, + { 0.88066, 0.25334, 0.03521 }, + { 0.87422, 0.24526, 0.03297 }, + { 0.86760, 0.23730, 0.03082 }, + { 0.86079, 0.22945, 0.02875 }, + { 0.85380, 0.22170, 0.02677 }, + { 0.84662, 0.21407, 0.02487 }, + { 0.83926, 0.20654, 0.02305 }, + { 0.83172, 0.19912, 0.02131 }, + { 0.82399, 0.19182, 0.01966 }, + { 0.81608, 0.18462, 0.01809 }, + { 0.80799, 0.17753, 0.01660 }, + { 0.79971, 0.17055, 0.01520 }, + { 0.79125, 0.16368, 0.01387 }, + { 0.78260, 0.15693, 0.01264 }, + { 0.77377, 0.15028, 0.01148 }, + { 0.76476, 0.14374, 0.01041 }, + { 0.75556, 0.13731, 0.00942 }, + { 0.74617, 0.13098, 0.00851 }, + { 0.73661, 0.12477, 0.00769 }, + { 0.72686, 0.11867, 0.00695 }, + { 0.71692, 0.11268, 0.00629 }, + { 0.70680, 0.10680, 0.00571 }, + { 0.69650, 0.10102, 0.00522 }, + { 0.68602, 0.09536, 0.00481 }, + { 0.67535, 0.08980, 0.00449 }, + { 0.66449, 0.08436, 0.00424 }, + { 0.65345, 0.07902, 0.00408 }, + { 0.64223, 0.07380, 0.00401 }, + { 0.63082, 0.06868, 0.00401 }, + { 0.61923, 0.06367, 0.00410 }, + { 0.60746, 0.05878, 0.00427 }, + { 0.59550, 0.05399, 0.00453 }, + { 0.58336, 0.04931, 0.00486 }, + { 0.57103, 0.04474, 0.00529 }, + { 0.55852, 0.04028, 0.00579 }, + { 0.54583, 0.03593, 0.00638 }, + { 0.53295, 0.03169, 0.00705 }, + { 0.51989, 0.02756, 0.00780 }, + { 0.50664, 0.02354, 0.00863 }, + { 0.49321, 0.01963, 0.00955 }, + { 0.47960, 0.01583, 0.01055 } + }; + + return internal::CalcLerp(x, data); + } + + inline Color GetHotColor(double x) + { + x = internal::Clamp01(x); + + constexpr Color r{ 1.0, 0.0, 0.0 }; + constexpr Color g{ 0.0, 1.0, 0.0 }; + constexpr Color b{ 0.0, 0.0, 1.0 }; + + if (x < 0.4) + { + const double t = x / 0.4; + return t * r; + } + else if (x < 0.8) + { + const double t = (x - 0.4) / (0.8 - 0.4); + return r + t * g; + } + else + { + const double t = (x - 0.8) / (1.0 - 0.8); + return r + g + t * b; + } + } + + inline constexpr Color GetGrayColor(double x) noexcept + { + return Color{ 1.0 - internal::Clamp01(x) }; + } + + inline Color GetMagmaColor(double x) + { + constexpr Color data[] = + { + { 0.001462, 0.000466, 0.013866 }, + { 0.002258, 0.001295, 0.018331 }, + { 0.003279, 0.002305, 0.023708 }, + { 0.004512, 0.003490, 0.029965 }, + { 0.005950, 0.004843, 0.037130 }, + { 0.007588, 0.006356, 0.044973 }, + { 0.009426, 0.008022, 0.052844 }, + { 0.011465, 0.009828, 0.060750 }, + { 0.013708, 0.011771, 0.068667 }, + { 0.016156, 0.013840, 0.076603 }, + { 0.018815, 0.016026, 0.084584 }, + { 0.021692, 0.018320, 0.092610 }, + { 0.024792, 0.020715, 0.100676 }, + { 0.028123, 0.023201, 0.108787 }, + { 0.031696, 0.025765, 0.116965 }, + { 0.035520, 0.028397, 0.125209 }, + { 0.039608, 0.031090, 0.133515 }, + { 0.043830, 0.033830, 0.141886 }, + { 0.048062, 0.036607, 0.150327 }, + { 0.052320, 0.039407, 0.158841 }, + { 0.056615, 0.042160, 0.167446 }, + { 0.060949, 0.044794, 0.176129 }, + { 0.065330, 0.047318, 0.184892 }, + { 0.069764, 0.049726, 0.193735 }, + { 0.074257, 0.052017, 0.202660 }, + { 0.078815, 0.054184, 0.211667 }, + { 0.083446, 0.056225, 0.220755 }, + { 0.088155, 0.058133, 0.229922 }, + { 0.092949, 0.059904, 0.239164 }, + { 0.097833, 0.061531, 0.248477 }, + { 0.102815, 0.063010, 0.257854 }, + { 0.107899, 0.064335, 0.267289 }, + { 0.113094, 0.065492, 0.276784 }, + { 0.118405, 0.066479, 0.286321 }, + { 0.123833, 0.067295, 0.295879 }, + { 0.129380, 0.067935, 0.305443 }, + { 0.135053, 0.068391, 0.315000 }, + { 0.140858, 0.068654, 0.324538 }, + { 0.146785, 0.068738, 0.334011 }, + { 0.152839, 0.068637, 0.343404 }, + { 0.159018, 0.068354, 0.352688 }, + { 0.165308, 0.067911, 0.361816 }, + { 0.171713, 0.067305, 0.370771 }, + { 0.178212, 0.066576, 0.379497 }, + { 0.184801, 0.065732, 0.387973 }, + { 0.191460, 0.064818, 0.396152 }, + { 0.198177, 0.063862, 0.404009 }, + { 0.204935, 0.062907, 0.411514 }, + { 0.211718, 0.061992, 0.418647 }, + { 0.218512, 0.061158, 0.425392 }, + { 0.225302, 0.060445, 0.431742 }, + { 0.232077, 0.059889, 0.437695 }, + { 0.238826, 0.059517, 0.443256 }, + { 0.245543, 0.059352, 0.448436 }, + { 0.252220, 0.059415, 0.453248 }, + { 0.258857, 0.059706, 0.457710 }, + { 0.265447, 0.060237, 0.461840 }, + { 0.271994, 0.060994, 0.465660 }, + { 0.278493, 0.061978, 0.469190 }, + { 0.284951, 0.063168, 0.472451 }, + { 0.291366, 0.064553, 0.475462 }, + { 0.297740, 0.066117, 0.478243 }, + { 0.304081, 0.067835, 0.480812 }, + { 0.310382, 0.069702, 0.483186 }, + { 0.316654, 0.071690, 0.485380 }, + { 0.322899, 0.073782, 0.487408 }, + { 0.329114, 0.075972, 0.489287 }, + { 0.335308, 0.078236, 0.491024 }, + { 0.341482, 0.080564, 0.492631 }, + { 0.347636, 0.082946, 0.494121 }, + { 0.353773, 0.085373, 0.495501 }, + { 0.359898, 0.087831, 0.496778 }, + { 0.366012, 0.090314, 0.497960 }, + { 0.372116, 0.092816, 0.499053 }, + { 0.378211, 0.095332, 0.500067 }, + { 0.384299, 0.097855, 0.501002 }, + { 0.390384, 0.100379, 0.501864 }, + { 0.396467, 0.102902, 0.502658 }, + { 0.402548, 0.105420, 0.503386 }, + { 0.408629, 0.107930, 0.504052 }, + { 0.414709, 0.110431, 0.504662 }, + { 0.420791, 0.112920, 0.505215 }, + { 0.426877, 0.115395, 0.505714 }, + { 0.432967, 0.117855, 0.506160 }, + { 0.439062, 0.120298, 0.506555 }, + { 0.445163, 0.122724, 0.506901 }, + { 0.451271, 0.125132, 0.507198 }, + { 0.457386, 0.127522, 0.507448 }, + { 0.463508, 0.129893, 0.507652 }, + { 0.469640, 0.132245, 0.507809 }, + { 0.475780, 0.134577, 0.507921 }, + { 0.481929, 0.136891, 0.507989 }, + { 0.488088, 0.139186, 0.508011 }, + { 0.494258, 0.141462, 0.507988 }, + { 0.500438, 0.143719, 0.507920 }, + { 0.506629, 0.145958, 0.507806 }, + { 0.512831, 0.148179, 0.507648 }, + { 0.519045, 0.150383, 0.507443 }, + { 0.525270, 0.152569, 0.507192 }, + { 0.531507, 0.154739, 0.506895 }, + { 0.537755, 0.156894, 0.506551 }, + { 0.544015, 0.159033, 0.506159 }, + { 0.550287, 0.161158, 0.505719 }, + { 0.556571, 0.163269, 0.505230 }, + { 0.562866, 0.165368, 0.504692 }, + { 0.569172, 0.167454, 0.504105 }, + { 0.575490, 0.169530, 0.503466 }, + { 0.581819, 0.171596, 0.502777 }, + { 0.588158, 0.173652, 0.502035 }, + { 0.594508, 0.175701, 0.501241 }, + { 0.600868, 0.177743, 0.500394 }, + { 0.607238, 0.179779, 0.499492 }, + { 0.613617, 0.181811, 0.498536 }, + { 0.620005, 0.183840, 0.497524 }, + { 0.626401, 0.185867, 0.496456 }, + { 0.632805, 0.187893, 0.495332 }, + { 0.639216, 0.189921, 0.494150 }, + { 0.645633, 0.191952, 0.492910 }, + { 0.652056, 0.193986, 0.491611 }, + { 0.658483, 0.196027, 0.490253 }, + { 0.664915, 0.198075, 0.488836 }, + { 0.671349, 0.200133, 0.487358 }, + { 0.677786, 0.202203, 0.485819 }, + { 0.684224, 0.204286, 0.484219 }, + { 0.690661, 0.206384, 0.482558 }, + { 0.697098, 0.208501, 0.480835 }, + { 0.703532, 0.210638, 0.479049 }, + { 0.709962, 0.212797, 0.477201 }, + { 0.716387, 0.214982, 0.475290 }, + { 0.722805, 0.217194, 0.473316 }, + { 0.729216, 0.219437, 0.471279 }, + { 0.735616, 0.221713, 0.469180 }, + { 0.742004, 0.224025, 0.467018 }, + { 0.748378, 0.226377, 0.464794 }, + { 0.754737, 0.228772, 0.462509 }, + { 0.761077, 0.231214, 0.460162 }, + { 0.767398, 0.233705, 0.457755 }, + { 0.773695, 0.236249, 0.455289 }, + { 0.779968, 0.238851, 0.452765 }, + { 0.786212, 0.241514, 0.450184 }, + { 0.792427, 0.244242, 0.447543 }, + { 0.798608, 0.247040, 0.444848 }, + { 0.804752, 0.249911, 0.442102 }, + { 0.810855, 0.252861, 0.439305 }, + { 0.816914, 0.255895, 0.436461 }, + { 0.822926, 0.259016, 0.433573 }, + { 0.828886, 0.262229, 0.430644 }, + { 0.834791, 0.265540, 0.427671 }, + { 0.840636, 0.268953, 0.424666 }, + { 0.846416, 0.272473, 0.421631 }, + { 0.852126, 0.276106, 0.418573 }, + { 0.857763, 0.279857, 0.415496 }, + { 0.863320, 0.283729, 0.412403 }, + { 0.868793, 0.287728, 0.409303 }, + { 0.874176, 0.291859, 0.406205 }, + { 0.879464, 0.296125, 0.403118 }, + { 0.884651, 0.300530, 0.400047 }, + { 0.889731, 0.305079, 0.397002 }, + { 0.894700, 0.309773, 0.393995 }, + { 0.899552, 0.314616, 0.391037 }, + { 0.904281, 0.319610, 0.388137 }, + { 0.908884, 0.324755, 0.385308 }, + { 0.913354, 0.330052, 0.382563 }, + { 0.917689, 0.335500, 0.379915 }, + { 0.921884, 0.341098, 0.377376 }, + { 0.925937, 0.346844, 0.374959 }, + { 0.929845, 0.352734, 0.372677 }, + { 0.933606, 0.358764, 0.370541 }, + { 0.937221, 0.364929, 0.368567 }, + { 0.940687, 0.371224, 0.366762 }, + { 0.944006, 0.377643, 0.365136 }, + { 0.947180, 0.384178, 0.363701 }, + { 0.950210, 0.390820, 0.362468 }, + { 0.953099, 0.397563, 0.361438 }, + { 0.955849, 0.404400, 0.360619 }, + { 0.958464, 0.411324, 0.360014 }, + { 0.960949, 0.418323, 0.359630 }, + { 0.963310, 0.425390, 0.359469 }, + { 0.965549, 0.432519, 0.359529 }, + { 0.967671, 0.439703, 0.359810 }, + { 0.969680, 0.446936, 0.360311 }, + { 0.971582, 0.454210, 0.361030 }, + { 0.973381, 0.461520, 0.361965 }, + { 0.975082, 0.468861, 0.363111 }, + { 0.976690, 0.476226, 0.364466 }, + { 0.978210, 0.483612, 0.366025 }, + { 0.979645, 0.491014, 0.367783 }, + { 0.981000, 0.498428, 0.369734 }, + { 0.982279, 0.505851, 0.371874 }, + { 0.983485, 0.513280, 0.374198 }, + { 0.984622, 0.520713, 0.376698 }, + { 0.985693, 0.528148, 0.379371 }, + { 0.986700, 0.535582, 0.382210 }, + { 0.987646, 0.543015, 0.385210 }, + { 0.988533, 0.550446, 0.388365 }, + { 0.989363, 0.557873, 0.391671 }, + { 0.990138, 0.565296, 0.395122 }, + { 0.990871, 0.572706, 0.398714 }, + { 0.991558, 0.580107, 0.402441 }, + { 0.992196, 0.587502, 0.406299 }, + { 0.992785, 0.594891, 0.410283 }, + { 0.993326, 0.602275, 0.414390 }, + { 0.993834, 0.609644, 0.418613 }, + { 0.994309, 0.616999, 0.422950 }, + { 0.994738, 0.624350, 0.427397 }, + { 0.995122, 0.631696, 0.431951 }, + { 0.995480, 0.639027, 0.436607 }, + { 0.995810, 0.646344, 0.441361 }, + { 0.996096, 0.653659, 0.446213 }, + { 0.996341, 0.660969, 0.451160 }, + { 0.996580, 0.668256, 0.456192 }, + { 0.996775, 0.675541, 0.461314 }, + { 0.996925, 0.682828, 0.466526 }, + { 0.997077, 0.690088, 0.471811 }, + { 0.997186, 0.697349, 0.477182 }, + { 0.997254, 0.704611, 0.482635 }, + { 0.997325, 0.711848, 0.488154 }, + { 0.997351, 0.719089, 0.493755 }, + { 0.997351, 0.726324, 0.499428 }, + { 0.997341, 0.733545, 0.505167 }, + { 0.997285, 0.740772, 0.510983 }, + { 0.997228, 0.747981, 0.516859 }, + { 0.997138, 0.755190, 0.522806 }, + { 0.997019, 0.762398, 0.528821 }, + { 0.996898, 0.769591, 0.534892 }, + { 0.996727, 0.776795, 0.541039 }, + { 0.996571, 0.783977, 0.547233 }, + { 0.996369, 0.791167, 0.553499 }, + { 0.996162, 0.798348, 0.559820 }, + { 0.995932, 0.805527, 0.566202 }, + { 0.995680, 0.812706, 0.572645 }, + { 0.995424, 0.819875, 0.579140 }, + { 0.995131, 0.827052, 0.585701 }, + { 0.994851, 0.834213, 0.592307 }, + { 0.994524, 0.841387, 0.598983 }, + { 0.994222, 0.848540, 0.605696 }, + { 0.993866, 0.855711, 0.612482 }, + { 0.993545, 0.862859, 0.619299 }, + { 0.993170, 0.870024, 0.626189 }, + { 0.992831, 0.877168, 0.633109 }, + { 0.992440, 0.884330, 0.640099 }, + { 0.992089, 0.891470, 0.647116 }, + { 0.991688, 0.898627, 0.654202 }, + { 0.991332, 0.905763, 0.661309 }, + { 0.990930, 0.912915, 0.668481 }, + { 0.990570, 0.920049, 0.675675 }, + { 0.990175, 0.927196, 0.682926 }, + { 0.989815, 0.934329, 0.690198 }, + { 0.989434, 0.941470, 0.697519 }, + { 0.989077, 0.948604, 0.704863 }, + { 0.988717, 0.955742, 0.712242 }, + { 0.988367, 0.962878, 0.719649 }, + { 0.988033, 0.970012, 0.727077 }, + { 0.987691, 0.977154, 0.734536 }, + { 0.987387, 0.984288, 0.742002 }, + { 0.987053, 0.991438, 0.749504 } + }; + + return internal::CalcLerp(x, data); + } + + inline Color GetInfernoColor(double x) + { + constexpr Color data[] = + { + { 0.001462, 0.000466, 0.013866 }, + { 0.002267, 0.001270, 0.018570 }, + { 0.003299, 0.002249, 0.024239 }, + { 0.004547, 0.003392, 0.030909 }, + { 0.006006, 0.004692, 0.038558 }, + { 0.007676, 0.006136, 0.046836 }, + { 0.009561, 0.007713, 0.055143 }, + { 0.011663, 0.009417, 0.063460 }, + { 0.013995, 0.011225, 0.071862 }, + { 0.016561, 0.013136, 0.080282 }, + { 0.019373, 0.015133, 0.088767 }, + { 0.022447, 0.017199, 0.097327 }, + { 0.025793, 0.019331, 0.105930 }, + { 0.029432, 0.021503, 0.114621 }, + { 0.033385, 0.023702, 0.123397 }, + { 0.037668, 0.025921, 0.132232 }, + { 0.042253, 0.028139, 0.141141 }, + { 0.046915, 0.030324, 0.150164 }, + { 0.051644, 0.032474, 0.159254 }, + { 0.056449, 0.034569, 0.168414 }, + { 0.061340, 0.036590, 0.177642 }, + { 0.066331, 0.038504, 0.186962 }, + { 0.071429, 0.040294, 0.196354 }, + { 0.076637, 0.041905, 0.205799 }, + { 0.081962, 0.043328, 0.215289 }, + { 0.087411, 0.044556, 0.224813 }, + { 0.092990, 0.045583, 0.234358 }, + { 0.098702, 0.046402, 0.243904 }, + { 0.104551, 0.047008, 0.253430 }, + { 0.110536, 0.047399, 0.262912 }, + { 0.116656, 0.047574, 0.272321 }, + { 0.122908, 0.047536, 0.281624 }, + { 0.129285, 0.047293, 0.290788 }, + { 0.135778, 0.046856, 0.299776 }, + { 0.142378, 0.046242, 0.308553 }, + { 0.149073, 0.045468, 0.317085 }, + { 0.155850, 0.044559, 0.325338 }, + { 0.162689, 0.043554, 0.333277 }, + { 0.169575, 0.042489, 0.340874 }, + { 0.176493, 0.041402, 0.348111 }, + { 0.183429, 0.040329, 0.354971 }, + { 0.190367, 0.039309, 0.361447 }, + { 0.197297, 0.038400, 0.367535 }, + { 0.204209, 0.037632, 0.373238 }, + { 0.211095, 0.037030, 0.378563 }, + { 0.217949, 0.036615, 0.383522 }, + { 0.224763, 0.036405, 0.388129 }, + { 0.231538, 0.036405, 0.392400 }, + { 0.238273, 0.036621, 0.396353 }, + { 0.244967, 0.037055, 0.400007 }, + { 0.251620, 0.037705, 0.403378 }, + { 0.258234, 0.038571, 0.406485 }, + { 0.264810, 0.039647, 0.409345 }, + { 0.271347, 0.040922, 0.411976 }, + { 0.277850, 0.042353, 0.414392 }, + { 0.284321, 0.043933, 0.416608 }, + { 0.290763, 0.045644, 0.418637 }, + { 0.297178, 0.047470, 0.420491 }, + { 0.303568, 0.049396, 0.422182 }, + { 0.309935, 0.051407, 0.423721 }, + { 0.316282, 0.053490, 0.425116 }, + { 0.322610, 0.055634, 0.426377 }, + { 0.328921, 0.057827, 0.427511 }, + { 0.335217, 0.060060, 0.428524 }, + { 0.341500, 0.062325, 0.429425 }, + { 0.347771, 0.064616, 0.430217 }, + { 0.354032, 0.066925, 0.430906 }, + { 0.360284, 0.069247, 0.431497 }, + { 0.366529, 0.071579, 0.431994 }, + { 0.372768, 0.073915, 0.432400 }, + { 0.379001, 0.076253, 0.432719 }, + { 0.385228, 0.078591, 0.432955 }, + { 0.391453, 0.080927, 0.433109 }, + { 0.397674, 0.083257, 0.433183 }, + { 0.403894, 0.085580, 0.433179 }, + { 0.410113, 0.087896, 0.433098 }, + { 0.416331, 0.090203, 0.432943 }, + { 0.422549, 0.092501, 0.432714 }, + { 0.428768, 0.094790, 0.432412 }, + { 0.434987, 0.097069, 0.432039 }, + { 0.441207, 0.099338, 0.431594 }, + { 0.447428, 0.101597, 0.431080 }, + { 0.453651, 0.103848, 0.430498 }, + { 0.459875, 0.106089, 0.429846 }, + { 0.466100, 0.108322, 0.429125 }, + { 0.472328, 0.110547, 0.428334 }, + { 0.478558, 0.112764, 0.427475 }, + { 0.484789, 0.114974, 0.426548 }, + { 0.491022, 0.117179, 0.425552 }, + { 0.497257, 0.119379, 0.424488 }, + { 0.503493, 0.121575, 0.423356 }, + { 0.509730, 0.123769, 0.422156 }, + { 0.515967, 0.125960, 0.420887 }, + { 0.522206, 0.128150, 0.419549 }, + { 0.528444, 0.130341, 0.418142 }, + { 0.534683, 0.132534, 0.416667 }, + { 0.540920, 0.134729, 0.415123 }, + { 0.547157, 0.136929, 0.413511 }, + { 0.553392, 0.139134, 0.411829 }, + { 0.559624, 0.141346, 0.410078 }, + { 0.565854, 0.143567, 0.408258 }, + { 0.572081, 0.145797, 0.406369 }, + { 0.578304, 0.148039, 0.404411 }, + { 0.584521, 0.150294, 0.402385 }, + { 0.590734, 0.152563, 0.400290 }, + { 0.596940, 0.154848, 0.398125 }, + { 0.603139, 0.157151, 0.395891 }, + { 0.609330, 0.159474, 0.393589 }, + { 0.615513, 0.161817, 0.391219 }, + { 0.621685, 0.164184, 0.388781 }, + { 0.627847, 0.166575, 0.386276 }, + { 0.633998, 0.168992, 0.383704 }, + { 0.640135, 0.171438, 0.381065 }, + { 0.646260, 0.173914, 0.378359 }, + { 0.652369, 0.176421, 0.375586 }, + { 0.658463, 0.178962, 0.372748 }, + { 0.664540, 0.181539, 0.369846 }, + { 0.670599, 0.184153, 0.366879 }, + { 0.676638, 0.186807, 0.363849 }, + { 0.682656, 0.189501, 0.360757 }, + { 0.688653, 0.192239, 0.357603 }, + { 0.694627, 0.195021, 0.354388 }, + { 0.700576, 0.197851, 0.351113 }, + { 0.706500, 0.200728, 0.347777 }, + { 0.712396, 0.203656, 0.344383 }, + { 0.718264, 0.206636, 0.340931 }, + { 0.724103, 0.209670, 0.337424 }, + { 0.729909, 0.212759, 0.333861 }, + { 0.735683, 0.215906, 0.330245 }, + { 0.741423, 0.219112, 0.326576 }, + { 0.747127, 0.222378, 0.322856 }, + { 0.752794, 0.225706, 0.319085 }, + { 0.758422, 0.229097, 0.315266 }, + { 0.764010, 0.232554, 0.311399 }, + { 0.769556, 0.236077, 0.307485 }, + { 0.775059, 0.239667, 0.303526 }, + { 0.780517, 0.243327, 0.299523 }, + { 0.785929, 0.247056, 0.295477 }, + { 0.791293, 0.250856, 0.291390 }, + { 0.796607, 0.254728, 0.287264 }, + { 0.801871, 0.258674, 0.283099 }, + { 0.807082, 0.262692, 0.278898 }, + { 0.812239, 0.266786, 0.274661 }, + { 0.817341, 0.270954, 0.270390 }, + { 0.822386, 0.275197, 0.266085 }, + { 0.827372, 0.279517, 0.261750 }, + { 0.832299, 0.283913, 0.257383 }, + { 0.837165, 0.288385, 0.252988 }, + { 0.841969, 0.292933, 0.248564 }, + { 0.846709, 0.297559, 0.244113 }, + { 0.851384, 0.302260, 0.239636 }, + { 0.855992, 0.307038, 0.235133 }, + { 0.860533, 0.311892, 0.230606 }, + { 0.865006, 0.316822, 0.226055 }, + { 0.869409, 0.321827, 0.221482 }, + { 0.873741, 0.326906, 0.216886 }, + { 0.878001, 0.332060, 0.212268 }, + { 0.882188, 0.337287, 0.207628 }, + { 0.886302, 0.342586, 0.202968 }, + { 0.890341, 0.347957, 0.198286 }, + { 0.894305, 0.353399, 0.193584 }, + { 0.898192, 0.358911, 0.188860 }, + { 0.902003, 0.364492, 0.184116 }, + { 0.905735, 0.370140, 0.179350 }, + { 0.909390, 0.375856, 0.174563 }, + { 0.912966, 0.381636, 0.169755 }, + { 0.916462, 0.387481, 0.164924 }, + { 0.919879, 0.393389, 0.160070 }, + { 0.923215, 0.399359, 0.155193 }, + { 0.926470, 0.405389, 0.150292 }, + { 0.929644, 0.411479, 0.145367 }, + { 0.932737, 0.417627, 0.140417 }, + { 0.935747, 0.423831, 0.135440 }, + { 0.938675, 0.430091, 0.130438 }, + { 0.941521, 0.436405, 0.125409 }, + { 0.944285, 0.442772, 0.120354 }, + { 0.946965, 0.449191, 0.115272 }, + { 0.949562, 0.455660, 0.110164 }, + { 0.952075, 0.462178, 0.105031 }, + { 0.954506, 0.468744, 0.099874 }, + { 0.956852, 0.475356, 0.094695 }, + { 0.959114, 0.482014, 0.089499 }, + { 0.961293, 0.488716, 0.084289 }, + { 0.963387, 0.495462, 0.079073 }, + { 0.965397, 0.502249, 0.073859 }, + { 0.967322, 0.509078, 0.068659 }, + { 0.969163, 0.515946, 0.063488 }, + { 0.970919, 0.522853, 0.058367 }, + { 0.972590, 0.529798, 0.053324 }, + { 0.974176, 0.536780, 0.048392 }, + { 0.975677, 0.543798, 0.043618 }, + { 0.977092, 0.550850, 0.039050 }, + { 0.978422, 0.557937, 0.034931 }, + { 0.979666, 0.565057, 0.031409 }, + { 0.980824, 0.572209, 0.028508 }, + { 0.981895, 0.579392, 0.026250 }, + { 0.982881, 0.586606, 0.024661 }, + { 0.983779, 0.593849, 0.023770 }, + { 0.984591, 0.601122, 0.023606 }, + { 0.985315, 0.608422, 0.024202 }, + { 0.985952, 0.615750, 0.025592 }, + { 0.986502, 0.623105, 0.027814 }, + { 0.986964, 0.630485, 0.030908 }, + { 0.987337, 0.637890, 0.034916 }, + { 0.987622, 0.645320, 0.039886 }, + { 0.987819, 0.652773, 0.045581 }, + { 0.987926, 0.660250, 0.051750 }, + { 0.987945, 0.667748, 0.058329 }, + { 0.987874, 0.675267, 0.065257 }, + { 0.987714, 0.682807, 0.072489 }, + { 0.987464, 0.690366, 0.079990 }, + { 0.987124, 0.697944, 0.087731 }, + { 0.986694, 0.705540, 0.095694 }, + { 0.986175, 0.713153, 0.103863 }, + { 0.985566, 0.720782, 0.112229 }, + { 0.984865, 0.728427, 0.120785 }, + { 0.984075, 0.736087, 0.129527 }, + { 0.983196, 0.743758, 0.138453 }, + { 0.982228, 0.751442, 0.147565 }, + { 0.981173, 0.759135, 0.156863 }, + { 0.980032, 0.766837, 0.166353 }, + { 0.978806, 0.774545, 0.176037 }, + { 0.977497, 0.782258, 0.185923 }, + { 0.976108, 0.789974, 0.196018 }, + { 0.974638, 0.797692, 0.206332 }, + { 0.973088, 0.805409, 0.216877 }, + { 0.971468, 0.813122, 0.227658 }, + { 0.969783, 0.820825, 0.238686 }, + { 0.968041, 0.828515, 0.249972 }, + { 0.966243, 0.836191, 0.261534 }, + { 0.964394, 0.843848, 0.273391 }, + { 0.962517, 0.851476, 0.285546 }, + { 0.960626, 0.859069, 0.298010 }, + { 0.958720, 0.866624, 0.310820 }, + { 0.956834, 0.874129, 0.323974 }, + { 0.954997, 0.881569, 0.337475 }, + { 0.953215, 0.888942, 0.351369 }, + { 0.951546, 0.896226, 0.365627 }, + { 0.950018, 0.903409, 0.380271 }, + { 0.948683, 0.910473, 0.395289 }, + { 0.947594, 0.917399, 0.410665 }, + { 0.946809, 0.924168, 0.426373 }, + { 0.946392, 0.930761, 0.442367 }, + { 0.946403, 0.937159, 0.458592 }, + { 0.946903, 0.943348, 0.474970 }, + { 0.947937, 0.949318, 0.491426 }, + { 0.949545, 0.955063, 0.507860 }, + { 0.951740, 0.960587, 0.524203 }, + { 0.954529, 0.965896, 0.540361 }, + { 0.957896, 0.971003, 0.556275 }, + { 0.961812, 0.975924, 0.571925 }, + { 0.966249, 0.980678, 0.587206 }, + { 0.971162, 0.985282, 0.602154 }, + { 0.976511, 0.989753, 0.616760 }, + { 0.982257, 0.994109, 0.631017 }, + { 0.988362, 0.998364, 0.644924 } + }; + + return internal::CalcLerp(x, data); + } + + inline Color GetPlasmaColor(double x) + { + constexpr Color data[] = + { + { 0.050383, 0.029803, 0.527975 }, + { 0.063536, 0.028426, 0.533124 }, + { 0.075353, 0.027206, 0.538007 }, + { 0.086222, 0.026125, 0.542658 }, + { 0.096379, 0.025165, 0.547103 }, + { 0.105980, 0.024309, 0.551368 }, + { 0.115124, 0.023556, 0.555468 }, + { 0.123903, 0.022878, 0.559423 }, + { 0.132381, 0.022258, 0.563250 }, + { 0.140603, 0.021687, 0.566959 }, + { 0.148607, 0.021154, 0.570562 }, + { 0.156421, 0.020651, 0.574065 }, + { 0.164070, 0.020171, 0.577478 }, + { 0.171574, 0.019706, 0.580806 }, + { 0.178950, 0.019252, 0.584054 }, + { 0.186213, 0.018803, 0.587228 }, + { 0.193374, 0.018354, 0.590330 }, + { 0.200445, 0.017902, 0.593364 }, + { 0.207435, 0.017442, 0.596333 }, + { 0.214350, 0.016973, 0.599239 }, + { 0.221197, 0.016497, 0.602083 }, + { 0.227983, 0.016007, 0.604867 }, + { 0.234715, 0.015502, 0.607592 }, + { 0.241396, 0.014979, 0.610259 }, + { 0.248032, 0.014439, 0.612868 }, + { 0.254627, 0.013882, 0.615419 }, + { 0.261183, 0.013308, 0.617911 }, + { 0.267703, 0.012716, 0.620346 }, + { 0.274191, 0.012109, 0.622722 }, + { 0.280648, 0.011488, 0.625038 }, + { 0.287076, 0.010855, 0.627295 }, + { 0.293478, 0.010213, 0.629490 }, + { 0.299855, 0.009561, 0.631624 }, + { 0.306210, 0.008902, 0.633694 }, + { 0.312543, 0.008239, 0.635700 }, + { 0.318856, 0.007576, 0.637640 }, + { 0.325150, 0.006915, 0.639512 }, + { 0.331426, 0.006261, 0.641316 }, + { 0.337683, 0.005618, 0.643049 }, + { 0.343925, 0.004991, 0.644710 }, + { 0.350150, 0.004382, 0.646298 }, + { 0.356359, 0.003798, 0.647810 }, + { 0.362553, 0.003243, 0.649245 }, + { 0.368733, 0.002724, 0.650601 }, + { 0.374897, 0.002245, 0.651876 }, + { 0.381047, 0.001814, 0.653068 }, + { 0.387183, 0.001434, 0.654177 }, + { 0.393304, 0.001114, 0.655199 }, + { 0.399411, 0.000859, 0.656133 }, + { 0.405503, 0.000678, 0.656977 }, + { 0.411580, 0.000577, 0.657730 }, + { 0.417642, 0.000564, 0.658390 }, + { 0.423689, 0.000646, 0.658956 }, + { 0.429719, 0.000831, 0.659425 }, + { 0.435734, 0.001127, 0.659797 }, + { 0.441732, 0.001540, 0.660069 }, + { 0.447714, 0.002080, 0.660240 }, + { 0.453677, 0.002755, 0.660310 }, + { 0.459623, 0.003574, 0.660277 }, + { 0.465550, 0.004545, 0.660139 }, + { 0.471457, 0.005678, 0.659897 }, + { 0.477344, 0.006980, 0.659549 }, + { 0.483210, 0.008460, 0.659095 }, + { 0.489055, 0.010127, 0.658534 }, + { 0.494877, 0.011990, 0.657865 }, + { 0.500678, 0.014055, 0.657088 }, + { 0.506454, 0.016333, 0.656202 }, + { 0.512206, 0.018833, 0.655209 }, + { 0.517933, 0.021563, 0.654109 }, + { 0.523633, 0.024532, 0.652901 }, + { 0.529306, 0.027747, 0.651586 }, + { 0.534952, 0.031217, 0.650165 }, + { 0.540570, 0.034950, 0.648640 }, + { 0.546157, 0.038954, 0.647010 }, + { 0.551715, 0.043136, 0.645277 }, + { 0.557243, 0.047331, 0.643443 }, + { 0.562738, 0.051545, 0.641509 }, + { 0.568201, 0.055778, 0.639477 }, + { 0.573632, 0.060028, 0.637349 }, + { 0.579029, 0.064296, 0.635126 }, + { 0.584391, 0.068579, 0.632812 }, + { 0.589719, 0.072878, 0.630408 }, + { 0.595011, 0.077190, 0.627917 }, + { 0.600266, 0.081516, 0.625342 }, + { 0.605485, 0.085854, 0.622686 }, + { 0.610667, 0.090204, 0.619951 }, + { 0.615812, 0.094564, 0.617140 }, + { 0.620919, 0.098934, 0.614257 }, + { 0.625987, 0.103312, 0.611305 }, + { 0.631017, 0.107699, 0.608287 }, + { 0.636008, 0.112092, 0.605205 }, + { 0.640959, 0.116492, 0.602065 }, + { 0.645872, 0.120898, 0.598867 }, + { 0.650746, 0.125309, 0.595617 }, + { 0.655580, 0.129725, 0.592317 }, + { 0.660374, 0.134144, 0.588971 }, + { 0.665129, 0.138566, 0.585582 }, + { 0.669845, 0.142992, 0.582154 }, + { 0.674522, 0.147419, 0.578688 }, + { 0.679160, 0.151848, 0.575189 }, + { 0.683758, 0.156278, 0.571660 }, + { 0.688318, 0.160709, 0.568103 }, + { 0.692840, 0.165141, 0.564522 }, + { 0.697324, 0.169573, 0.560919 }, + { 0.701769, 0.174005, 0.557296 }, + { 0.706178, 0.178437, 0.553657 }, + { 0.710549, 0.182868, 0.550004 }, + { 0.714883, 0.187299, 0.546338 }, + { 0.719181, 0.191729, 0.542663 }, + { 0.723444, 0.196158, 0.538981 }, + { 0.727670, 0.200586, 0.535293 }, + { 0.731862, 0.205013, 0.531601 }, + { 0.736019, 0.209439, 0.527908 }, + { 0.740143, 0.213864, 0.524216 }, + { 0.744232, 0.218288, 0.520524 }, + { 0.748289, 0.222711, 0.516834 }, + { 0.752312, 0.227133, 0.513149 }, + { 0.756304, 0.231555, 0.509468 }, + { 0.760264, 0.235976, 0.505794 }, + { 0.764193, 0.240396, 0.502126 }, + { 0.768090, 0.244817, 0.498465 }, + { 0.771958, 0.249237, 0.494813 }, + { 0.775796, 0.253658, 0.491171 }, + { 0.779604, 0.258078, 0.487539 }, + { 0.783383, 0.262500, 0.483918 }, + { 0.787133, 0.266922, 0.480307 }, + { 0.790855, 0.271345, 0.476706 }, + { 0.794549, 0.275770, 0.473117 }, + { 0.798216, 0.280197, 0.469538 }, + { 0.801855, 0.284626, 0.465971 }, + { 0.805467, 0.289057, 0.462415 }, + { 0.809052, 0.293491, 0.458870 }, + { 0.812612, 0.297928, 0.455338 }, + { 0.816144, 0.302368, 0.451816 }, + { 0.819651, 0.306812, 0.448306 }, + { 0.823132, 0.311261, 0.444806 }, + { 0.826588, 0.315714, 0.441316 }, + { 0.830018, 0.320172, 0.437836 }, + { 0.833422, 0.324635, 0.434366 }, + { 0.836801, 0.329105, 0.430905 }, + { 0.840155, 0.333580, 0.427455 }, + { 0.843484, 0.338062, 0.424013 }, + { 0.846788, 0.342551, 0.420579 }, + { 0.850066, 0.347048, 0.417153 }, + { 0.853319, 0.351553, 0.413734 }, + { 0.856547, 0.356066, 0.410322 }, + { 0.859750, 0.360588, 0.406917 }, + { 0.862927, 0.365119, 0.403519 }, + { 0.866078, 0.369660, 0.400126 }, + { 0.869203, 0.374212, 0.396738 }, + { 0.872303, 0.378774, 0.393355 }, + { 0.875376, 0.383347, 0.389976 }, + { 0.878423, 0.387932, 0.386600 }, + { 0.881443, 0.392529, 0.383229 }, + { 0.884436, 0.397139, 0.379860 }, + { 0.887402, 0.401762, 0.376494 }, + { 0.890340, 0.406398, 0.373130 }, + { 0.893250, 0.411048, 0.369768 }, + { 0.896131, 0.415712, 0.366407 }, + { 0.898984, 0.420392, 0.363047 }, + { 0.901807, 0.425087, 0.359688 }, + { 0.904601, 0.429797, 0.356329 }, + { 0.907365, 0.434524, 0.352970 }, + { 0.910098, 0.439268, 0.349610 }, + { 0.912800, 0.444029, 0.346251 }, + { 0.915471, 0.448807, 0.342890 }, + { 0.918109, 0.453603, 0.339529 }, + { 0.920714, 0.458417, 0.336166 }, + { 0.923287, 0.463251, 0.332801 }, + { 0.925825, 0.468103, 0.329435 }, + { 0.928329, 0.472975, 0.326067 }, + { 0.930798, 0.477867, 0.322697 }, + { 0.933232, 0.482780, 0.319325 }, + { 0.935630, 0.487712, 0.315952 }, + { 0.937990, 0.492667, 0.312575 }, + { 0.940313, 0.497642, 0.309197 }, + { 0.942598, 0.502639, 0.305816 }, + { 0.944844, 0.507658, 0.302433 }, + { 0.947051, 0.512699, 0.299049 }, + { 0.949217, 0.517763, 0.295662 }, + { 0.951344, 0.522850, 0.292275 }, + { 0.953428, 0.527960, 0.288883 }, + { 0.955470, 0.533093, 0.285490 }, + { 0.957469, 0.538250, 0.282096 }, + { 0.959424, 0.543431, 0.278701 }, + { 0.961336, 0.548636, 0.275305 }, + { 0.963203, 0.553865, 0.271909 }, + { 0.965024, 0.559118, 0.268513 }, + { 0.966798, 0.564396, 0.265118 }, + { 0.968526, 0.569700, 0.261721 }, + { 0.970205, 0.575028, 0.258325 }, + { 0.971835, 0.580382, 0.254931 }, + { 0.973416, 0.585761, 0.251540 }, + { 0.974947, 0.591165, 0.248151 }, + { 0.976428, 0.596595, 0.244767 }, + { 0.977856, 0.602051, 0.241387 }, + { 0.979233, 0.607532, 0.238013 }, + { 0.980556, 0.613039, 0.234646 }, + { 0.981826, 0.618572, 0.231287 }, + { 0.983041, 0.624131, 0.227937 }, + { 0.984199, 0.629718, 0.224595 }, + { 0.985301, 0.635330, 0.221265 }, + { 0.986345, 0.640969, 0.217948 }, + { 0.987332, 0.646633, 0.214648 }, + { 0.988260, 0.652325, 0.211364 }, + { 0.989128, 0.658043, 0.208100 }, + { 0.989935, 0.663787, 0.204859 }, + { 0.990681, 0.669558, 0.201642 }, + { 0.991365, 0.675355, 0.198453 }, + { 0.991985, 0.681179, 0.195295 }, + { 0.992541, 0.687030, 0.192170 }, + { 0.993032, 0.692907, 0.189084 }, + { 0.993456, 0.698810, 0.186041 }, + { 0.993814, 0.704741, 0.183043 }, + { 0.994103, 0.710698, 0.180097 }, + { 0.994324, 0.716681, 0.177208 }, + { 0.994474, 0.722691, 0.174381 }, + { 0.994553, 0.728728, 0.171622 }, + { 0.994561, 0.734791, 0.168938 }, + { 0.994495, 0.740880, 0.166335 }, + { 0.994355, 0.746995, 0.163821 }, + { 0.994141, 0.753137, 0.161404 }, + { 0.993851, 0.759304, 0.159092 }, + { 0.993482, 0.765499, 0.156891 }, + { 0.993033, 0.771720, 0.154808 }, + { 0.992505, 0.777967, 0.152855 }, + { 0.991897, 0.784239, 0.151042 }, + { 0.991209, 0.790537, 0.149377 }, + { 0.990439, 0.796859, 0.147870 }, + { 0.989587, 0.803205, 0.146529 }, + { 0.988648, 0.809579, 0.145357 }, + { 0.987621, 0.815978, 0.144363 }, + { 0.986509, 0.822401, 0.143557 }, + { 0.985314, 0.828846, 0.142945 }, + { 0.984031, 0.835315, 0.142528 }, + { 0.982653, 0.841812, 0.142303 }, + { 0.981190, 0.848329, 0.142279 }, + { 0.979644, 0.854866, 0.142453 }, + { 0.977995, 0.861432, 0.142808 }, + { 0.976265, 0.868016, 0.143351 }, + { 0.974443, 0.874622, 0.144061 }, + { 0.972530, 0.881250, 0.144923 }, + { 0.970533, 0.887896, 0.145919 }, + { 0.968443, 0.894564, 0.147014 }, + { 0.966271, 0.901249, 0.148180 }, + { 0.964021, 0.907950, 0.149370 }, + { 0.961681, 0.914672, 0.150520 }, + { 0.959276, 0.921407, 0.151566 }, + { 0.956808, 0.928152, 0.152409 }, + { 0.954287, 0.934908, 0.152921 }, + { 0.951726, 0.941671, 0.152925 }, + { 0.949151, 0.948435, 0.152178 }, + { 0.946602, 0.955190, 0.150328 }, + { 0.944152, 0.961916, 0.146861 }, + { 0.941896, 0.968590, 0.140956 }, + { 0.940015, 0.975158, 0.131326 } + }; + + return internal::CalcLerp(x, data); + } + + inline Color GetViridisColor(double x) + { + constexpr Color data[] = + { + { 0.267004, 0.004874, 0.329415 }, + { 0.268510, 0.009605, 0.335427 }, + { 0.269944, 0.014625, 0.341379 }, + { 0.271305, 0.019942, 0.347269 }, + { 0.272594, 0.025563, 0.353093 }, + { 0.273809, 0.031497, 0.358853 }, + { 0.274952, 0.037752, 0.364543 }, + { 0.276022, 0.044167, 0.370164 }, + { 0.277018, 0.050344, 0.375715 }, + { 0.277941, 0.056324, 0.381191 }, + { 0.278791, 0.062145, 0.386592 }, + { 0.279566, 0.067836, 0.391917 }, + { 0.280267, 0.073417, 0.397163 }, + { 0.280894, 0.078907, 0.402329 }, + { 0.281446, 0.084320, 0.407414 }, + { 0.281924, 0.089666, 0.412415 }, + { 0.282327, 0.094955, 0.417331 }, + { 0.282656, 0.100196, 0.422160 }, + { 0.282910, 0.105393, 0.426902 }, + { 0.283091, 0.110553, 0.431554 }, + { 0.283197, 0.115680, 0.436115 }, + { 0.283229, 0.120777, 0.440584 }, + { 0.283187, 0.125848, 0.444960 }, + { 0.283072, 0.130895, 0.449241 }, + { 0.282884, 0.135920, 0.453427 }, + { 0.282623, 0.140926, 0.457517 }, + { 0.282290, 0.145912, 0.461510 }, + { 0.281887, 0.150881, 0.465405 }, + { 0.281412, 0.155834, 0.469201 }, + { 0.280868, 0.160771, 0.472899 }, + { 0.280255, 0.165693, 0.476498 }, + { 0.279574, 0.170599, 0.479997 }, + { 0.278826, 0.175490, 0.483397 }, + { 0.278012, 0.180367, 0.486697 }, + { 0.277134, 0.185228, 0.489898 }, + { 0.276194, 0.190074, 0.493001 }, + { 0.275191, 0.194905, 0.496005 }, + { 0.274128, 0.199721, 0.498911 }, + { 0.273006, 0.204520, 0.501721 }, + { 0.271828, 0.209303, 0.504434 }, + { 0.270595, 0.214069, 0.507052 }, + { 0.269308, 0.218818, 0.509577 }, + { 0.267968, 0.223549, 0.512008 }, + { 0.266580, 0.228262, 0.514349 }, + { 0.265145, 0.232956, 0.516599 }, + { 0.263663, 0.237631, 0.518762 }, + { 0.262138, 0.242286, 0.520837 }, + { 0.260571, 0.246922, 0.522828 }, + { 0.258965, 0.251537, 0.524736 }, + { 0.257322, 0.256130, 0.526563 }, + { 0.255645, 0.260703, 0.528312 }, + { 0.253935, 0.265254, 0.529983 }, + { 0.252194, 0.269783, 0.531579 }, + { 0.250425, 0.274290, 0.533103 }, + { 0.248629, 0.278775, 0.534556 }, + { 0.246811, 0.283237, 0.535941 }, + { 0.244972, 0.287675, 0.537260 }, + { 0.243113, 0.292092, 0.538516 }, + { 0.241237, 0.296485, 0.539709 }, + { 0.239346, 0.300855, 0.540844 }, + { 0.237441, 0.305202, 0.541921 }, + { 0.235526, 0.309527, 0.542944 }, + { 0.233603, 0.313828, 0.543914 }, + { 0.231674, 0.318106, 0.544834 }, + { 0.229739, 0.322361, 0.545706 }, + { 0.227802, 0.326594, 0.546532 }, + { 0.225863, 0.330805, 0.547314 }, + { 0.223925, 0.334994, 0.548053 }, + { 0.221989, 0.339161, 0.548752 }, + { 0.220057, 0.343307, 0.549413 }, + { 0.218130, 0.347432, 0.550038 }, + { 0.216210, 0.351535, 0.550627 }, + { 0.214298, 0.355619, 0.551184 }, + { 0.212395, 0.359683, 0.551710 }, + { 0.210503, 0.363727, 0.552206 }, + { 0.208623, 0.367752, 0.552675 }, + { 0.206756, 0.371758, 0.553117 }, + { 0.204903, 0.375746, 0.553533 }, + { 0.203063, 0.379716, 0.553925 }, + { 0.201239, 0.383670, 0.554294 }, + { 0.199430, 0.387607, 0.554642 }, + { 0.197636, 0.391528, 0.554969 }, + { 0.195860, 0.395433, 0.555276 }, + { 0.194100, 0.399323, 0.555565 }, + { 0.192357, 0.403199, 0.555836 }, + { 0.190631, 0.407061, 0.556089 }, + { 0.188923, 0.410910, 0.556326 }, + { 0.187231, 0.414746, 0.556547 }, + { 0.185556, 0.418570, 0.556753 }, + { 0.183898, 0.422383, 0.556944 }, + { 0.182256, 0.426184, 0.557120 }, + { 0.180629, 0.429975, 0.557282 }, + { 0.179019, 0.433756, 0.557430 }, + { 0.177423, 0.437527, 0.557565 }, + { 0.175841, 0.441290, 0.557685 }, + { 0.174274, 0.445044, 0.557792 }, + { 0.172719, 0.448791, 0.557885 }, + { 0.171176, 0.452530, 0.557965 }, + { 0.169646, 0.456262, 0.558030 }, + { 0.168126, 0.459988, 0.558082 }, + { 0.166617, 0.463708, 0.558119 }, + { 0.165117, 0.467423, 0.558141 }, + { 0.163625, 0.471133, 0.558148 }, + { 0.162142, 0.474838, 0.558140 }, + { 0.160665, 0.478540, 0.558115 }, + { 0.159194, 0.482237, 0.558073 }, + { 0.157729, 0.485932, 0.558013 }, + { 0.156270, 0.489624, 0.557936 }, + { 0.154815, 0.493313, 0.557840 }, + { 0.153364, 0.497000, 0.557724 }, + { 0.151918, 0.500685, 0.557587 }, + { 0.150476, 0.504369, 0.557430 }, + { 0.149039, 0.508051, 0.557250 }, + { 0.147607, 0.511733, 0.557049 }, + { 0.146180, 0.515413, 0.556823 }, + { 0.144759, 0.519093, 0.556572 }, + { 0.143343, 0.522773, 0.556295 }, + { 0.141935, 0.526453, 0.555991 }, + { 0.140536, 0.530132, 0.555659 }, + { 0.139147, 0.533812, 0.555298 }, + { 0.137770, 0.537492, 0.554906 }, + { 0.136408, 0.541173, 0.554483 }, + { 0.135066, 0.544853, 0.554029 }, + { 0.133743, 0.548535, 0.553541 }, + { 0.132444, 0.552216, 0.553018 }, + { 0.131172, 0.555899, 0.552459 }, + { 0.129933, 0.559582, 0.551864 }, + { 0.128729, 0.563265, 0.551229 }, + { 0.127568, 0.566949, 0.550556 }, + { 0.126453, 0.570633, 0.549841 }, + { 0.125394, 0.574318, 0.549086 }, + { 0.124395, 0.578002, 0.548287 }, + { 0.123463, 0.581687, 0.547445 }, + { 0.122606, 0.585371, 0.546557 }, + { 0.121831, 0.589055, 0.545623 }, + { 0.121148, 0.592739, 0.544641 }, + { 0.120565, 0.596422, 0.543611 }, + { 0.120092, 0.600104, 0.542530 }, + { 0.119738, 0.603785, 0.541400 }, + { 0.119512, 0.607464, 0.540218 }, + { 0.119423, 0.611141, 0.538982 }, + { 0.119483, 0.614817, 0.537692 }, + { 0.119699, 0.618490, 0.536347 }, + { 0.120081, 0.622161, 0.534946 }, + { 0.120638, 0.625828, 0.533488 }, + { 0.121380, 0.629492, 0.531973 }, + { 0.122312, 0.633153, 0.530398 }, + { 0.123444, 0.636809, 0.528763 }, + { 0.124780, 0.640461, 0.527068 }, + { 0.126326, 0.644107, 0.525311 }, + { 0.128087, 0.647749, 0.523491 }, + { 0.130067, 0.651384, 0.521608 }, + { 0.132268, 0.655014, 0.519661 }, + { 0.134692, 0.658636, 0.517649 }, + { 0.137339, 0.662252, 0.515571 }, + { 0.140210, 0.665859, 0.513427 }, + { 0.143303, 0.669459, 0.511215 }, + { 0.146616, 0.673050, 0.508936 }, + { 0.150148, 0.676631, 0.506589 }, + { 0.153894, 0.680203, 0.504172 }, + { 0.157851, 0.683765, 0.501686 }, + { 0.162016, 0.687316, 0.499129 }, + { 0.166383, 0.690856, 0.496502 }, + { 0.170948, 0.694384, 0.493803 }, + { 0.175707, 0.697900, 0.491033 }, + { 0.180653, 0.701402, 0.488189 }, + { 0.185783, 0.704891, 0.485273 }, + { 0.191090, 0.708366, 0.482284 }, + { 0.196571, 0.711827, 0.479221 }, + { 0.202219, 0.715272, 0.476084 }, + { 0.208030, 0.718701, 0.472873 }, + { 0.214000, 0.722114, 0.469588 }, + { 0.220124, 0.725509, 0.466226 }, + { 0.226397, 0.728888, 0.462789 }, + { 0.232815, 0.732247, 0.459277 }, + { 0.239374, 0.735588, 0.455688 }, + { 0.246070, 0.738910, 0.452024 }, + { 0.252899, 0.742211, 0.448284 }, + { 0.259857, 0.745492, 0.444467 }, + { 0.266941, 0.748751, 0.440573 }, + { 0.274149, 0.751988, 0.436601 }, + { 0.281477, 0.755203, 0.432552 }, + { 0.288921, 0.758394, 0.428426 }, + { 0.296479, 0.761561, 0.424223 }, + { 0.304148, 0.764704, 0.419943 }, + { 0.311925, 0.767822, 0.415586 }, + { 0.319809, 0.770914, 0.411152 }, + { 0.327796, 0.773980, 0.406640 }, + { 0.335885, 0.777018, 0.402049 }, + { 0.344074, 0.780029, 0.397381 }, + { 0.352360, 0.783011, 0.392636 }, + { 0.360741, 0.785964, 0.387814 }, + { 0.369214, 0.788888, 0.382914 }, + { 0.377779, 0.791781, 0.377939 }, + { 0.386433, 0.794644, 0.372886 }, + { 0.395174, 0.797475, 0.367757 }, + { 0.404001, 0.800275, 0.362552 }, + { 0.412913, 0.803041, 0.357269 }, + { 0.421908, 0.805774, 0.351910 }, + { 0.430983, 0.808473, 0.346476 }, + { 0.440137, 0.811138, 0.340967 }, + { 0.449368, 0.813768, 0.335384 }, + { 0.458674, 0.816363, 0.329727 }, + { 0.468053, 0.818921, 0.323998 }, + { 0.477504, 0.821444, 0.318195 }, + { 0.487026, 0.823929, 0.312321 }, + { 0.496615, 0.826376, 0.306377 }, + { 0.506271, 0.828786, 0.300362 }, + { 0.515992, 0.831158, 0.294279 }, + { 0.525776, 0.833491, 0.288127 }, + { 0.535621, 0.835785, 0.281908 }, + { 0.545524, 0.838039, 0.275626 }, + { 0.555484, 0.840254, 0.269281 }, + { 0.565498, 0.842430, 0.262877 }, + { 0.575563, 0.844566, 0.256415 }, + { 0.585678, 0.846661, 0.249897 }, + { 0.595839, 0.848717, 0.243329 }, + { 0.606045, 0.850733, 0.236712 }, + { 0.616293, 0.852709, 0.230052 }, + { 0.626579, 0.854645, 0.223353 }, + { 0.636902, 0.856542, 0.216620 }, + { 0.647257, 0.858400, 0.209861 }, + { 0.657642, 0.860219, 0.203082 }, + { 0.668054, 0.861999, 0.196293 }, + { 0.678489, 0.863742, 0.189503 }, + { 0.688944, 0.865448, 0.182725 }, + { 0.699415, 0.867117, 0.175971 }, + { 0.709898, 0.868751, 0.169257 }, + { 0.720391, 0.870350, 0.162603 }, + { 0.730889, 0.871916, 0.156029 }, + { 0.741388, 0.873449, 0.149561 }, + { 0.751884, 0.874951, 0.143228 }, + { 0.762373, 0.876424, 0.137064 }, + { 0.772852, 0.877868, 0.131109 }, + { 0.783315, 0.879285, 0.125405 }, + { 0.793760, 0.880678, 0.120005 }, + { 0.804182, 0.882046, 0.114965 }, + { 0.814576, 0.883393, 0.110347 }, + { 0.824940, 0.884720, 0.106217 }, + { 0.835270, 0.886029, 0.102646 }, + { 0.845561, 0.887322, 0.099702 }, + { 0.855810, 0.888601, 0.097452 }, + { 0.866013, 0.889868, 0.095953 }, + { 0.876168, 0.891125, 0.095250 }, + { 0.886271, 0.892374, 0.095374 }, + { 0.896320, 0.893616, 0.096335 }, + { 0.906311, 0.894855, 0.098125 }, + { 0.916242, 0.896091, 0.100717 }, + { 0.926106, 0.897330, 0.104071 }, + { 0.935904, 0.898570, 0.108131 }, + { 0.945636, 0.899815, 0.112838 }, + { 0.955300, 0.901065, 0.118128 }, + { 0.964894, 0.902323, 0.123941 }, + { 0.974417, 0.903590, 0.130215 }, + { 0.983868, 0.904867, 0.136897 }, + { 0.993248, 0.906157, 0.143936 } + }; + + return internal::CalcLerp(x, data); + } + + inline Color GetCividisColor(double x) + { + constexpr Color data[] = + { + { 0.0000, 0.1262, 0.3015 }, + { 0.0000, 0.1292, 0.3077 }, + { 0.0000, 0.1321, 0.3142 }, + { 0.0000, 0.1350, 0.3205 }, + { 0.0000, 0.1379, 0.3269 }, + { 0.0000, 0.1408, 0.3334 }, + { 0.0000, 0.1437, 0.3400 }, + { 0.0000, 0.1465, 0.3467 }, + { 0.0000, 0.1492, 0.3537 }, + { 0.0000, 0.1519, 0.3606 }, + { 0.0000, 0.1546, 0.3676 }, + { 0.0000, 0.1574, 0.3746 }, + { 0.0000, 0.1601, 0.3817 }, + { 0.0000, 0.1629, 0.3888 }, + { 0.0000, 0.1657, 0.3960 }, + { 0.0000, 0.1685, 0.4031 }, + { 0.0000, 0.1714, 0.4102 }, + { 0.0000, 0.1743, 0.4172 }, + { 0.0000, 0.1773, 0.4241 }, + { 0.0000, 0.1798, 0.4307 }, + { 0.0000, 0.1817, 0.4347 }, + { 0.0000, 0.1834, 0.4363 }, + { 0.0000, 0.1852, 0.4368 }, + { 0.0000, 0.1872, 0.4368 }, + { 0.0000, 0.1901, 0.4365 }, + { 0.0000, 0.1930, 0.4361 }, + { 0.0000, 0.1958, 0.4356 }, + { 0.0000, 0.1987, 0.4349 }, + { 0.0000, 0.2015, 0.4343 }, + { 0.0000, 0.2044, 0.4336 }, + { 0.0000, 0.2073, 0.4329 }, + { 0.0055, 0.2101, 0.4322 }, + { 0.0236, 0.2130, 0.4314 }, + { 0.0416, 0.2158, 0.4308 }, + { 0.0576, 0.2187, 0.4301 }, + { 0.0710, 0.2215, 0.4293 }, + { 0.0827, 0.2244, 0.4287 }, + { 0.0932, 0.2272, 0.4280 }, + { 0.1030, 0.2300, 0.4274 }, + { 0.1120, 0.2329, 0.4268 }, + { 0.1204, 0.2357, 0.4262 }, + { 0.1283, 0.2385, 0.4256 }, + { 0.1359, 0.2414, 0.4251 }, + { 0.1431, 0.2442, 0.4245 }, + { 0.1500, 0.2470, 0.4241 }, + { 0.1566, 0.2498, 0.4236 }, + { 0.1630, 0.2526, 0.4232 }, + { 0.1692, 0.2555, 0.4228 }, + { 0.1752, 0.2583, 0.4224 }, + { 0.1811, 0.2611, 0.4220 }, + { 0.1868, 0.2639, 0.4217 }, + { 0.1923, 0.2667, 0.4214 }, + { 0.1977, 0.2695, 0.4212 }, + { 0.2030, 0.2723, 0.4209 }, + { 0.2082, 0.2751, 0.4207 }, + { 0.2133, 0.2780, 0.4205 }, + { 0.2183, 0.2808, 0.4204 }, + { 0.2232, 0.2836, 0.4203 }, + { 0.2281, 0.2864, 0.4202 }, + { 0.2328, 0.2892, 0.4201 }, + { 0.2375, 0.2920, 0.4200 }, + { 0.2421, 0.2948, 0.4200 }, + { 0.2466, 0.2976, 0.4200 }, + { 0.2511, 0.3004, 0.4201 }, + { 0.2556, 0.3032, 0.4201 }, + { 0.2599, 0.3060, 0.4202 }, + { 0.2643, 0.3088, 0.4203 }, + { 0.2686, 0.3116, 0.4205 }, + { 0.2728, 0.3144, 0.4206 }, + { 0.2770, 0.3172, 0.4208 }, + { 0.2811, 0.3200, 0.4210 }, + { 0.2853, 0.3228, 0.4212 }, + { 0.2894, 0.3256, 0.4215 }, + { 0.2934, 0.3284, 0.4218 }, + { 0.2974, 0.3312, 0.4221 }, + { 0.3014, 0.3340, 0.4224 }, + { 0.3054, 0.3368, 0.4227 }, + { 0.3093, 0.3396, 0.4231 }, + { 0.3132, 0.3424, 0.4236 }, + { 0.3170, 0.3453, 0.4240 }, + { 0.3209, 0.3481, 0.4244 }, + { 0.3247, 0.3509, 0.4249 }, + { 0.3285, 0.3537, 0.4254 }, + { 0.3323, 0.3565, 0.4259 }, + { 0.3361, 0.3593, 0.4264 }, + { 0.3398, 0.3622, 0.4270 }, + { 0.3435, 0.3650, 0.4276 }, + { 0.3472, 0.3678, 0.4282 }, + { 0.3509, 0.3706, 0.4288 }, + { 0.3546, 0.3734, 0.4294 }, + { 0.3582, 0.3763, 0.4302 }, + { 0.3619, 0.3791, 0.4308 }, + { 0.3655, 0.3819, 0.4316 }, + { 0.3691, 0.3848, 0.4322 }, + { 0.3727, 0.3876, 0.4331 }, + { 0.3763, 0.3904, 0.4338 }, + { 0.3798, 0.3933, 0.4346 }, + { 0.3834, 0.3961, 0.4355 }, + { 0.3869, 0.3990, 0.4364 }, + { 0.3905, 0.4018, 0.4372 }, + { 0.3940, 0.4047, 0.4381 }, + { 0.3975, 0.4075, 0.4390 }, + { 0.4010, 0.4104, 0.4400 }, + { 0.4045, 0.4132, 0.4409 }, + { 0.4080, 0.4161, 0.4419 }, + { 0.4114, 0.4189, 0.4430 }, + { 0.4149, 0.4218, 0.4440 }, + { 0.4183, 0.4247, 0.4450 }, + { 0.4218, 0.4275, 0.4462 }, + { 0.4252, 0.4304, 0.4473 }, + { 0.4286, 0.4333, 0.4485 }, + { 0.4320, 0.4362, 0.4496 }, + { 0.4354, 0.4390, 0.4508 }, + { 0.4388, 0.4419, 0.4521 }, + { 0.4422, 0.4448, 0.4534 }, + { 0.4456, 0.4477, 0.4547 }, + { 0.4489, 0.4506, 0.4561 }, + { 0.4523, 0.4535, 0.4575 }, + { 0.4556, 0.4564, 0.4589 }, + { 0.4589, 0.4593, 0.4604 }, + { 0.4622, 0.4622, 0.4620 }, + { 0.4656, 0.4651, 0.4635 }, + { 0.4689, 0.4680, 0.4650 }, + { 0.4722, 0.4709, 0.4665 }, + { 0.4756, 0.4738, 0.4679 }, + { 0.4790, 0.4767, 0.4691 }, + { 0.4825, 0.4797, 0.4701 }, + { 0.4861, 0.4826, 0.4707 }, + { 0.4897, 0.4856, 0.4714 }, + { 0.4934, 0.4886, 0.4719 }, + { 0.4971, 0.4915, 0.4723 }, + { 0.5008, 0.4945, 0.4727 }, + { 0.5045, 0.4975, 0.4730 }, + { 0.5083, 0.5005, 0.4732 }, + { 0.5121, 0.5035, 0.4734 }, + { 0.5158, 0.5065, 0.4736 }, + { 0.5196, 0.5095, 0.4737 }, + { 0.5234, 0.5125, 0.4738 }, + { 0.5272, 0.5155, 0.4739 }, + { 0.5310, 0.5186, 0.4739 }, + { 0.5349, 0.5216, 0.4738 }, + { 0.5387, 0.5246, 0.4739 }, + { 0.5425, 0.5277, 0.4738 }, + { 0.5464, 0.5307, 0.4736 }, + { 0.5502, 0.5338, 0.4735 }, + { 0.5541, 0.5368, 0.4733 }, + { 0.5579, 0.5399, 0.4732 }, + { 0.5618, 0.5430, 0.4729 }, + { 0.5657, 0.5461, 0.4727 }, + { 0.5696, 0.5491, 0.4723 }, + { 0.5735, 0.5522, 0.4720 }, + { 0.5774, 0.5553, 0.4717 }, + { 0.5813, 0.5584, 0.4714 }, + { 0.5852, 0.5615, 0.4709 }, + { 0.5892, 0.5646, 0.4705 }, + { 0.5931, 0.5678, 0.4701 }, + { 0.5970, 0.5709, 0.4696 }, + { 0.6010, 0.5740, 0.4691 }, + { 0.6050, 0.5772, 0.4685 }, + { 0.6089, 0.5803, 0.4680 }, + { 0.6129, 0.5835, 0.4673 }, + { 0.6168, 0.5866, 0.4668 }, + { 0.6208, 0.5898, 0.4662 }, + { 0.6248, 0.5929, 0.4655 }, + { 0.6288, 0.5961, 0.4649 }, + { 0.6328, 0.5993, 0.4641 }, + { 0.6368, 0.6025, 0.4632 }, + { 0.6408, 0.6057, 0.4625 }, + { 0.6449, 0.6089, 0.4617 }, + { 0.6489, 0.6121, 0.4609 }, + { 0.6529, 0.6153, 0.4600 }, + { 0.6570, 0.6185, 0.4591 }, + { 0.6610, 0.6217, 0.4583 }, + { 0.6651, 0.6250, 0.4573 }, + { 0.6691, 0.6282, 0.4562 }, + { 0.6732, 0.6315, 0.4553 }, + { 0.6773, 0.6347, 0.4543 }, + { 0.6813, 0.6380, 0.4532 }, + { 0.6854, 0.6412, 0.4521 }, + { 0.6895, 0.6445, 0.4511 }, + { 0.6936, 0.6478, 0.4499 }, + { 0.6977, 0.6511, 0.4487 }, + { 0.7018, 0.6544, 0.4475 }, + { 0.7060, 0.6577, 0.4463 }, + { 0.7101, 0.6610, 0.4450 }, + { 0.7142, 0.6643, 0.4437 }, + { 0.7184, 0.6676, 0.4424 }, + { 0.7225, 0.6710, 0.4409 }, + { 0.7267, 0.6743, 0.4396 }, + { 0.7308, 0.6776, 0.4382 }, + { 0.7350, 0.6810, 0.4368 }, + { 0.7392, 0.6844, 0.4352 }, + { 0.7434, 0.6877, 0.4338 }, + { 0.7476, 0.6911, 0.4322 }, + { 0.7518, 0.6945, 0.4307 }, + { 0.7560, 0.6979, 0.4290 }, + { 0.7602, 0.7013, 0.4273 }, + { 0.7644, 0.7047, 0.4258 }, + { 0.7686, 0.7081, 0.4241 }, + { 0.7729, 0.7115, 0.4223 }, + { 0.7771, 0.7150, 0.4205 }, + { 0.7814, 0.7184, 0.4188 }, + { 0.7856, 0.7218, 0.4168 }, + { 0.7899, 0.7253, 0.4150 }, + { 0.7942, 0.7288, 0.4129 }, + { 0.7985, 0.7322, 0.4111 }, + { 0.8027, 0.7357, 0.4090 }, + { 0.8070, 0.7392, 0.4070 }, + { 0.8114, 0.7427, 0.4049 }, + { 0.8157, 0.7462, 0.4028 }, + { 0.8200, 0.7497, 0.4007 }, + { 0.8243, 0.7532, 0.3984 }, + { 0.8287, 0.7568, 0.3961 }, + { 0.8330, 0.7603, 0.3938 }, + { 0.8374, 0.7639, 0.3915 }, + { 0.8417, 0.7674, 0.3892 }, + { 0.8461, 0.7710, 0.3869 }, + { 0.8505, 0.7745, 0.3843 }, + { 0.8548, 0.7781, 0.3818 }, + { 0.8592, 0.7817, 0.3793 }, + { 0.8636, 0.7853, 0.3766 }, + { 0.8681, 0.7889, 0.3739 }, + { 0.8725, 0.7926, 0.3712 }, + { 0.8769, 0.7962, 0.3684 }, + { 0.8813, 0.7998, 0.3657 }, + { 0.8858, 0.8035, 0.3627 }, + { 0.8902, 0.8071, 0.3599 }, + { 0.8947, 0.8108, 0.3569 }, + { 0.8992, 0.8145, 0.3538 }, + { 0.9037, 0.8182, 0.3507 }, + { 0.9082, 0.8219, 0.3474 }, + { 0.9127, 0.8256, 0.3442 }, + { 0.9172, 0.8293, 0.3409 }, + { 0.9217, 0.8330, 0.3374 }, + { 0.9262, 0.8367, 0.3340 }, + { 0.9308, 0.8405, 0.3306 }, + { 0.9353, 0.8442, 0.3268 }, + { 0.9399, 0.8480, 0.3232 }, + { 0.9444, 0.8518, 0.3195 }, + { 0.9490, 0.8556, 0.3155 }, + { 0.9536, 0.8593, 0.3116 }, + { 0.9582, 0.8632, 0.3076 }, + { 0.9628, 0.8670, 0.3034 }, + { 0.9674, 0.8708, 0.2990 }, + { 0.9721, 0.8746, 0.2947 }, + { 0.9767, 0.8785, 0.2901 }, + { 0.9814, 0.8823, 0.2856 }, + { 0.9860, 0.8862, 0.2807 }, + { 0.9907, 0.8901, 0.2759 }, + { 0.9954, 0.8940, 0.2708 }, + { 1.0000, 0.8979, 0.2655 }, + { 1.0000, 0.9018, 0.2600 }, + { 1.0000, 0.9057, 0.2593 }, + { 1.0000, 0.9094, 0.2634 }, + { 1.0000, 0.9131, 0.2680 }, + { 1.0000, 0.9169, 0.2731 } + }; + + return internal::CalcLerp(x, data); + } + + inline Color GetGithubColor(double x) + { + constexpr Color data[] = + { + { 0.933333, 0.933333, 0.933333 }, + { 0.776470, 0.894117, 0.545098 }, + { 0.482352, 0.788235, 0.435294 }, + { 0.137254, 0.603921, 0.231372 }, + { 0.098039, 0.380392, 0.152941 } + }; + + return internal::CalcLerp(x, data); + } + + inline Color GetCubehelixColor(double x) + { + constexpr Color data[] = + { + { 0.000000, 0.000000, 0.000000 }, + { 0.006716, 0.002119, 0.005970 }, + { 0.013252, 0.004287, 0.012162 }, + { 0.019599, 0.006514, 0.018563 }, + { 0.025748, 0.008803, 0.025162 }, + { 0.031691, 0.011164, 0.031946 }, + { 0.037421, 0.013600, 0.038902 }, + { 0.042932, 0.016118, 0.046016 }, + { 0.048217, 0.018724, 0.053275 }, + { 0.053271, 0.021423, 0.060666 }, + { 0.058090, 0.024220, 0.068173 }, + { 0.062670, 0.027119, 0.075781 }, + { 0.067008, 0.030126, 0.083478 }, + { 0.071101, 0.033243, 0.091246 }, + { 0.074947, 0.036475, 0.099072 }, + { 0.078546, 0.039824, 0.106939 }, + { 0.081898, 0.043295, 0.114834 }, + { 0.085002, 0.046889, 0.122740 }, + { 0.087860, 0.050609, 0.130643 }, + { 0.090474, 0.054457, 0.138527 }, + { 0.092845, 0.058434, 0.146378 }, + { 0.094978, 0.062542, 0.154180 }, + { 0.096875, 0.066781, 0.161918 }, + { 0.098542, 0.071152, 0.169579 }, + { 0.099984, 0.075655, 0.177147 }, + { 0.101205, 0.080290, 0.184609 }, + { 0.102212, 0.085055, 0.191951 }, + { 0.103013, 0.089951, 0.199159 }, + { 0.103615, 0.094975, 0.206221 }, + { 0.104025, 0.100126, 0.213124 }, + { 0.104252, 0.105403, 0.219855 }, + { 0.104305, 0.110801, 0.226402 }, + { 0.104194, 0.116320, 0.232755 }, + { 0.103929, 0.121956, 0.238903 }, + { 0.103519, 0.127705, 0.244834 }, + { 0.102976, 0.133564, 0.250541 }, + { 0.102310, 0.139529, 0.256012 }, + { 0.101534, 0.145596, 0.261240 }, + { 0.100659, 0.151759, 0.266217 }, + { 0.099697, 0.158016, 0.270935 }, + { 0.098661, 0.164359, 0.275388 }, + { 0.097563, 0.170785, 0.279569 }, + { 0.096415, 0.177287, 0.283474 }, + { 0.095232, 0.183860, 0.287097 }, + { 0.094026, 0.190498, 0.290434 }, + { 0.092810, 0.197194, 0.293483 }, + { 0.091597, 0.203943, 0.296240 }, + { 0.090402, 0.210739, 0.298703 }, + { 0.089237, 0.217573, 0.300873 }, + { 0.088115, 0.224441, 0.302747 }, + { 0.087051, 0.231334, 0.304327 }, + { 0.086056, 0.238247, 0.305612 }, + { 0.085146, 0.245171, 0.306606 }, + { 0.084331, 0.252101, 0.307310 }, + { 0.083626, 0.259028, 0.307728 }, + { 0.083043, 0.265946, 0.307863 }, + { 0.082594, 0.272848, 0.307720 }, + { 0.082291, 0.279726, 0.307304 }, + { 0.082148, 0.286573, 0.306621 }, + { 0.082174, 0.293383, 0.305677 }, + { 0.082381, 0.300147, 0.304480 }, + { 0.082780, 0.306860, 0.303037 }, + { 0.083383, 0.313514, 0.301356 }, + { 0.084198, 0.320102, 0.299448 }, + { 0.085235, 0.326618, 0.297320 }, + { 0.086504, 0.333055, 0.294984 }, + { 0.088014, 0.339406, 0.292449 }, + { 0.089772, 0.345666, 0.289728 }, + { 0.091787, 0.351829, 0.286831 }, + { 0.094066, 0.357887, 0.283771 }, + { 0.096615, 0.363836, 0.280560 }, + { 0.099441, 0.369671, 0.277211 }, + { 0.102549, 0.375385, 0.273736 }, + { 0.105944, 0.380974, 0.270151 }, + { 0.109630, 0.386433, 0.266468 }, + { 0.113611, 0.391757, 0.262703 }, + { 0.117891, 0.396943, 0.258868 }, + { 0.122472, 0.401985, 0.254979 }, + { 0.127356, 0.406881, 0.251051 }, + { 0.132543, 0.411627, 0.247099 }, + { 0.138035, 0.416220, 0.243137 }, + { 0.143832, 0.420656, 0.239182 }, + { 0.149933, 0.424934, 0.235247 }, + { 0.156336, 0.429052, 0.231350 }, + { 0.163040, 0.433007, 0.227504 }, + { 0.170042, 0.436798, 0.223726 }, + { 0.177339, 0.440423, 0.220029 }, + { 0.184927, 0.443882, 0.216431 }, + { 0.192802, 0.447175, 0.212944 }, + { 0.200958, 0.450301, 0.209585 }, + { 0.209391, 0.453260, 0.206367 }, + { 0.218092, 0.456053, 0.203306 }, + { 0.227057, 0.458680, 0.200415 }, + { 0.236277, 0.461144, 0.197707 }, + { 0.245744, 0.463444, 0.195197 }, + { 0.255451, 0.465584, 0.192898 }, + { 0.265388, 0.467565, 0.190822 }, + { 0.275545, 0.469391, 0.188982 }, + { 0.285913, 0.471062, 0.187389 }, + { 0.296481, 0.472584, 0.186055 }, + { 0.307239, 0.473959, 0.184992 }, + { 0.318175, 0.475191, 0.184208 }, + { 0.329277, 0.476285, 0.183716 }, + { 0.340534, 0.477243, 0.183523 }, + { 0.351934, 0.478072, 0.183638 }, + { 0.363463, 0.478776, 0.184071 }, + { 0.375109, 0.479360, 0.184829 }, + { 0.386858, 0.479829, 0.185918 }, + { 0.398697, 0.480190, 0.187345 }, + { 0.410613, 0.480448, 0.189115 }, + { 0.422591, 0.480609, 0.191235 }, + { 0.434618, 0.480679, 0.193708 }, + { 0.446680, 0.480665, 0.196538 }, + { 0.458762, 0.480574, 0.199728 }, + { 0.470850, 0.480412, 0.203280 }, + { 0.482930, 0.480186, 0.207197 }, + { 0.494987, 0.479903, 0.211478 }, + { 0.507008, 0.479572, 0.216124 }, + { 0.518978, 0.479198, 0.221136 }, + { 0.530883, 0.478789, 0.226510 }, + { 0.542708, 0.478353, 0.232247 }, + { 0.554441, 0.477898, 0.238342 }, + { 0.566067, 0.477430, 0.244794 }, + { 0.577573, 0.476958, 0.251597 }, + { 0.588945, 0.476490, 0.258747 }, + { 0.600171, 0.476032, 0.266239 }, + { 0.611237, 0.475592, 0.274067 }, + { 0.622132, 0.475178, 0.282223 }, + { 0.632842, 0.474798, 0.290702 }, + { 0.643357, 0.474459, 0.299495 }, + { 0.653665, 0.474168, 0.308593 }, + { 0.663755, 0.473933, 0.317987 }, + { 0.673616, 0.473761, 0.327668 }, + { 0.683239, 0.473658, 0.337626 }, + { 0.692613, 0.473632, 0.347849 }, + { 0.701729, 0.473690, 0.358327 }, + { 0.710579, 0.473838, 0.369047 }, + { 0.719155, 0.474083, 0.379998 }, + { 0.727448, 0.474430, 0.391167 }, + { 0.735453, 0.474886, 0.402541 }, + { 0.743162, 0.475457, 0.414106 }, + { 0.750569, 0.476148, 0.425849 }, + { 0.757669, 0.476964, 0.437755 }, + { 0.764458, 0.477911, 0.449811 }, + { 0.770932, 0.478994, 0.462001 }, + { 0.777086, 0.480216, 0.474310 }, + { 0.782918, 0.481583, 0.486725 }, + { 0.788426, 0.483098, 0.499228 }, + { 0.793609, 0.484765, 0.511805 }, + { 0.798465, 0.486587, 0.524441 }, + { 0.802993, 0.488567, 0.537119 }, + { 0.807196, 0.490708, 0.549824 }, + { 0.811072, 0.493013, 0.562540 }, + { 0.814625, 0.495483, 0.575253 }, + { 0.817855, 0.498121, 0.587945 }, + { 0.820767, 0.500927, 0.600602 }, + { 0.823364, 0.503903, 0.613208 }, + { 0.825649, 0.507050, 0.625748 }, + { 0.827628, 0.510368, 0.638207 }, + { 0.829305, 0.513857, 0.650570 }, + { 0.830688, 0.517516, 0.662822 }, + { 0.831781, 0.521346, 0.674949 }, + { 0.832593, 0.525345, 0.686938 }, + { 0.833130, 0.529511, 0.698773 }, + { 0.833402, 0.533844, 0.710443 }, + { 0.833416, 0.538342, 0.721933 }, + { 0.833181, 0.543001, 0.733232 }, + { 0.832708, 0.547820, 0.744327 }, + { 0.832006, 0.552795, 0.755206 }, + { 0.831086, 0.557924, 0.765859 }, + { 0.829958, 0.563202, 0.776274 }, + { 0.828633, 0.568627, 0.786443 }, + { 0.827124, 0.574193, 0.796354 }, + { 0.825442, 0.579897, 0.805999 }, + { 0.823599, 0.585733, 0.815370 }, + { 0.821608, 0.591698, 0.824459 }, + { 0.819482, 0.597785, 0.833258 }, + { 0.817233, 0.603990, 0.841761 }, + { 0.814875, 0.610307, 0.849963 }, + { 0.812421, 0.616730, 0.857858 }, + { 0.809884, 0.623252, 0.865441 }, + { 0.807278, 0.629869, 0.872709 }, + { 0.804617, 0.636573, 0.879658 }, + { 0.801914, 0.643359, 0.886286 }, + { 0.799183, 0.650218, 0.892592 }, + { 0.796438, 0.657146, 0.898574 }, + { 0.793692, 0.664134, 0.904231 }, + { 0.790959, 0.671176, 0.909565 }, + { 0.788253, 0.678264, 0.914576 }, + { 0.785586, 0.685392, 0.919267 }, + { 0.782973, 0.692553, 0.923639 }, + { 0.780425, 0.699738, 0.927695 }, + { 0.777957, 0.706942, 0.931441 }, + { 0.775579, 0.714157, 0.934879 }, + { 0.773305, 0.721375, 0.938016 }, + { 0.771147, 0.728589, 0.940857 }, + { 0.769116, 0.735793, 0.943409 }, + { 0.767224, 0.742979, 0.945678 }, + { 0.765481, 0.750140, 0.947673 }, + { 0.763898, 0.757269, 0.949402 }, + { 0.762485, 0.764360, 0.950874 }, + { 0.761251, 0.771405, 0.952098 }, + { 0.760207, 0.778399, 0.953084 }, + { 0.759360, 0.785335, 0.953843 }, + { 0.758718, 0.792207, 0.954386 }, + { 0.758290, 0.799008, 0.954724 }, + { 0.758082, 0.805734, 0.954869 }, + { 0.758101, 0.812378, 0.954833 }, + { 0.758353, 0.818934, 0.954629 }, + { 0.758842, 0.825399, 0.954270 }, + { 0.759575, 0.831767, 0.953769 }, + { 0.760554, 0.838033, 0.953140 }, + { 0.761784, 0.844192, 0.952397 }, + { 0.763267, 0.850242, 0.951554 }, + { 0.765006, 0.856178, 0.950625 }, + { 0.767001, 0.861997, 0.949624 }, + { 0.769255, 0.867695, 0.948567 }, + { 0.771766, 0.873270, 0.947467 }, + { 0.774535, 0.878718, 0.946340 }, + { 0.777561, 0.884039, 0.945201 }, + { 0.780841, 0.889230, 0.944063 }, + { 0.784374, 0.894289, 0.942942 }, + { 0.788156, 0.899216, 0.941853 }, + { 0.792184, 0.904010, 0.940809 }, + { 0.796453, 0.908669, 0.939825 }, + { 0.800958, 0.913194, 0.938916 }, + { 0.805694, 0.917586, 0.938095 }, + { 0.810654, 0.921845, 0.937376 }, + { 0.815832, 0.925971, 0.936772 }, + { 0.821221, 0.929967, 0.936297 }, + { 0.826811, 0.933833, 0.935962 }, + { 0.832595, 0.937572, 0.935781 }, + { 0.838565, 0.941187, 0.935766 }, + { 0.844709, 0.944679, 0.935927 }, + { 0.851018, 0.948053, 0.936275 }, + { 0.857482, 0.951311, 0.936822 }, + { 0.864090, 0.954457, 0.937578 }, + { 0.870830, 0.957495, 0.938550 }, + { 0.877690, 0.960430, 0.939749 }, + { 0.884659, 0.963266, 0.941183 }, + { 0.891723, 0.966009, 0.942858 }, + { 0.898871, 0.968662, 0.944783 }, + { 0.906088, 0.971233, 0.946962 }, + { 0.913362, 0.973726, 0.949402 }, + { 0.920679, 0.976147, 0.952108 }, + { 0.928026, 0.978504, 0.955083 }, + { 0.935387, 0.980802, 0.958331 }, + { 0.942750, 0.983048, 0.961854 }, + { 0.950101, 0.985249, 0.965654 }, + { 0.957424, 0.987412, 0.969733 }, + { 0.964706, 0.989543, 0.974090 }, + { 0.971932, 0.991652, 0.978724 }, + { 0.979088, 0.993744, 0.983635 }, + { 0.986161, 0.995828, 0.988820 }, + { 0.993136, 0.997910, 0.994276 }, + { 1.000000, 1.000000, 1.000000 } + }; + + return internal::CalcLerp(x, data); + } + +#if defined(TINYCOLORMAP_WITH_QT5) && defined(TINYCOLORMAP_WITH_EIGEN) + inline QImage CreateMatrixVisualization(const Eigen::MatrixXd& matrix) + { + const int w = matrix.cols(); + const int h = matrix.rows(); + const double max_coeff = matrix.maxCoeff(); + const double min_coeff = matrix.minCoeff(); + const Eigen::MatrixXd normalized = (1.0 / (max_coeff - min_coeff)) * (matrix - Eigen::MatrixXd::Constant(h, w, min_coeff)); + + QImage image(w, h, QImage::Format_ARGB32); + for (int x = 0; x < w; ++ x) + { + for (int y = 0; y < h; ++ y) + { + const QColor color = tinycolormap::GetColor(normalized(y, x)).ConvertToQColor(); + image.setPixel(x, y, color.rgb()); + } + } + + return image; + } + + inline void ExportMatrixVisualization(const Eigen::MatrixXd& matrix, const std::string& path) + { + CreateMatrixVisualization(matrix).save(QString::fromStdString(path)); + } +#endif +} + +#endif From 6225ad83e5a12733591645648d413e83613eb011 Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Sun, 12 Jun 2022 20:49:29 +0200 Subject: [PATCH 5/6] Add color scheme settings --- command_line/commoncommandlinefunctions.cpp | 29 +++- command_line/commoncommandlinefunctions.h | 2 + graph/nodecolorer.cpp | 16 +- program/globals.cpp | 93 +++++++++++ program/globals.h | 14 +- program/settings.cpp | 3 +- program/settings.h | 4 +- tests/bandagetests.cpp | 8 +- thirdparty/colormap/tinycolormap.hpp | 7 +- thirdparty/colormap/tinycolormap_fwd.hpp | 7 + ui/settingsdialog.cpp | 10 +- ui/settingsdialog.ui | 161 +++++++++----------- 12 files changed, 223 insertions(+), 131 deletions(-) create mode 100644 thirdparty/colormap/tinycolormap_fwd.hpp diff --git a/command_line/commoncommandlinefunctions.cpp b/command_line/commoncommandlinefunctions.cpp index 536c27c7..841a0ef7 100644 --- a/command_line/commoncommandlinefunctions.cpp +++ b/command_line/commoncommandlinefunctions.cpp @@ -132,9 +132,8 @@ void getSettingsUsage(QStringList * text) *text << ""; *text << "Depth colour scheme"; *text << dashes; - *text << "These settings only apply when the depth colour scheme is used."; - *text << "--depcollow Colour for nodes with depth below the low depth value " + getDefaultColour(g_settings->lowDepthColour); - *text << "--depcolhi Colour for nodes with depth above the high depth value " + getDefaultColour(g_settings->highDepthColour); + *text << "These settings only apply when the depth / GC colour scheme is used."; + *text << "--colormap Color map to use " + getDefaultColorMap(g_settings->colorMap); *text << "--depvallow Low depth value " + getRangeAndDefault(g_settings->lowDepthValue, "auto"); *text << "--depvalhi High depth value " + getRangeAndDefault(g_settings->highDepthValue, "auto"); *text << ""; @@ -527,10 +526,8 @@ void parseSettings(QStringList arguments) if (isOptionPresent("--unicolspe", &arguments)) g_settings->uniformNodeSpecialColour = getColourOption("--unicolspe", &arguments); - if (isOptionPresent("--depcollow", &arguments)) - g_settings->lowDepthColour = getColourOption("--depcollow", &arguments); - if (isOptionPresent("--depcolhi", &arguments)) - g_settings->highDepthColour = getColourOption("--depcolhi", &arguments); + if (isOptionPresent("--colormap", &arguments)) + g_settings->colorMap = getColorMapOption("--colormap", &arguments); if (isOptionPresent("--depvallow", &arguments)) { g_settings->lowDepthValue = getFloatOption("--depvallow", &arguments); @@ -1122,6 +1119,19 @@ QColor getColourOption(const QString& option, QStringList * arguments) return {arguments->at(colIndex)}; } +ColorMap getColorMapOption(const QString& option, QStringList * arguments) +{ + int optionIndex = arguments->indexOf(option); + if (optionIndex == -1) + return {}; + + int colIndex = optionIndex + 1; + if (colIndex >= arguments->size()) + return {}; + + return colorMapFromName(arguments->at(colIndex)); +} + QString getStringOption(const QString& option, QStringList * arguments) { @@ -1283,6 +1293,11 @@ QString getDefaultColour(QColor colour) return "(default: " + getColourName(colour.name()) + ")"; } +QString getDefaultColorMap(ColorMap colorMap) +{ + return "(default: " + getColorMapName(colorMap) + ")"; +} + QString getBandageTitleAsciiArt() { return " ____ _ \n | _ \\ | | \n | |_) | __ _ _ __ __| | __ _ __ _ ___ \n | _ < / _` | '_ \\ / _` |/ _` |/ _` |/ _ \\\n | |_) | (_| | | | | (_| | (_| | (_| | __/\n |____/ \\__,_|_| |_|\\__,_|\\__,_|\\__, |\\___|\n __/ | \n |___/ "; diff --git a/command_line/commoncommandlinefunctions.h b/command_line/commoncommandlinefunctions.h index f73d2b7c..1daf0db0 100644 --- a/command_line/commoncommandlinefunctions.h +++ b/command_line/commoncommandlinefunctions.h @@ -59,6 +59,7 @@ int getIntOption(const QString& option, QStringList * arguments); double getFloatOption(const QString& option, QStringList * arguments); SciNot getSciNotOption(const QString& option, QStringList * arguments); QColor getColourOption(const QString& option, QStringList * arguments); +ColorMap getColorMapOption(const QString& option, QStringList * arguments); NodeColorScheme getColourSchemeOption(const QString& option, QStringList * arguments); std::set getBlastAnnotationViews(const QString& option, QStringList * arguments); GraphScope getGraphScopeOption(const QString& option, QStringList * arguments); @@ -95,6 +96,7 @@ QString getRangeAndDefault(double min, double max, double defaultVal); QString getRangeAndDefault(double min, double max, QString defaultVal); QString getRangeAndDefault(const QString& min, QString max, QString defaultVal); QString getDefaultColour(QColor colour); +QString getDefaultColorMap(ColorMap colorMap); QString getBandageTitleAsciiArt(); bool isOption(QString text); diff --git a/graph/nodecolorer.cpp b/graph/nodecolorer.cpp index 8fd02e1b..db6ea7ef 100644 --- a/graph/nodecolorer.cpp +++ b/graph/nodecolorer.cpp @@ -129,23 +129,15 @@ static QColor interpolateRgb(QColor from, QColor to, float fraction) { QColor DepthNodeColorer::get(const GraphicsItemNode *node) { const DeBruijnNode *deBruijnNode = node->m_deBruijnNode; double depth = deBruijnNode->getDepth(); - double lowValue; - double highValue; + + double lowValue = g_settings->lowDepthValue, highValue = g_settings->highDepthValue; if (g_settings->autoDepthValue) { lowValue = m_graph->m_firstQuartileDepth; highValue = m_graph->m_thirdQuartileDepth; - } else { - lowValue = g_settings->lowDepthValue; - highValue = g_settings->highDepthValue; } - if (depth <= lowValue) - return g_settings->lowDepthColour; - if (depth >= highValue) - return g_settings->highDepthColour; - float fraction = (depth - lowValue) / (highValue - lowValue); - return interpolateRgb(g_settings->lowDepthColour, g_settings->highDepthColour, fraction); + return tinycolormap::GetColor(fraction, colorMap(g_settings->colorMap)).ConvertToQColor(); } QColor UniformNodeColorer::get(const GraphicsItemNode *node) { @@ -244,5 +236,5 @@ QColor GCNodeColorer::get(const GraphicsItemNode *node) { const DeBruijnNode *deBruijnNode = node->m_deBruijnNode; float lowValue = 0.2, highValue = 0.8, value = deBruijnNode->getGC(); float fraction = (value - lowValue) / (highValue - lowValue); - return tinycolormap::GetColor(fraction).ConvertToQColor(); + return tinycolormap::GetColor(fraction, colorMap(g_settings->colorMap)).ConvertToQColor(); } diff --git a/program/globals.cpp b/program/globals.cpp index 919b9891..03ff2049 100644 --- a/program/globals.cpp +++ b/program/globals.cpp @@ -446,3 +446,96 @@ QString getColourName(QColor colour) return colour.name(); } + +ColorMap colorMapFromName(const QString& name) { + if (name == "viridis") + return Viridis; + if (name == "parula") + return Parula; + if (name == "heat") + return Heat; + if (name == "jet") + return Jet; + if (name == "turbo") + return Turbo; + if (name == "hot") + return Hot; + if (name == "gray") + return Gray; + if (name == "magma") + return Magma; + if (name == "inferno") + return Inferno; + if (name == "plasma") + return Plasma; + if (name == "cividis") + return Cividis; + if (name == "github") + return Github; + if (name == "cubehelix") + return Cubehelix; + + return Viridis; +} + +tinycolormap::ColormapType colorMap(ColorMap colorMap) { + switch (colorMap) { + case Viridis: + return tinycolormap::ColormapType::Viridis; + case Parula: + return tinycolormap::ColormapType::Parula; + case Heat: + return tinycolormap::ColormapType::Heat; + case Jet: + return tinycolormap::ColormapType::Jet; + case Turbo: + return tinycolormap::ColormapType::Turbo; + case Hot: + return tinycolormap::ColormapType::Hot; + case Gray: + return tinycolormap::ColormapType::Gray; + case Magma: + return tinycolormap::ColormapType::Magma; + case Inferno: + return tinycolormap::ColormapType::Inferno; + case Plasma: + return tinycolormap::ColormapType::Plasma; + case Cividis: + return tinycolormap::ColormapType::Cividis; + case Github: + return tinycolormap::ColormapType::Github; + case Cubehelix: + return tinycolormap::ColormapType::Cubehelix; + } + +} +QString getColorMapName(ColorMap colorMap) { + switch (colorMap) { + case Viridis: + return "viridis"; + case Parula: + return "parula"; + case Heat: + return "heat"; + case Jet: + return "jet"; + case Turbo: + return "turbo"; + case Hot: + return "hot"; + case Gray: + return "gray"; + case Magma: + return "magma"; + case Inferno: + return "inferno"; + case Plasma: + return "plasma"; + case Cividis: + return "cividis"; + case Github: + return "github"; + case Cubehelix: + return "cubehelix"; + } +} \ No newline at end of file diff --git a/program/globals.h b/program/globals.h index 22fe9402..7030f7f2 100644 --- a/program/globals.h +++ b/program/globals.h @@ -19,12 +19,15 @@ #ifndef GLOBALS_H #define GLOBALS_H -#include +#include + #include #include #include #include +#include + class Settings; class Memory; class MyGraphicsView; @@ -56,6 +59,11 @@ enum NodeNameStatus {NODE_NAME_OKAY, NODE_NAME_TAKEN, NODE_NAME_CONTAINS_TAB, NODE_NAME_CONTAINS_SPACE}; enum SequencesLoadedFromFasta {NOT_READY, NOT_TRIED, TRIED}; +// FIXME: factor out +enum ColorMap : int { + Viridis = 0, + Parula, Heat, Jet, Turbo, Hot, Gray, Magma, Inferno, Plasma, Cividis, Github, Cubehelix +}; using AnnotationGroupId = int; using ViewId = int; @@ -80,7 +88,9 @@ QString formatDepthForDisplay(double depth); std::vector getPresetColours(); QString getColourName(QColor colour); - +ColorMap colorMapFromName(const QString& name); +tinycolormap::ColormapType colorMap(ColorMap colorMap); +QString getColorMapName(ColorMap colorMap); // Often used function for access const reference to value in map even if it doesn't exist template typename MapLike> diff --git a/program/settings.cpp b/program/settings.cpp index c9cfc9af..f2c8c71c 100644 --- a/program/settings.cpp +++ b/program/settings.cpp @@ -107,9 +107,8 @@ Settings::Settings() autoDepthValue = true; lowDepthValue = FloatSetting(5.0, 0.0, 1000000.0); - lowDepthColour = QColor(0, 0, 0); highDepthValue = FloatSetting(50.0, 0.0, 1000000.0); - highDepthColour = QColor(255, 0, 0); + colorMap = ColorMap::Viridis; pathHighlightShadingColour = QColor(0, 0, 0, 60); pathHighlightOutlineColour = QColor(0, 0, 0); diff --git a/program/settings.h b/program/settings.h index d90d7265..46236b68 100644 --- a/program/settings.h +++ b/program/settings.h @@ -77,7 +77,6 @@ struct AnnotationSetting { using AnnotationSettings = std::unordered_map; - class Settings { public: @@ -173,9 +172,8 @@ class Settings bool autoDepthValue; FloatSetting lowDepthValue; - QColor lowDepthColour; FloatSetting highDepthValue; - QColor highDepthColour; + ColorMap colorMap; QColor pathHighlightShadingColour; QColor pathHighlightOutlineColour; diff --git a/tests/bandagetests.cpp b/tests/bandagetests.cpp index 9a3c8cf6..75bb6d38 100644 --- a/tests/bandagetests.cpp +++ b/tests/bandagetests.cpp @@ -925,13 +925,13 @@ void BandageTests::commandLineSettings() parseSettings(commandLineSettings); QCOMPARE(getColourName(g_settings->uniformNodeSpecialColour), QString("papayawhip")); - commandLineSettings = QString("--depcollow mediumorchid").split(" "); + commandLineSettings = QString("--colormap github").split(" "); parseSettings(commandLineSettings); - QCOMPARE(getColourName(g_settings->lowDepthColour), QString("mediumorchid")); + QCOMPARE(getColorMapName(g_settings->colorMap), QString("github")); - commandLineSettings = QString("--depcolhi linen").split(" "); + commandLineSettings = QString("--colormap heat").split(" "); parseSettings(commandLineSettings); - QCOMPARE(getColourName(g_settings->highDepthColour), QString("linen")); + QCOMPARE(g_settings->colorMap, ColorMap::Heat); QCOMPARE(g_settings->autoDepthValue, true); commandLineSettings = QString("--depvallow 56.7").split(" "); diff --git a/thirdparty/colormap/tinycolormap.hpp b/thirdparty/colormap/tinycolormap.hpp index bed482f5..873cfb16 100644 --- a/thirdparty/colormap/tinycolormap.hpp +++ b/thirdparty/colormap/tinycolormap.hpp @@ -69,17 +69,14 @@ #include #endif +#include "tinycolormap_fwd.hpp" + namespace tinycolormap { ////////////////////////////////////////////////////////////////////////////////// // Interface ////////////////////////////////////////////////////////////////////////////////// - enum class ColormapType - { - Parula, Heat, Jet, Turbo, Hot, Gray, Magma, Inferno, Plasma, Viridis, Cividis, Github, Cubehelix - }; - struct Color { explicit constexpr Color(double gray) noexcept : data{ gray, gray, gray } {} diff --git a/thirdparty/colormap/tinycolormap_fwd.hpp b/thirdparty/colormap/tinycolormap_fwd.hpp new file mode 100644 index 00000000..baf2a808 --- /dev/null +++ b/thirdparty/colormap/tinycolormap_fwd.hpp @@ -0,0 +1,7 @@ +#pragma once + +namespace tinycolormap { + enum class ColormapType { + Parula, Heat, Jet, Turbo, Hot, Gray, Magma, Inferno, Plasma, Viridis, Cividis, Github, Cubehelix + }; +}; diff --git a/ui/settingsdialog.cpp b/ui/settingsdialog.cpp index 7dd148c5..c5634f9e 100644 --- a/ui/settingsdialog.cpp +++ b/ui/settingsdialog.cpp @@ -51,8 +51,6 @@ SettingsDialog::SettingsDialog(QWidget *parent) : ui->uniformPositiveNodeColourButton->m_name = "Uniform positive node colour"; ui->uniformNegativeNodeColourButton->m_name = "Uniform negative node colour"; ui->uniformNodeSpecialColourButton->m_name = "Uniform special node colour"; - ui->lowDepthColourButton->m_name = "Low depth colour"; - ui->highDepthColourButton->m_name = "High depth colour"; ui->noBlastHitsColourButton->m_name = "No BLAST hits colour"; ui->contiguousStrandSpecificColourButton->m_name = "Contiguous (strand-specific) colour"; ui->contiguousEitherStrandColourButton->m_name = "Contiguous (either strand) colour"; @@ -198,8 +196,6 @@ void SettingsDialog::loadOrSaveSettingsToOrFromWidgets(bool setWidgets, Settings colourFunctionPointer(&settings->uniformPositiveNodeColour, ui->uniformPositiveNodeColourButton); colourFunctionPointer(&settings->uniformNegativeNodeColour, ui->uniformNegativeNodeColourButton); colourFunctionPointer(&settings->uniformNodeSpecialColour, ui->uniformNodeSpecialColourButton); - colourFunctionPointer(&settings->lowDepthColour, ui->lowDepthColourButton); - colourFunctionPointer(&settings->highDepthColour, ui->highDepthColourButton); doubleFunctionPointer(&settings->lowDepthValue, ui->lowDepthValueSpinBox, false); doubleFunctionPointer(&settings->highDepthValue, ui->highDepthValueSpinBox, false); colourFunctionPointer(&settings->grayColor, ui->noBlastHitsColourButton); @@ -249,6 +245,7 @@ void SettingsDialog::loadOrSaveSettingsToOrFromWidgets(bool setWidgets, Settings ui->nodeLengthPerMegabaseManualRadioButton->setChecked(settings->nodeLengthMode != AUTO_NODE_LENGTH); ui->positionVisibleRadioButton->setChecked(!settings->positionTextNodeCentre); ui->positionCentreRadioButton->setChecked(settings->positionTextNodeCentre); + ui->colorMapCombo->setCurrentIndex(int(settings->colorMap)); } else { @@ -262,6 +259,7 @@ void SettingsDialog::loadOrSaveSettingsToOrFromWidgets(bool setWidgets, Settings else settings->nodeLengthMode = MANUAL_NODE_LENGTH; settings->positionTextNodeCentre = ui->positionCentreRadioButton->isChecked(); + settings->colorMap = ColorMap(ui->colorMapCombo->currentIndex()); } } @@ -351,10 +349,6 @@ void SettingsDialog::setInfoTexts() "Set to the minimum value for fully transparent nodes. Set to the maximum value for completely opaque nodes.

" "Note that negative nodes are only visible when the graph is drawn in double mode."); - ui->lowDepthColourInfoText->setInfoText("When Bandage is set to the 'Colour by depth' option, this colour is used for nodes with depth at or below the low depth value.

" - "Nodes with depth between the low and high depth values will get an intermediate colour."); - ui->highDepthColourInfoText->setInfoText("When Bandage is set to the 'Colour by depth' option, this colour is used for nodes with depth above the high depth value.

" - "Nodes with depth between the low and high depth values will get an intermediate colour."); ui->depthAutoValuesInfoText->setInfoText("When set to 'Auto', the low depth value is set to the first quartile and the high depth value is set to the third quartile."); ui->depthManualValuesInfoText->setInfoText("When set to 'Manual', you can specify the values used for depth colouring."); ui->noBlastHitsColourInfoText->setInfoText("When Bandage is set to the 'Colour using BLAST hits' option, this colour is used for nodes that do not have any BLAST hits. It is also used for any region of a node without BLAST hits, even if there are BLAST hits in other regions of that node."); diff --git a/ui/settingsdialog.ui b/ui/settingsdialog.ui index c8631710..3f848bc9 100644 --- a/ui/settingsdialog.ui +++ b/ui/settingsdialog.ui @@ -41,9 +41,9 @@ 0 - -2839 - 402 - 3466 + -1924 + 373 + 3388 @@ -51,7 +51,6 @@ - 75 true @@ -537,7 +536,6 @@ per megabase: - 75 true @@ -880,7 +878,6 @@ per megabase: - 75 true @@ -1318,7 +1315,6 @@ single node style: - 75 true @@ -1687,7 +1683,6 @@ single node style: - 75 true @@ -2057,7 +2052,6 @@ single node style: - 75 true @@ -2522,7 +2516,6 @@ single node style: - 75 true @@ -2744,7 +2737,6 @@ single node style: - 75 true @@ -2812,22 +2804,6 @@ single node style: 0 - - - - - 0 - 0 - - - - - 16 - 16 - - - - @@ -2844,36 +2820,7 @@ single node style: - - - - - 0 - 0 - - - - Low depth: - - - - - - - 100 - 0 - - - - Qt::StrongFocus - - - - - - - Qt::Horizontal @@ -2889,24 +2836,77 @@ single node style: - - - - - 0 - 0 - - - - - 16 - 16 - - + + + + + Viridis + + + + + Parula + + + + + Heat + + + + + Jet + + + + + Turbo + + + + + Hot + + + + + Gray + + + + + Magma + + + + + Inferno + + + + + Plasma + + + + + Cividis + + + + + Github + + + + + Cubehelix + + - - + + 0 @@ -2914,17 +2914,7 @@ single node style: - High depth: - - - - - - - Qt::StrongFocus - - - + Color scheme: @@ -3220,7 +3210,6 @@ single node style: - 75 true @@ -3364,7 +3353,6 @@ single node style: - 75 true @@ -3709,7 +3697,6 @@ single node style: - 75 true @@ -4390,8 +4377,6 @@ discrepancy (bases): uniformPositiveNodeColourButton uniformNegativeNodeColourButton uniformNodeSpecialColourButton - lowDepthColourButton - highDepthColourButton depthValueAutoRadioButton depthValueManualRadioButton lowDepthValueSpinBox From fde87a39e18c53efb9a965d4f50dae2d73afcc1e Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Sun, 12 Jun 2022 23:17:18 +0200 Subject: [PATCH 6/6] Add support for graph coloring using tag values Fixes #38 --- CMakeLists.txt | 2 +- graph/assemblygraph.cpp | 4 + graph/nodecolorer.cpp | 126 +++++++++++-------------- graph/nodecolorer.h | 3 +- graph/nodecolorers.h | 107 +++++++++++++++++++++ ui/mainwindow.cpp | 26 +++++- ui/mainwindow.h | 1 + ui/mainwindow.ui | 200 +++++++++++++++++++++------------------- ui/settingsdialog.cpp | 1 + 9 files changed, 299 insertions(+), 171 deletions(-) create mode 100644 graph/nodecolorers.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 814604cc..e105e21e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,7 +71,7 @@ set(LIB_SOURCES ui/tablewidgetitemname.cpp ui/tablewidgetitemshown.cpp ui/verticallabel.cpp - ui/verticalscrollarea.cpp graph/nodecolorer.cpp graph/nodecolorer.h) + ui/verticalscrollarea.cpp graph/nodecolorer.cpp graph/nodecolorer.h graph/nodecolorers.h) set(FORMS ui/aboutdialog.ui diff --git a/graph/assemblygraph.cpp b/graph/assemblygraph.cpp index e62b19c4..63ef26e4 100644 --- a/graph/assemblygraph.cpp +++ b/graph/assemblygraph.cpp @@ -648,7 +648,11 @@ bool AssemblyGraph::loadGraphFromFile(const QString& filename) { } determineGraphInfo(); + + // FIXME: get rid of this! g_memory->clearGraphSpecificMemory(); + g_settings->nodeColorer->reset(); + return true; } diff --git a/graph/nodecolorer.cpp b/graph/nodecolorer.cpp index db6ea7ef..99ecbbf3 100644 --- a/graph/nodecolorer.cpp +++ b/graph/nodecolorer.cpp @@ -16,16 +16,20 @@ // along with Bandage. If not, see . #include "nodecolorer.h" +#include "nodecolorers.h" #include "assemblygraph.h" #include "debruijnnode.h" #include "program/globals.h" #define TINYCOLORMAP_WITH_QT5 #include +#include "parallel_hashmap/phmap.h" -INodeColorer::INodeColorer(NodeColorScheme scheme) - : m_graph(g_assemblyGraph), m_scheme(scheme) {} +#include +INodeColorer::INodeColorer(NodeColorScheme scheme) + : m_graph(g_assemblyGraph), m_scheme(scheme) { +} std::pair INodeColorer::get(const GraphicsItemNode *node, const GraphicsItemNode *rcNode) { @@ -35,64 +39,6 @@ std::pair INodeColorer::get(const GraphicsItemNode *node, return { posColor, negColor }; } -class DepthNodeColorer : public INodeColorer { -public: - using INodeColorer::INodeColorer; - - QColor get(const GraphicsItemNode *node) override; - [[nodiscard]] const char* name() const override { return "Color by depth"; }; -}; - -class UniformNodeColorer : public INodeColorer { -public: - using INodeColorer::INodeColorer; - - QColor get(const GraphicsItemNode *node) override; - [[nodiscard]] const char* name() const override { return "Uniform color"; }; -}; - -class RandomNodeColorer : public INodeColorer { -public: - using INodeColorer::INodeColorer; - - QColor get(const GraphicsItemNode *node) override; - [[nodiscard]] std::pair get(const GraphicsItemNode *node, - const GraphicsItemNode *rcNode) override; - [[nodiscard]] const char* name() const override { return "Random colors"; }; -}; - -class GrayNodeColorer : public INodeColorer { -public: - using INodeColorer::INodeColorer; - - QColor get(const GraphicsItemNode *node) override; - [[nodiscard]] const char* name() const override { return "Gray colors"; }; -}; - -class CustomNodeColorer : public INodeColorer { -public: - using INodeColorer::INodeColorer; - - QColor get(const GraphicsItemNode *node) override; - [[nodiscard]] const char* name() const override { return "Custom colors"; }; -}; - -class ContiguityNodeColorer : public INodeColorer { -public: - using INodeColorer::INodeColorer; - - QColor get(const GraphicsItemNode *node) override; - [[nodiscard]] const char* name() const override { return "Color by contiguity"; }; -}; - -class GCNodeColorer : public INodeColorer { -public: - using INodeColorer::INodeColorer; - - QColor get(const GraphicsItemNode *node) override; - [[nodiscard]] const char* name() const override { return "Color by GC content"; }; -}; - std::unique_ptr INodeColorer::create(NodeColorScheme scheme) { switch (scheme) { case UNIFORM_COLOURS: @@ -109,23 +55,13 @@ std::unique_ptr INodeColorer::create(NodeColorScheme scheme) { return std::make_unique(scheme); case GC_CONTENT: return std::make_unique(scheme); + case TAG_VALUE: + return std::make_unique(scheme); } return nullptr; } -static QColor interpolateRgb(QColor from, QColor to, float fraction) { - float rDiff = to.redF() - from.redF(); - float gDiff = to.greenF() - from.greenF(); - float bDiff = to.blueF() - from.blueF(); - float aDiff = to.alphaF() - from.alphaF(); - - return QColor::fromRgbF(from.redF() + rDiff * fraction, - from.greenF() + gDiff * fraction, - from.blueF() + bDiff * fraction, - from.alphaF() + aDiff * fraction); -} - QColor DepthNodeColorer::get(const GraphicsItemNode *node) { const DeBruijnNode *deBruijnNode = node->m_deBruijnNode; double depth = deBruijnNode->getDepth(); @@ -238,3 +174,49 @@ QColor GCNodeColorer::get(const GraphicsItemNode *node) { float fraction = (value - lowValue) / (highValue - lowValue); return tinycolormap::GetColor(fraction, colorMap(g_settings->colorMap)).ConvertToQColor(); } + +QColor TagValueNodeColorer::get(const GraphicsItemNode *node) { + const DeBruijnNode *deBruijnNode = node->m_deBruijnNode; + + auto tags = g_assemblyGraph->m_nodeTags.find(deBruijnNode); + if (tags != g_assemblyGraph->m_nodeTags.end()) { + if (auto tag = gfa::getTag(m_tagName.c_str(), tags->second)) { + std::stringstream stream; + stream << *tag; + return m_allTags.at(stream.str()); + } + } + + return {}; +} + +void TagValueNodeColorer::reset() { + m_allTags.clear(); + m_tagNames.clear(); + + // Collect all tags and their corresponding values + for (const auto &entry : g_assemblyGraph->m_nodeTags) { + for (const auto &tag: entry.second) { + std::stringstream stream; + stream << tag; + std::string tagWithValue = stream.str(); + std::string tagName{std::string_view(tag.name, 2)}; + m_allTags.insert(tagWithValue, QColor()); + m_tagNames.insert(tagName); + } + } + + // Assign colors + for (const auto &tagName : m_tagNames) { + auto tagRange = m_allTags.equal_prefix_range(tagName); + size_t sz = std::distance(tagRange.first, tagRange.second), i = 0; + for (auto it = tagRange.first; it != tagRange.second; ++it) { + *it = tinycolormap::GetColor(double(i) / double(sz), + colorMap(g_settings->colorMap)).ConvertToQColor(); + i += 1; + } + } + + if (!m_tagNames.empty()) + m_tagName = *m_tagNames.begin(); +} \ No newline at end of file diff --git a/graph/nodecolorer.h b/graph/nodecolorer.h index f0dd036e..5a3dbf32 100644 --- a/graph/nodecolorer.h +++ b/graph/nodecolorer.h @@ -32,7 +32,8 @@ enum NodeColorScheme : int { CONTIGUITY_COLOUR = 4, CUSTOM_COLOURS = 5, GC_CONTENT = 6, - LAST_SCHEME = GC_CONTENT + TAG_VALUE = 7, + LAST_SCHEME = TAG_VALUE }; class INodeColorer { diff --git a/graph/nodecolorers.h b/graph/nodecolorers.h new file mode 100644 index 00000000..ca2dc3ec --- /dev/null +++ b/graph/nodecolorers.h @@ -0,0 +1,107 @@ +// Copyright 2022 Anton Korobeynikov + +// This file is part of Bandage + +// Bandage 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. + +// Bandage 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 Bandage. If not, see . + +#pragma once + +#include "nodecolorer.h" + +#include +#include +#include + +class DepthNodeColorer : public INodeColorer { +public: + using INodeColorer::INodeColorer; + + QColor get(const GraphicsItemNode *node) override; + [[nodiscard]] const char* name() const override { return "Color by depth"; }; +}; + +class UniformNodeColorer : public INodeColorer { +public: + using INodeColorer::INodeColorer; + + QColor get(const GraphicsItemNode *node) override; + [[nodiscard]] const char* name() const override { return "Uniform color"; }; +}; + +class RandomNodeColorer : public INodeColorer { +public: + using INodeColorer::INodeColorer; + + QColor get(const GraphicsItemNode *node) override; + [[nodiscard]] std::pair get(const GraphicsItemNode *node, + const GraphicsItemNode *rcNode) override; + [[nodiscard]] const char* name() const override { return "Random colors"; }; +}; + +class GrayNodeColorer : public INodeColorer { +public: + using INodeColorer::INodeColorer; + + QColor get(const GraphicsItemNode *node) override; + [[nodiscard]] const char* name() const override { return "Gray colors"; }; +}; + +class CustomNodeColorer : public INodeColorer { +public: + using INodeColorer::INodeColorer; + + QColor get(const GraphicsItemNode *node) override; + [[nodiscard]] const char* name() const override { return "Custom colors"; }; +}; + +class ContiguityNodeColorer : public INodeColorer { +public: + using INodeColorer::INodeColorer; + + QColor get(const GraphicsItemNode *node) override; + [[nodiscard]] const char* name() const override { return "Color by contiguity"; }; +}; + +class GCNodeColorer : public INodeColorer { +public: + using INodeColorer::INodeColorer; + + QColor get(const GraphicsItemNode *node) override; + [[nodiscard]] const char* name() const override { return "Color by GC content"; }; +}; + +class TagValueNodeColorer : public INodeColorer { +public: + explicit TagValueNodeColorer(NodeColorScheme scheme) + : INodeColorer(scheme) { + if (m_graph) + TagValueNodeColorer::reset(); + } + + QColor get(const GraphicsItemNode *node) override; + void reset() override; + [[nodiscard]] const char* name() const override { return "Color by tag value"; }; + + void setTagName(const std::string &tagName) { m_tagName = tagName; } + [[nodiscard]] auto tagNames() const { + std::vector names(m_tagNames.begin(), m_tagNames.end()); + std::sort(names.begin(), names.end()); + return names; + } + +private: + std::string m_tagName; + tsl::htrie_map m_allTags; + std::unordered_set m_tagNames; +}; diff --git a/ui/mainwindow.cpp b/ui/mainwindow.cpp index 0db5e1d2..ed9f1a55 100644 --- a/ui/mainwindow.cpp +++ b/ui/mainwindow.cpp @@ -66,7 +66,7 @@ #include "graphinfodialog.h" #include "graph/sequenceutils.hpp" #include "graph/assemblygraphbuilder.h" -#include "graph/nodecolorer.h" +#include "graph/nodecolorers.h" MainWindow::MainWindow(QString fileToLoadOnStartup, bool drawGraphAfterLoad) : QMainWindow(nullptr), @@ -145,6 +145,7 @@ MainWindow::MainWindow(QString fileToLoadOnStartup, bool drawGraphAfterLoad) : connect(ui->actionCopy_selected_node_path_to_clipboard, SIGNAL(triggered(bool)), this, SLOT(copySelectedPathToClipboard())); connect(ui->actionSave_selected_node_path_to_FASTA, SIGNAL(triggered(bool)), this, SLOT(saveSelectedPathToFile())); connect(ui->coloursComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(switchColourScheme())); + connect(ui->tagsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(switchTagValue())); connect(ui->actionSave_image_current_view, SIGNAL(triggered()), this, SLOT(saveImageCurrentView())); connect(ui->actionSave_image_entire_scene, SIGNAL(triggered()), this, SLOT(saveImageEntireScene())); connect(ui->nodeCustomLabelsCheckBox, SIGNAL(toggled(bool)), this, SLOT(setTextDisplaySettings())); @@ -392,8 +393,8 @@ void MainWindow::loadGraph(QString fullFileName) // If the graph has custom colours, automatically switch the colour scheme to custom colours. if (customColours) { - if (ui->coloursComboBox->currentIndex() != 6) - ui->coloursComboBox->setCurrentIndex(6); + if (ui->coloursComboBox->currentIndex() != CUSTOM_COLOURS) + ui->coloursComboBox->setCurrentIndex(CUSTOM_COLOURS); else switchColourScheme(); } @@ -1133,6 +1134,13 @@ void MainWindow::resetAllNodeColours() { g_graphicsView->viewport()->update(); } +void MainWindow::switchTagValue() { + auto *colorer = dynamic_cast(&*g_settings->nodeColorer); + colorer->setTagName(ui->tagsComboBox->currentText().toStdString()); + + resetAllNodeColours(); +} + void MainWindow::switchColourScheme() { NodeColorScheme scheme = (NodeColorScheme)ui->coloursComboBox->currentIndex(); @@ -1140,6 +1148,18 @@ void MainWindow::switchColourScheme() ui->contiguityButton->setVisible(scheme == CONTIGUITY_COLOUR); ui->contiguityInfoText->setVisible(scheme == CONTIGUITY_COLOUR); + if (scheme == TAG_VALUE) { + ui->tagsComboBox->clear(); + auto *colorer = dynamic_cast(&*g_settings->nodeColorer); + auto tagNames = colorer->tagNames(); + for (const auto &tag : tagNames) + ui->tagsComboBox->addItem(tag.c_str()); + colorer->setTagName(tagNames.front()); + ui->tagsComboBox->setVisible(true); + } else { + ui->tagsComboBox->setVisible(false); + } + resetAllNodeColours(); } diff --git a/ui/mainwindow.h b/ui/mainwindow.h index bf3108e2..5a601c8e 100644 --- a/ui/mainwindow.h +++ b/ui/mainwindow.h @@ -115,6 +115,7 @@ private slots: void copySelectedPathToClipboard(); void saveSelectedPathToFile(); void switchColourScheme(); + void switchTagValue(); void determineContiguityFromSelectedNode(); void saveImageCurrentView(); void saveImageEntireScene(); diff --git a/ui/mainwindow.ui b/ui/mainwindow.ui index 04cafe2b..35feba72 100644 --- a/ui/mainwindow.ui +++ b/ui/mainwindow.ui @@ -58,9 +58,9 @@ 0 - -644 + -322 283 - 1487 + 1486 @@ -864,52 +864,51 @@ 0 - - - - - 0 - 0 - - - - - 16 - 16 - - - - - - - - - 0 - 0 - - - - - 16 - 16 - - - - - - - - - 0 - 0 - - - - - 16 - 16 - + + + + Qt::StrongFocus + + + Gray color + + + + + Random colours + + + + + Uniform colour + + + + + Colour by depth + + + + + Colour by contiguity + + + + + Custom colours + + + + + GC content + + + + + Colour by GFA tag + + @@ -956,60 +955,56 @@ - - - - Qt::StrongFocus + + + + + 0 + 0 + + + + + 16 + 16 + - - - Gray color - - - - - Random colours - - - - - Uniform colour - - - - - Colour by depth - - - - - Colour by contiguity - - - - - Custom colours - - - - - GC content - - - - - - Zoom: + + + + + 0 + 0 + - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 16 + 16 + - - + + + + + 0 + 0 + + + + + 16 + 16 + + + + + + 0 @@ -1068,6 +1063,23 @@ + + + + Zoom: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::StrongFocus + + +
diff --git a/ui/settingsdialog.cpp b/ui/settingsdialog.cpp index c5634f9e..15ec8d4f 100644 --- a/ui/settingsdialog.cpp +++ b/ui/settingsdialog.cpp @@ -260,6 +260,7 @@ void SettingsDialog::loadOrSaveSettingsToOrFromWidgets(bool setWidgets, Settings settings->nodeLengthMode = MANUAL_NODE_LENGTH; settings->positionTextNodeCentre = ui->positionCentreRadioButton->isChecked(); settings->colorMap = ColorMap(ui->colorMapCombo->currentIndex()); + settings->nodeColorer->reset(); } }