From e41ab0552d28c18b661498e2c424178dc01aa82c Mon Sep 17 00:00:00 2001 From: Kinvert Date: Mon, 17 Aug 2026 23:01:59 -0400 Subject: [PATCH 1/3] Highlight the selected point across all plot panes --- src/constellation.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/constellation.c b/src/constellation.c index 9520da0f05..325d174a1d 100644 --- a/src/constellation.c +++ b/src/constellation.c @@ -785,7 +785,8 @@ void draw_axes3() { ); } -void boxplot(Table* table, int col, int x_scale, int i, int hyper_count, PlotArgs args, Color color, bool* filter) { +void boxplot(Table* table, int col, int x_scale, int i, int hyper_count, PlotArgs args, Color color, + bool* filter, bool has_highlight, float highlight_val) { int width = args.width; int height = args.height; @@ -818,6 +819,13 @@ void boxplot(Table* table, int col, int x_scale, int i, int hyper_count, PlotArg left = fminf(fmax(left, args.left_margin), width - args.right_margin); right = fmaxf(fmin(right, width - args.right_margin), 0); DrawRectangle(left, args.top_margin + i*dy, right - left, dy, color); + + if (has_highlight) { + float hval = scale_val(x_scale, highlight_val); + float hx = args.left_margin + (hval - x_min)/(x_max - x_min)*plot_width; + hx = fminf(fmaxf(hx, args.left_margin), width - args.right_margin); + DrawRectangle(hx - 1, args.top_margin + i*dy, 3, dy, BLUE); + } } void plot_gl(Glyph* glyphs, int size, Shader* shader) { @@ -971,6 +979,19 @@ void update_closest(Tooltip* tooltip, Vector2 *indices, Glyph* glyphs, int size, } } +void draw_highlight(Tooltip* tooltip, Vector2* indices, Glyph* glyphs, int size) { + if (!tooltip->active) { + return; + } + // TODO Ugly but can't yet find a better way. Checking ary_idx first makes this cheap + for (int i=0; iary_idx && (int)indices[i].x == tooltip->env_idx) { + DrawRing((Vector2){glyphs[i].x, glyphs[i].y}, 10, 13, 0, 360, 36, PUFF_CYAN); + return; + } + } +} + void copy_hypers_to_clipboard(Table *table, char* buffer, int row) { char* start = buffer; char* prefix = NULL; @@ -1327,6 +1348,7 @@ int main(void) { toPx(points, glyphs, size, args1); update_closest(&tooltip, env_indices, glyphs, size, 0, 2*SETTINGS_HEIGHT); plot_gl(glyphs, size, &shader); + draw_highlight(&tooltip, env_indices, glyphs, size); BeginMode3D(args1.camera); CustomUpdateCamera(&args1.camera, CAMERA_ORBITAL_SPEED); @@ -1352,6 +1374,7 @@ int main(void) { toPx(points, glyphs, size, args2); update_closest(&tooltip, env_indices, glyphs, size, fig1.texture.width, 2*SETTINGS_HEIGHT); plot_gl(glyphs, size, &shader); + draw_highlight(&tooltip, env_indices, glyphs, size); draw_axes(args2); draw_all_ticks(args2); EndTextureMode(); @@ -1390,6 +1413,7 @@ int main(void) { toPx(points, glyphs, size, args3); update_closest(&tooltip, env_indices, glyphs, size, 0, fig1.texture.height + 2*SETTINGS_HEIGHT); plot_gl(glyphs, size, &shader); + draw_highlight(&tooltip, env_indices, glyphs, size); //draw_axes(args3); EndTextureMode(); @@ -1422,7 +1446,10 @@ int main(void) { } apply_filter(filter, table, filter_param_1, fig_range1_min_val, fig_range1_max_val); apply_filter(filter, table, filter_param_2, fig_range2_min_val, fig_range2_max_val); - boxplot(table, col, args4.scale[0], j, hyper_count, args4, color, filter); + bool has_highlight = tooltip.active && i == tooltip.env_idx; + float highlight_val = has_highlight ? table_get(table, tooltip.ary_idx, col) : 0.0f; + boxplot(table, col, args4.scale[0], j, hyper_count, args4, color, filter, + has_highlight, highlight_val); } } EndBlendMode(); From fdc2316c986fb4f6db85779f17ff19e9e62f29a8 Mon Sep 17 00:00:00 2001 From: Kinvert Date: Mon, 17 Aug 2026 23:10:22 -0400 Subject: [PATCH 2/3] Drop int cast --- src/constellation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/constellation.c b/src/constellation.c index 325d174a1d..9e56640de5 100644 --- a/src/constellation.c +++ b/src/constellation.c @@ -985,7 +985,7 @@ void draw_highlight(Tooltip* tooltip, Vector2* indices, Glyph* glyphs, int size) } // TODO Ugly but can't yet find a better way. Checking ary_idx first makes this cheap for (int i=0; iary_idx && (int)indices[i].x == tooltip->env_idx) { + if (indices[i].y == tooltip->ary_idx && indices[i].x == tooltip->env_idx) { DrawRing((Vector2){glyphs[i].x, glyphs[i].y}, 10, 13, 0, 360, 36, PUFF_CYAN); return; } From 035ed0ac5ab04ebdd86fa4cc835ead1c2c201ca6 Mon Sep 17 00:00:00 2001 From: Kinvert Date: Tue, 18 Aug 2026 03:35:59 -0400 Subject: [PATCH 3/3] View Rotation and Fixed Existing Bug --- src/constellation.c | 57 +++++++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/src/constellation.c b/src/constellation.c index 9e56640de5..d3b0f024e7 100644 --- a/src/constellation.c +++ b/src/constellation.c @@ -481,12 +481,19 @@ int main(int argc, char** argv) { #include "raymath.h" #define CAMERA_ORBITAL_SPEED 0.05f -void CustomUpdateCamera(Camera *camera, float orbitSpeed) { - float cameraOrbitalSpeed = CAMERA_ORBITAL_SPEED*GetFrameTime(); - Matrix rotation = MatrixRotate(GetCameraUp(camera), cameraOrbitalSpeed); - Vector3 view = Vector3Subtract(camera->position, camera->target); - view = Vector3Transform(view, rotation); - camera->position = Vector3Add(camera->target, view); +#define MOUSE_ROTATE_SPEED 0.005f +void CustomUpdateCamera(Camera *camera, float orbitSpeed, Rectangle bounds) { + if (CheckCollisionPointRec(GetMousePosition(), bounds) && IsMouseButtonDown(MOUSE_LEFT_BUTTON)) { + Vector2 delta = GetMouseDelta(); + CameraYaw(camera, -delta.x*MOUSE_ROTATE_SPEED, true); + CameraPitch(camera, -delta.y*MOUSE_ROTATE_SPEED, true, true, false); + } else { + float cameraOrbitalSpeed = CAMERA_ORBITAL_SPEED*GetFrameTime(); + Matrix rotation = MatrixRotate(GetCameraUp(camera), cameraOrbitalSpeed); + Vector3 view = Vector3Subtract(camera->position, camera->target); + view = Vector3Transform(view, rotation); + camera->position = Vector3Add(camera->target, view); + } CameraMoveToTarget(camera, -GetMouseWheelMove()); if (IsKeyPressed(KEY_KP_SUBTRACT)) CameraMoveToTarget(camera, 2.0f); if (IsKeyPressed(KEY_KP_ADD)) CameraMoveToTarget(camera, -2.0f); @@ -979,13 +986,16 @@ void update_closest(Tooltip* tooltip, Vector2 *indices, Glyph* glyphs, int size, } } -void draw_highlight(Tooltip* tooltip, Vector2* indices, Glyph* glyphs, int size) { +void draw_highlight(Tooltip* tooltip, Vector2* indices, Glyph* glyphs, int size, + float x_offset, float y_offset, float* disp_x, float* disp_y) { if (!tooltip->active) { return; } // TODO Ugly but can't yet find a better way. Checking ary_idx first makes this cheap for (int i=0; iary_idx && indices[i].x == tooltip->env_idx) { + *disp_x = x_offset + glyphs[i].x; + *disp_y = y_offset + glyphs[i].y; DrawRing((Vector2){glyphs[i].x, glyphs[i].y}, 10, 13, 0, 360, 36, PUFF_CYAN); return; } @@ -1210,6 +1220,7 @@ int main(void) { args1.scale[2] = 1; RenderTexture2D fig1 = LoadRenderTexture(args1.width, args1.height); RenderTexture2D fig1_overlay = LoadRenderTexture(args1.width, args1.height); + Rectangle fig1_bounds = {0, 2*SETTINGS_HEIGHT, args1.width, args1.height}; int fig_env_idx = 0; bool fig_env_active = false; bool fig_x_active = false; @@ -1276,6 +1287,8 @@ int main(void) { bool *filter = calloc(max_data_points, sizeof(bool)); Tooltip tooltip = {0}; + float disp_x = 0; + float disp_y = 0; Vector2 focus = {0, 0}; @@ -1287,7 +1300,9 @@ int main(void) { if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { focus = GetMousePosition(); - tooltip.active = false; + if (!CheckCollisionPointRec(focus, fig1_bounds)) { + tooltip.active = false; + } } if (IsMouseButtonPressed(MOUSE_RIGHT_BUTTON)) { Vector2 mouse_pos = GetMousePosition(); @@ -1346,12 +1361,14 @@ int main(void) { } autoscale(points, size, &args1); toPx(points, glyphs, size, args1); - update_closest(&tooltip, env_indices, glyphs, size, 0, 2*SETTINGS_HEIGHT); + if (right_clicked) { + update_closest(&tooltip, env_indices, glyphs, size, 0, 2*SETTINGS_HEIGHT); + } plot_gl(glyphs, size, &shader); - draw_highlight(&tooltip, env_indices, glyphs, size); + draw_highlight(&tooltip, env_indices, glyphs, size, 0, 2*SETTINGS_HEIGHT, &disp_x, &disp_y); BeginMode3D(args1.camera); - CustomUpdateCamera(&args1.camera, CAMERA_ORBITAL_SPEED); + CustomUpdateCamera(&args1.camera, CAMERA_ORBITAL_SPEED, fig1_bounds); draw_axes3(); EndMode3D(); EndTextureMode(); @@ -1372,9 +1389,11 @@ int main(void) { args2.mmin[2] = 0.0f; args2.mmax[2] = 0.0f; toPx(points, glyphs, size, args2); - update_closest(&tooltip, env_indices, glyphs, size, fig1.texture.width, 2*SETTINGS_HEIGHT); + if (right_clicked) { + update_closest(&tooltip, env_indices, glyphs, size, fig1.texture.width, 2*SETTINGS_HEIGHT); + } plot_gl(glyphs, size, &shader); - draw_highlight(&tooltip, env_indices, glyphs, size); + draw_highlight(&tooltip, env_indices, glyphs, size, fig1.texture.width, 2*SETTINGS_HEIGHT, &disp_x, &disp_y); draw_axes(args2); draw_all_ticks(args2); EndTextureMode(); @@ -1411,9 +1430,11 @@ int main(void) { } autoscale(points, size, &args3); toPx(points, glyphs, size, args3); - update_closest(&tooltip, env_indices, glyphs, size, 0, fig1.texture.height + 2*SETTINGS_HEIGHT); + if (right_clicked) { + update_closest(&tooltip, env_indices, glyphs, size, 0, fig1.texture.height + 2*SETTINGS_HEIGHT); + } plot_gl(glyphs, size, &shader); - draw_highlight(&tooltip, env_indices, glyphs, size); + draw_highlight(&tooltip, env_indices, glyphs, size, 0, fig1.texture.height + 2*SETTINGS_HEIGHT, &disp_x, &disp_y); //draw_axes(args3); EndTextureMode(); @@ -1623,8 +1644,8 @@ int main(void) { if (tooltip.active) { const char* text = TextFormat("%s\nscore = %f\ncost = %f\nsteps = %f", env_key, score, cost, steps); Vector2 text_size = MeasureTextEx(args1.font_small, text, args1.axis_tick_font_size, 0); - float x = tooltip.x; - float y = tooltip.y; + float x = disp_x; + float y = disp_y; if (x + text_size.x + 4 > GetScreenWidth()) { x = x - text_size.x - 4; } @@ -1632,7 +1653,7 @@ int main(void) { y = y - text_size.y - 4; } DrawRectangle(x, y, text_size.x + 4, text_size.y + 4, PUFF_BACKGROUND); - DrawCircle(tooltip.x, tooltip.y, 2, PUFF_CYAN); + DrawCircle(disp_x, disp_y, 2, PUFF_CYAN); DrawTextEx(args1.font_small, text, (Vector2){x + 2, y + 2}, args1.axis_tick_font_size, 0, WHITE); } EndDrawing();