Thanks, Thaddeus. That's a good suggestion. It turns out my case can
be simplified considerably by using explicit id's for the sparklines,
e.g.
$(function() {
$(this).everyTime(1000,function(i) {
$.getJSON('/peertool/sparkline/call/json/sparkdata/
13/0/20', function(data) {
$("#dynbar0").sparkline(data.dynbar0, {type: 'bar',
barColor: 'green'});
$("#dynbar1").sparkline(data.dynbar1, {type: 'bar',
barColor: 'green'});
// etc ...
});
});
});
This works because I know how many plots will be needed when the page
is rendered by the view, so it's fairly trivial to generate the
necessary id's server side. If I were doing something that required
consulting a different server to get the data for each plot, then I'd
certainly look seriously at writing a plugin.
In case it's useful to anyone else, here's a complete working example
that's kind of fun to see in action. When you browse to the index
page, it puts up between 5 and 25 bar graphs with random values
reverse sorted to emulate Pareto charts. The charts update once per
second with new data from the server.
(WARNING - a few minutes of this drives my MacBook's cpu usage up
because I don't have indexing turned off for wherever the json data is
going.)
1. web2py_ajax.html - add the sparkline and timer plugins
response.files.insert(4,URL(r=request,c='static',f='jquery.sparkline.js'))
response.files.insert(5,URL(r=request,c='static',f='jquery.timers-1.2.js'))
2. The controller
# coding: utf8
import sys
import random
def index():
ngraphs = random.choice(range(5,25))
return dict(message="hello from sparkline.py", ngraphs=ngraphs,
chartmin=0, chartmax=20)
def call():
session.forget()
return service()
@service.json
def sparkdata(ngraphs,chartmin,chartmax):
ngraphs = int(ngraphs)
chartmin = int(chartmin)
chartmax = int(chartmax)
sys.stderr.write("\nsparkdata() called with ngraphs=%d\n"%ngraphs)
d = dict()
for n in xrange(ngraphs):
id = "dynbar" + str(n)
## data for bar graph. 9 random ints between chartmax and
chartmin
data = [random.choice(range(chartmin,chartmax)) for i in
xrange(9)]
## simulate a Pareto plot
data.sort()
data.reverse()
d[id] = data
sys.stderr.write("\n%s : %s"%(id, str(d[id])))
return d
3. The view (index.html)
{{extend 'layout.html'}}
{{
chartoptions = "{type: 'bar', barColor: 'green', 'chartRangeMin':
'%d', 'chartRangeMax': '%d'}"%(chartmin,chartmax)
jsonurl = URL(r=request,f='call/json/sparkdata/%(ngraphs)d/%
(chartmin)d/%(chartmax)d'%locals())
}}
<script type="text/javascript">
/* <![CDATA[ */
$(function() {
$(this).everyTime(1000,function(i) {
$.getJSON('{{=jsonurl}}', function(data) {
{{for n in xrange(ngraphs):}}
$("#dynbar{{=n}}").sparkline(data.dynbar{{=n}},
{{=chartoptions}});
{{pass}}
});
});
});
/* ]]> */
</script>
<h1>This is the sparkline.html template</h1>
{{for n in xrange(ngraphs):}}
<p>
Bar chart with dynamic data: <span id="dynbar{{=n}}"
class="dynamicbar">Loading..</span>
</p>
{{pass}}
{{=BEAUTIFY(response._vars)}}
That's it. BTW, sparkline charts are really useful in applications
where you need to visually compare lots of similar data series. Here's
a link to a chapter in Edward Tufte's "Beautiful Evidence" with more
info
http://www.edwardtufte.com/bboard/q-and-a-fetch-msg?msg_id=0001OR
The JQuery Sparklines plug-in page is also useful.
http://omnipotent.net/jquery.sparkline/
Cheers,
Mike
On May 15, 3:27 pm, Thadeus Burgess <[email protected]> wrote:
> For multiple elements you might want to try and put it into a jQuery
> plugin, allowing you to re-use the code for each sparkline.
>
> $(".spark").makeSparkline({url:/path/to/call/sparkdata, args:etc});
>
> --
> Thadeus
>
> On Sat, May 15, 2010 at 1:34 PM, MikeEllis <[email protected]> wrote:
>
> > After spending some time with Firebug to find and fix a couple of
> > typos, I've got it working now. There seems to be no way around
> > explicitly referring to the SPAN element (see below), but I can live
> > with that.
>
> > Now I need to tackle the next level, which is to expand the server-
> > side JSON function to return data for multiple sparklines on a page
> > and arrange to call sparkline() with the right data for each of the
> > corresponding elements.
>
> > Thanks again for the help!
>
> > Here's what's working correctly:
>
> > In the view ...
>
> > <script type="text/javascript">
> > /* <![CDATA[ */
> > $(function() {
> > $('.dynamicsparkline').everyTime(1000,function(i) {
> > var j = 2+i%5;
> > $.getJSON('{{=URL(r=request,f='call/json/
> > sparkdata')}}/'+j, function(data) {
> > var sparkdata = [10,9,8,7,6,5,4];
> > for(var k=0; k<sparkdata.length; k++) { sparkdata[k] =
> > data.a[k];}
> > console.log("sparkdata = " + sparkdata);
> > $('.dynamicsparkline').sparkline(sparkdata); // WORKS
> > // $(this).sparkline(sparkdata) // DOES NOT WORK!
> > });
> > });
> > });
> > /* ]]> */
> > </script>
>
> > <h1>This is the sparkline.html template</h1>
> > <p>
> > Sparkline with dynamic data: <span class="dynamicsparkline">Loading..</
> > span>
> > </
> > p>
>
> > and in the controller ...
>
> > @service.json
> > def sparkdata(j):
> > sys.stderr.write("\nsparkdata() called with j=%d\n"%int(j))
> > j = int(j)
> > return dict(a=[n%j for n in [10,9,8,7,6,5,4]])
>
> > Cheers,
> > Mike
>
> > On May 14, 9:51 pm, mdipierro <[email protected]> wrote:
> >> aha try replace
>
> >> $(function() {
> >> $('.dynamicsparkline').everyTime(1000,function(i) {
> >> $.getJSON('{{=URL(r=request,f='call/json/
> >> datapoints')}}/'+i, function(data) {
> >> var b = [0,0,0,0,0,0,0]
> >> var j = 2+i%5;
> >> for(var k=0; k<b.length; k++) { b[k] = data.a[k]
> >> %j;}
> >> $(this).sparkline(b);
> >> });
> >> });
> >> });
>
> >> with
>
> >> $(function() {
> >> $('.dynamicsparkline').each(function(index){
> >> var obj=$(this);
> >> obj.everyTime(1000,function(i) {
> >> $.getJSON('{{=URL(r=request,f='call/json/
> >> datapoints')}}/'+i, function(data) {
> >> var b = [0,0,0,0,0,0,0]
> >> var j = 2+i%5;
> >> for(var k=0; k<b.length; k++) { b[k] = data.a[k] %j;}
> >> obj.sparkline(b);
> >> });
> >> });
> >> });
> >> });
>
>