diff --git a/SimoxUtility/CMakeLists.txt b/SimoxUtility/CMakeLists.txt
index 81e193c2933f7e3ab47eef53db83a619935dac27..c0e2539f397d1333ac1441216c7eac6d03a38f6f 100644
--- a/SimoxUtility/CMakeLists.txt
+++ b/SimoxUtility/CMakeLists.txt
@@ -93,6 +93,7 @@ SET(INCLUDES
     algorithm/for_each_if.h
     algorithm/apply.hpp
     algorithm/get_map_keys_values.h
+    algorithm/minmax.h
     algorithm/string/string_tools.h
     algorithm/string/string_conversion.h
     algorithm/string/string_conversion_eigen.h
diff --git a/SimoxUtility/algorithm.h b/SimoxUtility/algorithm.h
index 53e55e3b48d89ff17a21649b83f055116f6699c2..e8217b97bca1c0b684dbe4c62dd1911271b507f0 100644
--- a/SimoxUtility/algorithm.h
+++ b/SimoxUtility/algorithm.h
@@ -4,4 +4,5 @@
 
 #include "algorithm/for_each_if.h"
 #include "algorithm/get_map_keys_values.h"
+#include "algorithm/minmax.h"
 #include "algorithm/string.h"
diff --git a/SimoxUtility/algorithm/minmax.h b/SimoxUtility/algorithm/minmax.h
new file mode 100644
index 0000000000000000000000000000000000000000..c4347ed8e2806d17024eb06cbb750cae88d8aca3
--- /dev/null
+++ b/SimoxUtility/algorithm/minmax.h
@@ -0,0 +1,43 @@
+#pragma once
+
+#include <algorithm>
+#include <functional>
+#include <vector>
+
+
+namespace simox::alg
+{
+
+    /// Return a function comparing the results of applying `unaryFunc` to values of type `T`.
+    template <class T, class Scalar>
+    std::function<bool(const T&, const T&)> get_compare_fn(const std::function<Scalar(const T&)> unaryFunc)
+    {
+        return [unaryFunc](const auto& lhs, const auto& rhs)
+        {
+            return unaryFunc(lhs) < unaryFunc(rhs);
+        };
+    }
+
+    /// @brief Get the maximum of applying `unaryFunc` to `values`.
+    template <class T, class Scalar>
+    Scalar min(const std::vector<T>& values, std::function<Scalar(const T&)> unaryFunc)
+    {
+        return unaryFunc(*std::min_element(values.begin(), values.end(), get_compare_fn(unaryFunc)));
+    }
+
+    /// @brief Get the maximum of applying `unaryFunc` to `values`
+    template <class T, class Scalar>
+    Scalar max(const std::vector<T>& values, std::function<Scalar(const T&)> unaryFunc)
+    {
+        return unaryFunc(*std::max_element(values.begin(), values.end(), get_compare_fn(unaryFunc)));
+    }
+
+    /// @brief Get minimum and maximum of applying `unaryFunc` to `values`
+    template <class T, class Scalar>
+    std::pair<Scalar, Scalar> minmax(const std::vector<T>& values, std::function<Scalar(const T&)> unaryFunc)
+    {
+        const auto [min, max] = std::minmax_element(values.begin(), values.end(), get_compare_fn(unaryFunc));
+        return std::make_pair(*min, *max);
+    }
+
+}
diff --git a/SimoxUtility/color/ColorMap.h b/SimoxUtility/color/ColorMap.h
index ebead5ddaaa6a4e9cc8651651ecd08b054e3bce8..2cb6bdcd6333d127f78abf3969b1801ae1625129 100644
--- a/SimoxUtility/color/ColorMap.h
+++ b/SimoxUtility/color/ColorMap.h
@@ -1,11 +1,13 @@
 #pragma once
 
 #include <algorithm>
+#include <functional>
 #include <initializer_list>
 #include <map>
 #include <string>
 
 #include <SimoxUtility/algorithm/apply.hpp>
+#include <SimoxUtility/algorithm/minmax.h>
 
 #include "Color.h"
 #include "interpolation.h"
@@ -78,6 +80,24 @@ namespace simox::color
         void set_vmax(float vmax) { this->_vmax = vmax; }
         void set_vmin(const std::vector<float>& values) { set_vmin(*std::max_element(values.begin(), values.end())); }
         void set_vmax(const std::vector<float>& values) { set_vmax(*std::max_element(values.begin(), values.end())); }
+        /**
+         * @brief Set the value minimum to the minimum of `values`, measured by `unaryFunc`.
+         * You may have to specify the template argument (when template argument deduction fails).
+         */
+        template <class T>
+        void set_vmin(const std::vector<T>& values, std::function<float(const T&)> unaryFunc)
+        {
+            set_vmax(simox::alg::min(values, unaryFunc));
+        }
+        /**
+         * @brief Set the value maximum to the maximum of `values`, measured by `unaryFunc`.
+         * You may have to specify the template argument (when template argument deduction fails).
+         */
+        template <class T>
+        void set_vmax(const std::vector<T>& values, std::function<float(const T&)> unaryFunc)
+        {
+            set_vmax(simox::alg::max(values, unaryFunc));
+        }
 
         /// Sets the value limits, i.e. scales the color map to the range [vmin, vmax].
         void set_vlimits(float vmin, float vmax)
@@ -91,9 +111,20 @@ namespace simox::color
             set_vmin(*min);
             set_vmax(*max);
         }
+        /**
+         * @brief Set the value minimum and maximum to the minimum and maximum of `values`, measured by `unaryFunc`.
+         * You may have to specify the template argument (when template argument deduction fails).
+         */
+        template <class T>
+        void set_vlimits(const std::vector<T>& values, std::function<float(const T&)> unaryFunc)
+        {
+            const auto [min, max] = simox::alg::minmax(simox::alg::min(values, unaryFunc));
+            set_vmin(unaryFunc(min));
+            set_vmax(unaryFunc(max));
+        }
 
 
-        /// Get this colormap reversed (but defined in the same value range as this).
+        /// Get this colormap reversed (but defined in the same value range as `*this`).
         ColorMap reversed() const;