How to specify the color scale within the data object in Victory Pie
Asked Answered
T

6

7

I used VictoryChart to implement a pie graph and it works fine...

render() {

    const data_distribution = this.state.pie_keys.map((d) => ({x:d, y:this.state.pie_data[d], label:d }));

    return (
      <div className="App">
        <div className="pie_wrapper">
          <VictoryPie
            labelComponent={<VictoryTooltip cornerRadius={0} />}   
            padAngle={0.5}
            innerRadius={100}
            width={400} height={400}
            style={{ 
              labels: { fontSize: 15, fill: "black"},
              data: {
                  fillOpacity: 0.9, stroke: "white", strokeWidth: 3
              }
            }}
            labelRadius={90}
            data = {data_distribution}
          />
        </div>
      </div>
    );
  }

It is important to note that data_distribution simply looks as follows...

data={[
    { x: "Fac of Engineering & Appl Sci", y: 8.557902403495994 },
    { x: "Faculty of Arts and Science", y: 53.775188152464196 },
    { x: "Faculty of Education", y: 13.085700412721534 },
    ...
    ...
  ]}

So I'm wondering if I can set the color for each piece of the pie within the data object. The documentation specifies that...

color scales: "grayscale", "qualitative", "heatmap", "warm", "cool", "red", "green", "blue". VictoryPie will assign a color to each slice by index, unless they are explicitly specified in the data object.

This says that you can but I cannot figure out how. I tried the following...

data={[
    { x: "Fac of Engineering & Appl Sci", y: 8.557902403495994, colorScale:"red" },
    { x: "Faculty of Arts and Science", y: 53.775188152464196, colorScale:"red" },
    { x: "Faculty of Education", y: 13.085700412721534, colorScale:"red" },
    ...
    ...
]}

which translates to...

const data_distribution = this.state.pie_keys.map((d) => ({x:d, y:this.state.pie_data[d], label:d, colorScale:"red"}));

However, they do not turn red. I cannot find an example online. Is this possible to do or not?

I know that I can define colorScale: {[...]} but that is not what I'm asking. I want to be able to set each piece of the pie from within the data object.

Tequila answered 1/8, 2018 at 5:44 Comment(6)
The first line inside your render function, which looks like your data_distribution mapping, doesn't include colorScale at all ... is this intentional ?Janot
@AlexMcMillan I do not know how to include it, that is essentially what I am trying to figure out.Tequila
@AlexMcMillan I tried the following const data_distribution = this.state.pie_keys.map((d) => ({x:d, y:this.state.pie_data[d], label:d, colorScale:"red"})); because I do not know how to do it properlyTequila
try putting a console.log(data_dictionary); immediately after that line, and look in the browser console at what you're creating. See if it makes sense to you and is what you expected, then compare it to the documentation for the VictoryChart libraryJanot
Okay, it looks like you need to pass colorScale: ["red"] as an argument to the VictoryPie component, not as a field in your data. Try <VictoryPie ...{everything else}... colorScale={["red"]} />Janot
@AlexMcMillan Yeah I can do this, but VictoryChart documentation states that I can also set it explicitly within the data object and I'm trying to find out how and if it is possible.Tequila
S
9

I know this question has been "answered", but the answer is unsatisfactory to me. Since I came here and left frustrated, I've decided to post my solution in the hopes that others might get some use out of it.

You can override the colors for individual slices using the style prop:

<VictoryPie
  data={[
    { x: "Cats", y: 35 },
    { x: "Dogs", y: 40 },
    { x: "Birds", y: 55 }
  ]}
  style={{
    data: {
      fill: ({ y }) =>
        y > 49 ? 'green'
        : y > 39 ? 'yellow'
        : 'tomato'
    }
  }}
/>

In this case, you should not use colorScale at all. I've read the source, and far as I can tell, this is the only way to do a data-based color mapping in VictoryPie.

Slam answered 31/10, 2018 at 19:8 Comment(5)
Thank you, I was frustrated as well and chose an answer that was unsatisfactory.Tequila
For some reason, this does tomato for all dataPiotrowski
On the fill callback you get the current item. You have access its index and to the original data. That way you can do the following: fill: d => d.data[d.index].colorScaleObsolescent
The latest version of victory passes a different value to the callback. You can access y via obj.slice.data.y.Chili
FYI: Using datum.y instead of y should solve the problem: data: { fill: ({ datum }) => datum.y > 49 ? 'green' : datum.y > 39 ? 'yellow' : 'tomato' }Pearse
H
7

You can derive the fill color based on your data, but you have to provide that logic. Your accepted answer applies color based on y value, however you can also specify the color in the data itself so long as you set the style to do so:

<VictoryPie
  data={[
    { x: "Cats", y: 35, yourAttribute: "#0000FF" },
    { x: "Dogs", y: 40, yourAttribute: "#00FF00" },
    { x: "Birds", y: 55, yourAttribute:"#FF0000" }
  ]}
  style={{
    data: {
      fill: (d) => d.yourAttribute
    }
  }}
/>
Helminthology answered 28/2, 2019 at 0:37 Comment(2)
On the latest version of Victory, the callback should be (d) => d.slice.data.yourAttributeChili
style={{ data: { fill: ({ d}) => d.yourAttribute } }}Mulcahy
W
5

For the current version

"victory": "^35.4.0",
"victory-native": "^35.3.1"

you can do:

 <VictoryPie
        data={[
            { x: "Cats", y: 35, fill: "gold" },
            { x: "Dogs", y: 40, fill: "tomato" },
            { x: "Birds", y: 55, fill: "navy" }
        ]}
        style={{
            data: {
                fill: ({datum}) => datum.fill
            }
        }}
   />

See https://formidable.com/open-source/victory/docs/common-props/#data

Wonderwork answered 2/12, 2020 at 12:42 Comment(0)
H
3

I manually added a function to generate randomly try if this helps you `var stats = this.state.statistics;

var stat = this.state.statistic;
        if (stats.length>0) {
            if(this.colors.length<stats.length){
                for(let i=0;i<stats.length;i++){
                    this.colors.push(getRandomColor());
                }
            }
        }
        const color = ['#9167f1', '#f26893', '#99cfef', '#99ef9a'];
        const colors = this.colors;`

function getRandomColor() {
    var letters = '0123456789abcdef';
    var color = '#';
    for (var i = 0; i < 6; i++) {
        color += letters[Math.floor(Math.random() * 16)];
    }
    return color;
}
Hamil answered 7/8, 2018 at 8:14 Comment(0)
H
2

If you know the data rendering order then you can use the colors in same order it will automatically take the color in order

<VictoryPie
  colorScale={["black", "red", "green", "#4cc9ff", "navy" ]}
  data={sampleData}
/>
Hamil answered 1/8, 2018 at 5:54 Comment(3)
That is true and I have noticed that, but if you have more pieces then colors, then it will start choosing colors at random after you have exhausted all the colors.Tequila
Essentially I am trying to figure out a way in which I can keep track of what color is being used by each piece if I have more pieces then colors.Tequila
Seeing as I couldn't figure out what I wanted, this was the approach I ended up going with.Tequila
S
2

I think instead of colorScale: "red", you want fill: "red" in the data object since Victory's Slice primitives are just svg <Path> elements.

Suppurative answered 8/10, 2018 at 17:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.