Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

More Line Charts, Area Charts, and Scatter Plots

Save for later
  • 780 min read
  • 2014-08-26 00:00:00

article-image

In this article by Scott Gottreu, the author of Learning jqPlot, we'll learn how to import data from remote sources. We will discuss what area charts, stacked area charts, and scatter plots are. Then we will learn how to implement these newly learned charts. We will also learn about trend lines.

(For more resources related to this topic, see here.)

Working with remote data sources

We return from lunch and decide to start on our line chart showing social media conversions. With this chart, we want to pull the data in from other sources. You start to look for some internal data sources, coming across one that returns the data as an object. We can see an excerpt of data returned by the data source. We will need to parse the object and create data arrays for jqPlot:

{ "twitter":[ ["2012-11-01",289],...["2012-11-30",225] ],
  "facebook":[ ["2012-11-01",27],...["2012-11-30",48] ] }
  1. We solve this issue using a data renderer to pull our data and then format it properly for jqPlot. We can pass a function as a variable to jqPlot and when it is time to render the data, it will call this new function. We start by creating the function to receive our data and then format it. We name it remoteDataSource. jqPlot will pass the following three parameters to our function:
    • url: This is the URL of our data source.
    • plot: The jqPlot object we create is passed by reference, which means we could modify the object from within remoteDataSource. However, it is best to treat it as a read-only object.
    • options: We can pass any type of option in the dataRendererOptions option when we create our jqPlot object. For now, we will not be passing in any options:
      <script src="../js/jqplot.dateAxisRenderer.min.js"></script>  
      <script>
      $(document).ready(function(){
       var remoteDataSource = function(url, plot, options)
      {
  2. Next we create a new array to hold our formatted data. Then, we use the $.ajax method in jQuery to pull in our data. We set the async option to false. If we don't, the function will continue to run before getting the data and we'll have an empty chart:
    var data = new Array;
        $.ajax({
          async: false,
  3. We set the url option to the url variable that jqPlot passed in. We also set the data type to json:
    url: url,
          dataType:"json",
          success: function(remoteData) {
  4. Then we will take the twitter object in our JSON and make that the first element of our data array and make facebook the second element. We then return the whole array back to jqPlot to finish rendering our chart:
    data.push(remoteData.twitter);
            data.push(remoteData.facebook);
          }
        });
        return data;
      };
  5. With our previous charts, after the id attribute, we would have passed in a data array. This time, instead of passing in a data array, we pass in a URL. Then, within the options, we declare the dataRenderer option and set remoteDataSource as the value. Now when our chart is created, it will call our renderer and pass in all the three parameters we discussed earlier:
      var socialPlot = $.jqplot ('socialMedia', 
    "./data/social_shares.json",
      {
        title:'Social Media Shares',
        dataRenderer: remoteDataSource,
  6. We create labels for both our data series and enable the legend:
        series:[
          { label: 'Twitter' },
          { label: 'Facebook' }
        ],
        legend: {
          show: true,
          placement: 'outsideGrid'
        },
  7. We enable DateAxisRenderer for the x axis and set min to 0 on the y axis, so jqPlot will not extend the axis below zero:
        axes:{
          xaxis:{
            renderer:$.jqplot.DateAxisRenderer,
            label: 'Days in November'
          },
          yaxis: {
            min:0,
            label: 'Number of Shares'
          }
        }
      });
    });
    </script>
    <div id="socialMedia" style="width:600px;"></div>

If you are running the code samples from your filesystem in Chrome, you will get an error message similar to this:

No 'Access-Control-Allow-Origin' header is present on the requested resource.

The security settings do not allow AJAX requests to be run against files on the filesystem. It is better to use a local web server such as MAMP, WAMP, or XAMPP. This way, we avoid the access control issues. Further information about cross-site HTTP requests can be found at the Mozilla Developer Network at https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS.

We load this new chart in our browser and can see the result.

more-line-charts-area-charts-and-scatter-plots-img-0

We are likely to run into cross-domain issues when trying to access remote sources that do not allow cross-domain requests. The common practice to overcome this hurdle would be to use the JSONP data type in our AJAX call. jQuery will only run JSONP calls asynchronously. This keeps your web page from hanging if a remote source stops responding. However, because jqPlot requires all the data from the remote source before continuing, we can't use cross-domain sources with our data renderers.

We start to think of ways we can use external APIs to pull in data from all kinds of sources. We make a note to contact the server guys to write some scripts to pull from the external APIs we want and pass along the data to our charts. By doing it in this way, we won't have to implement OAuth (OAuth is a standard framework used for authentication), http://oauth.net/2, in our web app or worry about which sources allow cross-domain access.

