Skip to content

feat: Line averaging, width, and color controls - #300

Open
ShrimpCryptid wants to merge 12 commits into
feat/connect-by-linesfrom
feat/line-smoothing
Open

feat: Line averaging, width, and color controls#300
ShrimpCryptid wants to merge 12 commits into
feat/connect-by-linesfrom
feat/line-smoothing

Conversation

@ShrimpCryptid

@ShrimpCryptid ShrimpCryptid commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Problem

Part 2 of 2 for #296, "connect points with lines!" This change adds additional controls for line averaging, color, and line width.

Estimated review size: large, 30-40 minutes

Solution

  • Added state fields for line width, line color, and line moving average window.
  • Copied moving average logic from TFE, with unit tests.
  • Updated line trace calculation in MainPlot to use moving window averaging.
  • Added settings components for controlling line properties.

Type of change

  • New feature (non-breaking change which adds functionality)

Steps to Verify:

  1. Open PR preview: https://allencell.github.io/cell-feature-explorer/pr-preview/pr-300/?cellSelectedFor3D=2800&colorBy=trajectory_id&dataset=csv&csvUrl=https%253A%252F%252Fvast-files.int.allencell.org%252Fusers%252Fmajid.farhadloo%252F2026-07-23%252Fdetect_normal_abnormal_growth%252Flumenoid_laca_8593__frame_embeddings.csv&plotByOnX=pacmap_y&plotByOnY=pacmap_x&groupBy=trajectory_id&connectByCategory=trajectory_id&connectByFeature=timepoint&connectBy=true&colorOverrides=-3741ff&ptOpacity=1&lineWindow=11&lineColor=%23316119&selectedPoint%5B0%5D=1158&selectedPoint%5B1%5D=2316&selectedPoint%5B2%5D=2800&selectedPoint%5B3%5D=166&selectedPoint%5B4%5D=1100
  2. Hide all groups except for one or two of them.
  3. Click the gear icon in the plot control bar to open up the plot settings. Adjust the line color, averaging window, and width.

Screenshots (optional):

{015B0C5E-7962-4B6F-94AE-E4618F0D77CC}

Keyfiles (delete if not relevant):

  1. util/math.ts
  2. MainPlotContainer/selectors.ts
  3. PlotLineSettings/index.ts

@ShrimpCryptid ShrimpCryptid self-assigned this Aug 11, 2026
@ShrimpCryptid ShrimpCryptid added the enhancement New feature or request label Aug 11, 2026
@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown
PR Preview Action v1.6.3

🚀 View preview at
https://AllenCell.github.io/cell-feature-explorer/pr-preview/pr-300/

Built to branch gh-pages at 2026-08-17 20:46 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@@ -0,0 +1,24 @@
import { InfoCircleOutlined } from "@ant-design/icons";

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copied from TFE. Appears as a small hoverable or tab-focusable tooltip.

Image

