Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Designing Multi–Y-Axis Charts in ECharts with Bars, Lines, and Mixed Series

Tech 2

Designing multi–Y-axis charts in ECharts becomes essential when visualizing measures at different scales (for example, thousands of devices vs. tens of products). The following patterns progressively build from a single axis to several Y-axes and finallly to mixed-series charts.

Setup

  • Include ECharts and prepare a container sized explicitly with width and height.
<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <title>Multi-Y Axis with ECharts</title>
    <script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
    <style>
      #chart { width: 1200px; height: 500px; }
    </style>
  </head>
  <body>
    <div id="chart"></div>
    <script>
      const months = [
        '2016-01','2016-02','2016-03','2016-04','2016-05','2016-06',
        '2016-07','2016-08','2016-09','2016-10','2016-11','2016-12'
      ];

      const dataDevices  = [9200, 1800, 1400, 3100, 6200, 9800, 2300, 3400, 3720, 5300, 1600, 8700];
      const dataProducts = [12, 44, 85, 31, 49, 90, 36, 22, 48, 110, 27, 160];
      const dataVendors  = [8, 12, 22, 28, 18, 15, 14, 40, 55, 63, 88, 120];
      const dataUsers    = [25000, 6200, 47000, 12000, 28000, 19000, 60000, 42000, 44000, 70000, 89000, 15000];
      const dataMetricX  = [120000, 40000, 240000, 100000, 230000, 150000, 90000, 470000, 130000, 560000, 280000, 140000];

      const palette = ['#5470C6', '#91CC75', '#EE6666', '#73C0DE', '#FAC858'];

      const chart = echarts.init(document.getElementById('chart'));

      function render(option) {
        chart.clear();
        chart.setOption(option, true);
      }
    </script>
  </body>
</html>

Single Y-axis, single series A basic column chart with one Y-axis and one series.

<script>
const singleAxisOption = {
  color: [palette[0]],
  tooltip: { trigger: 'axis' },
  grid: { left: 50, right: 20, top: 30, bottom: 40 },
  legend: { data: ['Devices Added'] },
  xAxis: {
    type: 'category',
    data: months,
    axisTick: { alignWithLabel: true }
  },
  yAxis: {
    type: 'value',
    name: 'Devices',
    min: 0, max: 11000,
    axisLabel: { formatter: (v) => v }
  },
  series: [
    { name: 'Devices Added', type: 'bar', barMaxWidth: 30, data: dataDevices }
  ]
};
render(singleAxisOption);
</script>

Single Y-axis, two series (scale mismatch) Adding a second measure of a much smaller magnitude makes the smaller series hard to read when sharing a single Y-axis.

<script>
const singleAxisTwoSeriesOption = {
  color: [palette[0], palette[1]],
  tooltip: { trigger: 'axis' },
  grid: { left: 50, right: 20, top: 30, bottom: 40 },
  legend: { data: ['Devices Added', 'Products Added'] },
  xAxis: { type: 'category', data: months },
  yAxis: { type: 'value', name: 'Count' },
  series: [
    { name: 'Devices Added', type: 'bar', data: dataDevices },
    { name: 'Products Added', type: 'bar', data: dataProducts }
  ]
};
render(singleAxisTwoSeriesOption);
</script>

Dual Y-axes Map each series to its own axis using yAxisIndex. Place one axis on the left and one on the right.

<script>
const twoAxesOption = {
  color: [palette[0], palette[1]],
  tooltip: { trigger: 'axis' },
  grid: { left: 50, right: 60, top: 30, bottom: 40 },
  legend: { data: ['Devices Added', 'Products Added'] },
  xAxis: { type: 'category', data: months },
  yAxis: [
    { type: 'value', name: 'Devices', position: 'left', min: 0, max: 11000, axisLine: { lineStyle: { color: palette[0] } } },
    { type: 'value', name: 'Products', position: 'right', min: 0, max: 200, axisLine: { lineStyle: { color: palette[1] } } }
  ],
  series: [
    { name: 'Devices Added', type: 'bar', barMaxWidth: 30, data: dataDevices, yAxisIndex: 0 },
    { name: 'Products Added', type: 'bar', barMaxWidth: 30, data: dataProducts, yAxisIndex: 1 }
  ]
};
render(twoAxesOption);
</script>

Three Y-axes Add a third axis on the right and push it away using offset to avoid overlap.

