Assigning fixed colors to charts

  1. My goal: Assign fixed colors to bar groups
  1. Issue: I have a checkbox filter that filters the bar chart. But because the colors are auto- assigned to the data in place they are not fixed to each category - see screen grabs. First screen grab shows all colors in the chart and all options selected. When first option is deselected, pink is removed from the chart, but when 2nd option is deselected, pink is also removed suggesting that colors are auto-assigned.

  2. Steps I've taken to troubleshoot: I have tried to manually change the group colors

  3. Additional info: (Cloud or Self-hosted, Screenshots) See screen shots

1 Like

Hi @Babs1,

To keep colors fixed when filtering, you need to bind them to the category labels instead of using the default auto-assignment. Otherwise, the charting library will reshuffle colors whenever a category is removed.

If using the new Bar Chart component: Go to “Series color mapping” and assign a color to each category, for example:
On-campus HCP → #007bff
HCP in non-college community setting → #28a745
HCP in college community setting → #ff00ff

If using the legacy Chart component: Switch to “Custom” mode and add a colors object to your config:
type: 'bar',
data: myData,
colors: {
"On-campus HCP": "#007bff",
"HCP in non-college community setting": "#28a745",
"HCP in college community setting": "#ff00ff"
}

With this setup, filtering categories won’t cause colors to change.

Thanks @DavidTech for getting back to me!
I have attached some screen grabs of where I think you are directing me. I have already assigned colors there. Is there someplace else I should map the colors?

Also please note the chart is a module, and the "group by" is a dynamic field based on a module input.


If your “Group by” value is coming from a dynamic module input, the color mapping you set in the module editor won’t always persist unless the group labels match exactly at runtime.

When you assign colors in the chart editor, Retool ties them to the exact string value in the “Group by” field. If the dynamic input returns different strings (or a different order) when filtered, Retool can reassign colors.

Two ways to lock it down:

  1. Make sure your dynamic Group by value always resolves to the exact same set of strings, even if filtered.
  2. Or, instead of relying only on the UI color picker, explicitly pass a groupStyles mapping to the chart via the module’s input props, for example:

{
"On-campus HCP": { fill: "#0072f0" },
"HCP in non-college community setting": { fill: "#76B342" },
"HCP in college community setting": { fill: "#ff00ff" }
}

Then bind the chart’s Group styles to that object so the mapping is fixed regardless of filtering.

This way, your module can keep the same colors no matter how the data changes.

1 Like

Hey @Babs1 ,

I ran into a similar issue with colors being reassigned dynamically when filtering categories in a Plotly JSON Chart. The fix is to use a transformer where you explicitly define categories, assign fixed colors, and then filter based on the selected checkboxes.

Here’s how I approached it:

1. Mock Data (sample dataset)

I mocked up data similar to what you shared:

return [
  {
    "label": "A. Critical self-reflection (correct)",
    "On-campus HCP": 3,
    "HCP in non-college community setting": 11,
    "HCP in college community setting": 4
  },
  {
    "label": "B. Concrete, finite facts",
    "On-campus HCP": 0,
    "HCP in non-college community setting": 5,
    "HCP in college community setting": 0
  },
  {
    "label": "C. Working collaboratively",
    "On-campus HCP": 0,
    "HCP in non-college community setting": 4,
    "HCP in college community setting": 4
  },
  {
    "label": "D. Knowing everything about different cultures",
    "On-campus HCP": 0,
    "HCP in non-college community setting": 2,
    "HCP in college community setting": 2
  }
]

2. Plotly JSON Transformer Code

const raw = {{ transformer14.value }};   // mockData array
const selected = {{ checkboxGroup1.value }};  // array of selected series

// Define categories & fixed colors
const categories = [
  { name: "On-campus HCP", color: "#1f77b4" },
  { name: "HCP in non-college community setting", color: "#2ca02c" },
  { name: "HCP in college community setting", color: "#d62728" }
];

// Wrap long labels (optional for readability)
const wrapLabel = (text, width = 30) =>
  text.length > width ? text.match(new RegExp('.{1,' + width + '}', 'g')).join('<br>') : text;

const yLabels = raw.map(d => wrapLabel(d.label));

// Build traces but only include selected categories
const traces = categories
  .filter(cat => selected.includes(cat.name))   // keep only selected
  .map(cat => ({
    name: cat.name,
    type: "bar",
    orientation: "h",
    y: yLabels,
    x: raw.map(d => d[cat.name] || 0),
    marker: { color: cat.color }
  }));

// Dynamic margin for labels
const longestLabel = Math.max(...raw.map(d => d.label.length));
const leftMargin = Math.min(350, Math.max(120, longestLabel * 7));

return {
  data: traces,
  layout: {
    barmode: "stack",
    title: "Survey Results",
    plot_bgcolor: "#ffffff",
    paper_bgcolor: "#ffffff",
    font: { color: "#333" },
    margin: {
      l: leftMargin,
      r: 40,
      t: 60,
      b: 60
    },
    legend: {
      orientation: "h",
      y: -0.3
    }
  },
  config: { responsive: true }
};

3. Why this works

  • Fixed colors per category → no more auto-reassignment when filtering.
  • Checkbox filtering → chart only shows selected series (checkboxGroup1.value).
  • Dynamic margins → chart automatically adjusts left margin based on longest label, so text doesn’t overlap or get cut off.
  • Wrapped labels → improves readability for very long labels.

4. Example Result

When some categories are selected:

When one or two are deselected, only the chosen traces appear but colors stay consistent.

3 Likes

Hey @Babs1, glad to see you got some help. Just checking in to see if you were able to assign the colors successfully?

Hey @Babs1, just checking in to see if you were able to assign the colors successfully by using the suggestion above? And if you still need help?