Skip to content

Showing a visualization in a view

asterite edited this page · 12 revisions
Clone this wiki locally

Showing a visualization in a view using the rgviz method

The basic way to do it is write this in your view template:

<%= rgviz :id => 'my_visualization',
  :kind => 'BarChart',
  :url => '/some_endpoint',
  :query => 'select country_name, sum(age) group by country_name',
  :options => {:width => 640, :height => 480, :is3D => true}
  %>

The rgviz method accepts an options hash as its single argument. The options are:

  • id: (required) the id of the visualization. This will be used as the id of the div tag where the visualization will be drawn.

  • kind: (required) the visualization to show. Can be one of these (check their names in the code usage). For example: 'BarChart', 'PieChart', 'ImageLineChart', etc.

  • url: (required) the endpoint that implements the Google Visualization wire protocol. This usually points to a method in your controller where use used render :rgviz => .… This argument behaves like the options you would pass to the url_for method. The endpoint does not necessarily have to be in your application, not even be implemented with rgviz (you can use Google Spreadsheets, for instance). This parameter can also be an ActiveRecord::Base class, an Rgviz::Table, an array of arrays or a class that responds to execute. If this is the case, the endpoint won't be used, and instead the DataTable will be put inline in the javascript code.

  • query: (required) the query to send to the endpoint.

  • options: (optional) the options you would pass to render the visualization, like width and height. If not given it defaults to a 640x480 dimension with no title. Option values can also be magic names.

  • events: (optional) a hash mapping event names to javascript function callbacks. For example: :events => {:select => 'select_handler'}. The handler receives a single argument containing the event, as described here. There are also additional events specifically for rgviz, these are described below.

  • html: (optional) a hash specifying html attributes to put on the div tag where the visualization will be rendered.

  • hidden: (optional) true to not display the visualization as soon as the page is loaded.

  • package: (optional) the package to load in google.load(“visualization”, “1”, …). Usually defaults to the correct one but, just in case, you can override it here.

  • load_google: (optional, default true) set to false to not load google jsapi ( www.google.com/jsapi )

  • load_package: (optional, default true) set to false to not emit the javascript line that loads the google package for the visualization (i.e. google.load(“visualization”, “1”, …))

  • ajax: (optional, default false) set to true to not load google jsapi nor load the visualization package. This is useful when loading a visualization after an ajax callback.

  • load: (optional, default nil) the way google is loaded. When set to :dynamic, dynamic-loading will be used. When set to :auto, auto-loading will be used.

  • html_prefix, js_prefix, param_prefix: custom prefixes to use for magic names.

  • conditions: (optional) conditions to pass if url is an ActiveRecord::Base class.

  • debug: (optional) true to alert the generated query before sending it to the endpoint.

Magic names

Magic names allow you to connect html elements and javascript functions to your visualization in a very simple way.

Important: magic names must always appear on the right side of a comparison.

The html_ magic name

Imagine you have a combo box of countries and you want your visualization query to use the selected country. You would do something like this:

<select id="countries" onchange="rgviz_draw_foo()">
  <option>Argentina</option>
  <option>Brasil</option>
  ...
</select>

<%= rgviz :id => 'foo',
  :kind => 'BarChart',
  :url => '/some_endpoint',
  :query => 'select city_name, avg(age) where city_country_name = html_countries group by city_name',
  :options => {:title => 'Average age per city'}
  %>

The first important part here is this piece of query: 'city_country_name = html_countries'. What that means is: I want the city country name to be the value of the html input (or select, whatever) whose id is 'countries'.

The second important part here is the onchange handler of the select element: rgviz_draw_foo(). Each time you define a visualization with an id you get these objects:

  • rgviz_draw_<id>(): a function to redraw the visualization for the given id

  • rgviz_<id>: the visualization of the given id (for example a google.visualization.BarChart)

  • rgviz_<id>_data: the data shown in the visualization of the given id. This is a DataTable.

  • rgviz_<id>_options: the original options used to render the visualization

Together, you get the dynamic visualization you wanted.

What if my input is a select with multiple options selected?

It works, try it! The equality will be transformed in a concatenation of ORs. So for instance if you have selected 'Argentina' and 'Brazil', the query will be rewritten to:

select city_name, avg(age) where (city_country_name = 'Argentina' or city_country_name = 'Brasil') group by city_name

Of course, this will only work when comparing by equality.

The js_ magic name

This is similar to the html_ magic name, but instead of retrieving the value of an html element it will get the value from a javascript function:

<script type="text/javascript">
function my_func() {
  return 'Argentina';
}
</script>