Adding to the project's scope

As we continue thinking up new ways to work with this data, Calvin stops by. "Hey guys, I've shown your work to a few of the regional vice-presidents and they love it." Your reply is that all of this is simply an experiment and was not designed for public consumption.

Calvin holds up his hands as if to hold our concerns at bay. "Don't worry, they know it's all in beta. They did have a couple of ideas. Can you insert in the expenses with the revenue and profit reports? They also want to see those same charts but formatted differently."

He continues, "One VP mentioned that maybe we could have one of those charts where everything under the line is filled in. Oh, and they would like to see these by Wednesday ahead of the meeting." With that, Calvin turns around and makes his customary abrupt exit.

Adding a fill between two lines

We talk through Calvin's comments. Adding in expenses won't be too much of an issue. We could simply add the expense line to one of our existing reports but that will likely not be what they want. Visually, the gap on our chart between profit and revenue should be the total amount of expenses. You mention that we could fill in the gap between the two lines. We decide to give this a try:

  1. We leave the plugins and the data arrays alone. We pass an empty array into our data array as a placeholder for our expenses. Next, we update our title. After this, we add a new series object and label it Expenses:
    ...
        var rev_profit = $.jqplot ('revPrfChart', [revenue, profit, 
    []
    ],
        {
          
    title:'Monthly Revenue & Profit with Highlighted Expenses',
    
          series:[ { label: 'Revenue' }, { label: 'Profit' }, 
    { label: 'Expenses' }
    ],
          legend: { show: true, placement: 'outsideGrid' },
  2. To fill in the gap between the two lines, we use the fillBetween option. The only two required options are series1 and series2. These require the positions of the two data series in the data array. So in our chart, series1 would be 0 and series2 would be 1.

    The other three optional settings are: baseSeries, color, and fill. The baseSeries option tells jqPlot to place the fill on a layer beneath the given series. It will default to 0. If you pick a series above zero, then the fill will hide any series below the fill layer:

    fillBetween: {
    series1: 0,
    series2: 1,
    
  3. We want to assign a different value to color because it will default to the color of the first data series option. The color option will accept either a hexadecimal value or the rgba option, which allows us to change the opacity of the fill. Even though the fill option defaults to true, we explicitly set it. This option also gives us the ability to turn off the fill after the chart is rendered:
    color: "rgba(232, 44, 12, 0.5)",
    fill: true
    },
    
  4. The settings for the rest of the chart remain unchanged:
          axes:{
            xaxis:{
              renderer:$.jqplot.DateAxisRenderer,
              label: 'Months'
            },
            yaxis:{
              label: 'Totals Dollars',
              tickOptions: {
                formatString: "$%'d"
              }
            }
          }
        });
    });
    </script>
    <div id="revPrfChart" style="width:600px;"></div>

We switch back to our web browser and load the new page. We see the result of our efforts in the following screenshot. This chart layout works but we think Calvin and the others will want something else. We decide we need to make an area chart.

Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €14.99/month. Cancel anytime

Understanding area and stacked area charts

Area charts come in two varieties. The default type of area chart is simply a modification of a line chart. Everything from the data point on the y axis all the way to zero is shaded. In the event your numbers are negative, then the data above the line up to zero is shaded in. Each data series you have is laid upon the others. Area charts are best to use when we want to compare similar elements, for example, sales by each division in our company or revenue among product categories.

The other variation of an area chart is the stacked area chart. The chart starts off being built in the same way as a normal area chart. The first line is plotted and shaded below the line to zero. The difference occurs with the remaining lines. We simply stack them. To understand what happens, consider this analogy.

Each shaded line represents a wall built to the height given in the data series. Instead of building one wall behind another, we stack them on top of each other. What can be hard to understand is the y axis. It now denotes a cumulative total, not the individual data points.

For example, if the first y value of a line is 4 and the first y value on the second line is 5, then the second point will be plotted at 9 on our y axis. Consider this more complicated example: if the y value in our first line is 2, 7 for our second line, and 4 for the third line, then the y value for our third line will be plotted at 13. That's why we need to compare similar elements.

Creating an area chart

