Data Visualization with ElasticSearch and Protovis

The primary purpose of a search engine is, quite unsurprisingly: searching. You pass it a query, and it returns bunch of matching documents, in the order of relevance. We can get creative with query construction, experimenting with different analyzers for our documents, and the search engine tries hard to provide best results.

Nevertheless, a modern full-text search engine can do much more than that. At its core lies the inverted index, a highly optimized data structure for efficient lookup of documents matching the query. But it also allows to compute complex aggregations of our data, called facets.

The usual purpose of facets is to offer the user a faceted navigation, or faceted search. When you search for “camera" at an online store, you can refine your search by choosing different manufacturers, price ranges, or features, usually by clicking on a link, not by fiddling with the query syntax.

A canonical example of a faceted navigation at LinkedIn is pictured below.

Faceted search is one of the few ways to make powerful queries accessible to your users: see Moritz Stefaner's experiments with “Elastic Lists" for inspiration.

But, we can do much more with facets then just displaying these links and checkboxes. We can use the data for makings charts, which is exactly what we'll do in this article.

Live Dashboards

In almost any analytical, monitoring or data-mining service you'll hit the requirement “We need a dashboard!" sooner or later. Because everybody loves dashboards, whether they're useful or just pretty. As it happens, we can use facets as a pretty powerful analytical engine for our data, without writing any OLAP implementations.

The screenshot below is from a social media monitoring application which uses ElasticSearch not only to search and mine the data, but also to provide data aggregation for the interactive dashboard.


When the user drills down into the data, adds a keyword, uses a custom query, all the charts change in real-time, thanks to the way how facet aggregation works. The dashboard is not a static snapshot of the data, pre-calculated periodically, but a truly interactive tool for data exploration.

In this article, we'll learn how to retrieve data for charts like these from ElasticSearch, and how to create the charts themselves.

Pie charts with a terms facet

For the first chart, we'll use a simple terms facet in ElasticSearch. This facet returns the most frequent terms for a field, together with occurence counts.

Let's index some example data first.

<span class="pln">curl </span><span class="pun">-</span><span class="pln">X DELETE </span><span class="str">"http://localhost:9200/dashboard"</span><span class="pln">
curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/article"</span><span class="pln"> </span><span class="pun">-</span><span class="pln">d </span><span class="str">'
             { "title" : "One",
               "tags"  : ["ruby", "java", "search"]}
'</span><span class="pln">
curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/article"</span><span class="pln"> </span><span class="pun">-</span><span class="pln">d </span><span class="str">'
             { "title" : "Two",
               "tags"  : ["java", "search"] }
'</span><span class="pln">
curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/article"</span><span class="pln"> </span><span class="pun">-</span><span class="pln">d </span><span class="str">'
             { "title" : "Three",
               "tags"  : ["erlang", "search"] }
'</span><span class="pln">
curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/article"</span><span class="pln"> </span><span class="pun">-</span><span class="pln">d </span><span class="str">'
             { "title" : "Four",
               "tags"  : ["search"] }
'</span><span class="pln">
curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/_refresh"</span>

As you see, we are storing four articles, each with a couple of tags; an article can have multiple tags, which is trivial to express in ElasticSearch's document format, JSON.

Now, to retrieve “Top Ten Tags" across the documents, we can simply do:

<span class="pln">curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/_search?pretty=true"</span><span class="pln"> </span><span class="pun">-</span><span class="pln">d </span><span class="str">'
{
    "query" : { "match_all" : {} },

    "facets" : {
        "tags" : { "terms" : {"field" : "tags", "size" : 10} }
    }
}
'</span>

You can see that we are retrieving all documents, and we have defined a terms facet called “tags". This query will return something like this:

