2

I have DB relation that holds information that I wish to display. each record holds a numerical value, and a 'name' that looks like '20140325_064532'.

The order of creating the records doesn't matter, and so I wish to present the numerical value on the y-axis and the x axis to have:

  1. to have constant margin between ticks.
  2. to present the data based on 'name' order (lexicographic).
  3. the x-axis label shouldn't present all the values, but "selected ones", such that no overlapping should be displayed.
  4. to prevent two point to be placed in the same x-value, even if they hold the same 'name' (the inner order has no meaning).

how should I define my Flot chart so this can be achieved?

EDIT: My implementation thoughts so far:

  1. I will fetch (distinctly) from the DB the 'name' field along with a row_number value (starting from 1).
  2. Based on that I'll create a Hash, using the names as the key to the row number. Lets say :name => row#
  3. I'll generate the series(s) with the following structure: rawdata = [ [row#1, numericValue1], [row#2, numericValue2], ....];

    Note that row# will be a numerical value starting at 1.

  4. I'll define the ticks to represent the actual names. (This will be a line graph with dots, and not a bar chart).

Now, all of this will work (I think) but looks really messy. And, ontop, the ticks will almost surely overlap, and as to the fact that it will be hard coded, any zooming-in and out will not render the ticks with overlapping thoughts.

Update #2:

I passed the data to the js using two data attributes. the 'results' has an array that representing the series, and holds 4 fields, such that data-results="[[[0,371144,"20140206_000030-std",375],[1,373141,"20140328_230027",343],[2,374196,"20140401_230051",436],[3,374734,"20140401_230051_2",460],[4,374394,"20140401_230051_3",484],[5,376029,"20140401_230051_4",508]],... ,[another_series]]]

The 3rd field is 'name' and the last one is 'id'

the 'series' reresents the name I have for each series (and how it is displayed in the legend), and looks like:

data-series="["PLATFORM_A__CONFIG_B","PLATFORM_B__CONFIG_NONE"]"

I tried editing the content of the tooltip trying to integrate information from the last part of each point, so that I'll have something like this displayed: Run: ID: value: $y (the 2nd array field, representing the y-axis value)

I searched the web but couldn't find anything that works using tooltip (which looks nicer to handle). in the docs it is mentioned:

If you require even more control over how the tooltip is generated you can pass a callback function(label, xval, yval, flotItem) that must return a string with the format described.

I tried implementing this by calling Chart.getTooltip but all I get in the console is

Uncaught TypeError: undefined is not a function jquery.flot.tooltip.min.js?body=1:2h jquery.flot.tooltip.min.js?body=1:2(anonymous function) jquery.flot.tooltip.min.js?body=1:2jQuery.event.dispatch jquery.js?body=1:4642elemData.handle jquery.js?body=1:4310jQuery.event.trigger jquery.js?body=1:4551(anonymous function) jquery.js?body=1:5261jQuery.extend.each jquery.js?body=1:384jQuery.fn.jQuery.each jquery.js?body=1:137jQuery.fn.extend.trigger jquery.js?body=1:5260Y jquery.flot.cust.min.js?body=1:2V jquery.flot.cust.min.js?body=1:2jQuery.event.dispatch jquery.js?body=1:4642elemData.handle jquery.js?body=1:4310

Update #3 Thanks to @Ryley great tips and guidance, I was able to correctly display my chart using the unique values passed into Flot. I've updated my code so that in order to avoid overlapping in the ticks values, I used flot-tickrotor js to rotate the looks. I've came across with a problem, in which my bottom values gets cut-off. I've also noticed that this is a reported issue, but I couldn't find any solution or workaround for this. Is there any solution for this issue?