<script>
const threeAxesOption = {
  color: [palette[0], palette[1], palette[2]],
  tooltip: { trigger: 'axis' },
  grid: { left: 50, right: 120, top: 30, bottom: 40 },
  legend: { data: ['Devices Added', 'Products Added', 'Vendors Onboarded'] },
  xAxis: { type: 'category', data: months },
  yAxis: [
    { type: 'value', name: 'Devices', position: 'left',  min: 0, max: 11000, axisLine: { lineStyle: { color: palette[0] } } },
    { type: 'value', name: 'Products', position: 'right', min: 0, max: 200,   axisLine: { lineStyle: { color: palette[1] } } },
    { type: 'value', name: 'Vendors',  position: 'right', offset: 70, min: 0, max: 200, axisLine: { lineStyle: { color: palette[2] } } }
  ],
  series: [
    { name: 'Devices Added', type: 'bar', data: dataDevices,  yAxisIndex: 0 },
    { name: 'Products Added', type: 'bar', data: dataProducts, yAxisIndex: 1 },
    { name: 'Vendors Onboarded', type: 'bar', data: dataVendors, yAxisIndex: 2 }
  ]
};
render(threeAxesOption);
</script>

Four Y-axes Introduce a fourth measure with a much larger scale (e.g., new users). Increase right grid spacing and manage offsets.

<script>
const fourAxesOption = {
  color: [palette[0], palette[1], palette[2], palette[3]],
  tooltip: { trigger: 'axis' },
  grid: { left: 50, right: 200, top: 30, bottom: 40 },
  legend: { data: ['Devices Added', 'Products Added', 'Vendors Onboarded', 'Users Joined'] },
  xAxis: { type: 'category', data: months },
  yAxis: [
    { type: 'value', name: 'Devices', position: 'left',  min: 0, max: 11000, axisLine: { lineStyle: { color: palette[0] } } },
    { type: 'value', name: 'Products', position: 'right', min: 0, max: 200,   axisLine: { lineStyle: { color: palette[1] } } },
    { type: 'value', name: 'Vendors',  position: 'right', offset: 70, min: 0, max: 200, axisLine: { lineStyle: { color: palette[2] } } },
    { type: 'value', name: 'Users',    position: 'right', offset: 150, min: 0, max: 90000, axisLine: { lineStyle: { color: palette[3] } } }
  ],
  series: [
    { name: 'Devices Added', type: 'bar', data: dataDevices,  yAxisIndex: 0 },
    { name: 'Products Added', type: 'bar', data: dataProducts, yAxisIndex: 1 },
    { name: 'Vendors Onboarded', type: 'bar', data: dataVendors, yAxisIndex: 2 },
    { name: 'Users Joined', type: 'bar', data: dataUsers, yAxisIndex: 3 }
  ]
};
render(fourAxesOption);
</script>

Five Y-axes Add a fifth axis for an even larger metric (e.g., revenue), with an additional offset.

<script>
const fiveAxesOption = {
  color: [palette[0], palette[1], palette[2], palette[3], palette[4]],
  tooltip: { trigger: 'axis' },
  grid: { left: 50, right: 260, top: 30, bottom: 40 },
  legend: { data: ['Devices Added', 'Products Added', 'Vendors Onboarded', 'Users Joined', 'Metric X'] },
  xAxis: { type: 'category', data: months },
  yAxis: [
    { type: 'value', name: 'Devices', position: 'left',  min: 0, max: 11000, axisLine: { lineStyle: { color: palette[0] } } },
    { type: 'value', name: 'Products', position: 'right', min: 0, max: 200,   axisLine: { lineStyle: { color: palette[1] } } },
    { type: 'value', name: 'Vendors',  position: 'right', offset: 70,  min: 0, max: 200,    axisLine: { lineStyle: { color: palette[2] } } },
    { type: 'value', name: 'Users',    position: 'right', offset: 150, min: 0, max: 90000,  axisLine: { lineStyle: { color: palette[3] } } },
    { type: 'value', name: 'Metric X', position: 'right', offset: 220, min: 0, max: 600000, axisLine: { lineStyle: { color: palette[4] } } }
  ],
  series: [
    { name: 'Devices Added', type: 'bar', data: dataDevices,  yAxisIndex: 0 },
    { name: 'Products Added', type: 'bar', data: dataProducts, yAxisIndex: 1 },
    { name: 'Vendors Onboarded', type: 'bar', data: dataVendors, yAxisIndex: 2 },
    { name: 'Users Joined', type: 'bar', data: dataUsers, yAxisIndex: 3 },
    { name: 'Metric X', type: 'bar', data: dataMetricX, yAxisIndex: 4 }
  ]
};
render(fiveAxesOption);
</script>

