File indexing completed on 2025-01-30 09:32:37
0001
0002
0003
0004
0005
0006
0007
0008
0009 #pragma once
0010
0011 #include <algorithm>
0012 #include <string>
0013 #include <utility>
0014 #include <vector>
0015
0016 #include "actsvg/core.hpp"
0017 #include "actsvg/proto/cluster.hpp"
0018
0019 namespace actsvg {
0020
0021 using namespace defaults;
0022
0023 namespace display {
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038 template <size_t DIM>
0039 static inline std::pair<svg::object, svg::object> cluster(
0040 const svg::object& grid_, const std::string& id_,
0041 const proto::cluster<DIM>& cluster_,
0042 const style::fill& fill_low_ = style::fill{style::color{{255, 255, 0}}},
0043 const style::fill& fill_high_ = style::fill{style::color{{250, 0, 0}}},
0044 const style::fill& fill_m_ = style::fill{style::color{{0, 0, 255}}},
0045 const std::array<unsigned int, 2>& expand_ = {2, 2}) {
0046
0047 svg::object cluster_group;
0048 cluster_group._tag = "g";
0049 cluster_group._id = id_;
0050
0051
0052 unsigned int i_min = std::numeric_limits<unsigned int>::max();
0053 unsigned int i_max = std::numeric_limits<unsigned int>::min();
0054 unsigned int j_min = std::numeric_limits<unsigned int>::max();
0055 unsigned int j_max = std::numeric_limits<unsigned int>::min();
0056
0057
0058 scalar low_data = std::numeric_limits<scalar>::max();
0059 scalar high_data = std::numeric_limits<scalar>::lowest();
0060
0061 for (const auto& c : cluster_._channels) {
0062 low_data = std::min(low_data, c._data);
0063 high_data = std::max(high_data, c._data);
0064 }
0065
0066 scalar delta_data = high_data - low_data;
0067
0068 int low_r = fill_low_._fc._rgb[0];
0069 int low_g = fill_low_._fc._rgb[1];
0070 int low_b = fill_low_._fc._rgb[2];
0071 int delta_r = (fill_high_._fc._rgb[0] - low_r);
0072 int delta_g = (fill_high_._fc._rgb[1] - low_g);
0073 int delta_b = (fill_high_._fc._rgb[2] - low_b);
0074
0075
0076 scalar t_x = 0.;
0077 scalar t_y = 0.;
0078 scalar t_r = 0.;
0079 scalar t_phi = 0.;
0080
0081 scalar m_x = 0.;
0082 scalar m_y = 0.;
0083 scalar m_r = 0.;
0084 scalar m_phi = 0.;
0085
0086 scalar d_r = 0.;
0087 scalar d_phi = 0.;
0088
0089 scalar c_x = 0.;
0090 scalar c_y = 0.;
0091 scalar c_r = 0.;
0092
0093 std::array<scalar, 2> x_range = {std::numeric_limits<scalar>::max(),
0094 std::numeric_limits<scalar>::lowest()};
0095 std::array<scalar, 2> y_range = x_range;
0096 std::array<scalar, 2> r_range = x_range;
0097 std::array<scalar, 2> phi_range = x_range;
0098
0099
0100
0101
0102 auto generate_fill =
0103 [&](const proto::channel<DIM>& channel_) -> style::fill {
0104
0105 scalar rel_delta_data = (channel_._data - low_data) / delta_data;
0106
0107 int ch_r = low_r + rel_delta_data * delta_r;
0108 int ch_g = low_g + rel_delta_data * delta_g;
0109 int ch_b = low_b + rel_delta_data * delta_b;
0110
0111 return style::fill{style::color{{ch_r, ch_g, ch_b}}};
0112 };
0113
0114 if constexpr (DIM == 2) {
0115
0116 if (cluster_._type == proto::cluster<DIM>::e_polar) {
0117
0118 m_r = cluster_._measurement[DIM - 2];
0119 m_phi = cluster_._measurement[DIM - 1];
0120
0121 d_r = cluster_._variance[DIM - 2];
0122 d_phi = cluster_._variance[DIM - 1];
0123
0124 t_r = cluster_._measurement[DIM - 2];
0125 t_phi = cluster_._measurement[DIM - 1];
0126
0127 } else {
0128
0129 m_x = cluster_._measurement[DIM - 2];
0130 m_y = cluster_._measurement[DIM - 1];
0131 c_x = cluster_._variance[DIM - 2];
0132 c_y = cluster_._variance[DIM - 1];
0133 t_x = cluster_._truth[DIM - 2];
0134 t_y = cluster_._truth[DIM - 1];
0135
0136
0137 scalar corr = cluster_._correlation;
0138 corr = corr < -1. ? -1. : (corr > 1. ? 1. : corr);
0139 c_r = -corr * 45;
0140 }
0141 }
0142
0143
0144 for (const auto& c : cluster_._channels) {
0145
0146 size_t i = 0;
0147 size_t j = 0;
0148
0149 if constexpr (DIM == 2) {
0150 i = c._cid[DIM - 2];
0151 j = c._cid[DIM - 1];
0152 }
0153
0154 if constexpr (DIM == 1) {
0155 if (cluster_._coords[DIM - 1] == proto::cluster<DIM>::e_r or
0156 cluster_._coords[DIM - 1] == proto::cluster<DIM>::e_x) {
0157 i = c._cid[DIM - 1];
0158 } else {
0159 j = c._cid[DIM - 1];
0160 }
0161 }
0162
0163 i_min = i < i_min ? i : i_min;
0164 i_max = i_max < i ? i : i_max;
0165 j_min = j < j_min ? j : j_min;
0166 j_max = j_max < j ? j : j_max;
0167
0168
0169
0170 std::string tile_id =
0171 grid_._id + "_" + std::to_string(i) + "_" + std::to_string(j);
0172 std::optional<svg::object> grid_tile = grid_.find_object(tile_id);
0173
0174 if (grid_tile.has_value()) {
0175
0176 svg::object tile = grid_tile.value();
0177
0178 x_range[0] = std::min(x_range[0], tile._x_range[0]);
0179 x_range[1] = std::max(x_range[1], tile._x_range[1]);
0180 y_range[0] = std::min(y_range[0], tile._y_range[0]);
0181 y_range[1] = std::max(y_range[1], tile._y_range[1]);
0182 r_range[0] = std::min(r_range[0], tile._r_range[0]);
0183 r_range[1] = std::max(r_range[1], tile._r_range[1]);
0184 phi_range[0] = std::min(phi_range[0], tile._phi_range[0]);
0185 phi_range[1] = std::max(phi_range[1], tile._phi_range[1]);
0186
0187 auto points = tile._attribute_map.find("points");
0188 if (points != tile._attribute_map.end()) {
0189 svg::object cell;
0190 cell._tag = "polygon";
0191 cell._id = id_ + "_cell_" + std::to_string(i) + "_" +
0192 std::to_string(j);
0193 cell._fill = generate_fill(c);
0194 cell._stroke = style::stroke();
0195 cell._attribute_map["points"] = points->second;
0196
0197 cluster_group.add_object(cell);
0198 }
0199 }
0200 }
0201
0202
0203 if constexpr (DIM == 1) {
0204 if (cluster_._coords[DIM - 1] == proto::cluster<DIM>::e_r) {
0205 m_r = cluster_._measurement[DIM - 1];
0206 t_r = cluster_._truth[DIM - 1];
0207
0208 d_r = cluster_._variance[DIM - 1];
0209 d_phi = std::abs(phi_range[1] - phi_range[0]) / std::sqrt(12.);
0210
0211 m_phi = 0.5 * (phi_range[0] + phi_range[1]);
0212 t_phi = m_phi;
0213 } else if (cluster_._coords[DIM - 1] == proto::cluster<DIM>::e_phi) {
0214 m_phi = cluster_._measurement[DIM - 1];
0215 t_phi = cluster_._truth[DIM - 1];
0216
0217 d_r = std::abs(r_range[1] - r_range[0]) / std::sqrt(12.);
0218 d_phi = cluster_._variance[DIM - 1];
0219
0220 m_r = 0.5 * (r_range[0] + r_range[1]);
0221 t_r = m_r;
0222 } else if (cluster_._coords[DIM - 1] == proto::cluster<DIM>::e_x) {
0223 m_x = cluster_._measurement[DIM - 1];
0224 t_x = cluster_._truth[DIM - 1];
0225 c_x = cluster_._variance[DIM - 1];
0226 c_y = std::abs(y_range[1] - y_range[0]) / std::sqrt(12.);
0227 m_y = 0.5 * (y_range[0] + y_range[1]);
0228 t_y = m_y;
0229
0230
0231 scalar corr = cluster_._correlation;
0232 corr = corr < -1. ? -1. : (corr > 1. ? 1. : corr);
0233 c_r = -corr * 45;
0234
0235 } else {
0236 m_y = cluster_._measurement[DIM - 1];
0237 t_y = cluster_._truth[DIM - 1];
0238 c_y = cluster_._variance[DIM - 1];
0239 c_x = std::abs(x_range[1] - x_range[0]) / std::sqrt(12.);
0240 m_x = 0.5 * (x_range[0] + x_range[1]);
0241 t_x = m_x;
0242
0243
0244 scalar corr = cluster_._correlation;
0245 corr = corr < -1. ? -1. : (corr > 1. ? 1. : corr);
0246 c_r = corr * 45;
0247 }
0248 }
0249
0250
0251 if (cluster_._type == proto::cluster<DIM>::e_polar) {
0252
0253 m_x = m_r * std::cos(m_phi);
0254 m_y = m_r * std::sin(m_phi);
0255
0256 scalar cos_phi = std::cos(m_phi);
0257 scalar sin_phi = std::sin(m_phi);
0258
0259 c_x = std::abs(cos_phi * d_r - m_r * sin_phi * d_phi);
0260 c_y = std::abs(sin_phi * d_r + m_r * cos_phi * d_phi);
0261
0262 c_r = m_phi * 180 / M_PI;
0263
0264 t_x = t_r * std::cos(t_phi);
0265 t_y = t_r * std::sin(t_phi);
0266 }
0267
0268
0269 style::fill fill_c = fill_m_;
0270 fill_c._fc._opacity = 0.5;
0271 style::stroke stroke_c;
0272 style::transform t_c;
0273 t_c._rot = {c_r, m_x, m_y};
0274 cluster_group.add_object(
0275 draw::ellipse("c", {m_x, m_y}, {c_x, c_y}, fill_c, stroke_c, t_c));
0276
0277
0278 style::marker marker{"o"};
0279 marker._fill = fill_m_;
0280 cluster_group.add_object(draw::marker("m", {m_x, m_y}, marker));
0281
0282 if (cluster_._mc) {
0283 style::marker truth_marker{"o"};
0284 cluster_group.add_object(draw::marker("t", {t_x, t_y}, truth_marker));
0285 }
0286
0287
0288 svg::object grid_area;
0289 grid_area._tag = "g";
0290 grid_area._id = id_ + std::string("_focussed_grid");
0291
0292
0293 i_min = (i_min >= expand_[0]) ? i_min - expand_[0] : 0;
0294 i_max += expand_[0];
0295 j_min = (j_min >= expand_[1]) ? j_min - expand_[1] : 0;
0296 j_max += expand_[1];
0297
0298 for (unsigned int i = i_min; i <= i_max; ++i) {
0299 for (unsigned int j = j_min; j < j_max; ++j) {
0300 std::string tile_id =
0301 grid_._id + "_" + std::to_string(i) + "_" + std::to_string(j);
0302 std::optional<svg::object> grid_tile = grid_.find_object(tile_id);
0303 if (grid_tile.has_value()) {
0304 grid_area.add_object(grid_tile.value());
0305 }
0306 }
0307 }
0308
0309 return {cluster_group, grid_area};
0310 }
0311
0312 }
0313 }