0
votes

The goal

What i need is one Flot chart that contains different coloured bars, with different coloured lines over the top.

Many questions answer how to achieve different coloured bars.

And many pages answer how to add bars AND lines.

But i want to combine these two solutions.

An added bonus would be to be able to add custom parameters to each bar / line (see the "testId" example below) - however this is not necessarily required, as a workaround I could create an object on page load that references each bar's position (e.g. the "ticks" array).

My current workaround

I can already achieve this using multiple data sets as seen in this jFiddle, which i have constructed based off this answer's jFiddle, however this requires multiple different data sets per colour variant of each bar / line like so:

var dataBarsRed = {
  data: [
    [0, 1],
    [2, 1.9], 
  ],
  color: 'red'
};

var dataBarsOrange = {
  data: [
    [1, 2],
    [3, 3.9], 
  ],
  color: 'orange'
};

var dataBarsGreen = {
  data: [
    [4, 4],
    [5, 4.5]
  ],
  color: 'green'
};

var dataLineRed = {
  data: [
    [0, 2, 2],
    [1, 2, 2],
    [2, 2, 2],
    [3, 2, 2],
    [4, 2, 2],
    [5, 2, 2],
  ],
  label: '60% efficiency',
  color: 'red',
  bars: {
    barWidth: 1
  }
};

var dataLineOrange = {
  data: [
    [0, 4, 4],
    [1, 4, 4],
    [2, 4, 4],
    [3, 4, 4],
    [4, 4, 4],
    [5, 4, 4],
  ],
  label: '85% efficency',
  color: 'orange',
  bars: {
    barWidth: 1
  }
};

And add them like so:

$.plot("#placeholder", [dataBarsRed, dataBarsOrange, dataBarsGreen, dataLineRed, dataLineOrange],...

From what i can tell, there is no way to add any custom data parameters to this data structure, in which each item has it's own set of custom variables (e.g. object id's to link to the back-end, like "testId" - see "The Rationale").

The rationale

Is there a way to achieve what i need using the same structure for the bar data as the first link:

var data = [
  { data: [[0,1]], color: "red", testId: 30 },
  { data: [[1,2]], color: "yellow", testId: 31 },
  { data: [[2,3]], color: "green", testId: 32 }
];

The reason i'd like to do it this way is that it would be much simpler to build the Flot Data Object on the Java side (return it as JSON from ajax) but also it has the added benefit of adding your own parameters to each bar / line (e.g. "testId" shown above. The id's themselves would be utilised to retrieve more data via ajax on click or hover of the bar.

For Example:

$(container).bind('plothover', function(event, position, item){

  console.log(item.series.testId)
});

Final thoughts

I feel like i'm going round in circles with this. I love the Flot charts plugin and it's flexibility, but there are numerous ways to implement the same visual outcome.

Thanks.
- Steve.

2
Not sure why you had problems with this. It is as straight forward as you yourself put it in the "The rationale" section :) - Raidri
It is straight forward if you want just different coloured bars (with or without custom properties) or different coloured lines. I've provided many examples showing the individual implementations, but I can not find any examples or documentation that show a combination of both. - Steve
Why can't i mark my question as the answer? I can only mark it as a favourite question (the star). - Steve
You should create an answer isntead of putting the answer into the question. You can then accept (mark) it. - Raidri

2 Answers

1
votes

The Solution

See this jFiddle for the complete code.

After considering what Raidri is saying regarding it's simplicity, I've taken another stab at it and I've gotten something working as i need it to, with a bit more consistency. I feel a bit silly for not seeing this before (perhaps i did and a syntax error caused me to move on). Anyway, if anyone is interested here's the code:

NOTE: This does feel like a bodge or a hack - i'm not sure if this kind of data structure was ever intended, but it gets the job done for my purposes.

var data = [
  { data: [[0,1]], color: "red", testId: 30, isBar: true },
  { data: [[1,2]], color: "orange", testId: 31, isBar: true },
  { data: [[2,1.9]], color: "red", testId: 32, isBar: true },
  { data: [[3,3.9]], color: "orange", testId: 33, isBar: true },
  { data: [[4,4]], color: "green", testId: 34, isBar: true },
  { data: [[5,4.5]], color: "green", testId: 35, isBar: true },
  { data: [[0, 4, 4],[0.5, 4, 4],[1, 4, 4],[1.5, 4, 4],[2, 4, 4],[2.5, 4, 4],[3, 4, 4],[3.5, 4, 4],[4, 4, 4],[4.5, 4, 4],[5, 4, 4]], shadowSize: 0, color: 'orange', isLine: true, label: '85% efficiency' },
  { data: [[0, 2, 2],[0.5, 2, 2],[1, 2, 2],[1.5, 2, 2],[2, 2, 2],[2.5, 2, 2],[3, 2, 2],[3.5, 2, 2],[4, 2, 2],[4.5, 2, 2],[5, 2, 2]], shadowSize: 0, color: 'red', isLine: true, label: '60% efficiency' },
  { data: [[0, -1, -1]], shadowSize: 0, color: 'green', label: '100% efficiency', isLine: true }
];

var plot = $.plot("#placeholder", data, {       
  bars: {
      show: true,
      align: 'center',
      barWidth: 0.5
  },
  lines: { 
    show: true, 
    lineWidth: 0.1, 
    fill: false 
  },
  grid: {
      hoverable: true,
      autoHighlight: true
  },
  xaxis: {
    ticks: [[0,'Steve'],[1,'Bob'],[2,'Chris'],[3,'Joe'],[4,'Dave'], [5, 'Jon']]
  },
  yaxis: {
      min: 0,
      max: 5
  },
  legend:{
    container: '#legend'
  }
});

There are some slight nuances, such as the number of line points (data elements per line) need to take into account the bar width. E.g. if my bar width was 1 i'd only need 5 elements, but since i have a width of 0.5 i need 10 line elements per data array (to fill in the gaps). Also, "shadowSize: 0" is required or you'd get a grey shadow in the middle of the line.

I've also added "isBar" and "isLine" to each element so my hover event can distinguish between them so it does not update the info box when the line is hovered. This is because the way I've done this is a bit of a "hack" in the sense that the line is not one line, but a line per column. Without this further distinction of type, hovering over the line would display the bar's name depending on your mouse's x-position.

I've also had to add a "fake" green line for the legend - position 0, referencing start and end positions that are outside the axis range (-1, in this example, 6 would also work). I realise i can probably create a custom legend...but it was simpler to just let flot deal with it itself.

0
votes

You can simply combine your five data objects into one array of objects und you can also add your own properties to these objects, like this:

var data = [ {
  data: [
    [0, 1],
    [2, 1.9], 
  ],
  color: 'red',
  testId: 31
}, {
  data: [
    [1, 2],
    [3, 3.9], 
  ],
  color: 'orange',
  testId: 32
}, {
    //...
}];

And using your own properties for example in the hover-event is as simple as

$('#details').html("<span class='detail'>...(testId = " + item.series.testId + ")</span>");

See the updated fiddle for the full example.

PS: For the lines in your chart, maybe markings are a better fit (see the documentation and this fiddle, where one of the lines is replaced by a marking).