What do you want to see in a Sparklines Library?

This is sort of an interest gauging/feature request poll.

I saw Joe Gregorio's Sparklines webservice written in Python and
decided to try and do an implementation in Ruby thinking that I may
want to be able to have access to some quick Sparklines for a Rails
app or something one day.

Well, writing it in Ruby didn't take too long (mostly just issues with
Apache and RMagick) and I generally like the outcome. But I was
thinking that there might be some interest for some more features that
could make doing Sparklines for anything a piece of cake.

What would you like to see in a sparklines library?

···

--
-Dan Nugent

Daniel Nugent wrote:

This is sort of an interest gauging/feature request poll.

...

What would you like to see in a sparklines library?

Pure Ruby, nothing but Ruby, implementation.

As long as you're asking.

James

···

--

http://www.ruby-doc.org - The Ruby Documentation Site
http://www.rubyxml.com - News, Articles, and Listings for Ruby & XML
http://www.rubystuff.com - The Ruby Store for Ruby Stuff
http://www.jamesbritt.com - Playing with Better Toys

See what's already been done before you get too far.

http://redhanded.hobix.com/inspect/sparklinesForMinimalists.html

Dan

Well... what does it do right now?
I was looking into writing a nice ruby-centric charting library, then
again I am always looking into doing things I never get around to :wink:

I suppose if you're using RMagick then they can already be writtent to
a variety of formats, which is good. One thing I haven't seen yet
which might be neat would be mini pie charts, along the lines of
sparklines, but to show proportions of various things.
  .adam sanderson

Yup, seen the stuff on RedHanded, I was planning on writing a little
something that'll let me do data: URIs.

As for Pure Ruby, I assume you mean no image manipulation libraries.
Frankly, that's out of the question unless someone's already written
an image manipulation library in Pure Ruby. I don't have any interest
in doing that.

Right now, I'm using RMagick, but if you know of an image manipulation
library in Pure Ruby, please do tell.

···

On 6/26/05, Daniel Amelang <daniel.amelang@gmail.com> wrote:

See what's already been done before you get too far.

http://redhanded.hobix.com/inspect/sparklinesForMinimalists.html
http://www.whytheluckystiff.net/bumpspark/

Dan

--
-Dan Nugent

Right now I'm outputting 3 different types of sparklines.

2 of them, discrete and smooth, were lifted from Joe's Python code and
use exactly the same query parameters as seen here:
http://bitworking.org/projects/sparklines/

The third is a bit of a blend between the 2 which you can access if
you change the type parameter to "area".

Here's an example query running on my dev server (the IP isn't static
though, so don't expect it to be up forever):
http://68.195.83.222/spark.cgi?height=25&type=area&d=88,84,82,92,82,86,66,82,44,64,66,88,90,80,24,26,14,0,0,26,8,6,6,24,52,66,36,6,10,14,30&min-m=true&max-m=true&last-m=true&min-color=red&max-color=blue&last-color=green&step=5&upper=45