We grab the quarterly report with the divisional profits we created this morning. We will extend the data to a year and plot the divisional profits as an area chart:

  1. We remove the data arrays for revenue and the overall profit array. We also add data to the three arrays containing the divisional profits:
    <script src="../js/jqplot.dateAxisRenderer.min.js"></script>
    <script>
    $(document).ready(function(){
    var electronics = [["2011-11-20", 123487.87], ...];
    var media = [["2011-11-20", 66449.15], ...];  
    var nerd_corral = [["2011-11-20", 2112.55], ...];
      var div_profit = $.jqplot ('division_profit', [
    media, nerd_corral, electronics
    ],
      {
        title:'12 Month Divisional Profits',
  2. Under seriesDefaults, we assign true to fill and fillToZero. Without setting fillToZero to true, the fill would continue to the bottom of the chart. With the option set, the fill will extend downward to zero on the y axis for positive values and stop. For negative data points, the fill will extend upward to zero:
          seriesDefaults: { 
    fill: true, fillToZero: true
    },
          series:[ { label: 'Media & Software' }, { label: 'Nerd Corral' }, { label: 'Electronics' } ],
          legend: { show: true, placement: 'outsideGrid' },
  3. For our x axis, we set numberTicks to 6. The rest of our options we leave unchanged:
          axes:{
            xaxis:{
              label: 'Months',
              renderer:$.jqplot.DateAxisRenderer,
              numberTicks: 6,
              tickOptions: { formatString: "%B" }
            },
            yaxis: {
                label: 'Total Dollars',
                tickOptions: { formatString: "$%'d" }
            }
          }
       });
    });
    </script>
    <div id="division_profit" style="width:600px;"></div>

We review the results of our changes in our browser.

We notice something is wrong: only the Electronics series, shown in brown, is showing. This goes back to how area charts are built. Revisiting our wall analogy, we have built a taller wall in front of our other two walls. We need to order our data series from largest to smallest:

  1. We move the Electronics series to be the first one in our data array:
    var div_profit = $.jqplot ('division_profit', [
    electronics, media, nerd_corral
    ],
  2. It's also hard to see where some of the lines go when they move underneath another layer. Thankfully, jqPlot has a fillAlpha option. We pass in a percentage in the form of a decimal and jqPlot will change the opacity of our fill area:
    ...
    seriesDefaults: {
      fill: true,
      fillToZero: true,
      
    fillAlpha: .6
    
    },
    ...

We reload our chart in our web browser and can see the updated changes.

Creating a stacked area chart with revenue

Calvin stops by while we're taking a break. "Hey guys, I had a VP call and they want to see revenue broken down by division. Can we do that?" We tell him we can. "Great" he says, before turning away and leaving. We discuss this new request and realize this would be a great chance to use a stacked area chart.

We dig around and find the divisional revenue numbers Calvin wanted. We can reuse the chart we just created and just change out the data and some options.

  1. We use the same variable names for our divisional data and plug in revenue numbers instead of profit. We use a new variable name for our chart object and a new id attribute for our div. We update our title and add the stackSeries option and set it to true:
      var 
    div_revenue
    = $.jqplot (
    'division_revenue'
    , [electronics, media, nerd_corral],
      {
        title:
    '12 Month Divisional Revenue',    
    stackSeries: true,
    
  2. We leave our series' options alone and the only option we change on our x axis is set numberTicks back to 3:
        seriesDefaults: { fill: true, fillToZero: true },
        series:[ { label: 'Electronics' }, { label: 'Media & Software' }, { label: 'Nerd Corral' } ], 
        legend: { show: true, placement: 'outsideGrid' },
        axes:{
          xaxis:{
            label: 'Months',
            renderer:$.jqplot.DateAxisRenderer,
            
    numberTicks: 3,
    
            tickOptions: { formatString: "%B" }
          },
  3. We finish our changes by updating the ID of our div container:
          yaxis: { 
            label: 'Total Dollars',
            tickOptions: { formatString: "$%'d" } 
          }
        }
      });
    });
    </script>
    <div id="
    division_revenue
    " style="width:600px;"></div>

With our changes complete, we load this new chart in our browser. As we can see in the following screenshot, we have a chart with each of the data series stacked on top of each other. Because of the nature of a stacked chart, the individual data points are no longer decipherable; however, with the visualization, this is less of an issue.

We decide that this is a good place to stop for the day. We'll start on scatterplots and trend lines tomorrow morning. As we begin gathering our things, Calvin stops by on his way out and we show him our recent work. "This is amazing. You guys are making great progress." We tell him we're going to move on to trend lines tomorrow.

"Oh, good," Calvin says. "I've had requests to show trending data for our revenue and profit. Someone else mentioned they would love to see trending data of shares on Twitter for our daily deals site. But, like you said, that can wait till tomorrow. Come on, I'll walk with you two."