Re: Line chart with multiple series on multiple axes

2,482 views
Skip to first unread message
Message has been deleted

asgallant

unread,
Sep 18, 2012, 11:52:11 PM9/18/12
to google-visua...@googlegroups.com
Setting up series to target different axes is fairly straightforward.  The "series" option is a map of series indices to series suboptions, one of which is the "targetAxisIndex" option, which controls which axis the series is drawn against (index 0 is the left axis, index 1 is the right axis).  Set up the options for each axis using the "vAxes" options, which is a map of axis indices to vAxis suboptions.

Converting from one unit to another is also relatively easy.  DataViews allow you to create calculated columns that take values from a DataTable (or another DataView) and convert them into different values.  If you hook up an event handler for an HTML element (like a button), you can switch the data around, change chart options, whatever else you need to do, and redraw the chart on a click of the button.

Ok, that probably sounded rather complicated, but I promise that it really isn't.  Here's an example of all of this in action: http://jsfiddle.net/asgallant/LWDP4/1/.  Feel free to mess around with it, see what everything does, and to ask any questions you have about the API.

On Tuesday, September 18, 2012 7:41:00 PM UTC-4, Gizamo wrote:
Hello. I'm trying to make something similar to this line graph: http://jsfiddle.net/LuP4K/

The actual chart layout I'm trying to replicate is here: http://wkfluidhandling.com/media/images/performance-curves/psu060-performance-curves-665x435.png  (but I'd like to use only Standard or Metric units and allow the user to choose whichever they prefer with a toggle button).

Anyway, it was simple enough to setup in Highcharts, but I can't seem to figure out how to create a GoogleCharts version of it (in part because I am struggling with the API features/language). Can someone please get me started in the correct path?

Gizamo

unread,
Sep 19, 2012, 4:36:00 PM9/19/12
to google-visua...@googlegroups.com
Thank you so much. That got me off to a great start. It is exactly what I was trying to do. But, I still have three hang ups:

1. The metric/imperial conversion is returning a value of 0 for null items. Is there a way to change any value 0 to null? Also, I rounded the conversions to 2 decimals with:  return Math.round(dt.getValue(rowxyz123 *100)/100;   The 0/null issue was happening before I made that change, but it seemed like a good change to share (for others who might use this code as a reference).  

2. I can't seem to get the haxis to change values. I was able to get the title to change by adding: 
     document.getElementById('clickMe').onclick function ({
        // change from metric to imperial and vice-versa
        metric !metric;
        if (metric{
            // set up everything to draw the chart in imperial units
            chart.setOption('hAxes.0.title''GPM');
            chart.setOption('hAxes.0.maxValue'20); ...
        }
        else {
            // set up everything to draw the chart in metric units
            chart.setOption('hAxes.0.title''LPM');
            chart.setOption('hAxes.0.maxValue'80); ... 

            This is where I believe I am going wrong.   
            // use calculated columns in the DataView to convert from metric to imperial
            view.setColumns([0{
                type'number',
                label'GPM',
                calcfunction (dtrow{
                    // convert GPM to LPM, round to 2 decimals
                    return Math.round(dt.getValue(row03.78541178 *100)/100;
                }
            }, ...
            ]); 
            this.value 'Switch from imperial to metric';
        }

3. I cannot get the labels to change in the tooltip, and I can't seem to include the label for the hAxes in the tooltip. Is there someway to fix those? Or, could I create a dynamic statement at the bottom that says "At 'X value' there is 'Y1 value' and/or 'Y2 value'". ..I imagine it would be something like the top right of Google's Annotated Time Line example  https://code.google.com/apis/ajax/playground/?type=visualization#annotated_time_line.

Oh, and in this case there are three standard units of measure. PSI/GPM/SCFM, MPa/LPM(liquid)/LPM(air), and Bar/m^3perHR/ Nm^3perMin. Can I set up a single button for each, or toggle between all three? I haven't gotten this far, but I thought I'd ask before spending a bunch of time trying.

Thanks again. Your help probably saved me a few hours. I really appreciate it. 

asgallant

unread,
Sep 19, 2012, 5:44:58 PM9/19/12
to google-visua...@googlegroups.com
1) to keep nulls the same, you have to set it up to return null if the original is null:

return (dt.getValue(row0== nullnull Math.round(dt.getValue(row03.78541178 100100; 

2) to change the hAxis values, you need to make column 0 into a calculated column in the view, which your code will do, but you left the unmodified column 0 in the array.  Take out the leading 0 in the #setColumns call and you should be good.

3) to include the unit labels for the base data set in the tooltip, you need to format the original DataTable using NumberFormatters, like this:

// format column 0 as GPM
var GPMformatter new google.visualization.NumberFormat({suffix' GPM'});
GPMformatter.format(data0); 

To include the units for the other systems, you need to return both the value and formatted value in the column calculation:

var value dt.getValue(row03.78541178;
return (dt.getValue(row0== nullnull {
    vvalue,
    fMath.round(value 100100 ' LPM'
}; 

Rounding only the formatted value keeps the tooltip the way you want but allows for more accurate rendering of the chart.

If you want to use more than two systems of measurement, you can certainly do so.  You can use pretty much any method you want to change between systems (links, buttons, radio buttons, checkboxes, dropdowns, etc).  Create something which allows you to track which system the user wants, adjust the value based on the user's choice, and draw the chart with the corresponding data.  Here's one way of doing it with a dropdown:

HTML:

<select id="selectMe">
    <option value="0" selected="selected">System 1</option>
    <option value="1">System 2</option>
    <option value="2">System 3</option>
</select> 

Javascript:

var system 0;
document.getElementById('selectMe').onchange function ({

    // change from metric to imperial and vice-versa
    system this[this.selectedIndex].value;
    
    if (system == 0{
        // set up as system 0
    }
    else if (system == 1{
        // set up as system 1
    }
    else {
        // set up as system 2
    }
    // redraw the chart with the new options and data
    chart.draw();
}

Gizamo

unread,
Sep 21, 2012, 3:43:58 PM9/21/12
to google-visua...@googlegroups.com
That worked great! Thank you.

Sorry to keep bugging you, but I ran into another (big) snag that is out of my range of capabilities.. The problem is that I am plotting multiple series and they do not share x or y values. For example, SeriesA uses the (x,y) points of (1,3);(2,6);(3,8);(4,9),... but SeriesB uses (0.8, 1.8);(1.6,2.4);(2.4,5.6);(3.8,7.5),...  Is there a way to use the x and y coordinates to plot the lines instead of requiring all x values to be fixed?  Currently, the numbers in col1 are the x points for both SeriesA and SeriesB; col2 numbers are y points for Series A; col3 numbers are y points for SeriesB. Is there a way to do both (x,y) coordinate points in a single column? And, if so, how would the calculation code be set up for it.?  My current set up is here: http://jsfiddle.net/LWDP4/6/

Also, I will end up with quite a few lines, so I would like to set up check boxes to toggle them visible/invisible, and (if possible) I'd like each checkbox to be associated with two separate series. To explain: There are 4 lines in my chart, and the top blue and top gray lines represent data for the same 100 PSI Air Supply Line (so they share the label "100 PSI Air Supply"). The second blue and second gray lines represent the 90 PSI Air Supply data. So if I could associate the blues line with their corresponding gray lines and allow users to toggle visibility on/off via checkbox, it would simplify things for the user. (oh, and if it helps, the x value for both the blue line and corresponding gray line would always be the same). Lastly, I found this focusTarget: 'category', in the documentation. It allows me to put all of the y data for each x value in a tooltip. It seems logical that if the associated blue and gray lines share the same x value with each other but not with other the series, the only those two values would go into the tool tip if I could set points. Is that correct/possible?

Thanks again. 

Side note: I've noticed that you are answering a lot of questions on this forum. Hopefully, I'll learn enough of the code during this project so I can help you help others (because I know how it feels to be one of a few guys answering tough questions for dozens of people). 

asgallant

unread,
Sep 21, 2012, 4:34:59 PM9/21/12
to google-visua...@googlegroups.com
To answer in order:

1) you don't need to have data points for each individual series for every x value.  If a data series does not have a value for a given x, leave it null in the table.  Set the "interpolateNulls" option to true to avoid the gaps that otherwise appear when data is missing.  

To address the second part of this question, I don't see any practical means of charting two data series given a single set of (x,y) coordinate pairs.  Every series would have to have some sort of defining characteristics that allow for each coordinate pair to be assigned to one and only one series.  Perhaps your application would allow this, but generically speaking, it is not practical.  From a technical perspective, you would have to split the data into multiple series anyway when drawing the chart, so I don't see any advantage to attempting to set something like this up, even if it is feasible.

2) turning individual lines on and off is actually fairly easy.  There are a number of techniques to accomplish this, but of particular interest to you might be my hack that turns the CategoryFilter into a series selector: http://jsfiddle.net/asgallant/WaUu2/.  In your particular application this would require a bit of tweaking (since you have duplicate column labels), but once tweaked, it would turn on/off both the grey and blue lines for the selected series.

When setting the "focusTarget" option to "category", the tooltip only displays data points available for that axis value, so if I understood your question correctly, then the behavior you want is actually the default behavior here.

And yes, I do answer a lot of questions here >;o)

We get some really creative people stopping by here with some really cool ideas that they need help with, and if I can help turn those ideas into reality, then I like to think that in some small way, I have helped bring more awesome into the world.  If you want to join in, the more the merrier, but don't feel obligated to do so relieve the "burden" from me.

DFTBA

Gizamo

unread,
Sep 24, 2012, 6:42:01 PM9/24/12
to google-visua...@googlegroups.com
InterpolateNulls and the focusTarget:Category behaviors are exactly what I needed. I was unaware of InterpolateNulls, and the focusTarget behavior wasn't working earlier because I did not put the x values in proper order. I had done one series and then the next, and they had overlapping x coordinates... Anyway, that part all works great now, and using (x,y) coordinate pairs was indeed unnecessary and impractical. You can see it all working here:  http://jsfiddle.net/LWDP4/8/

I looked through your CategoryFilter/SeriesSelector code, but I couldn't figure out how to tweak it to select both blue and gray lines. The 2nd axes in my chart is also causing some other problems, and I couldn't seem to solve them either.. For example, if selectMultiple is set to True, and I remove the series1, the data in column1 is deleted and the data from column2 is assigned to column1 - the result is that my first gray line becomes my last blue line, and it is now set to axes y1 instead of y2. There are also issues when filtering series and switching among the various units.. Oh, and if I set selectMultiple to False, any selected series is assigned to the y1 axes. You can see it here: http://jsfiddle.net/LWDP4/9/ 

Lastly, I found this code: http://jsfiddle.net/gTxkN/8/, which showed me how to use the column number to select a series instead of the column label. This is good for me because I had to remove the columns labels to get the tooltip formatted the way I wanted.. Anyway, I plugged that code into my chart, but it has the same/similar issues with the second axes in my chart. See: http://jsfiddle.net/LWDP4/10/

Thanks again. The stuff we have working is awesome.

asgallant

unread,
Sep 25, 2012, 2:30:56 PM9/25/12
to google-visua...@googlegroups.com
It takes a bit of tweaking, less on the selector and more on the structure of the rest of the code, to make it work: http://jsfiddle.net/asgallant/LWDP4/12/.  Basically, you have to track which columns you are using and which options need to change based on the columns.

While I was working on that, I noticed issues with the way you had set up things before, but I can't recall precisely what they were.  If you decide not to use this, I'll go over your other code again.

Gizamo

unread,
Sep 27, 2012, 10:13:44 AM9/27/12
to google-visua...@googlegroups.com
Ah ha. That makes much more sense than what I was trying to do.. Don't bother reviewing the old code again, I can certainly get this latest version to fit my needs. It is awesome. Thank you for all of your help, and thanks for helping others too. I'm sure they appreciated it, and a few of your past projects were also great reference tools for me.

asgallant

unread,
Sep 27, 2012, 10:51:50 AM9/27/12
to google-visua...@googlegroups.com
You're welcome.
Reply all
Reply to author
Forward
0 new messages