(the code is http://68.195.83.222/spark.rb if you want to grab it)

Changing the image output type would be a snap, I could probablly have
that working in 10 minutes.

Pie charts could definitley be a possibility. RMagick's got some
excellent drawing functions that make doing something like that a
snap.

···

On 6/26/05, Adam Sanderson <netghost@gmail.com> wrote:

Well... what does it do right now?
I was looking into writing a nice ruby-centric charting library, then
again I am always looking into doing things I never get around to :wink:

I suppose if you're using RMagick then they can already be writtent to
a variety of formats, which is good. One thing I haven't seen yet
which might be neat would be mini pie charts, along the lines of
sparklines, but to show proportions of various things.
  .adam sanderson

--
-Dan Nugent

Yup, seen the stuff on RedHanded, I was planning on writing a little
something that'll let me do data: URIs.

As for Pure Ruby, I assume you mean no image manipulation libraries.
Frankly, that's out of the question unless someone's already written
an image manipulation library in Pure Ruby. I don't have any interest
in doing that.

Right now, I'm using RMagick, but if you know of an image manipulation
library in Pure Ruby, please do tell.

Not an image manipulation library, but a simple-to-use pure ruby png writer:
  http://www.ruby-talk.org/cgi-bin/scat.rb/ruby/ruby-talk/120493
Not being an image manipulation library shouldn't be a problem unless
you want to draw text in there... I use this a lot for plotting data.

cheers,
Mark

···

On 6/26/05, Daniel Nugent <nugend@gmail.com> wrote:

On 6/26/05, Daniel Amelang <daniel.amelang@gmail.com> wrote:
> See what's already been done before you get too far.
>
> http://redhanded.hobix.com/inspect/sparklinesForMinimalists.html
> http://www.whytheluckystiff.net/bumpspark/
>
> Dan
>
>

--
-Dan Nugent

Adam, your wish is my command:

http://68.195.83.222/spark.cgi?type=pie&d=85&diameter=40&share-color=pink&remain-color=tan

I'm not sure what Mr. Tufte would think about this though, as I'm
pretty sure that pie charts are taboo. However, DAMN THE MAN! We'll
have our pie and eat it too!

···

On 6/26/05, Daniel Nugent <nugend@gmail.com> wrote:

Right now I'm outputting 3 different types of sparklines.

2 of them, discrete and smooth, were lifted from Joe's Python code and
use exactly the same query parameters as seen here:
http://bitworking.org/projects/sparklines/

The third is a bit of a blend between the 2 which you can access if
you change the type parameter to "area".

Here's an example query running on my dev server (the IP isn't static
though, so don't expect it to be up forever):
http://68.195.83.222/spark.cgi?height=25&type=area&d=88,84,82,92,82,86,66,82,44,64,66,88,90,80,24,26,14,0,0,26,8,6,6,24,52,66,36,6,10,14,30&min-m=true&max-m=true&last-m=true&min-color=red&max-color=blue&last-color=green&step=5&upper=45

(the code is http://68.195.83.222/spark.rb if you want to grab it)

Changing the image output type would be a snap, I could probablly have
that working in 10 minutes.

Pie charts could definitley be a possibility. RMagick's got some
excellent drawing functions that make doing something like that a
snap.

On 6/26/05, Adam Sanderson <netghost@gmail.com> wrote:
> Well... what does it do right now?
> I was looking into writing a nice ruby-centric charting library, then
> again I am always looking into doing things I never get around to :wink:
>
> I suppose if you're using RMagick then they can already be writtent to
> a variety of formats, which is good. One thing I haven't seen yet
> which might be neat would be mini pie charts, along the lines of
> sparklines, but to show proportions of various things.
> .adam sanderson
>
>
>

--
-Dan Nugent

--
-Dan Nugent

One thing that would make sparklines a lot more universally accessible to
all browsers would be to get rid of the dependency on data urls. The basic
idea is to return the proper MIME type to the browser and then just start
spitting out the raw binary data of the PNG.

Here is an example:

#!/usr/bin/ruby

require 'base64'
require 'cgi'
require 'zlib'

def build_png_chunk(type,data)
to_check = type + data
return [data.length].pack("N") + to_check +
[Zlib.crc32(to_check)].pack("N")
end

def build_png(image_rows)
header = [137, 80, 78, 71, 13, 10, 26, 10].pack("C*")
raw_data = image_rows.map { |row| [0] + row }.flatten.pack("C*")
ihdr_data = [image_rows.first.length,
image_rows.length,
8,2,0,0,0].pack("NNCCCCC")
ihdr = build_png_chunk("IHDR", ihdr_data)
idat = build_png_chunk("IDAT", Zlib::Deflate.deflate(raw_data))
iend = build_png_chunk("IEND", "")

return header + ihdr + idat + iend
end

def bumpspark(results)
white, red, grey = [0xFF,0xFF,0xFF], [0,0,0xFF], [0x99,0x99,0x99]
rows = results.inject([]) do |ary, r|
ary << [white]*15 << [white]*15
ary.last[r/9,4] = [(r > 50 and red or grey)]*4
ary
end.transpose
return build_png(rows)
end

def send_to_browser(results)
puts "Content-type: image/png"
puts "Expires: Wed, 11 Nov 1998 11:11:11 GMT"
puts "Cache-Control: no-cache"
puts "Cache-Control: must-revalidate"
puts
print bumpspark(results)
end

send_to_browser (0..22).map { rand 100 }

See this in action at the following URL:

http://youngbloods.org/sparkline.cgi

Carl

I can't seem to access your pages. Perhaps someone has eaten all the
pie?

A pie chart has a valid purpose, when you're trying to visualize
realtions of data ie (30% sunny, 20% cloudy, 50% rainy). What I think
he rightly doesn't like is that people like to make them 3d, and then
have horrible labels, and such.

Anyways, want to send me a screenshot or two?
  .adam sanderson

Here's an improvement. Make your CGI script accept parameters so that you
can make a generic script that will generate sparklines for all types of
data:

...

cgi = CGI.new
data = cgi['data']
if data.empty?
send_to_browser (0..22).map { rand 100 }
else
send_to_browser data.split(',').collect! {|e| e.to_i}
end

Example in action:

http://youngbloods.org/sparkline2.cgi?data=23,19,67,20,5

Carl

···

On 6/27/05, Carl Youngblood <carl.youngblood@gmail.com> wrote:

One thing that would make sparklines a lot more universally accessible to
all browsers would be to get rid of the dependency on data urls. The basic
idea is to return the proper MIME type to the browser and then just start
spitting out the raw binary data of the PNG.

Here is an example:

#!/usr/bin/ruby

require 'base64'
require 'cgi'
require 'zlib'

def build_png_chunk(type,data)
to_check = type + data
return [data.length].pack("N") + to_check +
[Zlib.crc32(to_check)].pack("N")
end

def build_png(image_rows)
header = [137, 80, 78, 71, 13, 10, 26, 10].pack("C*")
raw_data = image_rows.map { |row| [0] + row }.flatten.pack("C*")
ihdr_data = [image_rows.first.length,
image_rows.length,
8,2,0,0,0].pack("NNCCCCC")
ihdr = build_png_chunk("IHDR", ihdr_data)
idat = build_png_chunk("IDAT", Zlib::Deflate.deflate(raw_data))
iend = build_png_chunk("IEND", "")

return header + ihdr + idat + iend
end

def bumpspark(results)
white, red, grey = [0xFF,0xFF,0xFF], [0,0,0xFF], [0x99,0x99,0x99]
rows = results.inject() do |ary, r|
ary << [white]*15 << [white]*15
ary.last[r/9,4] = [(r > 50 and red or grey)]*4
ary
end.transpose
return build_png(rows)
end

def send_to_browser(results)
puts "Content-type: image/png"
puts "Expires: Wed, 11 Nov 1998 11:11:11 GMT"
puts "Cache-Control: no-cache"
puts "Cache-Control: must-revalidate"
puts
print bumpspark(results)
end

send_to_browser (0..22).map { rand 100 }

See this in action at the following URL:

http://youngbloods.org/sparkline.cgi

Carl

Here's an improvement. Make your CGI script accept parameters so that you
can make a generic script that will generate sparklines for all types of
data:

...

cgi = CGI.new
data = cgi['data']
if data.empty?
send_to_browser (0..22).map { rand 100 }
else
send_to_browser data.split(',').collect! {|e| e.to_i}
end

Example in action:

http://youngbloods.org/sparkline2.cgi?data=23,19,67,20,5

Carl

I'm doing that right now actually, I just want to add the ability to
do data: URIs, which should be pretty easy I think.

It's strange that you can't access my server Adam, is anyone else
having that problem?

···

On 6/27/05, Carl Youngblood <carl.youngblood@gmail.com> wrote:

One thing that would make sparklines a lot more universally accessible to
all browsers would be to get rid of the dependency on data urls. The basic
idea is to return the proper MIME type to the browser and then just start
spitting out the raw binary data of the PNG.

Here is an example:

#!/usr/bin/ruby

require 'base64'
require 'cgi'
require 'zlib'

def build_png_chunk(type,data)
to_check = type + data
return [data.length].pack("N") + to_check +
[Zlib.crc32(to_check)].pack("N")
end

def build_png(image_rows)
header = [137, 80, 78, 71, 13, 10, 26, 10].pack("C*")
raw_data = image_rows.map { |row| [0] + row }.flatten.pack("C*")
ihdr_data = [image_rows.first.length,
image_rows.length,
8,2,0,0,0].pack("NNCCCCC")
ihdr = build_png_chunk("IHDR", ihdr_data)
idat = build_png_chunk("IDAT", Zlib::Deflate.deflate(raw_data))
iend = build_png_chunk("IEND", "")

return header + ihdr + idat + iend
end

def bumpspark(results)
white, red, grey = [0xFF,0xFF,0xFF], [0,0,0xFF], [0x99,0x99,0x99]
rows = results.inject() do |ary, r|
ary << [white]*15 << [white]*15
ary.last[r/9,4] = [(r > 50 and red or grey)]*4
ary
end.transpose
return build_png(rows)
end

def send_to_browser(results)
puts "Content-type: image/png"
puts "Expires: Wed, 11 Nov 1998 11:11:11 GMT"
puts "Cache-Control: no-cache"
puts "Cache-Control: must-revalidate"
puts
print bumpspark(results)
end

send_to_browser (0..22).map { rand 100 }

See this in action at the following URL:

http://youngbloods.org/sparkline.cgi

Carl

--
-Dan Nugent

Sorry about the duplicate posts. Gmail problem...

I cannot access your server either. I have tried both times you posted it and it would just time out multiple times.
-Ezra

···

On Jun 27, 2005, at 1:24 PM, Daniel Nugent wrote:

I'm doing that right now actually, I just want to add the ability to
do data: URIs, which should be pretty easy I think.

It's strange that you can't access my server Adam, is anyone else
having that problem?

On 6/27/05, Carl Youngblood <carl.youngblood@gmail.com> wrote:

One thing that would make sparklines a lot more universally accessible to
all browsers would be to get rid of the dependency on data urls. The basic
idea is to return the proper MIME type to the browser and then just start
spitting out the raw binary data of the PNG.

Here is an example:

#!/usr/bin/ruby

require 'base64'
require 'cgi'
require 'zlib'

def build_png_chunk(type,data)
to_check = type + data
return [data.length].pack("N") + to_check +
[Zlib.crc32(to_check)].pack("N")
end

def build_png(image_rows)
header = [137, 80, 78, 71, 13, 10, 26, 10].pack("C*")
raw_data = image_rows.map { |row| [0] + row }.flatten.pack("C*")
ihdr_data = [image_rows.first.length,
image_rows.length,
8,2,0,0,0].pack("NNCCCCC")
ihdr = build_png_chunk("IHDR", ihdr_data)
idat = build_png_chunk("IDAT", Zlib::Deflate.deflate(raw_data))
iend = build_png_chunk("IEND", "")

return header + ihdr + idat + iend
end

def bumpspark(results)
white, red, grey = [0xFF,0xFF,0xFF], [0,0,0xFF], [0x99,0x99,0x99]
rows = results.inject() do |ary, r|
ary << [white]*15 << [white]*15
ary.last[r/9,4] = [(r > 50 and red or grey)]*4
ary
end.transpose
return build_png(rows)
end

def send_to_browser(results)
puts "Content-type: image/png"
puts "Expires: Wed, 11 Nov 1998 11:11:11 GMT"
puts "Cache-Control: no-cache"
puts "Cache-Control: must-revalidate"
puts
print bumpspark(results)
end

send_to_browser (0..22).map { rand 100 }

See this in action at the following URL:

http://youngbloods.org/sparkline.cgi

Carl

--
-Dan Nugent

-Ezra Zygmuntowicz
Yakima Herald-Republic
WebMaster
509-577-7732
ezra@yakima-herald.com

I also cannot access your server.

···

On 6/27/05, Ezra Zygmuntowicz <ezra@yakima-herald.com> wrote:

I cannot access your server either. I have tried both times you
posted it and it would just time out multiple times.
-Ezra
On Jun 27, 2005, at 1:24 PM, Daniel Nugent wrote:

> I'm doing that right now actually, I just want to add the ability to
> do data: URIs, which should be pretty easy I think.
>
> It's strange that you can't access my server Adam, is anyone else
> having that problem?
>
> On 6/27/05, Carl Youngblood <carl.youngblood@gmail.com> wrote:
>
>> One thing that would make sparklines a lot more universally
>> accessible to
>> all browsers would be to get rid of the dependency on data urls.
>> The basic
>> idea is to return the proper MIME type to the browser and then
>> just start
>> spitting out the raw binary data of the PNG.
>>
>> Here is an example:
>>
>> #!/usr/bin/ruby
>>
>> require 'base64'
>> require 'cgi'
>> require 'zlib'
>>
>> def build_png_chunk(type,data)
>> to_check = type + data
>> return [data.length].pack("N") + to_check +
>> [Zlib.crc32(to_check)].pack("N")
>> end
>>
>> def build_png(image_rows)
>> header = [137, 80, 78, 71, 13, 10, 26, 10].pack("C*")
>> raw_data = image_rows.map { |row| [0] + row }.flatten.pack("C*")
>> ihdr_data = [image_rows.first.length,
>> image_rows.length,
>> 8,2,0,0,0].pack("NNCCCCC")
>> ihdr = build_png_chunk("IHDR", ihdr_data)
>> idat = build_png_chunk("IDAT", Zlib::Deflate.deflate(raw_data))
>> iend = build_png_chunk("IEND", "")
>>
>> return header + ihdr + idat + iend
>> end
>>
>> def bumpspark(results)
>> white, red, grey = [0xFF,0xFF,0xFF], [0,0,0xFF], [0x99,0x99,0x99]
>> rows = results.inject() do |ary, r|
>> ary << [white]*15 << [white]*15
>> ary.last[r/9,4] = [(r > 50 and red or grey)]*4
>> ary
>> end.transpose
>> return build_png(rows)
>> end
>>
>> def send_to_browser(results)
>> puts "Content-type: image/png"
>> puts "Expires: Wed, 11 Nov 1998 11:11:11 GMT"
>> puts "Cache-Control: no-cache"
>> puts "Cache-Control: must-revalidate"
>> puts
>> print bumpspark(results)
>> end
>>
>> send_to_browser (0..22).map { rand 100 }
>>
>>
>> See this in action at the following URL:
>>
>> http://youngbloods.org/sparkline.cgi
>>
>> Carl
>>
>>
>>
>
>
> --
> -Dan Nugent
>
>

-Ezra Zygmuntowicz
Yakima Herald-Republic
WebMaster
509-577-7732
ezra@yakima-herald.com

I'll bet it's my ISP blocking access from outside the subnet. I'm
sorry about that.

I'm not quite sure how to let you guys see what it does, I'll email
the source if you'd like it, or you can look at Joe's Python version
(sans my two additions): .http://bitworking.org/projects/sparklines/

Carl: I'm not sure if what you're doing there is any different from
what's in the script right now.

···

On 6/27/05, Ezra Zygmuntowicz <ezra@yakima-herald.com> wrote:

I cannot access your server either. I have tried both times you
posted it and it would just time out multiple times.
-Ezra
On Jun 27, 2005, at 1:24 PM, Daniel Nugent wrote:

> I'm doing that right now actually, I just want to add the ability to
> do data: URIs, which should be pretty easy I think.
>
> It's strange that you can't access my server Adam, is anyone else
> having that problem?
>
> On 6/27/05, Carl Youngblood <carl.youngblood@gmail.com> wrote:
>
>> One thing that would make sparklines a lot more universally
>> accessible to
>> all browsers would be to get rid of the dependency on data urls.
>> The basic
>> idea is to return the proper MIME type to the browser and then
>> just start
>> spitting out the raw binary data of the PNG.
>>
>> Here is an example:
>>
>> #!/usr/bin/ruby
>>
>> require 'base64'
>> require 'cgi'
>> require 'zlib'
>>
>> def build_png_chunk(type,data)
>> to_check = type + data
>> return [data.length].pack("N") + to_check +
>> [Zlib.crc32(to_check)].pack("N")
>> end
>>
>> def build_png(image_rows)
>> header = [137, 80, 78, 71, 13, 10, 26, 10].pack("C*")
>> raw_data = image_rows.map { |row| [0] + row }.flatten.pack("C*")
>> ihdr_data = [image_rows.first.length,
>> image_rows.length,
>> 8,2,0,0,0].pack("NNCCCCC")
>> ihdr = build_png_chunk("IHDR", ihdr_data)
>> idat = build_png_chunk("IDAT", Zlib::Deflate.deflate(raw_data))
>> iend = build_png_chunk("IEND", "")
>>
>> return header + ihdr + idat + iend
>> end
>>
>> def bumpspark(results)
>> white, red, grey = [0xFF,0xFF,0xFF], [0,0,0xFF], [0x99,0x99,0x99]
>> rows = results.inject() do |ary, r|
>> ary << [white]*15 << [white]*15
>> ary.last[r/9,4] = [(r > 50 and red or grey)]*4
>> ary
>> end.transpose
>> return build_png(rows)
>> end
>>
>> def send_to_browser(results)
>> puts "Content-type: image/png"
>> puts "Expires: Wed, 11 Nov 1998 11:11:11 GMT"
>> puts "Cache-Control: no-cache"
>> puts "Cache-Control: must-revalidate"
>> puts
>> print bumpspark(results)
>> end
>>
>> send_to_browser (0..22).map { rand 100 }
>>
>>
>> See this in action at the following URL:
>>
>> http://youngbloods.org/sparkline.cgi
>>
>> Carl
>>
>>
>>
>
>
> --
> -Dan Nugent
>
>

-Ezra Zygmuntowicz
Yakima Herald-Republic
WebMaster
509-577-7732
ezra@yakima-herald.com

--
-Dan Nugent