All-line variant (multi–Y-axis) Switch all series to lines by changing series.type to 'line'.

<script>
const fiveAxesLinesOption = {
  color: [palette[0], palette[1], palette[2], palette[3], palette[4]],
  tooltip: { trigger: 'axis' },
  grid: { left: 50, right: 260, top: 30, bottom: 40 },
  legend: { data: ['Devices Added', 'Products Added', 'Vendors Onboarded', 'Users Joined', 'Metric X'] },
  xAxis: { type: 'category', data: months },
  yAxis: [
    { type: 'value', name: 'Devices', position: 'left',  min: 0, max: 11000, axisLine: { lineStyle: { color: palette[0] } } },
    { type: 'value', name: 'Products', position: 'right', min: 0, max: 200,   axisLine: { lineStyle: { color: palette[1] } } },
    { type: 'value', name: 'Vendors',  position: 'right', offset: 70,  min: 0, max: 200,    axisLine: { lineStyle: { color: palette[2] } } },
    { type: 'value', name: 'Users',    position: 'right', offset: 150, min: 0, max: 90000,  axisLine: { lineStyle: { color: palette[3] } } },
    { type: 'value', name: 'Metric X', position: 'right', offset: 220, min: 0, max: 600000, axisLine: { lineStyle: { color: palette[4] } } }
  ],
  series: [
    { name: 'Devices Added', type: 'line', smooth: true, data: dataDevices,  yAxisIndex: 0 },
    { name: 'Products Added', type: 'line', smooth: true, data: dataProducts, yAxisIndex: 1 },
    { name: 'Vendors Onboarded', type: 'line', smooth: true, data: dataVendors, yAxisIndex: 2 },
    { name: 'Users Joined', type: 'line', smooth: true, data: dataUsers, yAxisIndex: 3 },
    { name: 'Metric X', type: 'line', smooth: true, data: dataMetricX, yAxisIndex: 4 }
  ]
};
render(fiveAxesLinesOption);
</script>

Mixed bars and lines (multi–Y-axis) Mixing series types (some bars, some lines) highlights different dynamics while keeping separate axes for scale.

<script>
const mixedOption = {
  color: [palette[0], palette[1], palette[2], palette[3], palette[4]],
  tooltip: { trigger: 'axis' },
  grid: { left: 50, right: 260, top: 30, bottom: 40 },
  legend: { data: ['Devices Added', 'Products Added', 'Vendors Onboarded', 'Users Joined', 'Metric X'] },
  xAxis: { type: 'category', data: months },
  yAxis: [
    { type: 'value', name: 'Devices', position: 'left',  min: 0, max: 11000, axisLine: { lineStyle: { color: palette[0] } } },
    { type: 'value', name: 'Products', position: 'right', min: 0, max: 200,   axisLine: { lineStyle: { color: palette[1] } } },
    { type: 'value', name: 'Vendors',  position: 'right', offset: 70,  min: 0, max: 200,    axisLine: { lineStyle: { color: palette[2] } } },
    { type: 'value', name: 'Users',    position: 'right', offset: 150, min: 0, max: 90000,  axisLine: { lineStyle: { color: palette[3] } } },
    { type: 'value', name: 'Metric X', position: 'right', offset: 220, min: 0, max: 600000, axisLine: { lineStyle: { color: palette[4] } } }
  ],
  series: [
    { name: 'Devices Added', type: 'line', smooth: true, data: dataDevices,  yAxisIndex: 0 },
    { name: 'Products Added', type: 'line', smooth: true, data: dataProducts, yAxisIndex: 1 },
    { name: 'Vendors Onboarded', type: 'bar', barMaxWidth: 28, data: dataVendors, yAxisIndex: 2 },
    { name: 'Users Joined',     type: 'bar', barMaxWidth: 28, data: dataUsers,   yAxisIndex: 3 },
    { name: 'Metric X',         type: 'bar', barMaxWidth: 28, data: dataMetricX, yAxisIndex: 4 }
  ]
};
render(mixedOption);
</script>

Implementation notes

  • Add a new Y-axis by appending an entry to the yAxis array; place additional right-side axes using offset to prevent overlap.
  • Bind each series to its axis with yAxisIndex.
  • Tune grid.right to leave space for multiple right-side axes.
  • Optionally color-code axisLine.lineStyle.color to match series for readability.
  • Choose bar or line series types to emphasize distribution or trend.

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.