SmartChart

SmartChart is an easy way to render charts on web pages. It uses the Google Charts engine so there are no server-side dependencies or performance issues–just install and go.

SmartChart is still in the early stages of development. Only bar charts, line graphs, maps, and barcodes are working. However, much of the interface is described below (plus to-do list) and if you’d like to contribute, please do.

Key Benefits

1. Designed as a chart-making interface, not as a Google Charts wrapper. Other APIs effectively just give Google Chart parameters different names, leading you to wonder: why am I learning an API to an API? SmartChart is an intelligent chart-authoring syntax that happens to use Google Charts as a back-end. It may support other charting engines in the future.

2. Place chart elements with respect to data points, not chart size. If you want horizontal axis lines on your graph every 10 units (along the Y-axis) you simply specify this. If you’ve worked much with the native Google Charts interface you know you have to do several calculations to get this to work, and any library that simply “wraps” Google Charts suffers from this same annoyance.

3. You get useful feedback when you do something wrong. If you specify more data points than Google can handle, you get an error message. If you specify a bigger chart than Google will serve, you get an error message. Forget to specify a required parameter? That’s an error message too. The thing is, with the raw Google Charts interface you get no useful feedback in any of these cases, which can lead to very long and frustrating debugging sessions.

4. The best data encoding is selected automatically. SmartChart examines your data and selects the optimal way to encode your data to keep HTTP requests short while preserving granularity. There’s no way a chart author should have to think about Google’s data encoding methods. Forget I even mentioned it.

Examples

SmartChart::Line.new(

  # y-axis range
  :y_min  => -40,
  :y_max  => 80,

  # data (specify line/bar styles with data)
  :data => [
    {
      :values    => [1,2,3,4],
      :label     => "Profit",
      :thickness => 2,                      # float, default is 1.5
      :color     => '550055',
      :style     => {
                      :solid => 3,
                      :blank => 2
                    }
    },
    {
      :values    => [2,4,6,8],
      :label     => "Reputation",
      :thickness => 2,
      :color     => 'AABBCC',
      :style     => :dotted
    }
  ],

  # axis lines and labels
  :axis => {
    :bottom => {
      :color      => 'DDDDDD',              # false or nil for hidden
      :ticks      => 'DDDDDD',              # false or nil for hidden
      :font_size  => 12,
      :text_align => :left,
      :labels     => {
        1  => "Jan",
        4  => "Apr",
        7  => "Jul",
        10 => "Oct"
      }
    }
  }

  # grid lines
  :grid => {
    :x     => {:every => 10, :offset => 2}, # based on number of data points
    :y     => {:every => 5},                # based on numeric data range
    :style => :dashed                       # no :color or :thickness
  },

  # options for HTML tag
  :html => {
    :id    => "stock_graph",
    :class => "graph"
  }
)

SmartChart::Pie.new(
  :style  => "3d",
  :rotate => 45,   # degrees from vertical (start of first slice)
  ...
)

# display
g = SmartChart::Line.new(...)
g.to_url
g.to_html

# QR Code
g = SmartChart::QRCode.new(:data => "some data").to_s

Specifying Data

Data is specified in slightly different ways for different charts. In the simplest case, a QR code (SmartChart::QRCode), the data is simply a string:

chart.data = "A sentence full of data."

Another simple case is a map (SmartChart::Map), where data is specified as a hash of region-value pairs:

chart.data = {
  :US => 74,
  :CA => 81,
  :MX => 52,
  :RU => 19,
  :AU => 41
}

Data can be passed to pie charts in a similar way. For more complex graphs depicting multiple series, data and other information about each series is given as a hash (in an array if there is more than one), for example for a line graph:

chart.data = [
  {
    :values    => [23, 26, 46, 52, 51, 78],
    :label     => "Stock price",
    :thickness => 2,
    :color     => '0099FF'
  },
  {
    :values    => [65, 64, 58, 52, 63, 79],
    :label     => "Consumer interest",
    :thickness => 1,
    :color     => 'FF0099',
    :style     => :dotted
  }
]

Axis Lines

Actual output is limited by Google’s requirements. For example, while Google provides for a line chart with no axis lines (“sparkline”), there is no analogous bar chart type. However, SmartChart will simulate this for you by cropping the chart image using a <div> when you call the to_html method.

To-do List

  • validate height and width

    • must be integers

    • dimensions must be >= 1px

  • bar graphs

    • add chbh tests

    • style and orientation tests

  • labels

    • on line, scatter, bar graphs

    • labels on other axes (top and right)

    • multiple rows of labels on same axis

  • axes

    • hide bar graph axes by hiding 1px from left and bottom of image when to_html is called

    • eliminate unnecessary characters from chxs parameter

    • chxr parameter? if :auto is given for labels

    • tests for chxl and chxp parameters

    • make sure labels are escaped (commas, pipes, etc)

  • support OEmbed (oembed.com)

  • check out flotomatic (github.com/xdotcommer/flotomatic)

  • use :section: directive in RDoc comments

  • classes should use inheritable query_string_params (like ActiveRecord validations) so features can add params

  • change arguments to to_html method so attributes are easier to pass

  • validations

    • axis colors, font sizes, and alignments

    • margins and legend dimensions are integers

    • grid line attributes

  • legend

  • grids

    • easy placement of y-gridline at zero, if exists

    • easy placement of gridlines at label positions

  • general

    • support advanced background (“fill”) options like gradients

  • markers

  • SingleDataSetChart

    • document attributes

  • QRCode

  • data and encoding

    • The best encoding type should be selected automatically (whatever is shortest with enough granularity). Avoid URLs longer than 2074 characters. Default to Extended, but use Simple if (1) URL would be too long, (2) image is less than 100px tall, or (3) not enough data point to justify it.

    • data granularity adjustment (curve smoothing, rolling average?)

References

Other Google Charts APIs: groups.google.com/group/google-chart-api/web/useful-links-to-api-libraries

Seer: www.idolhands.com/ruby-on-rails/gems-plugins-and-engines/graphing-for-ruby-on-rails-with-seer

Copyright © 2009 Alex Reisner. See LICENSE for details.