Next, I want to enable to viewer to show/hide the series with a click. I found bunch of solutions, both official and others, but none of those worked for me. I'll explain:

  1. Official turning series on/off: this works, but looks very messy as the legend is eventually duplicated twice (disappears from official legend once the series turned off).
  2. Hiddengraphs.js: this is a plugin which can be found at the plugin repository, but it doesn't work and interact well with Chrome (tried more than one machine, it just don't work).
  3. This solution is actually really nice (I don't mind that there are no checkboxes to check), but when I integrated it into my code, all I got was "jumping" to the top of the page, and nothing happens.
  4. Lastly, I found this solution, which also works, altough using another js library, called flot.togglelegend.js. In this implementation I found some major conflicts with flot.cust.js, and couldn't get them both to work together.

Finally, I tried to implement the select-zooming and double-click zoom-reset, using flot.selection.js I was able indeed to get the functionality to work, but the re-rendering process generates into my second and third chart the data of the first one.

It is also worth saying that I'm rendering 3 charts in this page, all rendered in the same way.

Here's my updated code:

Here's my current js (written in coffeescript)

colorArray = []
colorArray.push "rgba(180, 0, 75,    0.6)"
colorArray.push "rgba(0, 150, 100,   0.6)"
colorArray.push "rgba(0, 0, 255,     0.6)"
colorArray.push "rgba(140, 0, 255,   0.6)"
colorArray.push "rgba(90, 180, 20,   0.6)"
colorArray.push "rgba(255, 236, 0,   0.6)"
colorArray.push "rgba(234, 170, 21,  0.6)"
colorArray.push "rgba(95, 180, 190,  0.6)"
colorArray.push "rgba(214, 92, 63,   0.6)"
colorArray.push "rgba(218, 106, 234, 0.6)"
colorArray.push "rgba(213, 128, 155, 0.6)"

# chart colors default 
$chrt_border_color = "#efefef"
$chrt_grid_color = "#DDD"
$chrt_main = "#E24913"

# red       
$chrt_second = "#6595b4"
# blue      
$chrt_third = "#FF9F01"
# orange    
$chrt_fourth = "#7e9d3a"
# green     
$chrt_fifth = "#BD362F"
# dark red  
$chrt_mono = "#000"

Chart = 

generateDataObjects: (all_series, all_series_data) ->
    plotData = []

    for series, i in all_series
        obj =
            label: series.replace /__/g, "|"
            data: all_series_data[i]
            color: colorArray[i]

        plotData.push obj

    return plotData

getTooltip: (label, xval, yval, flotItem) ->
    return 'Build: <span>'+ flotItem.series.data[flotItem.dataIndex][2]+'</span>' +" | Run ID: <strong> #{flotItem.series.data[flotItem.dataIndex][3].toString()}</strong>" + '<br> Result: <span>'+Chart.commify(yval)+'</span>'

commify: (x) ->
    return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");

generateChartOptions: (legend_container, ticks) ->
    return (
        series:
            lines:
                show: true

            points:
                show: true

        crosshair:
            mode: "x"

        legend:
            container: $("##{legend_container}")
            # labelFormatter: (label, series) ->
#                   "<a href=\"#\" onClick=\"togglePlot(" + series.idx + "); return false;\">" + label + "</a>"
            noColumns: 4
            # hideable: true

        grid:
          hoverable: true
          clickable: true
          tickColor: $chrt_border_color
          borderWidth: 0
          borderColor: $chrt_border_color

        tooltip: true
        tooltipOpts: 
          content : Chart.getTooltip
          #content : "Value <b>$x</b> Value <span>$y</span>",
          defaultTheme: false

        xaxis:
            ticks: ticks
            rotateTicks: 30

        selection:
            mode: "xy"
        )

jQuery -> if $("#normalized_bw_chart").length # render only if the chart-id is present

    raw_data = $("#normalized_bw_chart").data('results')
    ticks = $("#normalized_bw_chart").data('ticks')
    all_series = $("#normalized_bw_chart").data('series')

    plot = $.plot($("#normalized_bw_chart"), Chart.generateDataObjects(all_series, raw_data), Chart.generateChartOptions('normalized_bw_legend', ticks))    

if $("#concurrent_flows_chart").length      # render only if the chart-id is present

    raw_data = $("#concurrent_flows_chart").data('results')
    ticks = $("#concurrent_flows_chart").data('ticks')
    all_series = $("#concurrent_flows_chart").data('series')

    plot = $.plot($("#concurrent_flows_chart"), Chart.generateDataObjects(all_series, raw_data), Chart.generateChartOptions('concurrent_flows_legend', ticks))

if $("#bandwidth_chart").length         # render only if the chart-id is present

    raw_data = $("#bandwidth_chart").data('results')
    ticks = $("#bandwidth_chart").data('ticks')
    all_series = $("#bandwidth_chart").data('series')

    plot = $.plot($("#bandwidth_chart"), Chart.generateDataObjects(all_series, raw_data), Chart.generateChartOptions('bandwidth_legend', ticks))    

$("[data-behavior~=chart-selection]").bind "plotselected", (event, ranges) ->
        selected_chart = $(this).attr('id')[0...-6] # slicing the name of the selected item
        console.log  ("zooming in to " + selected_chart)
        plot = $.plot($("##{selected_chart}_chart"), plot.getData(), $.extend(true, {}, Chart.generateChartOptions(selected_chart+'_legend', ticks),
          xaxis:
            min: ranges.xaxis.from
            max: ranges.xaxis.to

          yaxis:
            min: ranges.yaxis.from
            max: ranges.yaxis.to
        ))
     return

$("[data-behavior~=chart-selection]").bind "dblclick", (event, pos, item) ->
        selected_chart = $(this).attr('id')[0...-6] # slicing the name of the selected item
        console.log  ("zooming out to " + selected_chart)
        plot = $.plot($("##{selected_chart}_chart"), plot.getData(), $.extend(true, {}, Chart.generateChartOptions(selected_chart+'_legend', ticks),
          xaxis:
            min: null
            max: null
      yaxis:
        min: null
        max: null
    ))
 return

thanks a lot!

cyber101
  • 899
  • 1
  • 9
  • 19
  • Hi @Ryley. I haven't implemented this just yet, But I've updated my current thoughts on this. Hope it is more clear now. – cyber101 Sep 17 '14 at 06:48
  • What is your specific question/problem? Show code and explain the issue you are having. – Blake Sep 17 '14 at 14:55
  • On this site we want you to get as far as possible before you ask the question. It sounds like you're on the right track. Take it a bit further - make a sample data set, put it into flot with the options you think will work, and then post the code with your sample data. Otherwise you're asking us to read your mind :) – Ryley Sep 17 '14 at 15:14
  • @Ryley, Thank you. I've made some progress today add updated my question accordingly. – cyber101 Sep 18 '14 at 11:33