<%= rgviz :id => 'foo',
  :kind => 'BarChart',
  :url => '/some_endpoint',
  :query => 'select city_name, avg(age) where city_country_name = js_my_func group by city_name',
  :options => {:title => 'Average age per city'}
  %>

Again, if the javascript function returns an array of elements this will work as expected: the query will be rewritten to a concatenation of ORs.

The param_ magic name

This will grab the value from the rgviz_draw_<id> function's parameters.

The format of these magic names is: param_0, param_1, param_2, param_3, etc. (or you can start with 1 if you like).

By default the rgviz_draw_<id> function doesn't accept parameters, but if you specify one or more param_ magic name then it will start accepting parameters and it will not be rendered as soon the page loads.

This is better understood with an example:

<%= rgviz :id => 'foo',
  :kind => 'BarChart',
  :url => '/some_endpoint',
  :query => 'select city_name, avg(age) where city_country_name = param_1 group by city_name',
  :options => {:title => 'Average age per city'}
  %>

Now you can render the visualization by writing:

<script type="text/javascript">
rgviz_draw_foo('Argentina');
</script>

If you had param_1 and param_2 in the query, the function would accept two parameters.

Why is this useful? You can have one visualization B depend on a visualization A. When a user selects something in A you do something in the 'select' event handler, process the selection and draw the B visualization with the selection.

Using magic names in visualization options

You can also use magic names in the options hash you give to the rgviz method. So for example you could toggle the 'isStacked' flag with a checkbox:

Stacked: <input type="checkbox" id="stacked" onclick="rgviz_draw_foo()" />

<%= rgviz :id => 'foo',
  :options => {:isStacked => 'html_stacked'},
  ...
  %>

Changing the default prefixes for magic names

If you have a column in your model named 'html_body' then you won't be able to query it because Rgviz will think it's a magic name. To overcome this issue just specify another prefix for your magic names:

<%= rgviz :id => 'foo',
  :kind => 'BarChart',
  :url => '/some_endpoint',
  :query => 'select city_name, avg(age) where city_country_name = my_prefix_countries group by city_name',
  :options => {:title => 'Average age per city'},
  :html_prefix => :my_prefix
  %>

Specifying data types

By default it will be assumed that every magic name will be of type string. If you wish to change that just specify the type after the html_, js_ or param_ part. For example html_date_foo will get the value of the html element with id 'foo' and interpret it as a date.

This is important because in Google's query language you need to specify datatypes, like writing “date '2010-01-02'” for specifying a date value. Rgviz will not guess the datatype for you.

Check the complete list of types.

Rgviz events

In the :events hash you can also specify these:

  • rgviz_start: the name of a function that will be invoked with the id of the visualization just before sending the query to the endpoint.

  • rgviz_end: the name of a function that will be invoked with the id of the visualization after receiving the result from the endpoint and rendering the visualization.

  • rgviz_before_draw: the name of a function that will be invoked with the visualization and the DataTable, just before drawing it.

With the first two you can show a “Loading” message while fetching the data from the server. For example:

<%= rgviz :id => 'foo',
  :events => {:rgviz_start => 'show_loading', :rgviz_end => 'hide_loading'},
  ... %>

<script type="text/javascript">
function show_loading(id) {
  // Show a message
}

function hide_loading(id) {
  // Hide the message
}
</script>

With the last one you can manipulate the data in any way before it being drawn. For example, you could use a custom formatter:

<%= rgviz :id => 'foo',
  :events => {:rgviz_before_draw => 'before_draw'},
  ... %>

<script type="text/javascript">
function before_draw(visualization, data) {
  var formatter = new google.visualization.ArrowFormat();
  formatter.format(data, 1); // Apply formatter to second column
}
</script>

Using the helper without an endpoint

It is also possible to use the helper without an endpoint by pointing the url parameter to an ActiveRecord::Base class, an Rgviz::Table, an array of arrays or a class that responds to execute. For example:

<%= rgviz :id => 'my_visualization',
  :kind => 'BarChart',
  :url => Person,
  :conditions => 'age > 18'
  :query => 'select country_name, sum(age) group by country_name',
  :options => {:width => 640, :height => 480, :is3D => true}
  %>

In this case, the query will be run against the Person class and will be output inline in the generated javascript code. This is a little faster than querying the endpoint. But there's a drawback: you can't use magic names.

In the case of an Rgviz::Table, it's json representation will be used in the generated javascript.

In the case of an array of arrays, the google.visualization.arrayToDataTable will be used in the generated javascript.

In the case of a class that responds to execute, the query will be given to the execute method and an Rgviz::Table is expected to be returned from it.

Something went wrong with that request. Please try again.