Troubles mapping grafana to apache Echarts

Hi,

I am trying to display a line chart with two series on the yaxis, but I can not map correctly the values. When I do it with one series I have no problems, but when I query two series the following happen:

let values =
let floats =
let categories =

data.series.map((s) => {
categories = s.fields.find((f) => f.name === ‘Time’).values;
values = s.fields.find((f) => f.name === ‘Value’).values;
floats = s.fields.find((f) => f.name === ‘Value’).values;
});

The two series are labeled with the same name “Value” in the Json Dataframe, and so I can only map the first one.
I tried making two separate queries but the same problem arise.
Anyone with the same problem?

1 Like

Facing a similar problem to this as well

I had this issue, for days…it felt like. Finally got a nice boilerplate setup with GPT4.

It pulls from 3 queries right now, and i label the values as such…you should be able to figure it out.

// Function to process series data from multiple queries
function processData(context) {
  const seriesData = context.panel.data.series.flatMap((s) => {
    if (s.refId === "A") {
      // Assuming you've modified your query to include these fields
      const sTime = s.fields.find((f) => f.name === 'Datetime').values.buffer || s.fields.find((f) => f.name === 'Datetime').values;
      const sOpen = s.fields.find((f) => f.name === 'Open').values.buffer || s.fields.find((f) => f.name === 'Open').values;
      const sHigh = s.fields.find((f) => f.name === 'High').values.buffer || s.fields.find((f) => f.name === 'High').values;
      const sLow = s.fields.find((f) => f.name === 'Low').values.buffer || s.fields.find((f) => f.name === 'Low').values;
      const sClose = s.fields.find((f) => f.name === 'Close').values.buffer || s.fields.find((f) => f.name === 'Close').values;

      // Format data for candlestick chart
      const candlestickData = sTime.map((time, index) => {
        return [
          time, // Datetime
          parseFloat(sOpen[index]).toFixed(2), // Open
          parseFloat(sClose[index]).toFixed(2), // Close
          parseFloat(sLow[index]).toFixed(2),  // Lowest
          parseFloat(sHigh[index]).toFixed(2)  // Highest
        ];
      });

      return [{
        name: 'Price Movement',
        type: 'candlestick',
        data: candlestickData,
        yAxisIndex: 0,
        // Additional styling and options can be added here
      }];
      } else if (s.refId === "B") {
        // Process data for 'Size'
        const sTime = s.fields.find((f) => f.name === 'Time').values.buffer || s.fields.find((f) => f.name === 'Time').values;
        const sSize = s.fields.find((f) => f.name === 'Size').values.buffer || s.fields.find((f) => f.name === 'Size').values;
  
        return [{
          name: 'Size',
          type: 'bar',
          showSymbol: false,
          areaStyle: { opacity: 0.1 },
          lineStyle: { width: 1 },
          data: sTime.map((time, index) => [time, parseFloat(sSize[index]).toFixed(2)]),
          yAxisIndex: 1,
        }];
      } else if (s.refId === "C") {
        const sTime = s.fields.find((f) => f.name === 'Date').values.buffer || s.fields.find((f) => f.name === 'Date').values;
        const sDataC = s.fields.find((f) => f.name === 'AtAskFilledSum').values.buffer || s.fields.find((f) => f.name === 'AtAskFilledSum').values;
        const atBid = s.fields.find((f) => f.name === 'AtBidFilledSum').values.buffer || s.fields.find((f) => f.name === 'AtBidFilledSum').values;
        const noMatch = s.fields.find((f) => f.name === 'NoMatchFilledSum').values.buffer || s.fields.find((f) => f.name === 'NoMatchFilledSum').values;
      
        return [
          {
            name: 'AtAskFilledSum',
            type: 'bar',
            stack: 'total',
            data: sTime.map((time, index) => [time, parseFloat(sDataC[index]).toFixed(2)]),
            yAxisIndex: 1,
            barWidth: '15', // Sets the width of the bars. Can be in percentage or absolute value in pixels.
            itemStyle: {
              color: '#ff4d4f', // Sets the color of the bars. Can be a single color or a gradient.
              borderColor: '#333', // Border color of the bars.
              borderWidth: 1, // Border width of the bars.
              borderType: 'solid', // Border type. Other values: 'dashed', 'dotted'
              shadowBlur: 10, // Shadow blur size. Greater value for bigger blur. Set to 0 to disable.
              shadowColor: 'rgba(0, 0, 0, 0.5)', // Shadow color. Use RGBA values for transparency.
              shadowOffsetX: 0, // Horizontal shadow offset.
              shadowOffsetY: 0, // Vertical shadow offset.
              opacity: 1.0, // Opacity of the bars. Range from 0 to 1.
            },
            emphasis: { // Styling for when a bar is hovered
              itemStyle: {
                color: '#67e0e3', // Color when a bar is hovered.
                borderColor: '#67e0e3', // Border color when a bar is hovered.
                borderWidth: 2, // Border width when a bar is hovered.
              }
            },
          },
          {
            name: 'AtBidFilledSum',
            type: 'bar',
            stack: 'total',
            data: sTime.map((time, index) => [time, parseFloat(atBid[index]).toFixed(2)]),
            yAxisIndex: 1,
          },
          {
            name: 'NoMatchFilledSum',
            type: 'bar',
            stack: 'total',
            data: sTime.map((time, index) => [time, parseFloat(noMatch[index]).toFixed(2)]),
            yAxisIndex: 1,
          }
        ];
      }
      // No need for a return here; flatMap will flatten the arrays appropriately
    });
  
    // Configure the rest of the chart with the processed seriesData
    return {
      backgroundColor: 'transparent',
      tooltip: {
        trigger: 'axis',
        axisPointer: {
          type: 'shadow', // Recommended for bar charts to highlight the whole bar.
        },
        // Custom formatter function to display detailed information in the tooltip as needed.
      },
      legend: { left: '0', bottom: 'ee', data: seriesData.map(s => s.name), textStyle: { color: 'rgba(128, 128, 128, .9)' } },
      toolbox: {
        feature: {
          // The dataZoom tool in the toolbox allows users to select a zoom area on the chart.
          dataZoom: {
            yAxisIndex: 'none', // This disables zooming on the y-axis, only allowing x-axis (time) zoom.
            icon: { zoom: 'path://', back: 'path://' } // Icons can be customized here.
          },
          saveAsImage: {}
        }
      },
      xAxis: { type: 'time' },
      yAxis: [
        { type: 'value', min: 'dataMin' },
        { type: 'value', show: true } // Make sure the second y-axis is visible if needed.
      ],
      grid: { left: '2%', right: '2%', top: '2%', bottom: '24%', containLabel: true },
      series: seriesData,
      dataZoom: [ // This is where the zoom and scrollbar functionality is configured.
        {
          type: 'inside', // Enables zooming via mouse scroll or touch gestures.
          start: 0, // Initial zoom range start percentage.
          end: 100 // Initial zoom range end percentage.
        },
        {
          show: true, // Shows the zoom slider control at the bottom of the chart.
          type: 'slider', // Type of dataZoom, a visible slider.
          bottom: '15%', // Position of the slider.
          start: 0, // Initial zoom range start percentage.
          end: 100, // Initial zoom range end percentage.
          height: '40', // Set the height of the slider. Adjust as needed.
          handleSize: '20%',
          moveHandleSize: 20,
          handleStyle: {
            color: '#fff', // Handle color
            borderColor: '#666', // Handle border color
            borderWidth: 1, // Handle border width
            shadowBlur: 2, // Shadow blur effect for the handle
            shadowColor: 'rgba(0, 0, 0, 0.6)', // Shadow color for the handle
            shadowOffsetX: 1, // Horizontal shadow offset for the handle
            shadowOffsetY: 2  // Vertical shadow offset for the handle
          },
          fillerColor: 'rgba(167,183,204,0.4)', // Color of the selected (zoomed) area in the slider.
          backgroundColor: '#000000', // Background color of the slider area.
          borderColor: '#ccc', // Border color of the slider.
        }
        
      ],
    };
  }
  
  // Use the function and pass the context to it
  const echartConfig = processData(context); // Assuming 'context' is defined in your environment
  return echartConfig;

How it works?

Query A- Select Datetime, Open etc etc
-Label the values as such and map them
-plot that series as a candlestick, give it options. etc etc

Query B- Select time, Size From database etc etc
-map it
-plot is as bars, give options etc etc

Query C-
Select Date, atask, atbid etc etc
-map it
-plot as bars, stack, give it opitions etc.

Then we define our regular chart options after that…

Your welcome