# Grapht
Grapht is a server-side graphing library built on [PhantomJS](https://github.com/ariya/phantomjs/wiki)
and utilizing [D3.js](http://d3js.org/). Grapht provides a CLI for simple Bash scripting.
It also profides a light-weight [Ruby](https://www.ruby-lang.org/en/)
API to make service-level integration simple.
### Why was Grapht built on PhantomJS?
- PhantomJS allows us to leverage [D3.js](http://d3js.org/), a best-of-breed data visualization library
authored by the formidable data visualization expert, Mike Bostock. [D3.js](http://d3js.org/) is a
battlefield tested library.
- Using PhantomJS allows us to reuse existing data visualization logic, originally
authored for our client-side application. This means we get consistent visualizations
across the various layers of our stack, and we minimize developer effort.
### How well does Grapht perform?
While PhantomJS is able to run Javascript extremely fast, it has a slow startup
time. When measured on a 2.4GHz Intel Core i7 laptop, with 16GB of DDR3 RAM, the
benchmarks† are as follows (_averaged over 10 runs_):
Bytes-In
Average, Real Time ( Seconds )
1,323
1.559
13,527
1.675
135,252
1.715
time (sec.) / bytes
Note that even when incrementing the amount of data-in by an order of magnitude,
time increases minimally (_roughly √n_). From this, we can infer a start-up time of ~1.5 seconds,
for PhantomJS, on the aforementioned hardware.
† _All measurements were collected using the following command: `time -p bin/grapht bar-horizontal < data/bar_data.json > /dev/null`_
## CLI
### Overview
Grapht provides a CLI, accessed using the `bin/grapht` command. The basic invocation
requires one argument specifying the desired graph type, and a JSON string provided
via `STDIN`. For example, if we want a **horizontal bar graph**:
bin/grapht bar-horizontal < ~/my-data.json
The result will be a string of **svg** markup:
### Usage
bin/grapht GRAPH_TYPE [options] < JSON_INPUT
### Options
Currently supported flags:
Flag
Description
Allowable Values
-f
Specifies an output format for the generated graph.
png|jpg|gif|pdf
## Ruby API
To generate the same **horizontal bar graph** generated in the CLI
section--using the Ruby API--we can do the following:
json = "[{ \"name\": \"foo\", \"value\": 20 },{ \"name\": \"bar\", \"value\": 40 },{ \"name\": \"baz\", \"value\": 35 }]"
type = Grapht::Type::BAR_HORIZONTAL
graph = Grapht::Shell.exec type, json
## Supported Graphs
Grapht is extensible, allowing users to create new graph definitions using
Javascript and [D3.js](http://d3js.org). However, Grapht provides a handful
of graph definitions out of the box:
- Horizontal Bar Graph
- Vertical Bar Graph
- Line Graph
- Pie Graph
### User Defined Graph Definitions
Users may create their own graph definitions with Grapht. To do this, we first
have to register a location where the new graph definitions will reside. This
is done simply by setting the `EXT_GRAPHT_DEFINITIONS_HOME` environment variable.
For example, if we have our custom definitions stored in
`~/Development/my_project/my_graph_defs`, we set our environment variable to this
path:
export EXT_GRAPHT_DEFINITIONS_HOME=~/Development/my_project/my_graph_defs
bin/grapht my-scatterplot < ~/my-data.json
In the example above, we supply the name of our new graph definition
(`my-scatterplot`) to the Grapht CLI. Grapht will first look in
`EXT_GRAPHT_DEFINITIONS_HOME` for the file `my-scatterplot.js`. If it's not
found, it will check its own internal set of graph definitions. If it is found,
Grapht will load the new definition.
##### Creating Your First Graph Definition
All graph definitions must comply with a short set of rules:
- They must be wrapped within a function that takes a single data argument.
- They must generate one, and only one root DOM node.
Here's an example of a valid graph definition:
function(data) { // <- our wrapper fuction
var width = 200,
height = 200;
// our single root node added to document.body
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height);
// a bunch of D3 operations on svg...
}
## Error Handling
Grapht will raise an error in the following scenarios:
- When any of its dependencies cannot be found. _Currently, Grapht
depends upon the D3.js and JSON2 javascript libraries. These dependencies
can be found in Grapht's `vendor` directory._
- When an unknown graph type is supplied to Grapht
- When malformed JSON is supplied to Grapht
- When PhantomJS raises an internal error
When using Grapht's CLI, all errors are printed to `STDERR` and Grapht exits
with an exit-code of `1`.
When accessing Grapht's features through the Ruby API, all errors are presented
as instances of `Grapht::Shell::Error`. The error messages, in this case, are
consistent with the errors messages raised from the CLI.
## Rails Integration
While Rails integration is not scripted by the Grapht library, it is quite
simple to integrate. The following steps are all that is required for integration:
- Add the following to your `Gemfile`:
- In the Rails `app` directory, create a directory named `graph-definitions`
- Create the file `config/initializers/grapht.rb`. In the file add the following:
- Place all user-defined graph definitions in the `app/graph-definitions`
## Contributing
1. Fork it (http://github.com/ibpinc/grapht/fork)
2. Create your feature branch `git checkout -b my-new-feature`
3. Commit your changes `git commit -am 'Add some feature'`
4. Push to the branch `git push origin my-new-feature`
5. Create a new pull request
## License
Copyright (c) 2014 Trade Informatics, Inc
[MIT License](https://github.com/ibpinc/grapht/blob/master/LICENSE.txt)