I have a grafana dashboard giving my an overview of the electricity usage in my house, from the grid and produced by solar panels. One of the plots is the cumultative production over the day. I made it initially as a grafana time series plot. On the time series plot, it was not possible to get the xaxis fixed for a certain time interval, so I had to give it a lot of air as the plot slid across the panel over the day. So I have recreated the plot using plotly for grafana. This works well, but I have some issues with how the legend is showing. The figure shows the time series panel on the top left and the plotly one at the bottom: (there is a thick cloud layer and even some snow on the panels today, so not much production)
This is not too bad, but I would like to have the plotly panel the same size as the present time series panel, if I do this, it gets messed up:
Is it possible to make the lines on the legend shorter so it could still fit in the same vertical size (preferably), or can I somehow make the graph area auto shrink to give space to the legend?
In case it helps, the data query from a postgresql database, the time field is the time stamp for the measurement, ppv_total is the momentary power production. as I get a datapoint each 5 min, I divide by 12 to get a kWh estimate, the now()::date+time::time is to move all the last days measurement into todays timeframe.
select to_char(time::date,'YYYY-mm-dd') as parameter, now()::date+time::time as time,
sum(ppv_total/12) over (partition by time::date order by time) as " "
from pv where pv.time > now()::date - interval '7 days'
order by time;
The result from this query is then handeled as a time series in grafana, basically doing a pivot table having the values from "parameter" as new column headers. A snippet of the table looks like this:
This is then run through this script ("data" is the input from grafana).
let dataset = []
for (set =1; set<9; set++){
let x = [];
let y = [];
data.series[0].fields[set].values.forEach(function (item, index) {
if (item > ''){ // must get rid of empty values
y.push(item/1000); // I want kWh, having production in Watt
x.push(data.series[0].fields[0].values[index]);
}
});
if (set == 8){ // Todays line should stand out
line={width:4,
color: "yellow"};
}else{
line={width:1};
}
let serie = {
x : x,
y : y,
name : data.series[0].fields[set].labels.parameter,
line: line
};
dataset.push(serie)
}
return {
data : dataset,
config : {
displayModeBar: false
}
}
The layout object as defined in grafana is:
{
"yaxis": {
"gridcolor": "#344",
"autorange": true,
"color": "#444",
"type": "linear",
"range": [
-0.3900152777777779,
7.49179027777778
]
},
"xaxis": {
"type": "date",
"gridwidth": 1,
"gridcolor": "#444",
"autorange": true,
"color": "#444",
"range": [
"2024-03-26 07:49:19",
"2024-03-26 19:40:08"
]
},
"annotations": [
{
"showarrow": false,
"text": "kWh",
"textangle": -90,
"x": -0.03,
"xanchor": "right",
"xref": "paper",
"y": 0.5,
"yanchor": "right",
"yref": "paper"
}
],
"font": {
"color": "darkgrey"
},
"hovermode": "closest",
"margin": {
"b": 10,
"t": 15,
"r": 10,
"l": 40
},
"paper_bgcolor": "rgba(0,0,0,0)",
"plot_bgcolor": "rgba(0,0,0,0)",
"legend": {
"orientation": "h",
"yanchor": "bottom",
"y": -0.5,
"xanchor": "mid",
"x": 0,
"entrywidth": 20
}
}
Is it possible to make the lines on the legend shorter so it could still fit in the same vertical size ?
No, in fact we can set the legend's itemwidth
but the default is already at its minimum :
itemwidth
- number greater than or equal to 30. Sets the width (in px) of the legend item symbols (the part other than the title.text).
or can I somehow make the graph area auto shrink to give space to the legend?
Yes, by tweaking the layout :
autoexpand
is enabled.entrywidth
to 0 to size the entry based on the text width.yanchor
to "middle"
instead of "bottom"
.tickformat
to "%H:%M"
to remove the date Mar 26, 2024
on the first tick.Assuming you can return only the changes compared to grafana settings (override), in your script you would have something like this :
return {
data: dataset,
config: {
displayModeBar: false
},
layout: {
margin: {
b: 50, // increase as needed
t: 15,
r: 10,
l: 40,
autoexpand: true,
},
xaxis: {
title: '',
tickformat: "%H:%M",
},
legend:{
"yanchor": "middle",
"entrywidth": 0
}
}
}
You could also play with the legend font size but I'm not sure it will do the trick because the height of the symbols (line/marker, a symbol having a minimum height too) is independent of the text font size.