Customized Grafana visualizations with Plotly Panel

grafana_plotly

Customized Grafana visualizations with Plotly Panel

  • Grafana does not directly support many visualizations out of the box (like scatter plots, box plots, sunburst chart etc.
  • We will use the Plotly panel Grafana plugin to create highly customizable visualizations

How Plotly Panel works

  • Plotly panel uses Plotly JS JavaScript library to create the visualization in Grafana Panel
  • Plotly JS is a famous and opensource charting library that has a provision to easily create various types of visualizations (like scatter plots, box plots, bar charts, 3d charts, sunburst chart etc.)
  • The JavaScript code required to create the desired visualization is to be written in the “Script” input of a Plotly panel in Grafana dashboard.

Plotly Panel Grafana plugin installation

image.png

image.png

Using Plotly panel in Grafana dashboard

  • Create a panel in the dashboard. In the panel editing screen, select the visualization as “Plotly panel” as shown below

image.png

Plotly panel Script

image.png

  • The Plotly panel script should return a JavaScript object with attributes data, layout and config (layout and config are optional)
    • data is a list of traces. Each trace contains a data series like timeseries, bar chart etc. (refer examples of various trace types here).
    • layout is the non-data related visual attributes like title, margins, backgrounds, axis configuration etc. (refer various layout options here)
    • config is the high-level options for the chart like scroll zoom behavior, mode bar visibility etc. (refer various config options here)
  • The script will have 2 JavaScript variables data and variables populated
    • The data variable contains the data fetched by the Grafana queries. So, the data from Grafana data sources can be used by Plotly Script using the data variable. For example, data.series[0].fields[1].values is the values of the 1st query and data.series[0].fields[1].values is the timestamps of the 2nd query
    • The variables variable contains the Grafana variables of the current dashboard (like user variables, global variables like __from, __to, __interval and __interval_ms)

Examples

The following are the example scripts that can be used in a Grafana Plotly panel

Scatter plot example

// Correlation of stock prices between 2 companies
xData = data.series[0].fields[1].values;
yData = data.series[1].fields[1].values;

var trace1 = {
    x: xData,
    y: yData,
    mode: 'markers',
    type: 'scatter',
    marker: { size: 3 }
};

var tracesData = [trace1];

var layout = {
    title: {
        text: "Stock price correlation between Acme and Whimsey",
        font: {
            family: 'Helvetica, Arial, sans-serif',
            color: "rgb(200, 200, 200)"
        }
    },
    yaxis: {
        autorange: true,
        showgrid: true,
        gridcolor: "rgb(150, 150, 150)",
        gridwidth: 1,
        type: "linear",
    },
    xaxis: {
        type: "linear"
    },
    margin: {
        l: 40, r: 30, b: 80, t: 100
    },
    paper_bgcolor: "rgb(50, 50, 50)",
    plot_bgcolor: "rgb(50, 50, 50)",
    showlegend: false
};

return {
    data: tracesData,
    layout: layout
}

Box plot example

// Stock Price variations of companies over time
var xData = [];
var yData = [];
// console.log(data.series);
for (var i = 0; i < data.series.length; i++) {
    xData.push(data.series[i].refId);
    yData.push(data.series[i].fields[1].values);
}

var colors = ['rgba(93, 164, 214, 0.5)', 'rgba(255, 144, 14, 0.5)', 'rgba(44, 160, 101, 0.5)', 'rgba(255, 65, 54, 0.5)', 'rgba(207, 114, 255, 0.5)', 'rgba(127, 96, 0, 0.5)', 'rgba(255, 140, 184, 0.5)', 'rgba(79, 90, 117, 0.5)', 'rgba(222, 223, 0, 0.5)'];

var tracesdata = [];

for (var i = 0; i < xData.length; i++) {
    var result = {
        type: 'box',
        y: yData[i],
        name: xData[i],
        boxpoints: 'outlier',
        jitter: 0.5,
        whiskerwidth: 0.2,
        fillcolor: 'cls',
        marker: {
            size: 2
        },
        line: {
            width: 1
        }
    };
    tracesdata.push(result);
};
var layout = {
    title: {
        text: "Stock Price variations of companies",
        font: {
            family: 'Helvetica, Arial, sans-serif',
            color: "rgb(200, 200, 200)"
        }
    },
    yaxis: {
        autorange: true,
        showgrid: true,
        zeroline: true,
        gridcolor: "rgb(100, 100, 100)",
        gridwidth: 1,
        zerolinewidth: 2,
        type: "linear",
    },
    xaxis: {
        type: "category"
    },
    margin: {
        l: 40, r: 30, b: 80, t: 100
    },
    paper_bgcolor: "rgb(50, 50, 50)",
    plot_bgcolor: "rgb(50, 50, 50)",
    showlegend: false
}
// console.log(data);
return {
    data: tracesdata,
    layout: layout
}

Day wise box plot example

// Daywise stock price of a company
// console.log(data.series);

function formatTimestampToYYYYMMDD(timestamp) {
    const date = new Date(timestamp);

    const year = date.getFullYear();
    const month = (date.getMonth() + 1).toString().padStart(2, '0'); // Month is 0-indexed, so add 1
    const day = date.getDate().toString().padStart(2, '0');

    return `${year}-${month}-${day}`;
}

var dateDict = {};
for (var k = 0; k < data.series[0].fields[0].values.length; k++) {
    var dateKey = formatTimestampToYYYYMMDD(new Date(data.series[0].fields[0].values[k]));
    var val = data.series[0].fields[1].values[k];
    if (dateKey in dateDict) {
        dateDict[dateKey].push(val);
    }
    else {
        dateDict[dateKey] = [val];
    }
}

var xData = Object.keys(dateDict).sort();
var yData = xData.map(function (k) { return dateDict[k]; });

var colors = ['rgba(93, 164, 214, 0.5)', 'rgba(255, 144, 14, 0.5)', 'rgba(44, 160, 101, 0.5)', 'rgba(255, 65, 54, 0.5)', 'rgba(207, 114, 255, 0.5)', 'rgba(127, 96, 0, 0.5)', 'rgba(255, 140, 184, 0.5)', 'rgba(79, 90, 117, 0.5)', 'rgba(222, 223, 0, 0.5)'];

var tracesData = [];

for (var i = 0; i < xData.length; i++) {
    var result = {
        type: 'box',
        y: yData[i],
        name: xData[i],
        boxpoints: 'outlier',
        jitter: 0.5,
        whiskerwidth: 0.2,
        fillcolor: 'cls',
        marker: {
            size: 2
        },
        line: {
            width: 1
        }
    };
    tracesData.push(result);
};
var layout = {
    title: {
        text: "Daywise stock price of " + data.series[0].refId,
        font: {
            family: 'Helvetica, Arial, sans-serif',
            color: "rgb(200, 200, 200)"
        }
    },
    yaxis: {
        autorange: true,
        showgrid: true,
        zeroline: true,
        gridcolor: "rgb(100, 100, 100)",
        gridwidth: 1,
        zerolinewidth: 2,
        type: "linear",
    },
    xaxis: {
        "type": "date"
    },
    margin: {
        l: 40, r: 30, b: 80, t: 100
    },
    paper_bgcolor: "rgb(50, 50, 50)",
    plot_bgcolor: "rgb(50, 50, 50)",
    showlegend: false
}
// console.log(data);
return {
    data: tracesData,
    layout: layout
}

References

Comments