Solid bars in bar chart with react-native-chart-kit

14k Views Asked by At

I am using https://www.npmjs.com/package/react-native-chart-kit and am trying to make a chart to match the following design spec:

enter image description here

I can get most of the options to work with the code attached at the end of this question, however I can't seem to figure out how to remove the opacity of each individual bar, so it ends up looking like this:

enter image description here

I've been poring through the source code and playing with props and styles to no avail.. any help would be greatly appreciated!

const { width: screenWidth } = Dimensions.get('window');

export type DataSet = {
  data: Array<Number>;
};

export type BarChartData = {
  labels: Array<String>;
  datasets: Array<DataSet>;
};

export interface SalesChartProps {
  data: BarChartData;
}

const chartConfig = {
  backgroundGradientFrom: '#Ffffff',
  backgroundGradientTo: '#ffffff',
  barPercentage: 1.3,
  decimalPlaces: 0, // optional, defaults to 2dp
  color: (opacity = 1) => `rgba(1, 122, 205, 1)`,
  labelColor: (opacity = 1) => `rgba(0, 0, 0, 1)`,

  style: {
    borderRadius: 16,
    fontFamily: 'Bogle-Regular',
  },
  propsForBackgroundLines: {
    strokeWidth: 1,
    stroke: '#efefef',
    strokeDasharray: '0',
  },
  propsForLabels: {
    fontFamily: 'Bogle-Regular',
  },
};

const SalesBarChart: FunctionComponent<SalesChartProps> = (
  props: SalesChartProps,
) => (
  <>
    <Text style={styles.chartTitle}> Sales </Text>
    <BarChart
      style={styles.graphStyle}
      showBarTops={false}
      showValuesOnTopOfBars={true}
      withInnerLines={true}
      segments={3}
      data={props.data}
      width={screenWidth - 15}
      height={175}
      yAxisLabel=""
      chartConfig={chartConfig}
      verticalLabelRotation={0}
    />
  </>
);

const styles = StyleSheet.create<{
  graphStyle: ViewStyle;
  chartTitle: TextStyle;
}>({
  graphStyle: {
    flex: 1,
    paddingRight: 25,
  },
  chartTitle: {
    paddingLeft: 20,
    paddingBottom: 20,
    paddingTop: 10,
    fontFamily: 'Bogle-Regular',
    fontSize: 16,
  },
})

//storybook file:
const data: BarChartData = {
  labels: ['9/19', '9/20', '9/21', '9/22', '9/23', '9/24', '9/25'],
  datasets: [
    {
      data: [5, 0, 2, 4, 6, 3, 0],
    },
  ],
};

const props = {
  data,
};

storiesOf('SalesChart', module)
  .addDecorator(withKnobs)
  .add('BarChart', () => <SalesChart {...props} />);

4

There are 4 best solutions below

3
On BEST ANSWER