1 Answers1

1

Well, you got most of the way there, I just finished it off for you...

Basic issues:

  • Data format is [[x1,y1],[x2,y2],...

     data: [[all_series_data[i][0],all_series_data[i][1]]]
    
  • Specify ticks correctly (this just grabs every odd one)

    tick_labels = []
    for series, i in all_series
        if i % 2
            tick_labels.push [i,series]
        else
            tick_labels.push [i,'']  
    

and then in your plot options:

       xaxis:
            ticks: tick_labels  
  • include the tooltip library and use it in the default way. I used a copy from a CDN.
  • fix a basic coffeescript syntax error (probably just from copying it over here). In your GenerateChartOptions you open a ( and never close it at the end.

Here's a working example: http://jsfiddle.net/ryleyb/0tn1uzs9/2/

Based on comments I added this to the example:

    #in the flot options
        tooltipOpts:
            content: Chart.getToolTip

#to the Chart object
getToolTip: (label, xval, yval, flotItem) ->
    return 'Run: '+raw_data[xval][3]+': value: '+Chart.commify(yval)
commify: (x) ->
    return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
Ryley
  • 21,046
  • 2
  • 67
  • 81
  • thanks a lot for your input. My flot chart actually renders OK with the configuration I've provided (I generated the data, series and ticks array outside and passing them to the Coffeescript). The errors comes from trying to achieve a custom message in the hover box tooltip, using more data (which is why I inserted more than two items to the array, as seen in [this thread, second answer](http://stackoverflow.com/questions/22640112/customize-tooltip-in-flot-graph) and also manipulating the y-axis data. i.e. - I'd like to have instead of 1234567 value -> 1,234,567 – cyber101 Sep 19 '14 at 05:24
  • Sure, well... I added that now as well. – Ryley Sep 19 '14 at 15:18
  • Thanks! This worked perfectly!! It also turned out I didn't use one of he most recent tooltip.js, so that's why I got this `undefined is not a function` error. I'm really getting close to finish my implementation. I've posted an **Update #3** in the main question with my current issues. – cyber101 Sep 20 '14 at 11:18
  • The usual way to do this isn't to update your question as you fix things, more common is to make a new question asking your new questions. The idea is that this question should stand as is, so that other people with the same problem can come look at it and see the answers. By editing your question, it confuses things as to what the answer was for. – Ryley Sep 23 '14 at 15:24
  • Thanks for the tip! I've edited this post and [created a new one to the most troubling issue I have](http://stackoverflow.com/questions/26015056/flot-charts-toggling-a-series-on-off). If needed, I'll create a new post for the rest of the issues. – cyber101 Sep 24 '14 at 10:54