DevExtreme v24.1 is now available.

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

Your search did not match any results.

React Charts - Logarithmic vs Linear Axes

The Chart component supports two numeric axis types: linear (or continuous) and logarithmic. This demo shows two charts that display the same data but use different axis types. The bottom chart uses a linear axis, which makes it hard to analyze smaller value changes. For the top chart, a logarithmic Y axis is used to increase data readability.

Backend API
import React from 'react'; import { Chart, Pane, Series, CommonAxisSettings, ValueAxis, Tooltip, Crosshair, HorizontalLine, Label, Legend, } from 'devextreme-react/chart'; import { dataSource } from './data.ts'; const crosshairFormat = { type: 'fixedPoint', precision: 2, }; function App() { return ( <Chart id="chart" dataSource={dataSource} title="Damped Sine Wave" > <Pane name="top" /> <Pane name="bottom" /> <Series pane="top" /> <Series pane="bottom" /> <CommonAxisSettings endOnTick={false} /> <ValueAxis title="Logarithmic Axis" linearThreshold={-3} type="logarithmic" pane="top" /> <ValueAxis title="Linear Axis" pane="bottom" /> <Tooltip enabled={true} format="exponential" /> <Crosshair enabled={true}> <HorizontalLine visible={false} /> <Label visible={true} format={crosshairFormat} /> </Crosshair> <Legend visible={false} /> </Chart> ); } export default App;
import React from 'react'; import { Chart, Pane, Series, CommonAxisSettings, ValueAxis, Tooltip, Crosshair, HorizontalLine, Label, Legend, } from 'devextreme-react/chart'; import { dataSource } from './data.js'; const crosshairFormat = { type: 'fixedPoint', precision: 2, }; function App() { return ( <Chart id="chart" dataSource={dataSource} title="Damped Sine Wave" > <Pane name="top" /> <Pane name="bottom" /> <Series pane="top" /> <Series pane="bottom" /> <CommonAxisSettings endOnTick={false} /> <ValueAxis title="Logarithmic Axis" linearThreshold={-3} type="logarithmic" pane="top" /> <ValueAxis title="Linear Axis" pane="bottom" /> <Tooltip enabled={true} format="exponential" /> <Crosshair enabled={true}> <HorizontalLine visible={false} /> <Label visible={true} format={crosshairFormat} /> </Crosshair> <Legend visible={false} /> </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: ({ arg: number; val: number; })[] = []; for (let i = 0; i < 600; i += 1) { const argument = i / 100; dataSource.push({ arg: argument, val: Math.exp(-argument) * Math.cos(2 * Math.PI * argument) }); }
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, }, }, paths: { 'npm:': 'https://unpkg.com/', }, defaultExtension: 'js', map: { 'ts': 'npm:plugin-typescript@4.2.4/lib/plugin.js', 'typescript': 'npm:typescript@4.2.4/lib/typescript.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@15.8.1/prop-types.js', 'rrule': 'npm:rrule@2.6.4/dist/es5/rrule.js', 'luxon': 'npm:luxon@1.28.1/build/global/luxon.min.js', 'es6-object-assign': 'npm:es6-object-assign@1.1.0', 'devextreme': 'npm:devextreme@24.1.6/cjs', 'devextreme-react': 'npm:devextreme-react@24.1.6/cjs', 'jszip': 'npm:jszip@3.10.1/dist/jszip.min.js', 'devextreme-quill': 'npm:devextreme-quill@1.7.1/dist/dx-quill.min.js', 'devexpress-diagram': 'npm:devexpress-diagram@2.2.11/dist/dx-diagram.js', 'devexpress-gantt': 'npm:devexpress-gantt@4.1.56/dist/dx-gantt.js', '@devextreme/runtime': 'npm:@devextreme/runtime@3.0.13', '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@7.4.11/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.13/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 = []; for (let i = 0; i < 600; i += 1) { const argument = i / 100; dataSource.push({ arg: argument, val: Math.exp(-argument) * Math.cos(2 * Math.PI * argument) }); }
<!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="dx-theme" data-theme="generic.light" href="https://cdn3.devexpress.com/jslib/24.1.6/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: 450px; }

Logarithmic scales increment values not by adding a constant number, but by multiplying it by a specific factor - logarithmBase. On a base 10 scale, the visual range between 1 and 10 will be the same as range between 10 and 100. This makes it easier to analyze data that has high peaks, yet requires you to review changes for small argument values too.

Graphs in this demo display negative and zero values, and this scenario needs special consideration if you use logarithmic axes. The chart can build and unlimited number of tick marks that never reach 0 - 100, 10, 1, 0.1, 0.01, 0.001, and so on. To cut off this sequence, set the linearThreshold property. In this demo, it is set to -3, which means that between -10-3 and 10-3, or between -0.001 and 0.001, the chart uses linear data presentation.