I don't think it's possible to do this as of now for the BarChart component as the fill of the Rect components that represent the bars are all set to a gradient fillShadowGradient (https://github.com/indiespirit/react-native-chart-kit/blob/master/src/BarChart.tsx).

You can however change the color for these bars and their opacity by changing the following properties in the chartConfig:

fillShadowGradient: 'blue',
fillShadowGradientOpacity: 1,

If the opacity is set to 1 the color does look more solid, but the gradient remains.


An alternative approach is to use a StackedBarChart and put each element in your data in their own array so the bars don't stack:

const CustomStackedChart = () => {
  const data = {
    labels: ['9/19', '9/20', '9/21', '9/22', '9/23', '9/24', '9/25'],
    legend: [],
    data: [[5], [0], [2], [4], [6], [3], [0]],
    barColors: ['blue'],
  };
  return (
    <StackedBarChart
      style={styles.graphStyle}
      segments={3}
      data={data}
      width={300}
      height={175}
      chartConfig={chartConfig}
    />
  );
};

The StackedBarChart does allow a solid color. The color can be set by setting the barColors prop inside the data object.

The problem with this approach is that you can't have the bar labels on top of the bars like you have in your picture:

stacked bar chart showcase


If you really want to create something custom you could create a custom chart component that extends AbstractChart, but this is quite a lot of work to create if the only thing you really want to change is the color of the bars to solid.

https://github.com/indiespirit/react-native-chart-kit#abstract-chart.

1
On

I found this horrible solution, if you use height in the chart config and place it a very high number the bar seems solid, example:

const chartConfig = {
  backgroundGradientFrom: "#fff",
  backgroundGradientTo: "#fff",
  barPercentage: 0.7,
  height:5000,
  fillShadowGradient: `rgba(1, 122, 205, 1)`,
  fillShadowGradientOpacity: 1,
  decimalPlaces: 0, // optional, defaults to 2dp
  color: (opacity = 1) => `rgba(1, 122, 205, 1)`,
  labelColor: (opacity = 1) => `rgba(0, 0, 0, 1)`,

  style: {
    borderRadius: 16,
    fontFamily: "Bogle-Regular",
  },
  propsForBackgroundLines: {
    strokeWidth: 1,
    stroke: "#e3e3e3",
    strokeDasharray: "0",
  },
  propsForLabels: {
    fontFamily: "Bogle-Regular",
  },
};

enter image description here

0
On

Also you can pass individual colors and active flatColor

withCustomBarColorFromData={true}
flatColor={true}

Sample

const data = { 
            labels: ["1", "2", "3", "4", "5", "6","7","8","9"],
            datasets: [
                {
                    data: [40, 84, 56, 40, 60, 55, 40, 72, 40],
                    colors: [
                        (opacity = 1) => `#BE95FF`,
                        (opacity = 1) => `#78A9FF`,
                        (opacity = 1) => `#FFFFFF`,
                        (opacity = 1) => `#FFFFFF`,
                        (opacity = 1) => `#FFFFFF`,
                        (opacity = 1) => `#FFFFFF`,
                        (opacity = 1) => `#FFFFFF`,
                        (opacity = 1) => `#FFFFFF`,
                        (opacity = 1) => `#FFFFFF`,
                    ]
                } 
            ]
        }; 



<BarChart 
  style={{
  marginLeft: - Metrics.padding * 4
  }}
  data={data}
  width={chartStyles.chart.width}
  height={chartStyles.chart.height} 
  chartConfig={{ 
  backgroundColor: "transparent",
  backgroundGradientTo: "white",
  backgroundGradientFromOpacity: 0,
  backgroundGradientFrom: "white",
  backgroundGradientToOpacity: 0,
  color: (opacity = 1) => `#FFFFFF`,
  barPercentage: 0.28,
  barRadius : 5,  
 }}
 withHorizontalLabels={false}
 fromZero={true}
 withCustomBarColorFromData={true}
 flatColor={true}
 withInnerLines={false}
 showBarTops={false}
 showValuesOnTopOfBars={true}
 />

print

0
On

Set the fillShadowGradientFrom and fillShadowGradientTo to the same color and set both fillShadowGradientFromOpacity and fillShadowGradientToOpacity to 1:

fillShadowGradientFrom: `#017acd`,
fillShadowGradientFromOpacity: 1,
fillShadowGradientTo: `#017acd`,
fillShadowGradientToOpacity: 1,

This will result in the bars having solid color.

const chartConfig = {
    backgroundColor: "transparent",
    backGroundGradientTo: "#FFFFFF",
    backgroundGradientToOpacity: 0,
    backGroundGradientFrom: "#FFFFFF",
    backgroundGradientFromOpacity: 0,
    /* THIS IS WHAT YOU WANT */
    fillShadowGradientFrom: `#017acd`,
    fillShadowGradientFromOpacity: 1,
    fillShadowGradientTo: `#017acd`,
    fillShadowGradientToOpacity: 1,
    /* ************* */
    barPercentage: 1,
    decimalPlaces: 0,
    color: (opacity = 1) => `rgba(9, 136, 205, ${opacity})`,
    labelColor: (opacity = 1) => `rgba(0, 0, 0, ${opacity})`,
    style: {
        borderRadius: 0
    }
};
const chartWidth = Dimensions.get("window").width;

Barchart:

<BarChart
   data={{
          labels: ["Jan", "Feb", "Mar"],
          datasets: [
             {
                 data: [
                         Math.random() * 10,
                         Math.random() * 10,
                         Math.random() * 10
                        ]
                    }
                ]
            }}
    width={chartWidth}
    height={250}
    yAxisLabel="R"
    yAxisSuffix="m"
    withInnerLines={false}
    chartConfig={chartConfig}
    verticalLabelRotation={30}
    withHorizontalLabels={true}
    fromZero={false}
    withCustomBarColorFromData={false}
    showBarTops={false}
    showValuesOnTopOfBars={false}
 />

Bar chart with solid color bars (img)