<span class="pun">{</span><span class="pln">
    </span><span class="str">"took"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
    </span><span class="com">// ... snip ...</span><span class="pln">
    </span><span class="str">"hits"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="str">"total"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln">
        </span><span class="com">// ... snip ...</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    </span><span class="str">"facets"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="str">"tags"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="str">"_type"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">"terms"</span><span class="pun">,</span><span class="pln">
            </span><span class="str">"missing"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
            </span><span class="str">"terms"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
                </span><span class="pun">{</span><span class="pln"> </span><span class="str">"term"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">"search"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"count"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
                </span><span class="pun">{</span><span class="pln"> </span><span class="str">"term"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">"java"</span><span class="pun">,</span><span class="pln">   </span><span class="str">"count"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
                </span><span class="pun">{</span><span class="pln"> </span><span class="str">"term"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">"ruby"</span><span class="pun">,</span><span class="pln">   </span><span class="str">"count"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
                </span><span class="pun">{</span><span class="pln"> </span><span class="str">"term"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">"erlang"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"count"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
            </span><span class="pun">]</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span>

We are interested in the facets section of the JSON, notably in the facets.tags.terms array. It tells us that we have four articles tagged search, two tagged java, and so on. (Of course, we could add a size parameter to the query, to skip the results altogether.)

Suitable visualization for this type of ratio distribution is a pie chart, or its variation: a donut chart. The end result is displayed below (you may want to check out the working example).


We will use Protovis, a JavaScript data visualization toolkit. Protovis is 100% open source, and you could think of it as Ruby on Rails for data visualization; in stark contrast to similar tools, it does not ship with a limited set of chart types to “choose" from, but it defines a set of primitives and a flexible domain-specific language so you can easily build your own custom visualizations. Creating pie charts is pretty easy in Protovis.

Since ElasticSearch returns JSON data, we can load it with a simple Ajax call. Don't forget that you can clone or download the full source code for this example.

First, we need a HTML file to contain our chart and to load the data from ElasticSearch:

<span class="pun">&</span><span class="pln">lt</span><span class="pun">;!</span><span class="pln">DOCTYPE html</span><span class="pun">&</span><span class="pln">gt</span><span class="pun">;</span><span class="pln">
</span><span class="pun">&</span><span class="pln">lt</span><span class="pun">;</span><span class="pln">html</span><span class="pun">&</span><span class="pln">gt</span><span class="pun">;</span><span class="pln">
</span><span class="pun">&</span><span class="pln">lt</span><span class="pun">;</span><span class="pln">head</span><span class="pun">&</span><span class="pln">gt</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">&</span><span class="pln">lt</span><span class="pun">;</span><span class="pln">title</span><span class="pun">&</span><span class="pln">gt</span><span class="pun">;</span><span class="typ">ElasticSearch</span><span class="pln"> </span><span class="typ">Terms</span><span class="pln"> </span><span class="typ">Facet</span><span class="pln"> </span><span class="typ">Donut</span><span class="pln"> </span><span class="typ">Chart</span><span class="pun">&</span><span class="pln">lt</span><span class="pun">;</span><span class="str">/title>
    <meta http-equiv="Content-Type" content="text/</span><span class="pln">html</span><span class="pun">;</span><span class="pln"> charset</span><span class="pun">=</span><span class="pln">utf</span><span class="pun">-</span><span class="lit">8</span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln"> </span><span class="str">/>

    <!-- Load JS libraries -->
    <script src="jquery-1.5.1.min.js"></</span><span class="pln">script</span><span class="pun">&</span><span class="pln">gt</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">&</span><span class="pln">lt</span><span class="pun">;</span><span class="pln">script src</span><span class="pun">=&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln">protovis</span><span class="pun">-</span><span class="pln">r3</span><span class="pun">.</span><span class="lit">2.js</span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;&</span><span class="pln">gt</span><span class="pun">;&</span><span class="pln">lt</span><span class="pun">;</span><span class="str">/script>
    <script src="donut.js"></</span><span class="pln">script</span><span class="pun">&</span><span class="pln">gt</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">&</span><span class="pln">lt</span><span class="pun">;</span><span class="pln">script</span><span class="pun">&</span><span class="pln">gt</span><span class="pun">;</span><span class="pln">
        {replace1}lt;/span><span class="pun">(</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> load_data</span><span class="pun">();</span><span class="pln"> </span><span class="pun">});</span><span class="pln">

        </span><span class="kwd">var</span><span class="pln"> load_data </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            {replace1}lt;/span><span class="pun">.</span><span class="pln">ajax</span><span class="pun">({</span><span class="pln">   url</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&#</span><span class="pln">x27</span><span class="pun">;</span><span class="pln">http</span><span class="pun">:</span><span class="com">//localhost:9200/dashboard/article/_search?pretty=true&#x27;</span><span class="pln">
                     </span><span class="pun">,</span><span class="pln"> type</span><span class="pun">:</span><span class="pln"> </span><span class="pun">&#</span><span class="pln">x27</span><span class="pun">;</span><span class="pln">POST</span><span class="pun">&#</span><span class="pln">x27</span><span class="pun">;</span><span class="pln">
                     </span><span class="pun">,</span><span class="pln"> data </span><span class="pun">:</span><span class="pln"> JSON</span><span class="pun">.</span><span class="pln">stringify</span><span class="pun">({</span><span class="pln">
                           </span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln">query</span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln">match_all</span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">{}</span><span class="pln"> </span><span class="pun">},</span><span class="pln">

                           </span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln">facets</span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                               </span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln">tags</span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                                   </span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln">terms</span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                                       </span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln">field</span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln">tags</span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;,</span><span class="pln">
                                       </span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln">size</span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln">  </span><span class="pun">:</span><span class="pln"> </span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;</span><span class="lit">10</span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln">
                                   </span><span class="pun">}</span><span class="pln">
                               </span><span class="pun">}</span><span class="pln">
                           </span><span class="pun">}</span><span class="pln">
                       </span><span class="pun">})</span><span class="pln">
                     </span><span class="pun">,</span><span class="pln"> dataType </span><span class="pun">:</span><span class="pln"> </span><span class="pun">&#</span><span class="pln">x27</span><span class="pun">;</span><span class="pln">json</span><span class="pun">&#</span><span class="pln">x27</span><span class="pun">;</span><span class="pln">
                     </span><span class="pun">,</span><span class="pln"> processData</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln">
                     </span><span class="pun">,</span><span class="pln"> success</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">json</span><span class="pun">,</span><span class="pln"> statusText</span><span class="pun">,</span><span class="pln"> xhr</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                           </span><span class="kwd">return</span><span class="pln"> display_chart</span><span class="pun">(</span><span class="pln">json</span><span class="pun">);</span><span class="pln">
                       </span><span class="pun">}</span><span class="pln">
                     </span><span class="pun">,</span><span class="pln"> error</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">xhr</span><span class="pun">,</span><span class="pln"> message</span><span class="pun">,</span><span class="pln"> error</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                           console</span><span class="pun">.</span><span class="pln">error</span><span class="pun">(&</span><span class="pln">quot</span><span class="pun">;</span><span class="typ">Error</span><span class="pln"> </span><span class="kwd">while</span><span class="pln"> loading data from </span><span class="typ">ElasticSearch</span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;,</span><span class="pln"> message</span><span class="pun">);</span><span class="pln">
                           </span><span class="kwd">throw</span><span class="pun">(</span><span class="pln">error</span><span class="pun">);</span><span class="pln">
                       </span><span class="pun">}</span><span class="pln">
            </span><span class="pun">});</span><span class="pln">

            </span><span class="kwd">var</span><span class="pln"> display_chart </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">json</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="typ">Donut</span><span class="pun">().</span><span class="pln">data</span><span class="pun">(</span><span class="pln">json</span><span class="pun">.</span><span class="pln">facets</span><span class="pun">.</span><span class="pln">tags</span><span class="pun">.</span><span class="pln">terms</span><span class="pun">).</span><span class="pln">draw</span><span class="pun">();</span><span class="pln">
            </span><span class="pun">};</span><span class="pln">

        </span><span class="pun">};</span><span class="pln">
    </span><span class="pun">&</span><span class="pln">lt</span><span class="pun">;</span><span class="str">/script>
</</span><span class="pln">head</span><span class="pun">&</span><span class="pln">gt</span><span class="pun">;</span><span class="pln">
</span><span class="pun">&</span><span class="pln">lt</span><span class="pun">;</span><span class="pln">body</span><span class="pun">&</span><span class="pln">gt</span><span class="pun">;</span><span class="pln">

  </span><span class="pun">&</span><span class="pln">lt</span><span class="pun">;!--</span><span class="pln"> </span><span class="typ">Placeholder</span><span class="pln"> </span><span class="kwd">for</span><span class="pln"> the chart </span><span class="pun">--&</span><span class="pln">gt</span><span class="pun">;</span><span class="pln">
  </span><span class="pun">&</span><span class="pln">lt</span><span class="pun">;</span><span class="pln">div id</span><span class="pun">=&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln">chart</span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;&</span><span class="pln">gt</span><span class="pun">;&</span><span class="pln">lt</span><span class="pun">;</span><span class="str">/div>

</</span><span class="pln">body</span><span class="pun">&</span><span class="pln">gt</span><span class="pun">;</span><span class="pln">
</span><span class="pun">&</span><span class="pln">lt</span><span class="pun">;/</span><span class="pln">html</span><span class="pun">&</span><span class="pln">gt</span><span class="pun">;</span>