type LabeledSliderProps = {
sliderProps: SliderSingleProps;
label: string;
label: string | ReactNode;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to allow the inline hint to also be shown here.

I'd love to pull in a bunch of the components I've written in TFE, especially for handling input and settings organization......

@@ -0,0 +1,133 @@
import React, { ReactElement } from "react";

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image

Comment on lines +104 to +115
/**
* Returns the moving average for a list of values, using a specified window
* size.
* @param values A list of numeric values. Non-finite or null values will be
* ignored in the average calculation.
* @param windowSize The window size for the moving average. Rounds up to the
* nearest positive, odd integer.
* @param includeEnds Whether to calculate the average for values at the end of
* the list that do not have enough neighbors to fill the window size. If false,
* the returned list will have `Math.floor(windowSize / 2)` fewer values at the
* beginning and end.
*/

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment thread src/util/math.ts
@@ -0,0 +1,45 @@
/**

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copied with minimal changes from http://github.com/allen-cell-animated/timelapse-colorizer/blob/main/src/colorizer/utils/data_utils.ts#L850! The new changes are mostly to support null values in mixed number/null arrays.

@@ -0,0 +1,82 @@
import { describe, it, expect } from "vitest";

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds configurable connection-line rendering in the main plot (moving-average smoothing, line width, and default line color) and persists those settings via URL state so plots can be shared/reproduced.

Changes:

  • Add new selection-state fields + actions/reducer handling for line smoothing window, line width, and line color.
  • Apply moving-average smoothing to connection-line traces and plumb line style settings into Plotly trace creation.
  • Add UI controls for the new line settings and introduce a shared moving-average utility with tests.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
src/util/UrlState.ts Adds URL params for line window/width/color and maps them into state/actions.
src/util/test/UrlState.test.ts Extends URL state tests to cover new line params/actions.
src/util/math.ts Introduces getMovingAverage helper used for line smoothing.
src/util/test/math.test.ts Adds unit tests for getMovingAverage.
src/state/selection/types.ts Extends selection state + action types for new line settings.
src/state/selection/selectors.ts Adds selectors for new line settings and includes them in getMainPlotSettings.
src/state/selection/reducer.ts Initializes and updates line settings in reducer (including window rounding).
src/state/selection/constants.ts Adds action constants for line settings.
src/state/selection/actions.ts Adds action creators for updating line settings.
src/containers/MainPlotContainer/selectors.ts Applies moving average to line trace data and uses settings for line styling.
src/constants/index.ts Adds a general default for connectionLineDefaultColor.
src/components/PlotSettings/index.tsx Expands plot settings panel and includes the new line-settings component.
src/components/PlotLineSettings/index.tsx New UI controls for line averaging window, width, and default color.
src/components/LabeledSlider/index.tsx Extends label type to allow ReactNode labels and tweaks layout for label/slider sizing.
src/components/InlineHint/index.tsx New inline tooltip hint icon used in the line-settings UI.
Suppressed comments (1)

src/components/PlotLineSettings/index.tsx:134

  • After renaming the component to PlotLineSettings, the connected export should use the renamed identifier as well.
)(PlotSettings);

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/components/PlotLineSettings/index.tsx
Comment thread src/components/PlotLineSettings/index.tsx Outdated
Comment thread src/components/PlotLineSettings/index.tsx
Comment thread src/components/LabeledSlider/index.tsx Outdated
Comment thread src/components/InlineHint/index.tsx Outdated
Comment thread src/containers/MainPlotContainer/selectors.ts Outdated
Comment thread src/util/UrlState.ts Outdated
Comment thread src/util/UrlState.ts Outdated
Comment thread src/state/selection/reducer.ts Outdated
Comment thread src/util/math.ts Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 15 out of 15 changed files in this pull request and generated no new comments.

Suppressed comments (8)

src/components/PlotLineSettings/index.tsx:76

  • The slider max (31) doesn’t match the InputNumber clamp max (101), so typing a value >31 will be accepted/clamped to 101 and pushed into state even though the slider can’t represent it. This can leave the slider out-of-range and make the UI inconsistent.
                sliderProps={{
                    value: lineAverageWindow,
                    onChange: setLineAverageWindow,
                    min: 1,
                    max: 31,
                    step: 2,
                }}
                inputMin={1}
                inputMax={101}
            ></LabeledSlider>

src/components/PlotLineSettings/index.tsx:93

  • The InputNumber bounds (0..100) don’t match the slider bounds (0.1..3.5). As-is, a user can type e.g. 100, which will be accepted and set as the line width, potentially making the plot unreadable and diverging from the slider’s intended range.
                inputMin={0}
                inputMax={100}
            ></LabeledSlider>

src/components/PlotLineSettings/index.tsx:44

  • This component is defined as PlotSettings, which is easily confused with components/PlotSettings. Renaming it to PlotLineSettings will make React DevTools/component stacks clearer.
const PlotSettings = (props: PlotSettingsProps): ReactElement => {

src/components/PlotLineSettings/index.tsx:134

  • Follow-up to the component rename: the connected export should reference the renamed component to keep component names consistent in stack traces.
export default connect<PropsFromState, DispatchProps, unknown, State>(
    mapStateToProps,
    dispatchToPropsMap
)(PlotSettings);

src/components/LabeledSlider/index.tsx:30

  • When label is a ReactNode (e.g. a JSX element), label.toString() typically becomes "[object Object]", which can create duplicate/invalid DOM ids (and break label/input association). Prefer deriving ids only from string labels and otherwise generate a unique stable id when props.id isn’t provided.
    const inputId =
        props.id || `labeled-slider-${props.label?.toString().toLowerCase().replace(/\s+/g, "-")}`;

src/state/selection/reducer.ts:111

  • connectLineDefaultColor is initialized to "#808080", which changes the default line color from the previous PALETTE.mediumDarkGray behavior (and also differs from GENERAL_PLOT_SETTINGS.connectionLineDefaultColor, which is BASE_PALETTE_COLORS.mediumDarkGray). If the intent is to preserve existing defaults, initialize to the same mediumDarkGray value.
    connectLineMovingAverageWindow: 1,
    connectLineWidth: 1.5,
    connectLineDefaultColor: "#808080",

src/util/math.ts:22

  • The implementation doesn’t currently match the docstring claim that windowSize is rounded up to the nearest positive odd integer (e.g. windowSize=3.1 produces an effective window of 3, not 5). Also, ret is inferred as any[] here. Normalizing windowSize up-front and typing ret keeps behavior/documentation aligned and preserves type-safety.
    // Number of values forward and backwards to include in the average.
    // For a window size of 7, the window offset will be 3.
    const windowOffset = Math.max(0, Math.floor(windowSize / 2));
    const ret = [];

src/containers/MainPlotContainer/selectors.ts:237

  • getMovingAverage defaults includeEnds to false, which drops windowOffset points at the start/end of each line. That means enabling smoothing will shorten each rendered line and omit the endpoints entirely, which is likely unintended for a “line averaging” control (and doesn’t match the UI hint about averaging at the ends).
        // Apply moving average to each line
        if (movingAverageWindow > 1) {
            for (const line of lineData) {
                line.y = getMovingAverage(line.y, movingAverageWindow);
                line.x = getMovingAverage(line.x, movingAverageWindow);
            }

@ShrimpCryptid
ShrimpCryptid marked this pull request as ready for review August 12, 2026 20:29
/** Opacity of points in the plot, in the [0, 1] range. */
pointOpacity: 0.5,
connectLineMovingAverageWindow: 1,
connectLineWidth: GENERAL_PLOT_SETTINGS.connectionLineWidth,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is a little nit picky, but I think "connection line" or "connecting line" reads better than connect line, especially when it comes to the state variables below and "connect" seems like a verb

@ShrimpCryptid ShrimpCryptid linked an issue Aug 18, 2026 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants