Skip to content

Add Support for Heatmap Plot Type in CVD Palette Feature #950 #951

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 1, 2025

Conversation

kishorprajapati1212
Copy link
Contributor

Description

This PR enhances the heatmap color scaling to provide a more visually accurate and accessible experience for users with color vision deficiencies (CVD). The key improvements include:

Changes:-

  1. Refined Color Selection Algorithm
  2. Minimum Updated Color Palettes for Protanopia, Deuteranopia, and Tritanopia
  3. Maintained Default Theme Consistency

Why is this change required? What problem does it solve?

  • Enhances readability and usability for users with different types of CVD.
  • Provides better visual contrast and smoother color transitions.
  • Aligns with best practices in heatmap color representation.

Related issue

Closes #950 (Add Support for Heatmap Plot Type in CVD Palette Feature)

How Has This Been Tested?

  • Manually tested with different palettes to ensure expected color transitions.
  • Verified the light-to-dark flow follows a natural progression in each mode.
  • Ensured consistency with the default theme logic.

Screenshots (if appropriate):

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.

…r e InternetHealthReport#950

I make minimum change as much as possible in colorPalettes
@dpgiakatos dpgiakatos self-requested a review March 31, 2025 04:06
Copy link
Member

@dpgiakatos dpgiakatos left a comment

Choose a reason for hiding this comment

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

This PR does not adhere to the code style established for adding a new plot type. Additionally, it modifies the CVD color palettes, whereas it was previously discussed that any changes to the CVD palettes should be made using a new variable rather than altering the existing one. This PR requires significant revisions.

Note: This PR appears to be generated by an LLM.

@@ -73,7 +73,7 @@ const created = ref(false)
const myId = ref(`ihrReactiveChart${uid()}`)
const layoutLocal = ref(props.layout)
const dropdownCVD = ref(false)
const supportedCVDPlots = ['treemap', 'pie', 'bar', 'box', 'scatter', 'scatterpolar']
const supportedCVDPlots = ['treemap', 'pie', 'bar', 'box', 'scatter', 'scatterpolar', 'heatmap']
Copy link
Member

Choose a reason for hiding this comment

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

Add heatmap third in the array

@@ -92,7 +92,7 @@ layoutLocal.value['images'] = [

const colorPalettes = {
protanopia: [
'#ffe41c',
'#ffe41c', //Light Yellow
Copy link
Member

Choose a reason for hiding this comment

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

remove comment

@@ -104,7 +104,7 @@ const colorPalettes = {
'#7e711b',
'#000000',
'#0060c7',
'#a18e21',
'#a18e21', // dark yellow
Copy link
Member

Choose a reason for hiding this comment

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

remove comment

@@ -114,10 +114,10 @@ const colorPalettes = {
'#686566'
],
deuteranopia: [
'#ffd592',
'#679bf2', //Light blue
Copy link
Member

Choose a reason for hiding this comment

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

remove comment

Copy link
Member

Choose a reason for hiding this comment

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

Revert to the old color code

'#b0bcf9',
'#c09300',
'#679bf2',
'#ffd592',
Copy link
Member

Choose a reason for hiding this comment

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

Revert to the old color code

@@ -136,7 +136,8 @@ const colorPalettes = {
'#8894ca'
],
tritanopia: [
'#fd6e74',
'#ed656c ', //light pink
//'#ffc0cd ',
Copy link
Member

Choose a reason for hiding this comment

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

remove line

@@ -148,10 +149,10 @@ const colorPalettes = {
'#ffc0cd',
'#67becd',
'#ff4346',
'#36aebb',
'#d46269', //dark pink
Copy link
Member

Choose a reason for hiding this comment

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

revert to old color code

Copy link
Member

Choose a reason for hiding this comment

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

remove comment

'#ed656c',
'#4d717a',
'#d46269',
'#36aebb',
Copy link
Member

Choose a reason for hiding this comment

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

revert to old color code

}
} else if (trace.type === supportedCVDPlots[1]) {
const colorsArray = colorPalettes[paletteKey];
if (trace.type === 'heatmap') {
Copy link
Member

Choose a reason for hiding this comment

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

Change to trace.type === supportedCVDPlots[3] and add this part of before the else part.

Copy link
Member

Choose a reason for hiding this comment

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

Why did you delete the const color = colorPalettes[paletteKey][index % colorPalettes[paletteKey].length]?

Comment on lines 186 to 193
return {
...trace,
marker: {
...trace.marker,
colors: colorsArray.slice(0, trace.labels?.length || colorsArray.length)
}
}
} else {
return {
...trace,
marker: { ...trace.marker, color },
line: { ...trace.line, color }
colorscale: [
[0, '#dddbd9'], // start with white
[0.5, colorsArray[0]], // Light color
[1, colorsArray[Math.floor(colorsArray.length * 0.6)]] // Strong color
]
};
Copy link
Member

Choose a reason for hiding this comment

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

This code block is not align with the code style of the file

@kishorprajapati1212
Copy link
Contributor Author

Thanks for reviewing my PR! After going through your feedback, I re-evaluated my approach:

  1. Static Array for Opacity & Colors – Initially, I tried defining a static array with opacity values and color hashes, but it didn’t fit well with the existing style.

  2. Sorting the Color Palette (Dark to Light) – Another approach was sorting colors dynamically, but this had performance issues and didn’t look great.

Your comment on this line caught my attention:
const color = colorPalettes[paletteKey][index % colorPalettes[paletteKey].length]
This made me rethink the solution why not just darken the existing color dynamically instead of pre-sorting.
I added a darkenHex function , which takes a hex color and a factor, then reduces its RGB values proportionally to make it darker:

const darkenHex = (hex, factor) => {
  const num = parseInt(hex.slice(1), 16);
  const r = Math.max(0, (num >> 16) * factor);
  const g = Math.max(0, ((num >> 8) & 0xff) * factor);
  const b = Math.max(0, (num & 0xff) * factor);

  return `#${((1 << 24) | (r << 16) | (g << 8) | b).toString(16).slice(1)}`;
};

Then applied it here:

else if (trace.type === supportedCVDPlots[2]) {
      let darkenedColor = darkenHex(color, 0.6); 

      return {
        ...trace,
        colorscale: [
          [0, '#dddbd9'],  
          [0.5, color], 
          [1, darkenedColor]  
        ]
      };
    }

and the result was same
https://github.com/user-attachments/assets/cd92dc28-6d43-46bb-80aa-221e8d77fd26

Does this approach make sense to you? If it looks good, I'll proceed with the next steps. Let me know if you think there's a better way to handle it!

@dpgiakatos
Copy link
Member

I have some questions:

  1. The heatmap color scale is always one. Why do you take the color dynamically?
  2. Which mathematical function do you use for the shading? (with references)
  3. Do we really need a shading function?

@kishorprajapati1212
Copy link
Contributor Author

  1. As per your instruction to start with a light color (like white) and gradually make it darker. That why I use a shading function to modify a given base color. The idea is to create a smooth transition from light to strong colors, making the heatmap visually clear.
  2. First, I convert the hex color into RGB values. Then, I apply scalar multiplication to the r, g, and b variables to darken the color. Finally, I convert the modified RGB values back into a hex code.
  3. No, it’s not necessary. You could just use fixed colors, but without the shading function, it’s much harder to see differences between values.

@dpgiakatos
Copy link
Member

I think you haven't understand my questions;

  1. You get the color dynamically using this const color = colorPalettes[paletteKey][index % colorPalettes[paletteKey].length. My question was about why do you use this variable when we have only one trace in a heatmap?
  2. I am asking about the kind of the function not to explain what the code does. So, do you use a linear or a logarithmic or a exponential or a cosine etc. methodology for the color shading?
  3. Have you tested it? Because the color scale function of plotly can work with declaring one light and one dark color.

@kishorprajapati1212
Copy link
Contributor Author

  1. I didn't get the color dynamically, it is already in the code, I reuse it.
  2. Yes I used the linear scaling for color intensity,
  3. Yes I test and result and also share the video before
    https://github.com/user-attachments/assets/cd92dc28-6d43-46bb-80aa-221e8d77fd26

@dpgiakatos
Copy link
Member

Ok, please remove the shade function, as it is unnecessary. You can simply declare the corresponding colors in constants, including the light version. For example:

const colorPalettesScaling = {
    protanopia: {
        light: '#ffe41c',
        dark: 'dark hex'
    },
    // etc.
};

Please adjust your code according to my comments and push the changes again. Thank you.

- Implemented static color mapping using `colorPalettesScaling`
- Adjusted the heatmap logic to use predefined light/dark colors
- Ensured the new approach aligns with the requested changes in PR InternetHealthReport#951
Copy link
Member

@dpgiakatos dpgiakatos left a comment

Choose a reason for hiding this comment

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

Thanks

@dpgiakatos dpgiakatos merged commit 434946c into InternetHealthReport:master Apr 1, 2025
5 of 6 checks passed
dpgiakatos added a commit that referenced this pull request Apr 1, 2025
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.

Add Support for Heatmap Plot Type in CVD Palette Feature
2 participants