DevExtreme v24.2 is now available.

Explore our newest features/capabilities and share your thoughts with us.

Your search did not match any results.

React Charts - Bi-Directional Bar Chart

To create a bi-directional bar chart, follow the steps below.

Backend API
import React from 'react'; import Chart, { CommonSeriesSettings, ValueAxis, Label, Legend, Series, Tooltip, Margin, } from 'devextreme-react/chart'; import { dataSource } from './data.ts'; function customizeTooltip(e: { valueText: number; }) { return { text: Math.abs(e.valueText) }; } function customizeLabel(e: {value: Date | number | string}) { return `${Math.abs(e.value as number)}%`; } function App() { return ( <Chart title="Population Pyramid For Norway 2016" dataSource={dataSource} id="chart" rotated={true} barGroupWidth={18} > <CommonSeriesSettings type="stackedbar" argumentField="age" /> <Series valueField="male" name="Male" color="#3F7FBF" /> <Series valueField="female" name="Female" color="#F87CCC" /> <Tooltip enabled={true} customizeTooltip={customizeTooltip} /> <ValueAxis> <Label customizeText={customizeLabel} /> </ValueAxis> <Legend verticalAlignment="bottom" horizontalAlignment="center" > <Margin left={50} /> </Legend> </Chart> ); } export default App;
import React from 'react'; import Chart, { CommonSeriesSettings, ValueAxis, Label, Legend, Series, Tooltip, Margin, } from 'devextreme-react/chart'; import { dataSource } from './data.js'; function customizeTooltip(e) { return { text: Math.abs(e.valueText) }; } function customizeLabel(e) { return `${Math.abs(e.value)}%`; } function App() { return ( <Chart title="Population Pyramid For Norway 2016" dataSource={dataSource} id="chart" rotated={true} barGroupWidth={18} > <CommonSeriesSettings type="stackedbar" argumentField="age" /> <Series valueField="male" name="Male" color="#3F7FBF" /> <Series valueField="female" name="Female" color="#F87CCC" /> <Tooltip enabled={true} customizeTooltip={customizeTooltip} /> <ValueAxis> <Label customizeText={customizeLabel} /> </ValueAxis> <Legend verticalAlignment="bottom" horizontalAlignment="center" > <Margin left={50} /> </Legend> </Chart> ); } export default App;
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App.tsx'; ReactDOM.render( <App />, document.getElementById('app'), );
export const dataSource = [{ age: '0-4', male: -3.1, female: 2.9, }, { age: '5-9', male: -3.1, female: 3.0, }, { age: '10-14', male: -3.0, female: 2.9, }, { age: '15-19', male: -3.2, female: 3.0, }, { age: '20-24', male: -3.5, female: 3.3, }, { age: '25-29', male: -3.5, female: 3.4, }, { age: '30-34', male: -3.5, female: 3.3, }, { age: '35-39', male: -3.3, female: 3.1, }, { age: '40-44', male: -3.7, female: 3.4, }, { age: '45-49', male: -3.8, female: 3.5, }, { age: '50-54', male: -3.4, female: 3.2, }, { age: '55-59', male: -3.1, female: 3.0, }, { age: '60-64', male: -2.7, female: 2.7, }, { age: '65-69', male: -2.9, female: 2.9, }, { age: '70-74', male: -2, female: 2.1, }, { age: '75-79', male: -1.2, female: 1.4, }, { age: '80-84', male: -0.8, female: 1.2, }, { age: '85-89', male: -0.5, female: 0.8, }, { age: '90-94', male: -0.2, female: 0.5, }, { age: '95+', male: 0, female: 0.1, }];
window.exports = window.exports || {}; window.config = { transpiler: 'ts', typescriptOptions: { module: 'system', emitDecoratorMetadata: true, experimentalDecorators: true, jsx: 'react', }, meta: { 'react': { 'esModule': true, }, 'typescript': { 'exports': 'ts', }, 'devextreme/time_zone_utils.js': { 'esModule': true, }, 'devextreme/localization.js': { 'esModule': true, }, 'devextreme/viz/palette.js': { 'esModule': true, }, 'openai': { 'esModule': true, }, }, paths: { 'npm:': 'https://unpkg.com/', 'bundles:': '../../../../bundles/', 'externals:': '../../../../bundles/externals/', }, defaultExtension: 'js', map: { 'ts': 'npm:plugin-typescript@8.0.0/lib/plugin.js', 'typescript': 'npm:typescript@4.2.4/lib/typescript.js', 'jszip': 'npm:jszip@3.10.1/dist/jszip.min.js', 'react': 'npm:react@17.0.2/umd/react.development.js', 'react-dom': 'npm:react-dom@17.0.2/umd/react-dom.development.js', 'prop-types': 'npm:prop-types/prop-types.js', 'rrule': 'npm:rrule@2.6.4/dist/es5/rrule.js', 'luxon': 'npm:luxon@3.4.4/build/global/luxon.min.js', 'es6-object-assign': 'npm:es6-object-assign', 'devextreme': 'npm:devextreme@link:../../packages/devextreme/artifacts/npm/devextreme/cjs', 'devextreme-react': 'npm:devextreme-react@link:../../packages/devextreme-react/npm/cjs', 'devextreme-quill': 'npm:devextreme-quill@1.7.1/dist/dx-quill.min.js', 'devexpress-diagram': 'npm:devexpress-diagram@2.2.5/dist/dx-diagram.js', 'devexpress-gantt': 'npm:devexpress-gantt@4.1.54/dist/dx-gantt.js', '@devextreme/runtime': 'npm:@devextreme/runtime@3.0.12', 'inferno': 'npm:inferno@7.4.11/dist/inferno.min.js', 'inferno-compat': 'npm:inferno-compat/dist/inferno-compat.min.js', 'inferno-create-element': 'npm:inferno-create-element@7.4.11/dist/inferno-create-element.min.js', 'inferno-dom': 'npm:inferno-dom/dist/inferno-dom.min.js', 'inferno-hydrate': 'npm:inferno-hydrate/dist/inferno-hydrate.min.js', 'inferno-clone-vnode': 'npm:inferno-clone-vnode/dist/inferno-clone-vnode.min.js', 'inferno-create-class': 'npm:inferno-create-class/dist/inferno-create-class.min.js', 'inferno-extras': 'npm:inferno-extras/dist/inferno-extras.min.js', 'devextreme-cldr-data': 'npm:devextreme-cldr-data@1.0.3', // SystemJS plugins 'plugin-babel': 'npm:systemjs-plugin-babel@0.0.25/plugin-babel.js', 'systemjs-babel-build': 'npm:systemjs-plugin-babel@0.0.25/systemjs-babel-browser.js', // Prettier 'prettier/standalone': 'npm:prettier@2.8.8/standalone.js', 'prettier/parser-html': 'npm:prettier@2.8.8/parser-html.js', }, packages: { 'devextreme': { defaultExtension: 'js', }, 'devextreme-react': { main: 'index.js', }, 'devextreme/events/utils': { main: 'index', }, 'devextreme/localization/messages': { format: 'json', defaultExtension: 'json', }, 'devextreme/events': { main: 'index', }, 'es6-object-assign': { main: './index.js', defaultExtension: 'js', }, }, packageConfigPaths: [ 'npm:@devextreme/*/package.json', 'npm:@devextreme/runtime@3.0.12/inferno/package.json', ], babelOptions: { sourceMaps: false, stage0: true, react: true, }, }; System.config(window.config);
import React from 'react'; import ReactDOM from 'react-dom'; import App from './App.js'; ReactDOM.render(<App />, document.getElementById('app'));
export const dataSource = [ { age: '0-4', male: -3.1, female: 2.9, }, { age: '5-9', male: -3.1, female: 3.0, }, { age: '10-14', male: -3.0, female: 2.9, }, { age: '15-19', male: -3.2, female: 3.0, }, { age: '20-24', male: -3.5, female: 3.3, }, { age: '25-29', male: -3.5, female: 3.4, }, { age: '30-34', male: -3.5, female: 3.3, }, { age: '35-39', male: -3.3, female: 3.1, }, { age: '40-44', male: -3.7, female: 3.4, }, { age: '45-49', male: -3.8, female: 3.5, }, { age: '50-54', male: -3.4, female: 3.2, }, { age: '55-59', male: -3.1, female: 3.0, }, { age: '60-64', male: -2.7, female: 2.7, }, { age: '65-69', male: -2.9, female: 2.9, }, { age: '70-74', male: -2, female: 2.1, }, { age: '75-79', male: -1.2, female: 1.4, }, { age: '80-84', male: -0.8, female: 1.2, }, { age: '85-89', male: -0.5, female: 0.8, }, { age: '90-94', male: -0.2, female: 0.5, }, { age: '95+', male: 0, female: 0.1, }, ];
<!DOCTYPE html> <html lang="en"> <head> <title>DevExtreme Demo</title> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0" /> <link rel="stylesheet" type="text/css" href="https://cdn3.devexpress.com/jslib/24.2.3/css/dx.light.css" /> <link rel="stylesheet" type="text/css" href="styles.css" /> <script src="https://unpkg.com/core-js@2.6.12/client/shim.min.js"></script> <script src="https://unpkg.com/systemjs@0.21.3/dist/system.js"></script> <script type="text/javascript" src="config.js"></script> <script type="text/javascript"> System.import("./index.tsx"); </script> </head> <body class="dx-viewport"> <div class="demo-container"> <div id="app"></div> </div> </body> </html>
#chart { height: 549px; width: 820px; margin: 0 auto; }
  1. Convert half of the data source values from positive to negative. In this demo, the male percentages are negative, while the female are positive.

  2. Implement a rotated stacked bar chart. Use the commonSeriesSettings object to specify the type and the argumentField property (age in this case). Set the rotated property to true.

  3. Declare two objects in the series array: one for negative values, the other for positive. Specify the color, name, and valueField for each series.

  4. Change the label text of the valueAxis so that the negative values appear as positive. To implement this technique, use the customizeText function.

To further customize your bi-directional bar chart, implement tooltips and change the legend's alignment.