Skip to content

Conversation

@NickAkhmetov
Copy link
Collaborator

This pull request introduces significant updates to the color scaling and normalization logic across multiple files, aiming to improve code clarity, modularity, and maintainability. Key changes include renaming the default scale in the ColorScaleContext to countsScale to make it easier to distinguish from the percentage and log scales, moving the normalization constant and type to a dedicated utility file to ensure that vite appropriately handles component refresh, and refactoring normalization-related logic in visualization components to avoid nested ternary statements.

Updates to Color Scaling:

  • Renamed scale to countsScale in ColorScaleContext to clarify its purpose and added consistent use of domain and range for better readability (src/contexts/ColorScaleContext.tsx, [1] [2].

Refactoring Normalization Logic:

  • Moved Normalization type and NORMALIZATIONS constant from NormalizationContext to a new utility file, src/utils/normalizations.ts, to centralize normalization-related definitions (src/contexts/NormalizationContext.tsx, [1]; src/utils/normalizations.ts, [2].
  • Renamed useIsNormalized to useIsNormalizedByRowOrColumn for better semantic clarity following the introduction of log normalization (src/contexts/NormalizationContext.tsx, src/contexts/NormalizationContext.tsxL48-R45).

Visualization Component Enhancements:

  • Introduced helper hooks (useLegendLabel, useMinValueLabel, useMaxValueLabel) in Legend to encapsulate label logic and improve readability (src/visx-visualization/Legend.tsx, [1] [2].
  • Added useCurrentNormalizedScale in Heatmap to abstract scale selection logic based on normalization type, replacing repetitive conditional checks (src/visx-visualization/heatmap/Heatmap.tsx, [1] [2] [3].

Code Simplification and Error Handling:

  • Refactored normalization info logic in DragOverlay using a switch statement for improved readability and added a default case for error reporting. If we add more normalization options in the future, this will alert us that we need to add a case to handle it here as well. (src/visx-visualization/heatmap/DragOverlay.tsx, src/visx-visualization/heatmap/DragOverlay.tsxL263-R280).

…or clarity, move non-react component exports out to separate utils file
@NickAkhmetov NickAkhmetov requested a review from thomcsmits July 23, 2025 14:07
Copy link
Collaborator

@thomcsmits thomcsmits left a comment

Choose a reason for hiding this comment

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

Great! Thanks for formalizing this and ensuring clarity and modularity!

@@ -0,0 +1,2 @@
export const NORMALIZATIONS = ["None", "Row", "Column", "Log"] as const;
Copy link
Collaborator

Choose a reason for hiding this comment

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

(I know I also treated it like a normalization but) in many ways I wonder if Log is really a normalization in the same way of row/column, or whether it's a different type of transformation. I can imagine many more transformations of the data, which are not normalizations. Perhaps at a certain point we want to allow users to add their own types of normalizations.

Although, perhaps row/col normalization is also a transformation.

What I am getting it, is that perhaps we want to handle these differently. Perhaps at a certain point, someone wants to do a transformation (like log) as well as a normalization (just row/col). Normalization of none/row/col is only possible on it's own (you can't normalize by both row and col), but in principle, many transformations are possible.

What do you think?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That's a really good point; I think that a separate transformations context and util would be a good solution in the long run.

const theme = heatmapThemes[heatmapTheme];

const range = colorThresholds.map((_, idx) => idx / 255);
const domain = colorThresholds.map((_, idx) => idx / 255);
Copy link
Collaborator

Choose a reason for hiding this comment

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

why this renaming?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

In the original:

  • The range list was generated from colorThresholds
  • Every scale mapped over the range object to create their own range/domain lists, duplicating this calculation
  • The percentageScale had a semantically awkward domain: range property assignment, which made things difficult to follow.

In the edited version:

  • The range list is renamed to domain so that it can be provided directly to the domain property of percentageScale; the domain lists are still calculated the same way, but with a semantically accurate name for the source list.
  • A range list that can be passed directly to all three scales without needing to be reinstantiated is created on the next line, which saves a bit of memory

Since these values are only used within the context of this useMemo, this should not cause any cascading changes.

@NickAkhmetov NickAkhmetov merged commit 1b99c0f into thomcsmits/log-normalization Aug 28, 2025
1 check passed
@thomcsmits thomcsmits deleted the nickakhmetov/log-normalization-edits branch November 4, 2025 14:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants