scimesh 0.3.2
Headless CPU-only 3D software renderer for scientific mesh visualization
Loading...
Searching...
No Matches
colormap.cpp
Go to the documentation of this file.
1
3
4#include <scimesh/colormap.h>
5#include <algorithm>
6#include <stdexcept>
7#include <limits>
8
9namespace scimesh {
10
11// =========================================================================
12// ColorMap::sample
13// =========================================================================
14
15Color ColorMap::sample(float t) const {
16 if (colors.empty()) {
17 return Color{0.0f, 0.0f, 0.0f, 0.0f};
18 }
19 if (colors.size() == 1) {
20 return colors[0];
21 }
22
23 // Clamp t to [0, 1]
24 if (t < 0.0f) t = 0.0f;
25 if (t > 1.0f) t = 1.0f;
26
27 const size_t n = colors.size();
28 float idx = t * static_cast<float>(n - 1);
29 size_t lo = static_cast<size_t>(idx);
30 size_t hi = (lo + 1 < n) ? (lo + 1) : lo;
31 float frac = idx - static_cast<float>(lo);
32
33 const Color& cLo = colors[lo];
34 const Color& cHi = colors[hi];
35
36 return Color{
37 cLo.r + (cHi.r - cLo.r) * frac,
38 cLo.g + (cHi.g - cLo.g) * frac,
39 cLo.b + (cHi.b - cLo.b) * frac,
40 cLo.a + (cHi.a - cLo.a) * frac
41 };
42}
43
44// =========================================================================
45// Internal helpers
46// =========================================================================
47
48namespace {
49
54float percentile(const std::vector<float>& sorted_finite, float pct) {
55 if (sorted_finite.empty()) return NAN;
56 if (pct <= 0.0f) return sorted_finite.front();
57 if (pct >= 100.0f) return sorted_finite.back();
58
59 float pos = (pct / 100.0f) * static_cast<float>(sorted_finite.size() - 1);
60 size_t lo = static_cast<size_t>(pos);
61 size_t hi = (lo + 1 < sorted_finite.size()) ? (lo + 1) : lo;
62 float frac = pos - static_cast<float>(lo);
63 return sorted_finite[lo] + (sorted_finite[hi] - sorted_finite[lo]) * frac;
64}
65
68void collect_finite_sorted(const std::vector<float>& data,
69 std::vector<float>& out_sorted,
70 size_t& out_nan_count) {
71 out_sorted.clear();
72 out_nan_count = 0;
73 out_sorted.reserve(data.size());
74 for (const auto& v : data) {
75 if (std::isfinite(v)) {
76 out_sorted.push_back(v);
77 } else if (std::isnan(v) || std::isinf(v)) {
78 out_nan_count++;
79 }
80 }
81 std::sort(out_sorted.begin(), out_sorted.end());
82}
83
85void collect_finite_sorted_pooled(
86 const std::vector<std::vector<float>>& datasets,
87 std::vector<float>& out_sorted,
88 size_t& out_nan_count) {
89 out_sorted.clear();
90 out_nan_count = 0;
91 size_t total = 0;
92 for (const auto& d : datasets) total += d.size();
93 out_sorted.reserve(total);
94 for (const auto& data : datasets) {
95 for (const auto& v : data) {
96 if (std::isfinite(v)) {
97 out_sorted.push_back(v);
98 } else if (std::isnan(v) || std::isinf(v)) {
99 out_nan_count++;
100 }
101 }
102 }
103 std::sort(out_sorted.begin(), out_sorted.end());
104}
105
108struct RangeResult { float lo; float hi; };
109RangeResult resolve_range(const std::vector<float>& sorted_finite,
110 float vmin, float vmax,
111 float lo_pct, float hi_pct,
112 float& out_winsor_lo, float& out_winsor_hi) {
113 out_winsor_lo = NAN;
114 out_winsor_hi = NAN;
115
116 if (sorted_finite.empty()) {
117 // All NaN — fall back to [0, 1]
118 return {0.0f, 1.0f};
119 }
120
121 float raw_lo = sorted_finite.front();
122 float raw_hi = sorted_finite.back();
123
124 // Compute winsor cutoffs if requested
125 float ws_lo = raw_lo;
126 float ws_hi = raw_hi;
127
128 if (lo_pct > 0.0f && lo_pct < 100.0f) {
129 ws_lo = percentile(sorted_finite, lo_pct);
130 out_winsor_lo = ws_lo;
131 }
132 if (hi_pct > 0.0f && hi_pct < 100.0f) {
133 ws_hi = percentile(sorted_finite, hi_pct);
134 out_winsor_hi = ws_hi;
135 }
136
137 // Explicit vmin/vmax override winsorized bounds
138 bool explicit_lo = !std::isnan(vmin);
139 bool explicit_hi = !std::isnan(vmax);
140 float data_lo = explicit_lo ? vmin : ws_lo;
141 float data_hi = explicit_hi ? vmax : ws_hi;
142
143 // Clamp winsorized bounds to not exceed raw range (explicit user values are
144 // NOT clamped — users may want e.g. vmax=20 on data that only goes to 10,
145 // to show data on a fixed reference scale)
146 if (!explicit_lo && data_lo < raw_lo) data_lo = raw_lo;
147 if (!explicit_hi && data_hi > raw_hi) data_hi = raw_hi;
148
149 // Ensure hi > lo for constant data
150 if (data_hi <= data_lo) {
151 data_hi = data_lo + 1.0f;
152 }
153
154 return {data_lo, data_hi};
155}
156
158void map_dataset(const std::vector<float>& data,
159 const ColorMap& colormap,
160 float vmin, float vmax,
161 const Color& nan_color,
162 std::vector<Color>& out_colors) {
163 out_colors.clear();
164 out_colors.reserve(data.size());
165
166 if (data.empty()) return;
167
168 float range = vmax - vmin;
169 bool constant = (range <= 0.0f);
170
171 for (const auto& val : data) {
172 if (!std::isfinite(val)) {
173 out_colors.push_back(nan_color);
174 continue;
175 }
176
177 float t;
178 if (constant) {
179 t = 0.5f;
180 } else {
181 t = (val - vmin) / range;
182 if (t < 0.0f) t = 0.0f;
183 if (t > 1.0f) t = 1.0f;
184 }
185 out_colors.push_back(colormap.sample(t));
186 }
187}
188
189} // anonymous namespace
190
191// =========================================================================
192// ColorMap::viridis — built-in colormap
193// =========================================================================
194
196 // Official matplotlib viridis LUT (256 entries, float RGB).
197 static const float lut[] = {
198 0.267004f, 0.004874f, 0.329415f, 0.268510f, 0.009605f, 0.335427f,
199 0.269944f, 0.014625f, 0.341379f, 0.271305f, 0.019942f, 0.347269f,
200 0.272594f, 0.025563f, 0.353093f, 0.273809f, 0.031497f, 0.358853f,
201 0.274952f, 0.037752f, 0.364543f, 0.276022f, 0.044167f, 0.370164f,
202 0.277018f, 0.050344f, 0.375715f, 0.277941f, 0.056324f, 0.381191f,
203 0.278791f, 0.062145f, 0.386592f, 0.279566f, 0.067836f, 0.391917f,
204 0.280267f, 0.073417f, 0.397163f, 0.280894f, 0.078907f, 0.402329f,
205 0.281446f, 0.084320f, 0.407414f, 0.281924f, 0.089666f, 0.412415f,
206 0.282327f, 0.094955f, 0.417331f, 0.282656f, 0.100196f, 0.422160f,
207 0.282910f, 0.105393f, 0.426902f, 0.283091f, 0.110553f, 0.431554f,
208 0.283197f, 0.115680f, 0.436115f, 0.283229f, 0.120777f, 0.440584f,
209 0.283187f, 0.125848f, 0.444960f, 0.283072f, 0.130895f, 0.449241f,
210 0.282884f, 0.135920f, 0.453427f, 0.282623f, 0.140926f, 0.457517f,
211 0.282290f, 0.145912f, 0.461510f, 0.281887f, 0.150881f, 0.465405f,
212 0.281412f, 0.155834f, 0.469201f, 0.280868f, 0.160771f, 0.472899f,
213 0.280255f, 0.165693f, 0.476498f, 0.279574f, 0.170599f, 0.479997f,
214 0.278826f, 0.175490f, 0.483397f, 0.278012f, 0.180367f, 0.486697f,
215 0.277134f, 0.185228f, 0.489898f, 0.276194f, 0.190074f, 0.493001f,
216 0.275191f, 0.194905f, 0.496005f, 0.274128f, 0.199721f, 0.498911f,
217 0.273006f, 0.204520f, 0.501721f, 0.271828f, 0.209303f, 0.504434f,
218 0.270595f, 0.214069f, 0.507052f, 0.269308f, 0.218818f, 0.509577f,
219 0.267968f, 0.223549f, 0.512008f, 0.266580f, 0.228262f, 0.514349f,
220 0.265145f, 0.232956f, 0.516599f, 0.263663f, 0.237631f, 0.518762f,
221 0.262138f, 0.242286f, 0.520837f, 0.260571f, 0.246922f, 0.522828f,
222 0.258965f, 0.251537f, 0.524736f, 0.257322f, 0.256130f, 0.526563f,
223 0.255645f, 0.260703f, 0.528312f, 0.253935f, 0.265254f, 0.529983f,
224 0.252194f, 0.269783f, 0.531579f, 0.250425f, 0.274290f, 0.533103f,
225 0.248629f, 0.278775f, 0.534556f, 0.246811f, 0.283237f, 0.535941f,
226 0.244972f, 0.287675f, 0.537260f, 0.243113f, 0.292092f, 0.538516f,
227 0.241237f, 0.296485f, 0.539709f, 0.239346f, 0.300855f, 0.540844f,
228 0.237441f, 0.305202f, 0.541921f, 0.235526f, 0.309527f, 0.542944f,
229 0.233603f, 0.313828f, 0.543914f, 0.231674f, 0.318106f, 0.544834f,
230 0.229739f, 0.322361f, 0.545706f, 0.227802f, 0.326594f, 0.546532f,
231 0.225863f, 0.330805f, 0.547314f, 0.223925f, 0.334994f, 0.548053f,
232 0.221989f, 0.339161f, 0.548752f, 0.220057f, 0.343307f, 0.549413f,
233 0.218130f, 0.347432f, 0.550038f, 0.216210f, 0.351535f, 0.550627f,
234 0.214298f, 0.355619f, 0.551184f, 0.212395f, 0.359683f, 0.551710f,
235 0.210503f, 0.363727f, 0.552206f, 0.208623f, 0.367752f, 0.552675f,
236 0.206756f, 0.371758f, 0.553117f, 0.204903f, 0.375746f, 0.553533f,
237 0.203063f, 0.379716f, 0.553925f, 0.201239f, 0.383670f, 0.554294f,
238 0.199430f, 0.387607f, 0.554642f, 0.197636f, 0.391528f, 0.554969f,
239 0.195860f, 0.395433f, 0.555276f, 0.194100f, 0.399323f, 0.555565f,
240 0.192357f, 0.403199f, 0.555836f, 0.190631f, 0.407061f, 0.556089f,
241 0.188923f, 0.410910f, 0.556326f, 0.187231f, 0.414746f, 0.556547f,
242 0.185556f, 0.418570f, 0.556753f, 0.183898f, 0.422383f, 0.556944f,
243 0.182256f, 0.426184f, 0.557120f, 0.180629f, 0.429975f, 0.557282f,
244 0.179019f, 0.433756f, 0.557430f, 0.177423f, 0.437527f, 0.557565f,
245 0.175841f, 0.441290f, 0.557685f, 0.174274f, 0.445044f, 0.557792f,
246 0.172719f, 0.448791f, 0.557885f, 0.171176f, 0.452530f, 0.557965f,
247 0.169646f, 0.456262f, 0.558030f, 0.168126f, 0.459988f, 0.558082f,
248 0.166617f, 0.463708f, 0.558119f, 0.165117f, 0.467423f, 0.558141f,
249 0.163625f, 0.471133f, 0.558148f, 0.162142f, 0.474838f, 0.558140f,
250 0.160665f, 0.478540f, 0.558115f, 0.159194f, 0.482237f, 0.558073f,
251 0.157729f, 0.485932f, 0.558013f, 0.156270f, 0.489624f, 0.557936f,
252 0.154815f, 0.493313f, 0.557840f, 0.153364f, 0.497000f, 0.557724f,
253 0.151918f, 0.500685f, 0.557587f, 0.150476f, 0.504369f, 0.557430f,
254 0.149039f, 0.508051f, 0.557250f, 0.147607f, 0.511733f, 0.557049f,
255 0.146180f, 0.515413f, 0.556823f, 0.144759f, 0.519093f, 0.556572f,
256 0.143343f, 0.522773f, 0.556295f, 0.141935f, 0.526453f, 0.555991f,
257 0.140536f, 0.530132f, 0.555659f, 0.139147f, 0.533812f, 0.555298f,
258 0.137770f, 0.537492f, 0.554906f, 0.136408f, 0.541173f, 0.554483f,
259 0.135066f, 0.544853f, 0.554029f, 0.133743f, 0.548535f, 0.553541f,
260 0.132444f, 0.552216f, 0.553018f, 0.131172f, 0.555899f, 0.552459f,
261 0.129933f, 0.559582f, 0.551864f, 0.128729f, 0.563265f, 0.551229f,
262 0.127568f, 0.566949f, 0.550556f, 0.126453f, 0.570633f, 0.549841f,
263 0.125394f, 0.574318f, 0.549086f, 0.124395f, 0.578002f, 0.548287f,
264 0.123463f, 0.581687f, 0.547445f, 0.122606f, 0.585371f, 0.546557f,
265 0.121831f, 0.589055f, 0.545623f, 0.121148f, 0.592739f, 0.544641f,
266 0.120565f, 0.596422f, 0.543611f, 0.120092f, 0.600104f, 0.542530f,
267 0.119738f, 0.603785f, 0.541400f, 0.119512f, 0.607464f, 0.540218f,
268 0.119423f, 0.611141f, 0.538982f, 0.119483f, 0.614817f, 0.537692f,
269 0.119699f, 0.618490f, 0.536347f, 0.120081f, 0.622161f, 0.534946f,
270 0.120638f, 0.625828f, 0.533488f, 0.121380f, 0.629492f, 0.531973f,
271 0.122312f, 0.633153f, 0.530398f, 0.123444f, 0.636809f, 0.528763f,
272 0.124780f, 0.640461f, 0.527068f, 0.126326f, 0.644107f, 0.525311f,
273 0.128087f, 0.647749f, 0.523491f, 0.130067f, 0.651384f, 0.521608f,
274 0.132268f, 0.655014f, 0.519661f, 0.134692f, 0.658636f, 0.517649f,
275 0.137339f, 0.662252f, 0.515571f, 0.140210f, 0.665859f, 0.513427f,
276 0.143303f, 0.669459f, 0.511215f, 0.146616f, 0.673050f, 0.508936f,
277 0.150148f, 0.676631f, 0.506589f, 0.153894f, 0.680203f, 0.504172f,
278 0.157851f, 0.683765f, 0.501686f, 0.162016f, 0.687316f, 0.499129f,
279 0.166383f, 0.690856f, 0.496502f, 0.170948f, 0.694384f, 0.493803f,
280 0.175707f, 0.697900f, 0.491033f, 0.180653f, 0.701402f, 0.488189f,
281 0.185783f, 0.704891f, 0.485273f, 0.191090f, 0.708366f, 0.482284f,
282 0.196571f, 0.711827f, 0.479221f, 0.202219f, 0.715272f, 0.476084f,
283 0.208030f, 0.718701f, 0.472873f, 0.214000f, 0.722114f, 0.469588f,
284 0.220124f, 0.725509f, 0.466226f, 0.226397f, 0.728888f, 0.462789f,
285 0.232815f, 0.732247f, 0.459277f, 0.239374f, 0.735588f, 0.455688f,
286 0.246070f, 0.738910f, 0.452024f, 0.252899f, 0.742211f, 0.448284f,
287 0.259857f, 0.745492f, 0.444467f, 0.266941f, 0.748751f, 0.440573f,
288 0.274149f, 0.751988f, 0.436601f, 0.281477f, 0.755203f, 0.432552f,
289 0.288921f, 0.758394f, 0.428426f, 0.296479f, 0.761561f, 0.424223f,
290 0.304148f, 0.764704f, 0.419943f, 0.311925f, 0.767822f, 0.415586f,
291 0.319809f, 0.770914f, 0.411152f, 0.327796f, 0.773980f, 0.406640f,
292 0.335885f, 0.777018f, 0.402049f, 0.344074f, 0.780029f, 0.397381f,
293 0.352360f, 0.783011f, 0.392636f, 0.360741f, 0.785964f, 0.387814f,
294 0.369214f, 0.788888f, 0.382914f, 0.377779f, 0.791781f, 0.377939f,
295 0.386433f, 0.794644f, 0.372886f, 0.395174f, 0.797475f, 0.367757f,
296 0.404001f, 0.800275f, 0.362552f, 0.412913f, 0.803041f, 0.357269f,
297 0.421908f, 0.805774f, 0.351910f, 0.430983f, 0.808473f, 0.346476f,
298 0.440137f, 0.811138f, 0.340967f, 0.449368f, 0.813768f, 0.335384f,
299 0.458674f, 0.816363f, 0.329727f, 0.468053f, 0.818921f, 0.323998f,
300 0.477504f, 0.821444f, 0.318195f, 0.487026f, 0.823929f, 0.312321f,
301 0.496615f, 0.826376f, 0.306377f, 0.506271f, 0.828786f, 0.300362f,
302 0.515992f, 0.831158f, 0.294279f, 0.525776f, 0.833491f, 0.288127f,
303 0.535621f, 0.835785f, 0.281908f, 0.545524f, 0.838039f, 0.275626f,
304 0.555484f, 0.840254f, 0.269281f, 0.565498f, 0.842430f, 0.262877f,
305 0.575563f, 0.844566f, 0.256415f, 0.585678f, 0.846661f, 0.249897f,
306 0.595839f, 0.848717f, 0.243329f, 0.606045f, 0.850733f, 0.236712f,
307 0.616293f, 0.852709f, 0.230052f, 0.626579f, 0.854645f, 0.223353f,
308 0.636902f, 0.856542f, 0.216620f, 0.647257f, 0.858400f, 0.209861f,
309 0.657642f, 0.860219f, 0.203082f, 0.668054f, 0.861999f, 0.196293f,
310 0.678489f, 0.863742f, 0.189503f, 0.688944f, 0.865448f, 0.182725f,
311 0.699415f, 0.867117f, 0.175971f, 0.709898f, 0.868751f, 0.169257f,
312 0.720391f, 0.870350f, 0.162603f, 0.730889f, 0.871916f, 0.156029f,
313 0.741388f, 0.873449f, 0.149561f, 0.751884f, 0.874951f, 0.143228f,
314 0.762373f, 0.876424f, 0.137064f, 0.772852f, 0.877868f, 0.131109f,
315 0.783315f, 0.879285f, 0.125405f, 0.793760f, 0.880678f, 0.120005f,
316 0.804182f, 0.882046f, 0.114965f, 0.814576f, 0.883393f, 0.110347f,
317 0.824940f, 0.884720f, 0.106217f, 0.835270f, 0.886029f, 0.102646f,
318 0.845561f, 0.887322f, 0.099702f, 0.855810f, 0.888601f, 0.097452f,
319 0.866013f, 0.889868f, 0.095953f, 0.876168f, 0.891125f, 0.095250f,
320 0.886271f, 0.892374f, 0.095374f, 0.896320f, 0.893616f, 0.096335f,
321 0.906311f, 0.894855f, 0.098125f, 0.916242f, 0.896091f, 0.100717f,
322 0.926106f, 0.897330f, 0.104071f, 0.935904f, 0.898570f, 0.108131f,
323 0.945636f, 0.899815f, 0.112838f, 0.955300f, 0.901065f, 0.118128f,
324 0.964894f, 0.902323f, 0.123941f, 0.974417f, 0.903590f, 0.130215f,
325 0.983868f, 0.904867f, 0.136897f, 0.993248f, 0.906157f, 0.143936f
326 };
327
328 static ColorMap cmap = []() {
329 ColorMap m;
330 m.colors.reserve(256);
331 for (int i = 0; i < 256; i++) {
332 m.colors.emplace_back(
333 lut[i * 3 + 0], lut[i * 3 + 1], lut[i * 3 + 2], 1.0f);
334 }
335 return m;
336 }();
337
338 return cmap;
339}
340
341// =========================================================================
342// apply_colormap — single dataset
343// =========================================================================
344
346 const std::vector<float>& data,
347 const ColorMap& colormap,
348 float vmin,
349 float vmax,
350 const Color& nan_color,
351 float lo_pct,
352 float hi_pct) {
353
354 ApplyColormapResult result;
355
356 // Validate inputs
357 if (colormap.empty()) {
358 throw std::invalid_argument("apply_colormap: colormap must not be empty");
359 }
360 if (lo_pct < 0.0f || lo_pct > 100.0f) {
361 throw std::invalid_argument("apply_colormap: lo_pct must be in [0, 100]");
362 }
363 if (hi_pct < 0.0f || hi_pct > 100.0f) {
364 throw std::invalid_argument("apply_colormap: hi_pct must be in [0, 100]");
365 }
366 if (lo_pct >= hi_pct && (lo_pct > 0.0f || hi_pct < 100.0f)) {
367 throw std::invalid_argument("apply_colormap: lo_pct must be less than hi_pct");
368 }
369
370 // Collect finite values
371 std::vector<float> sorted_finite;
372 collect_finite_sorted(data, sorted_finite, result.nan_count);
373
374 if (!sorted_finite.empty()) {
375 result.raw_min = sorted_finite.front();
376 result.raw_max = sorted_finite.back();
377 }
378
379 // Resolve effective range
380 auto range = resolve_range(sorted_finite, vmin, vmax,
381 lo_pct, hi_pct,
382 result.winsor_lo, result.winsor_hi);
383 result.data_min = range.lo;
384 result.data_max = range.hi;
385
386 // Map
387 map_dataset(data, colormap, result.data_min, result.data_max,
388 nan_color, result.colors);
389
390 return result;
391}
392
393// =========================================================================
394// apply_colormap — multi-dataset
395// =========================================================================
396
398 const std::vector<std::vector<float>>& datasets,
399 const ColorMap& colormap,
400 float vmin,
401 float vmax,
402 const Color& nan_color,
403 float lo_pct,
404 float hi_pct,
405 bool global_range) {
406
408
409 // Validate
410 if (colormap.empty()) {
411 throw std::invalid_argument("apply_colormap: colormap must not be empty");
412 }
413 if (datasets.empty()) {
414 return result;
415 }
416 if (lo_pct < 0.0f || lo_pct > 100.0f) {
417 throw std::invalid_argument("apply_colormap: lo_pct must be in [0, 100]");
418 }
419 if (hi_pct < 0.0f || hi_pct > 100.0f) {
420 throw std::invalid_argument("apply_colormap: hi_pct must be in [0, 100]");
421 }
422 if (lo_pct >= hi_pct && (lo_pct > 0.0f || hi_pct < 100.0f)) {
423 throw std::invalid_argument("apply_colormap: lo_pct must be less than hi_pct");
424 }
425
426 // --- Pooled statistics (always computed) ---
427 {
428 std::vector<float> pooled_sorted;
429 collect_finite_sorted_pooled(datasets, pooled_sorted,
430 result.total_nan_count);
431 if (!pooled_sorted.empty()) {
432 result.pooled_raw_min = pooled_sorted.front();
433 result.pooled_raw_max = pooled_sorted.back();
434 }
435
436 auto pooled_range = resolve_range(pooled_sorted, vmin, vmax,
437 lo_pct, hi_pct,
438 result.pooled_winsor_lo,
439 result.pooled_winsor_hi);
440 result.pooled_data_min = pooled_range.lo;
441 result.pooled_data_max = pooled_range.hi;
442 }
443
444 // --- Per-dataset mapping ---
445 result.per_dataset.reserve(datasets.size());
446
447 for (const auto& data : datasets) {
448 ApplyColormapResult ds_result;
449
450 std::vector<float> sorted_finite;
451 collect_finite_sorted(data, sorted_finite, ds_result.nan_count);
452
453 if (!sorted_finite.empty()) {
454 ds_result.raw_min = sorted_finite.front();
455 ds_result.raw_max = sorted_finite.back();
456 }
457
458 if (global_range || !std::isnan(vmin) || !std::isnan(vmax)) {
459 // Use pooled (or explicit) range for all datasets
460 ds_result.data_min = result.pooled_data_min;
461 ds_result.data_max = result.pooled_data_max;
462 ds_result.winsor_lo = result.pooled_winsor_lo;
463 ds_result.winsor_hi = result.pooled_winsor_hi;
464 } else {
465 // Independent per-dataset range
466 auto range = resolve_range(sorted_finite, vmin, vmax,
467 lo_pct, hi_pct,
468 ds_result.winsor_lo,
469 ds_result.winsor_hi);
470 ds_result.data_min = range.lo;
471 ds_result.data_max = range.hi;
472 }
473
474 map_dataset(data, colormap, ds_result.data_min, ds_result.data_max,
475 nan_color, ds_result.colors);
476
477 result.per_dataset.push_back(std::move(ds_result));
478 }
479
480 return result;
481}
482
483} // namespace scimesh
float lo
Definition colormap.cpp:108
float hi
Definition colormap.cpp:108
Colormap data structure and data-to-color mapping utilities.
ApplyColormapResult apply_colormap(const std::vector< float > &data, const ColorMap &colormap, float vmin, float vmax, const Color &nan_color, float lo_pct, float hi_pct)
Map a single vector of numeric data to RGBA colours using a colormap.
Definition colormap.cpp:345
Result of apply_colormap() for a single dataset.
Definition colormap.h:187
float data_min
The actual data range used for mapping (after winsorizing, or as explicitly set).
Definition colormap.h:194
std::vector< Color > colors
Per-element RGBA colours, same order and length as the input data vector.
Definition colormap.h:190
float raw_max
Raw finite maximum of the input data (before winsorizing).
Definition colormap.h:206
float data_max
The actual data range used for mapping (after winsorizing, or as explicitly set).
Definition colormap.h:198
size_t nan_count
Number of NaN / Inf values in the input data.
Definition colormap.h:217
float winsor_hi
Upper percentile cutoff used for winsorizing.
Definition colormap.h:214
float winsor_lo
Lower percentile cutoff used for winsorizing.
Definition colormap.h:210
float raw_min
Raw finite minimum of the input data (before winsorizing).
Definition colormap.h:202
Self-contained colormap — owns a colour lookup table and supports linearly interpolated sampling.
Definition colormap.h:79
bool empty() const
True if the colormap has no entries.
Definition colormap.h:103
static const ColorMap & viridis()
The Viridis perceptually-uniform sequential colormap (256 entries).
Definition colormap.cpp:195
Color sample(float t) const
Sample the colormap at a normalized position using linear interpolation.
Definition colormap.cpp:15
std::vector< Color > colors
The colour lookup table entries in [0, 1] float RGBA.
Definition colormap.h:81
An RGBA color with floating-point components.
Definition types.h:88
float g
Green channel, [0, 1].
Definition types.h:90
float r
Red channel, [0, 1].
Definition types.h:89
float b
Blue channel, [0, 1].
Definition types.h:91
float a
Alpha (opacity) channel, [0, 1]. 1.0 = fully opaque.
Definition types.h:92
Aggregate result of apply_colormap() for multiple datasets.
Definition colormap.h:231
float pooled_data_max
Pooled effective data range (post-winsorizing) across all datasets.
Definition colormap.h:241
float pooled_winsor_hi
Pooled upper percentile cutoff.
Definition colormap.h:253
size_t total_nan_count
Total number of NaN / Inf values across all datasets.
Definition colormap.h:256
float pooled_winsor_lo
Pooled lower percentile cutoff.
Definition colormap.h:250
std::vector< ApplyColormapResult > per_dataset
One result per input dataset, in the same order.
Definition colormap.h:233
float pooled_raw_max
Pooled raw finite maximum across all datasets.
Definition colormap.h:247
float pooled_data_min
Pooled effective data range (post-winsorizing) across all datasets.
Definition colormap.h:237
float pooled_raw_min
Pooled raw finite minimum across all datasets.
Definition colormap.h:244