On document load, we retrieve exactly the same facet, via Ajax, as we did earlier with curl. In the jQuery Ajax callback, we pass the returned JSON to the Donut() function via the display_chart() wrapper.

The Donut() function itself is displayed, with annotations, below:

<span class="com">// =====================================================================================================</span><span class="pln">
</span><span class="com">// A donut chart with Protovis - See http://vis.stanford.edu/protovis/ex/pie.html</span><span class="pln">
</span><span class="com">// =====================================================================================================</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> </span><span class="typ">Donut</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">dom_id</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(&#</span><span class="pln">x27</span><span class="pun">;</span><span class="kwd">undefined</span><span class="pun">&#</span><span class="pln">x27</span><span class="pun">;</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">typeof</span><span class="pln"> dom_id</span><span class="pun">)</span><span class="pln">  </span><span class="pun">{</span><span class="pln">                </span><span class="com">// Set the default DOM element ID to bind</span><span class="pln">
        dom_id </span><span class="pun">=</span><span class="pln"> </span><span class="pun">&#</span><span class="pln">x27</span><span class="pun">;</span><span class="pln">chart</span><span class="pun">&#</span><span class="pln">x27</span><span class="pun">;;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">var</span><span class="pln"> data </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">json</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">                         </span><span class="com">// Set the data for the chart</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data </span><span class="pun">=</span><span class="pln"> json</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">

    </span><span class="kwd">var</span><span class="pln"> draw </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

        </span><span class="kwd">var</span><span class="pln"> entries </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data</span><span class="pun">.</span><span class="pln">sort</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">a</span><span class="pun">,</span><span class="pln"> b</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  </span><span class="com">// Sort the data by term names, so the</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> a</span><span class="pun">.</span><span class="pln">term </span><span class="pun">&</span><span class="pln">lt</span><span class="pun">;</span><span class="pln"> b</span><span class="pun">.</span><span class="pln">term </span><span class="pun">?</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln">            </span><span class="com">// color scheme for wedges is preserved</span><span class="pln">
        </span><span class="pun">}),</span><span class="pln">                                             </span><span class="com">// with any order</span><span class="pln">

        values  </span><span class="pun">=</span><span class="pln"> pv</span><span class="pun">.</span><span class="pln">map</span><span class="pun">(</span><span class="pln">entries</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">         </span><span class="com">// Create an array holding just the counts</span><span class="pln">
            </span><span class="kwd">return</span><span class="pln"> e</span><span class="pun">.</span><span class="pln">count</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">});</span><span class="pln">
        </span><span class="com">// console.log(&#x27;Drawing&#x27;, entries, values);</span><span class="pln">

        </span><span class="kwd">var</span><span class="pln"> w </span><span class="pun">=</span><span class="pln"> </span><span class="lit">200</span><span class="pun">,</span><span class="pln">                                    </span><span class="com">// Dimensions and color scheme for the chart</span><span class="pln">
            h </span><span class="pun">=</span><span class="pln"> </span><span class="lit">200</span><span class="pun">,</span><span class="pln">
            colors </span><span class="pun">=</span><span class="pln"> pv</span><span class="pun">.</span><span class="typ">Colors</span><span class="pun">.</span><span class="pln">category10</span><span class="pun">().</span><span class="pln">range</span><span class="pun">();</span><span class="pln">

        </span><span class="kwd">var</span><span class="pln"> vis </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> pv</span><span class="pun">.</span><span class="typ">Panel</span><span class="pun">()</span><span class="pln">                        </span><span class="com">// Create the basis panel</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">width</span><span class="pun">(</span><span class="pln">w</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">height</span><span class="pun">(</span><span class="pln">h</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">margin</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span><span class="pln">

        vis</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">pv</span><span class="pun">.</span><span class="typ">Wedge</span><span class="pun">)</span><span class="pln">                               </span><span class="com">// Create the "wedges" of the chart</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">def</span><span class="pun">(&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln">active</span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;,</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">)</span><span class="pln">                          </span><span class="com">// Auxiliary variable to hold mouse over state</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">data</span><span class="pun">(</span><span class="pln"> pv</span><span class="pun">.</span><span class="pln">normalize</span><span class="pun">(</span><span class="pln">values</span><span class="pun">)</span><span class="pln"> </span><span class="pun">)</span><span class="pln">               </span><span class="com">// Pass the normalized data to Protovis</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">left</span><span class="pun">(</span><span class="pln">w</span><span class="pun">/</span><span class="lit">3</span><span class="pun">)</span><span class="pln">                                  </span><span class="com">// Set-up chart position and dimension</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">top</span><span class="pun">(</span><span class="pln">w</span><span class="pun">/</span><span class="lit">3</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">outerRadius</span><span class="pun">(</span><span class="pln">w</span><span class="pun">/</span><span class="lit">3</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">innerRadius</span><span class="pun">(</span><span class="lit">15</span><span class="pun">)</span><span class="pln">                            </span><span class="com">// Create a "donut hole" in the center</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">angle</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">d</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">                       </span><span class="com">// Compute the "width" of the wedge</span><span class="pln">
                </span><span class="kwd">return</span><span class="pln"> d </span><span class="pun">*</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">PI</span><span class="pun">;</span><span class="pln">
             </span><span class="pun">})</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">strokeStyle</span><span class="pun">(&</span><span class="pln">quot</span><span class="pun">;#</span><span class="pln">fff</span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;)</span><span class="pln">                        </span><span class="com">// Add white stroke</span><span class="pln">

            </span><span class="pun">.</span><span class="pln">event</span><span class="pun">(&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln">mouseover</span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">            </span><span class="com">// On "mouse over", set the "wedge" as active</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">active</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">index</span><span class="pun">);</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">cursor</span><span class="pun">(&#</span><span class="pln">x27</span><span class="pun">;</span><span class="pln">pointer</span><span class="pun">&#</span><span class="pln">x27</span><span class="pun">;);</span><span class="pln">
                </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">root</span><span class="pun">.</span><span class="pln">render</span><span class="pun">();</span><span class="pln">
             </span><span class="pun">})</span><span class="pln">

            </span><span class="pun">.</span><span class="pln">event</span><span class="pun">(&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln">mouseout</span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;,</span><span class="pln">  </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">            </span><span class="com">// On "mouse out", clear the active state</span><span class="pln">
                </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">active</span><span class="pun">(-</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
                </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">root</span><span class="pun">.</span><span class="pln">render</span><span class="pun">();</span><span class="pln">
            </span><span class="pun">})</span><span class="pln">

            </span><span class="pun">.</span><span class="pln">event</span><span class="pun">(&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln">mousedown</span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">d</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">           </span><span class="com">// On "mouse down", perform action,</span><span class="pln">
                </span><span class="kwd">var</span><span class="pln"> term </span><span class="pun">=</span><span class="pln"> entries</span><span class="pun">[</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">index</span><span class="pun">].</span><span class="pln">term</span><span class="pun">;</span><span class="pln">    </span><span class="com">// such as filtering the results...</span><span class="pln">
                </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">alert</span><span class="pun">(&</span><span class="pln">quot</span><span class="pun">;</span><span class="typ">Filter</span><span class="pln"> the results by </span><span class="pun">&#</span><span class="pln">x27</span><span class="pun">;&</span><span class="pln">quot</span><span class="pun">;+</span><span class="pln">term</span><span class="pun">+&</span><span class="pln">quot</span><span class="pun">;&#</span><span class="pln">x27</span><span class="pun">;&</span><span class="pln">quot</span><span class="pun">;));</span><span class="pln">
            </span><span class="pun">})</span><span class="pln">


            </span><span class="pun">.</span><span class="pln">anchor</span><span class="pun">(&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln">right</span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;).</span><span class="pln">add</span><span class="pun">(</span><span class="pln">pv</span><span class="pun">.</span><span class="typ">Dot</span><span class="pun">)</span><span class="pln">                </span><span class="com">// Add the left part of he "inline" label,</span><span class="pln">
                                                        </span><span class="com">// displayed inside the donut "hole"</span><span class="pln">

            </span><span class="pun">.</span><span class="pln">visible</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">                      </span><span class="com">// The label is visible when its wedge is active</span><span class="pln">
                </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">parent</span><span class="pun">.</span><span class="pln">children</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln">
                       </span><span class="pun">.</span><span class="pln">active</span><span class="pun">()</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">index</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">})</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">fillStyle</span><span class="pun">(&</span><span class="pln">quot</span><span class="pun">;#</span><span class="lit">222</span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">lineWidth</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">radius</span><span class="pun">(</span><span class="lit">14</span><span class="pun">)</span><span class="pln">

            </span><span class="pun">.</span><span class="pln">anchor</span><span class="pun">(&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln">center</span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;).</span><span class="pln">add</span><span class="pun">(</span><span class="pln">pv</span><span class="pun">.</span><span class="typ">Bar</span><span class="pun">)</span><span class="pln">               </span><span class="com">// Add the middle part of the label</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">fillStyle</span><span class="pun">(&</span><span class="pln">quot</span><span class="pun">;#</span><span class="lit">222</span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">width</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">(</span><span class="pln">d</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">                        </span><span class="com">// Compute width:</span><span class="pln">
                </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">d</span><span class="pun">*</span><span class="lit">100</span><span class="pun">).</span><span class="pln">toFixed</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln">               </span><span class="com">// add pixels for percents</span><span class="pln">
                              </span><span class="pun">.</span><span class="pln">toString</span><span class="pun">().</span><span class="pln">length</span><span class="pun">*</span><span class="lit">4</span><span class="pln"> </span><span class="pun">+</span><span class="pln">
                       </span><span class="lit">10</span><span class="pln"> </span><span class="pun">+</span><span class="pln">                             </span><span class="com">// add pixels for glyphs (%, etc)</span><span class="pln">
                       entries</span><span class="pun">[</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">index</span><span class="pun">]</span><span class="pln">              </span><span class="com">// add pixels for letters (very rough)</span><span class="pln">
                           </span><span class="pun">.</span><span class="pln">term</span><span class="pun">.</span><span class="pln">length</span><span class="pun">*</span><span class="lit">9</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">})</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">height</span><span class="pun">(</span><span class="lit">28</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">top</span><span class="pun">((</span><span class="pln">w</span><span class="pun">/</span><span class="lit">3</span><span class="pun">)-</span><span class="lit">14</span><span class="pun">)</span><span class="pln">

            </span><span class="pun">.</span><span class="pln">anchor</span><span class="pun">(&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln">right</span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;).</span><span class="pln">add</span><span class="pun">(</span><span class="pln">pv</span><span class="pun">.</span><span class="typ">Dot</span><span class="pun">)</span><span class="pln">                </span><span class="com">// Add the right part of the label</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">fillStyle</span><span class="pun">(&</span><span class="pln">quot</span><span class="pun">;#</span><span class="lit">222</span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">lineWidth</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">radius</span><span class="pun">(</span><span class="lit">14</span><span class="pun">)</span><span class="pln">


            </span><span class="pun">.</span><span class="pln">parent</span><span class="pun">.</span><span class="pln">children</span><span class="pun">[</span><span class="lit">2</span><span class="pun">].</span><span class="pln">anchor</span><span class="pun">(&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln">left</span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;)</span><span class="pln">          </span><span class="com">// Add the text to label</span><span class="pln">
                   </span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">pv</span><span class="pun">.</span><span class="typ">Label</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">left</span><span class="pun">((</span><span class="pln">w</span><span class="pun">/</span><span class="lit">3</span><span class="pun">)-</span><span class="lit">7</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">text</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">(</span><span class="pln">d</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">                         </span><span class="com">// Combine the text for label</span><span class="pln">
                </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">d</span><span class="pun">*</span><span class="lit">100</span><span class="pun">).</span><span class="pln">toFixed</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;%&</span><span class="pln">quot</span><span class="pun">;</span><span class="pln"> </span><span class="pun">+</span><span class="pln">
                       </span><span class="pun">&#</span><span class="pln">x27</span><span class="pun">;</span><span class="pln"> </span><span class="pun">&#</span><span class="pln">x27</span><span class="pun">;</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> entries</span><span class="pun">[</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">index</span><span class="pun">].</span><span class="pln">term </span><span class="pun">+</span><span class="pln">
                       </span><span class="pun">&#</span><span class="pln">x27</span><span class="pun">;</span><span class="pln"> </span><span class="pun">(&#</span><span class="pln">x27</span><span class="pun">;</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> values</span><span class="pun">[</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">index</span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="pun">&#</span><span class="pln">x27</span><span class="pun">;)&#</span><span class="pln">x27</span><span class="pun">;;</span><span class="pln">
            </span><span class="pun">})</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">textStyle</span><span class="pun">(&</span><span class="pln">quot</span><span class="pun">;#</span><span class="pln">fff</span><span class="pun">&</span><span class="pln">quot</span><span class="pun">;)</span><span class="pln">

            </span><span class="pun">.</span><span class="pln">root</span><span class="pun">.</span><span class="pln">canvas</span><span class="pun">(</span><span class="pln">dom_id</span><span class="pun">)</span><span class="pln">                        </span><span class="com">// Bind the chart to DOM element</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">render</span><span class="pun">();</span><span class="pln">                                  </span><span class="com">// And render it.</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">                                            </span><span class="com">// Create the public API</span><span class="pln">
        data   </span><span class="pun">:</span><span class="pln"> data</span><span class="pun">,</span><span class="pln">
        draw   </span><span class="pun">:</span><span class="pln"> draw
    </span><span class="pun">};</span><span class="pln">

</span><span class="pun">};</span>

As you can see, with a simple transformation of JSON data returned from ElasticSearch, we're able to create rich, attractive visualization of tag distribution among our articles. You can see the full example here.

It's worth repeating that the visualization will work in exactly the same way when we use a different query, such as displaying only articles written by a certain author or published in certain date range.

Timelines with a date histogram facets

Protovis makes it very easy to create another common form of visualization: the timeline. Any type of data, tied to a certain date, such as an article being published, an event taking place, a purchase being completed can be visualized on a timeline.

The end result should look like this (again, you may want to check out the working version):

So, let's store handful of articles with a published date in the index.

<span class="pln">curl </span><span class="pun">-</span><span class="pln">X DELETE </span><span class="str">"http://localhost:9200/dashboard"</span><span class="pln">
curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/article"</span><span class="pln"> </span><span class="pun">-</span><span class="pln">d </span><span class="str">'{ "t" : "1",  "published" : "2011-01-01" }'</span><span class="pln">
curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/article"</span><span class="pln"> </span><span class="pun">-</span><span class="pln">d </span><span class="str">'{ "t" : "2",  "published" : "2011-01-02" }'</span><span class="pln">
curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/article"</span><span class="pln"> </span><span class="pun">-</span><span class="pln">d </span><span class="str">'{ "t" : "3",  "published" : "2011-01-02" }'</span><span class="pln">
curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/article"</span><span class="pln"> </span><span class="pun">-</span><span class="pln">d </span><span class="str">'{ "t" : "4",  "published" : "2011-01-03" }'</span><span class="pln">
curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/article"</span><span class="pln"> </span><span class="pun">-</span><span class="pln">d </span><span class="str">'{ "t" : "5",  "published" : "2011-01-04" }'</span><span class="pln">
curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/article"</span><span class="pln"> </span><span class="pun">-</span><span class="pln">d </span><span class="str">'{ "t" : "6",  "published" : "2011-01-04" }'</span><span class="pln">
curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/article"</span><span class="pln"> </span><span class="pun">-</span><span class="pln">d </span><span class="str">'{ "t" : "7",  "published" : "2011-01-04" }'</span><span class="pln">
curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/article"</span><span class="pln"> </span><span class="pun">-</span><span class="pln">d </span><span class="str">'{ "t" : "8",  "published" : "2011-01-04" }'</span><span class="pln">
curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/article"</span><span class="pln"> </span><span class="pun">-</span><span class="pln">d </span><span class="str">'{ "t" : "9",  "published" : "2011-01-10" }'</span><span class="pln">
curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/article"</span><span class="pln"> </span><span class="pun">-</span><span class="pln">d </span><span class="str">'{ "t" : "10", "published" : "2011-01-12" }'</span><span class="pln">
curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/article"</span><span class="pln"> </span><span class="pun">-</span><span class="pln">d </span><span class="str">'{ "t" : "11", "published" : "2011-01-13" }'</span><span class="pln">
curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/article"</span><span class="pln"> </span><span class="pun">-</span><span class="pln">d </span><span class="str">'{ "t" : "12", "published" : "2011-01-14" }'</span><span class="pln">
curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/article"</span><span class="pln"> </span><span class="pun">-</span><span class="pln">d </span><span class="str">'{ "t" : "13", "published" : "2011-01-14" }'</span><span class="pln">
curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/article"</span><span class="pln"> </span><span class="pun">-</span><span class="pln">d </span><span class="str">'{ "t" : "14", "published" : "2011-01-15" }'</span><span class="pln">
curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/article"</span><span class="pln"> </span><span class="pun">-</span><span class="pln">d </span><span class="str">'{ "t" : "15", "published" : "2011-01-20" }'</span><span class="pln">
curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/article"</span><span class="pln"> </span><span class="pun">-</span><span class="pln">d </span><span class="str">'{ "t" : "16", "published" : "2011-01-20" }'</span><span class="pln">
curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/article"</span><span class="pln"> </span><span class="pun">-</span><span class="pln">d </span><span class="str">'{ "t" : "17", "published" : "2011-01-21" }'</span><span class="pln">
curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/article"</span><span class="pln"> </span><span class="pun">-</span><span class="pln">d </span><span class="str">'{ "t" : "18", "published" : "2011-01-22" }'</span><span class="pln">
curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/article"</span><span class="pln"> </span><span class="pun">-</span><span class="pln">d </span><span class="str">'{ "t" : "19", "published" : "2011-01-23" }'</span><span class="pln">
curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/article"</span><span class="pln"> </span><span class="pun">-</span><span class="pln">d </span><span class="str">'{ "t" : "20", "published" : "2011-01-24" }'</span><span class="pln">
curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/_refresh"</span>

To retrieve the frequency of articles being published, we'll use a date histogram facet in ElasticSearch.

<span class="pln">curl </span><span class="pun">-</span><span class="pln">X POST </span><span class="str">"http://localhost:9200/dashboard/_search?pretty=true"</span><span class="pln"> </span><span class="pun">-</span><span class="pln">d </span><span class="str">'
{
    "query" : { "match_all" : {} },

    "facets" : {
        "published_on" : {
            "date_histogram" : {
                "field"    : "published",
                "interval" : "day"
            }
        }
    }
}
'</span>

Notice how we set the interval to day; we could easily change the granularity of the histogram to week, month, or year.

This query will return JSON looking like this:

<span class="pun">{</span><span class="pln">
    </span><span class="str">"took"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln">
    </span><span class="com">// ... snip ...</span><span class="pln">
    </span><span class="str">"hits"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="str">"total"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="lit">4</span><span class="pun">,</span><span class="pln">
        </span><span class="com">// ... snip ...</span><span class="pln">
    </span><span class="pun">},</span><span class="pln">
    </span><span class="str">"facets"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="str">"published"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="str">"_type"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="str">"histogram"</span><span class="pun">,</span><span class="pln">
            </span><span class="str">"entries"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
                </span><span class="pun">{</span><span class="pln"> </span><span class="str">"time"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="lit">1293840000000</span><span class="pun">,</span><span class="pln"> </span><span class="str">"count"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pln"> </span><span class="pun">},</span><span class="pln">
                </span><span class="pun">{</span><span class="pln"> </span><span class="str">"time"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="lit">1293926400000</span><span class="pun">,</span><span class="pln"> </span><span class="str">"count"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
                </span><span class="com">// ... snip ...</span><span class="pln">
            </span><span class="pun">]</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span>

We are interested in the facets.published.entries array, as in the previous example. And again, we will need some HTML to hold our chart and load the data. Since the mechanics are very similar, please refer to the full source code for this example.

With the JSON data, it's very easy to create rich, interactive timeline in Protovis, by using a customized area chart.

The full, annotated code of the Timeline() JavaScript function is displayed below.

<span class="com">// =====================================================================================================</span><span class="pln">
</span><span class="com">// A timeline chart with Protovis - See http://vis.stanford.edu/protovis/ex/area.html</span><span class="pln">
</span><span class="com">// =====================================================================================================</span><span class="pln">

</span><span class="kwd">var</span><span class="pln"> </span><span class="typ">Timeline</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">dom_id</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="str">'undefined'</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">typeof</span><span class="pln"> dom_id</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">                 </span><span class="com">// Set the default DOM element ID to bind</span><span class="pln">
        dom_id </span><span class="pun">=</span><span class="pln"> </span><span class="str">'chart'</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">

    </span><span class="kwd">var</span><span class="pln"> data </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">json</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">                         </span><span class="com">// Set the data for the chart</span><span class="pln">
        </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data </span><span class="pun">=</span><span class="pln"> json</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">;</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">

    </span><span class="kwd">var</span><span class="pln"> draw </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

        </span><span class="kwd">var</span><span class="pln"> entries </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">data</span><span class="pun">;</span><span class="pln">                        </span><span class="com">// Set-up the data</span><span class="pln">
            entries</span><span class="pun">.</span><span class="pln">push</span><span class="pun">({</span><span class="pln">                              </span><span class="com">// Add the last "blank" entry for proper</span><span class="pln">
              count </span><span class="pun">:</span><span class="pln"> entries</span><span class="pun">[</span><span class="pln">entries</span><span class="pun">.</span><span class="pln">length</span><span class="pun">-</span><span class="lit">1</span><span class="pun">].</span><span class="pln">count   </span><span class="com">// timeline ending</span><span class="pln">
            </span><span class="pun">});</span><span class="pln">
        </span><span class="com">// console.log('Drawing, ', entries);</span><span class="pln">

        </span><span class="kwd">var</span><span class="pln"> w </span><span class="pun">=</span><span class="pln"> </span><span class="lit">600</span><span class="pun">,</span><span class="pln">                                    </span><span class="com">// Set-up dimensions and scales for the chart</span><span class="pln">
            h </span><span class="pun">=</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln">
            max </span><span class="pun">=</span><span class="pln"> pv</span><span class="pun">.</span><span class="pln">max</span><span class="pun">(</span><span class="pln">entries</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">d</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="kwd">return</span><span class="pln"> d</span><span class="pun">.</span><span class="pln">count</span><span class="pun">;}),</span><span class="pln">
            x </span><span class="pun">=</span><span class="pln"> pv</span><span class="pun">.</span><span class="typ">Scale</span><span class="pun">.</span><span class="pln">linear</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> entries</span><span class="pun">.</span><span class="pln">length</span><span class="pun">-</span><span class="lit">1</span><span class="pun">).</span><span class="pln">range</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> w</span><span class="pun">),</span><span class="pln">
            y </span><span class="pun">=</span><span class="pln"> pv</span><span class="pun">.</span><span class="typ">Scale</span><span class="pun">.</span><span class="pln">linear</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> max</span><span class="pun">).</span><span class="pln">range</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="pln"> h</span><span class="pun">);</span><span class="pln">

        </span><span class="kwd">var</span><span class="pln"> vis </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> pv</span><span class="pun">.</span><span class="typ">Panel</span><span class="pun">()</span><span class="pln">                        </span><span class="com">// Create the basis panel</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">width</span><span class="pun">(</span><span class="pln">w</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">height</span><span class="pun">(</span><span class="pln">h</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">bottom</span><span class="pun">(</span><span class="lit">20</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">left</span><span class="pun">(</span><span class="lit">20</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">right</span><span class="pun">(</span><span class="lit">40</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">top</span><span class="pun">(</span><span class="lit">40</span><span class="pun">);</span><span class="pln">

         vis</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">pv</span><span class="pun">.</span><span class="typ">Label</span><span class="pun">)</span><span class="pln">                              </span><span class="com">// Add the chart legend at top left</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">top</span><span class="pun">(-</span><span class="lit">20</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">text</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                 </span><span class="kwd">var</span><span class="pln"> first </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">(</span><span class="pln">entries</span><span class="pun">[</span><span class="lit">0</span><span class="pun">].</span><span class="pln">time</span><span class="pun">);</span><span class="pln">
                 </span><span class="kwd">var</span><span class="pln"> last  </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">(</span><span class="pln">entries</span><span class="pun">[</span><span class="pln">entries</span><span class="pun">.</span><span class="pln">length</span><span class="pun">-</span><span class="lit">2</span><span class="pun">].</span><span class="pln">time</span><span class="pun">);</span><span class="pln">
                 </span><span class="kwd">return</span><span class="pln"> </span><span class="str">"Articles published between "</span><span class="pln"> </span><span class="pun">+</span><span class="pln">
                     </span><span class="pun">[</span><span class="pln"> first</span><span class="pun">.</span><span class="pln">getDate</span><span class="pun">(),</span><span class="pln">
                       first</span><span class="pun">.</span><span class="pln">getMonth</span><span class="pun">()</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
                       first</span><span class="pun">.</span><span class="pln">getFullYear</span><span class="pun">()</span><span class="pln">
                     </span><span class="pun">].</span><span class="pln">join</span><span class="pun">(</span><span class="str">"/"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">+</span><span class="pln">

                     </span><span class="str">" and "</span><span class="pln"> </span><span class="pun">+</span><span class="pln">

                     </span><span class="pun">[</span><span class="pln"> last</span><span class="pun">.</span><span class="pln">getDate</span><span class="pun">(),</span><span class="pln">
                       last</span><span class="pun">.</span><span class="pln">getMonth</span><span class="pun">()</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pun">,</span><span class="pln">
                       last</span><span class="pun">.</span><span class="pln">getFullYear</span><span class="pun">()</span><span class="pln">
                     </span><span class="pun">].</span><span class="pln">join</span><span class="pun">(</span><span class="str">"/"</span><span class="pun">);</span><span class="pln">
             </span><span class="pun">})</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">textStyle</span><span class="pun">(</span><span class="str">"#B1B1B1"</span><span class="pun">)</span><span class="pln">

         vis</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">pv</span><span class="pun">.</span><span class="typ">Rule</span><span class="pun">)</span><span class="pln">                               </span><span class="com">// Add the X-ticks</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">data</span><span class="pun">(</span><span class="pln">entries</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">visible</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">(</span><span class="pln">d</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="kwd">return</span><span class="pln"> d</span><span class="pun">.</span><span class="pln">time</span><span class="pun">;})</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">left</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> x</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">index</span><span class="pun">);</span><span class="pln"> </span><span class="pun">})</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">bottom</span><span class="pun">(-</span><span class="lit">15</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">height</span><span class="pun">(</span><span class="lit">15</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">strokeStyle</span><span class="pun">(</span><span class="str">"#33A3E1"</span><span class="pun">)</span><span class="pln">

            </span><span class="pun">.</span><span class="pln">anchor</span><span class="pun">(</span><span class="str">"right"</span><span class="pun">).</span><span class="pln">add</span><span class="pun">(</span><span class="pln">pv</span><span class="pun">.</span><span class="typ">Label</span><span class="pun">)</span><span class="pln">              </span><span class="com">// Add the tick label (DD/MM)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">text</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">(</span><span class="pln">d</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                 </span><span class="kwd">var</span><span class="pln"> date </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Date</span><span class="pun">(</span><span class="pln">d</span><span class="pun">.</span><span class="pln">time</span><span class="pun">);</span><span class="pln">
                 </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">[</span><span class="pln">
                     date</span><span class="pun">.</span><span class="pln">getDate</span><span class="pun">(),</span><span class="pln">
                     date</span><span class="pun">.</span><span class="pln">getMonth</span><span class="pun">()</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="lit">1</span><span class="pln">
                 </span><span class="pun">].</span><span class="pln">join</span><span class="pun">(</span><span class="str">'/'</span><span class="pun">);</span><span class="pln">
             </span><span class="pun">})</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">textStyle</span><span class="pun">(</span><span class="str">"#2C90C8"</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">textMargin</span><span class="pun">(</span><span class="str">"5"</span><span class="pun">)</span><span class="pln">

         vis</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">pv</span><span class="pun">.</span><span class="typ">Rule</span><span class="pun">)</span><span class="pln">                               </span><span class="com">// Add the Y-ticks</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">data</span><span class="pun">(</span><span class="pln">y</span><span class="pun">.</span><span class="pln">ticks</span><span class="pun">(</span><span class="pln">max</span><span class="pun">))</span><span class="pln">                         </span><span class="com">// Compute tick levels based on the "max" value</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">bottom</span><span class="pun">(</span><span class="pln">y</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">strokeStyle</span><span class="pun">(</span><span class="str">"#eee"</span><span class="pun">)</span><span class="pln">
            </span><span class="pun">.</span><span class="pln">anchor</span><span class="pun">(</span><span class="str">"left"</span><span class="pun">).</span><span class="pln">add</span><span class="pun">(</span><span class="pln">pv</span><span class="pun">.</span><span class="typ">Label</span><span class="pun">)</span><span class="pln">
                </span><span class="pun">.</span><span class="pln">text</span><span class="pun">(</span><span class="pln">y</span><span class="pun">.</span><span class="pln">tickFormat</span><span class="pun">)</span><span class="pln">
                </span><span class="pun">.</span><span class="pln">textStyle</span><span class="pun">(</span><span class="str">"#c0c0c0"</span><span class="pun">)</span><span class="pln">

        vis</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">pv</span><span class="pun">.</span><span class="typ">Panel</span><span class="pun">)</span><span class="pln">                               </span><span class="com">// Add container panel for the chart</span><span class="pln">
           </span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="pln">pv</span><span class="pun">.</span><span class="typ">Area</span><span class="pun">)</span><span class="pln">                                </span><span class="com">// Add the area segments for each entry</span><span class="pln">
           </span><span class="pun">.</span><span class="pln">def</span><span class="pun">(</span><span class="str">"active"</span><span class="pun">,</span><span class="pln"> </span><span class="pun">-</span><span class="lit">1</span><span class="pun">)</span><span class="pln">                           </span><span class="com">// Auxiliary variable to hold mouse state</span><span class="pln">
           </span><span class="pun">.</span><span class="pln">data</span><span class="pun">(</span><span class="pln">entries</span><span class="pun">)</span><span class="pln">                               </span><span class="com">// Pass the data to Protovis</span><span class="pln">
           </span><span class="pun">.</span><span class="pln">bottom</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
           </span><span class="pun">.</span><span class="pln">left</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">(</span><span class="pln">d</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="kwd">return</span><span class="pln"> x</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">index</span><span class="pun">);})</span><span class="pln">   </span><span class="com">// Compute x-axis based on scale</span><span class="pln">
           </span><span class="pun">.</span><span class="pln">height</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">(</span><span class="pln">d</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="kwd">return</span><span class="pln"> y</span><span class="pun">(</span><span class="pln">d</span><span class="pun">.</span><span class="pln">count</span><span class="pun">);})</span><span class="pln">    </span><span class="com">// Compute y-axis based on scale</span><span class="pln">
           </span><span class="pun">.</span><span class="pln">interpolate</span><span class="pun">(</span><span class="str">'cardinal'</span><span class="pun">)</span><span class="pln">                     </span><span class="com">// Make the chart curve smooth</span><span class="pln">
           </span><span class="pun">.</span><span class="pln">segmented</span><span class="pun">(</span><span class="kwd">true</span><span class="pun">)</span><span class="pln">                             </span><span class="com">// Divide into "segments" (for interactivity)</span><span class="pln">
           </span><span class="pun">.</span><span class="pln">fillStyle</span><span class="pun">(</span><span class="str">"#79D0F3"</span><span class="pun">)</span><span class="pln">

           </span><span class="pun">.</span><span class="pln">event</span><span class="pun">(</span><span class="str">"mouseover"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">             </span><span class="com">// On "mouse over", set segment as active</span><span class="pln">
               </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">active</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">index</span><span class="pun">);</span><span class="pln">
               </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">root</span><span class="pun">.</span><span class="pln">render</span><span class="pun">();</span><span class="pln">
           </span><span class="pun">})</span><span class="pln">

           </span><span class="pun">.</span><span class="pln">event</span><span class="pun">(</span><span class="str">"mouseout"</span><span class="pun">,</span><span class="pln">  </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">             </span><span class="com">// On "mouse out", clear the active state</span><span class="pln">
               </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">active</span><span class="pun">(-</span><span class="lit">1</span><span class="pun">);</span><span class="pln">
               </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">root</span><span class="pun">.</span><span class="pln">render</span><span class="pun">();</span><span class="pln">
           </span><span class="pun">})</span><span class="pln">

           </span><span class="pun">.</span><span class="pln">event</span><span class="pun">(</span><span class="str">"mousedown"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">d</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">            </span><span class="com">// On "mouse down", perform action,</span><span class="pln">
               </span><span class="kwd">var</span><span class="pln"> time </span><span class="pun">=</span><span class="pln"> entries</span><span class="pun">[</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">index</span><span class="pun">].</span><span class="pln">time</span><span class="pun">;</span><span class="pln">     </span><span class="com">// eg filtering the results...</span><span class="pln">
               </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">(</span><span class="pln">alert</span><span class="pun">(</span><span class="str">"Timestamp: '"</span><span class="pun">+</span><span class="pln">time</span><span class="pun">+</span><span class="str">"'"</span><span class="pun">));</span><span class="pln">
           </span><span class="pun">})</span><span class="pln">

           </span><span class="pun">.</span><span class="pln">anchor</span><span class="pun">(</span><span class="str">"top"</span><span class="pun">).</span><span class="pln">add</span><span class="pun">(</span><span class="pln">pv</span><span class="pun">.</span><span class="typ">Line</span><span class="pun">)</span><span class="pln">                  </span><span class="com">// Add thick stroke to the chart</span><span class="pln">
           </span><span class="pun">.</span><span class="pln">lineWidth</span><span class="pun">(</span><span class="lit">3</span><span class="pun">)</span><span class="pln">
           </span><span class="pun">.</span><span class="pln">strokeStyle</span><span class="pun">(</span><span class="str">'#33A3E1'</span><span class="pun">)</span><span class="pln">

           </span><span class="pun">.</span><span class="pln">anchor</span><span class="pun">(</span><span class="str">"top"</span><span class="pun">).</span><span class="pln">add</span><span class="pun">(</span><span class="pln">pv</span><span class="pun">.</span><span class="typ">Dot</span><span class="pun">)</span><span class="pln">                   </span><span class="com">// Add the circle "label" displaying</span><span class="pln">
                                                        </span><span class="com">// the count for this day</span><span class="pln">

           </span><span class="pun">.</span><span class="pln">visible</span><span class="pun">(</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">                       </span><span class="com">// The label is only visible when</span><span class="pln">
               </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">parent</span><span class="pun">.</span><span class="pln">children</span><span class="pun">[</span><span class="lit">0</span><span class="pun">]</span><span class="pln">           </span><span class="com">// its segment is active</span><span class="pln">
                          </span><span class="pun">.</span><span class="pln">active</span><span class="pun">()</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="kwd">this</span><span class="pun">.</span><span class="pln">index</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">})</span><span class="pln">
           </span><span class="pun">.</span><span class="pln">left</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">(</span><span class="pln">d</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> x</span><span class="pun">(</span><span class="kwd">this</span><span class="pun">.</span><span class="pln">index</span><span class="pun">);</span><span class="pln"> </span><span class="pun">})</span><span class="pln">
           </span><span class="pun">.</span><span class="pln">bottom</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">(</span><span class="pln">d</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">return</span><span class="pln"> y</span><span class="pun">(</span><span class="pln">d</span><span class="pun">.</span><span class="pln">count</span><span class="pun">);</span><span class="pln"> </span><span class="pun">})</span><span class="pln">
           </span><span class="pun">.</span><span class="pln">fillStyle</span><span class="pun">(</span><span class="str">"#33A3E1"</span><span class="pun">)</span><span class="pln">
           </span><span class="pun">.</span><span class="pln">lineWidth</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span><span class="pln">
           </span><span class="pun">.</span><span class="pln">radius</span><span class="pun">(</span><span class="lit">14</span><span class="pun">)</span><span class="pln">

           </span><span class="pun">.</span><span class="pln">anchor</span><span class="pun">(</span><span class="str">"center"</span><span class="pun">).</span><span class="pln">add</span><span class="pun">(</span><span class="pln">pv</span><span class="pun">.</span><span class="typ">Label</span><span class="pun">)</span><span class="pln">             </span><span class="com">// Add text to the label</span><span class="pln">
           </span><span class="pun">.</span><span class="pln">text</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">(</span><span class="pln">d</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="kwd">return</span><span class="pln"> d</span><span class="pun">.</span><span class="pln">count</span><span class="pun">;})</span><span class="pln">
           </span><span class="pun">.</span><span class="pln">textStyle</span><span class="pun">(</span><span class="str">"#E7EFF4"</span><span class="pun">)</span><span class="pln">

           </span><span class="pun">.</span><span class="pln">root</span><span class="pun">.</span><span class="pln">canvas</span><span class="pun">(</span><span class="pln">dom_id</span><span class="pun">)</span><span class="pln">                        </span><span class="com">// Bind the chart to DOM element</span><span class="pln">
           </span><span class="pun">.</span><span class="pln">render</span><span class="pun">();</span><span class="pln">                                  </span><span class="com">// And render it.</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">

    </span><span class="kwd">return</span><span class="pln"> </span><span class="pun">{</span><span class="pln">                                            </span><span class="com">// Create the public API</span><span class="pln">
        data   </span><span class="pun">:</span><span class="pln"> data</span><span class="pun">,</span><span class="pln">
        draw   </span><span class="pun">:</span><span class="pln"> draw
    </span><span class="pun">};</span><span class="pln">

</span><span class="pun">};</span>

Again, you can see the full example here. Be sure to check out the documentation on the area primitive in Protovis, and watch what happens when you change interpolate('cardinal') to interpolate('step-after'). You should have no problems to draw a stacked area chart from multiple facets, add more interactivity, and completely customize the visualization.

The important thing to notice here is that the chart fully responds to any queries we pass to ElasticSearch, making it possible to simply and instantly visualize metrics such as “Display publishing frequence of this author on this topic in last three months", with a query such as:

<code> author:John AND topic:Search AND published:[2011-03-01 TO 2011-05-31]

tl;dr

When you need to make rich, interactive data visualization for complex, ad-hoc queries, using data returned by facets from ElasticSearch may well be one of the easiest ways to do it, since you can just pass the JSON response to a toolkit like Protovis.

By adapting the approach and code from this article, you should have a working example for your data in couple of hours.

Sign up for product updates!

Subscribe to the RSS feed RSS