This is brain dead, but is it stupid?


#1

I’m about to embark on my very first significant non-command line ruby
app. It will be a simple rails app that will parse my log file and show
me some statistics that I am interested in. Some of that will entail
some simple graphing.

I spent hours last night looking at some graphing libraries that are out
there. There are only a few to choose from on rubyforge. I wanted
something simple, but not toooo simple. I looked at sparklites and
gruff. One is too fancy and requires waaaaaay to much installation, the
other a little less installation, but doesn’t really cut it for a real
graph.

It occurred to me that the reason they were requiring rmagic and other
stuff has to do with needing a way to so some really simple drawing.
Sort of like using photoshop to paint a mustache on your girlfriends
picture - it works and inspires the expected knee reflex in the girl,
but it’s total overkill for the job.

So I says to myself, you could make a decent bargraph just by drawing a
simple little “color blob image” in different sizes. I tried it, and it
looks just fine to me. I’m thinking about cooking up a simple ruby lib
that will draw a bargraph with x and y labels on it using this
technique. Here’s a simple manual example:
http://www.mylittlecorneroftheinternet.com/BrainDeadBarGraph.html

What do you think, this is clearly brain dead, but is it stupid too?

thanks,
jp


#2

Jeff P. wrote:

So I says to myself, you could make a decent bargraph just by drawing a
simple little “color blob image” in different sizes. I tried it, and it
looks just fine to me. I’m thinking about cooking up a simple ruby lib
that will draw a bargraph with x and y labels on it using this
technique. Here’s a simple manual example:
http://www.mylittlecorneroftheinternet.com/BrainDeadBarGraph.html

What do you think, this is clearly brain dead, but is it stupid too?

No, it’s clearly very handy, and forum polls have been doing it this way
for a long time. 'Twould be a nice library, I think.

You can easily do horizontal graphs, too, this way.

A possible extra feature would be “caps” that don’t get stretched that
are added to top and bottom or left and right of each bar.

Cheers,
Dave


#3

Jeff P. wrote:

So I says to myself, you could make a decent bargraph just by drawing a
simple little “color blob image” in different sizes.

Use simple, one-color images and resize them in HTML using height and
width.


James B.

http://www.ruby-doc.org - Ruby Help & Documentation
http://www.artima.com/rubycs/ - The Journal By & For Rubyists
http://www.rubystuff.com - The Ruby Store for Ruby Stuff
http://web2.0validator.com - We’re the Dot in Web 2.0


#4

Yes, that’s the idea. You said it much better than me though.

jp

James B. wrote:

Jeff P. wrote:

So I says to myself, you could make a decent bargraph just by drawing a
simple little “color blob image” in different sizes.

Use simple, one-color images and resize them in HTML using height and
width.


James B.

http://www.ruby-doc.org - Ruby Help & Documentation
http://www.artima.com/rubycs/ - The Journal By & For Rubyists
http://www.rubystuff.com - The Ruby Store for Ruby Stuff
http://web2.0validator.com - We’re the Dot in Web 2.0


#5

On 1-Jun-06, at 6:34 PM, Jeff P. wrote:

I’m about to embark on my very first significant non-command line ruby
app. It will be a simple rails app that will parse my log file and
show
me some statistics that I am interested in. Some of that will entail
some simple graphing.

Not sure what your requirements are but have you seen:

http://nubyonrails.topfunky.com/pages/css_graphs

It’s pure html/css graphs - might do what you want.

Also from the same author, (but it requires rmagic iirc):

http://nubyonrails.topfunky.com/pages/gruff

… all just in case you didn’t spot them when you were looking for
solutions.

Regards,
Trevor


#6

Trevor S. wrote:

http://nubyonrails.topfunky.com/pages/css_graphs

It’s pure html/css graphs - might do what you want.

Trevor, I did miss this one when I was at Geofrey’s site. Looks
interesting. The “one graph per page” thing may be enough to make me go
ahead and implement a similar rails library using my even simpler
approach.

Clearly though, I’m the Jeffrey Come Lately to graphing libraries. :slight_smile:

thanks,
jp


#7

don’t forget SVG::Graph
http://www.germane-software.com/software/SVG/SVG::Graph/
(powerful and pretty simple but obviously limited to firefox or ie with
a
plugin. I think there is a bug in the current release so you might want
to
use the svn version instead)

PlotKit http://www.liquidx.net/plotkit/
uses MochiKit so be sure Prototype isn’t loaded on any page that uses
PlotKit (prototype and mochikit are incompatable)

If you’re doing log stats you might want to check out the flash based
graphing tool used by MeasureMap
http://www.measuremap.com/developer/slider/
(fairly easy to hook into rails)

-Kate == Masukomi


#8

On Jun 2, 2006, at 12:27 AM, Jeff P. wrote:

@barString = "<img src=\"blublock.jpg\" width= 

“replace_with_width”
height=“replace_with_height”>\n"

Any coding comments welcome.

I don’t think the replace technique is very elegant. One thing you
can do instead is make a string with %s for holes:

irb(main):001:0> x = “1 %s 3”
=> “1 %s 3”
irb(main):003:0> x %2
=> “1 2 3”

also instead of escaping lots of double quotes by hand you can using
a different way to surround the string. see pickaxe page 320

irb(main):007:0> %Q-a “b” c-
=> “a “b” c”
irb(main):008:0> %[dog “cat” rat]
=> “dog “cat” rat”

– Elliot T.


#9

On Jun 2, 2006, at 0:27, Jeff P. wrote about html-based graphing.

Seems worth doing. I added horizontal graphs using a similar technique
many years ago, although the scripting language was Tango 3, not Ruby.

You’ll almost certainly want to trap the bars within a table. Otherwise
any labels you try to add to either end of a bar run the risk of
wrapping in a narrow window.

You can also dispense with the color blob graphic by doing something
like this instead:
<table width=“replace_with_width” height="replace_with_height
cellspacing=0 cellpadding=0>

There’s also an argument for using CSS techniques instead of obsolete
HTML, as well.

On the other hand, if you do use an image file, there’s no point in a
boring old monocolor image. For the graphs I did, I created a one-pixel
wide image that was, say, 7 pixels tall, and the pixels were something
like this
medium red
light red
light red
medium red
medium red
dark red
dark red

When stretched out horizontally, it looks cylindrical, with the light
red becoming a ‘highlight,’ much like the roundness seen in OSX widgets
and whatnot.

So as you expand and enhance your bar graphing class, consider adding
optional .image and .styleclass methods. I could choose to
graph.image = “/images/bluebar.gif”
but if I don’t, then the bar graph uses tables (or some more modern CSS
equivalent).
graph.barcolor
might set the bar color to something other than the default, although
.image would override that anyway.
graph.styleclass = “vertbargraph”
could change the outer enclosing table from
<table …>
to
<table class=“vertbargraph” …>
so that I could define many of my graph characteristics in my
stylesheet.

I notice that the “Graphs Helper” for Rails that somebody else pointed
out not only is limited to one graph per page (how odd) but also a
range of 0-100. I like the fact you included min and max graph range
values in your code. My old graphing code also handled over-range
values with a special graphic that matched the regular bar, but had an
“s” shaped slice cut out of it. If a value was out of range, it would
draw a regular bar about 3/4 of the way, stick in the sliced graphic,
then finish the bar. Another way I could have done it was to have a
triangular end-cap to create an arrow indicating a value off the chart.
I can’t think of an easy way offhand to do that just with colored table
blocks, but there’s probably a way with CSS code. Anyway, don’t forget
to handle out of bounds data values, and/or possibly an auto-scaling
option.

Another thing the “Graphs Helper” shows off is value labels overlapping
the bars, and multiple bar colors per graph. If/when I next put graphs
on a web page, I’ll put my labels next to/below the bars, and the bars
are almost certainly all going to be the same color. Even Helper’s
first sample graph shows some problems with getting too fancy. “Apple”
didn’t get to have a value label, probably because the bar’s too short,
and the white writing on the yellow bar isn’t very legible. Fill the
niche for a nice simple bar graph tool. :slight_smile:

Finally, “draw” seems a bit odd as a rendering method to me. What I
expect I’d want back is the HTML, which I can then embed with other
stuff in my page. It won’t get “drawn” as such until the browser gets
it.
graph.htmlsource
maybe? Or something more like that?


#10

Thanks for all the great suggestions so far.

I like the idea of an option to skip the colorBlob.jpg file and just use
tables with cell background colors. Also agree with the concern over
making it into a psychedelic 70’s Acid graphing trip. I hate page
design that looks like something designed by Liberace. To each their
own…but that’s not me.

I was really hoping to get an answer to my question about the best way
to report errors in something that will be supplying html into an erb
document.

My goal is to make this library just barely complete enough to be useful
for real bar graphs, but keep it simple enough that using it is a ten
minute exercise rather than adding a bunch of installation and learning
curve to a project. Geoffrey and others have already cornered the
market on the heavy artillery. Geoffrey also covered the extreme low
end where you’re primarily after more of a customized graphics clip art,
with sparklines. I want to fill the niche between sparklines and gruff.
And with nothing more than including my library.rb file for installation
(and an optional color blob file).

I’m finding it a bit surprising that anybody is interested in horizontal
bar graphs. I’ve always found them a bit off-putting. Like I’m
supposed to lay my head on the table while I look at them. Will it be
unforgivably incomplete without support for horizontal bars?

Some other thoughts:

  • I’m thinking there are probably some other more convenient ways of
    adding points
    • maybe add an array parameter as an optional last parameter to the
      constructor
    • maybe provide a method for supplying an array of points
    • maybe optionally read a file full of CSV points
    • if it were a rails app with sql, what type of input method would
      be most convenient for sticking the results of an sql query right into a
      graph?
  • I want to make labeling pretty simple. I’m thinking just set it up
    such that there are ten evenly spaced “slots” for placing a custom ‘y’
    label. If none are supplied it would fill these ten spots in with
    calculated values based on the min and max.
  • I’m thinking an optional method that allows you to supply an array of
    ‘x’ labels - one per bar. If nothing is supplied, nothing will be
    “drawn”
  • I’m thinking that “titling” of the graph can be done outside of the
    graph and not handled by the library
  • In ‘erb’ land, is there any advantage to making it a “one liner”,
    where the constructor is big and hairy and allows all possible
    parameters to be filled in, and the constructor automatically provides
    the html output?

thanks,
jp


#11

Elliot T. wrote:

I don’t think the replace technique is very elegant. One thing you
can do instead is make a string with %s for holes:

irb(main):001:0> x = “1 %s 3”
=> “1 %s 3”
irb(main):003:0> x %2
=> “1 2 3”

– Elliot T.
http://www.curi.us/blog/

So my multiline gsub tempstring “<img src=“blublock.jpg”
width=“replace_with_width” height=“replace_with_height”>\n”
nastiness would become:

@barString = %Q(\n)
@htmlString << @barString % [barWidth,barHeight]

yes?

Very cool language.

thanks,
jp


#12

On 6/2/06, Jeff P. removed_email_address@domain.invalid wrote:

http://www.curi.us/blog/
Very cool language.

thanks,
jp


Posted via http://www.ruby-forum.com/.

Or you could just:

@htmlString = %Q(\n)

pth


#13

A modest beginning…

class BDBarGraph
def initialize(height,width,xmin,xmax)
@height = height * 1.0
@width = width * 1.0
@xmin = xmin * 1.0
@xmax = xmax * 1.0
@dataPoints = [] # the y values to plot
@htmlString = “”
@barString = “<img src=“blublock.jpg” width=“replace_with_width”
height=“replace_with_height”>\n”
end

attr_reader :xmin, :xmax, :dataPoints

def points
	@dataPoints.length
end

def add_point(value)
	@dataPoints << value * 1.0
end

def draw
	@dataPoints.each do |thisPoint|
	  tempString = ""
	  tempString << @barString
	  tempString.gsub!(/replace_with_width/,(@width/points).to_i.to_s)
	  barHeight = ((thisPoint - @xmin)/(@xmax - @xmin)) * @height
	  tempString.gsub!(/replace_with_height/,barHeight.to_i.to_s)
		@htmlString << tempString
	end

	puts @htmlString
end

end

bar = BDBarGraph.new(200,200,0,100)
bar.add_point(50)
bar.add_point(75)
bar.add_point(100)
bar.add_point(25)
bar.draw

[cpe-66-75-140-208:~] jeff% ruby BDBarGraph.rb




[cpe-66-75-140-208:~] jeff%

Still needs stuff to do x and y labels (probably using a table)
Still needs error checking
Maybe some refactoring to make it easier to use from erb

Question, something like this that is intended to be used from erb, how
is error checking usually handled? Just fail quietly? Seems like
assertions might not be handled gracefully in erb.

Any coding comments welcome.

thanks,
jp


#14

True enough Patrick, but that doesn’t use any new-to-me coolish aspects
of the language. :slight_smile:

I’m a bit disappointed nobody bothered to respond to my library design
questions. I’ll risk bad forum etiquette by reposting them here:

Some other thoughts:

  • What’s the best way to report parameter errors in a library intended
    for erb use?
  • I’m thinking there are probably some other more convenient ways of
    adding points
    • maybe add an array parameter as an optional last parameter to the
      constructor
    • maybe provide a method for supplying an array of points
    • maybe optionally read a file full of CSV points
    • if it were a rails app with sql, what type of input method would
      be most convenient for sticking the results of an sql query right into a
      graph?
  • I want to make labeling pretty simple. I’m thinking just set it up
    such that there are ten evenly spaced “slots” for placing a custom ‘y’
    label. If none are supplied it would fill these ten spots in with
    calculated values based on the min and max.
  • I’m thinking an optional method that allows you to supply an array of
    ‘x’ labels - one per bar. If nothing is supplied, nothing will be
    “drawn”
  • I’m thinking that “titling” of the graph can be done outside of the
    graph and not handled by the library
  • In ‘erb’ land, is there any advantage to making it a “one liner”,
    where the constructor is big and hairy and allows all possible
    parameters to be filled in, and the constructor automatically provides
    the html output?

thanks,
jp

Patrick H. wrote:

On 6/2/06, Jeff P. removed_email_address@domain.invalid wrote:

http://www.curi.us/blog/
Very cool language.

thanks,
jp


Posted via http://www.ruby-forum.com/.

Or you could just:

@htmlString = %Q(\n)

pth


#15

On 6/4/06, Patrick H. removed_email_address@domain.invalid wrote:

height="#{barHeight}">\n)
That doesn’t benefit from the template string only needing to be built
once. Compare these:

template = ‘T minus %d…’
15.downto(1) do |i|
puts(template % i)
end

vs.

15.downto(1) do |i|
puts “T minus #{i}”
end

I’ll admit, I use the latter as well when I’m not concerned with the
performance in that loop. It does look nicer and more compact. But I’m
guessing[0] that the former will be significantly faster when 1) the
number of iterations in the loop is high and 2) the template is
moderately complex. Why? I assume that String#% is implemented in C
using sprintf (or some cousin). So the performance of template % i is
almost entirely related to one very well used and thus well optimized
libc library call. “T minus #{i}” on the other hand involves parsing
of the string to determine interpolation etc. This is probably also
written in C, but involves more work than the quick sprintf call.

Jacob F.

[0] Yes, I’m guessing. I haven’t actually benchmarked this or looked
at the ruby sources, so I may be wrong.


#16

On 6/2/06, Jeff P. removed_email_address@domain.invalid wrote:

I’m finding it a bit surprising that anybody is interested in horizontal
bar graphs. I’ve always found them a bit off-putting. Like I’m
supposed to lay my head on the table while I look at them. Will it be
unforgivably incomplete without support for horizontal bars?

Simple example of why horizontal graphs are important:
Imaging you have 100+ records each of which gets a bar.
With a vertical bar graph you run off the side of page (even without
labels). How are you supposed to do it with a label on each bar?
Horizontal graph allows you to put label + bar on one line, and while
the full graph may scroll off bottom of page people don’t mind because
we’re used to things going below the fold. Horizontal graphs also
allow you to have more words in the label of each bar because they
don’t affect the length of the graph.

  • kate = masukomi

#17

Thanks Kate,
You make a good point. Right now I’m working towards a SimpleGraphs
v0.001 that satisfies my needs for the app that brought it into being.
Perhaps 0.002 will include horizontal graphs as well.

Still hoping for info on error reporting in an ‘erb’ library.

best,
jp

kate rhodes wrote:

On 6/2/06, Jeff P. removed_email_address@domain.invalid wrote:

I’m finding it a bit surprising that anybody is interested in horizontal
bar graphs. I’ve always found them a bit off-putting. Like I’m
supposed to lay my head on the table while I look at them. Will it be
unforgivably incomplete without support for horizontal bars?

Simple example of why horizontal graphs are important:
Imaging you have 100+ records each of which gets a bar.
With a vertical bar graph you run off the side of page (even without
labels). How are you supposed to do it with a label on each bar?
Horizontal graph allows you to put label + bar on one line, and while
the full graph may scroll off bottom of page people don’t mind because
we’re used to things going below the fold. Horizontal graphs also
allow you to have more words in the label of each bar because they
don’t affect the length of the graph.

  • kate = masukomi

#18

On Jun 2, 2006, at 18:20, Jeff P. wrote:

I’m finding it a bit surprising that anybody is interested in
horizontal
bar graphs. I’ve always found them a bit off-putting. Like I’m
supposed to lay my head on the table while I look at them. Will it be
unforgivably incomplete without support for horizontal bars?

I’d be perplexed, to be sure. As somebody else pointed out, because our
language lays out in horizontal boxes, you can just naturally get a lot
more information into a space if the labels are running the same
direction as the bars.

a
graph?

I sort of expect that a Graph would expect an array of GraphItems.
GraphItem would be something like
:value (required, numeric)
:label (default nil)
:barcolor (default to nil, aka Graph.barcolor)
:barimage (default to nil, aka Graph.barimage)

I could pass in an array like
[3, 65, 43, 1, 0, 0, 5]
or I could send in
[[4, “PCs”], [18, “Macs”], [9, “Other”]]
or I could do
[:rutabagas => 30, :pomegranates=>54, :kiwifruit => 4325]
or I could do
[ <#GraphItem:@label=“Spoon!”, @value=43, @barcolor=“FF0000”,
@barimage=nil>, <#GraphItem:@label=“Fork”, @value=12,
@barcolor=“777777”, @barimage=nil>, <#GraphItem:@label=“Knife”,
@value=14, @barcolor=“777777”, @barimage=nil>

  • I want to make labeling pretty simple. I’m thinking just set it up
    such that there are ten evenly spaced “slots” for placing a custom ‘y’
    label. If none are supplied it would fill these ten spots in with
    calculated values based on the min and max.

I think you’ll find value-axis labels to be a bit of a problem. If
they’re just numbers on a vertical graph, they’ll usually work OK. Big
numbers on a horiz. graph will be prone to distortion due to label
length. Vertically, it may not be very clear where the ‘tick’ mark
would be for that number. Would you try to span each label across two
rows? And what if my values are “3” “4” and “5”? Do I just get unevenly
spaced labels, or a graph with some dead space at some point?

  • I’m thinking an optional method that allows you to supply an array of
    ‘x’ labels - one per bar. If nothing is supplied, nothing will be
    “drawn”

Are these bar labels or value-axis labels? I’m not sure which one you
think is “x”, although since you seem to think in terms of vertical
graphs, I guess they’re bar labels.

I’d want to supply bar labels at the same time that I provided bar
values, not have to break them out and load them separately, which
seems kind of weird . . . but maybe that’s just me.

  • I’m thinking that “titling” of the graph can be done outside of the
    graph and not handled by the library
  • In ‘erb’ land, is there any advantage to making it a “one liner”,
    where the constructor is big and hairy and allows all possible
    parameters to be filled in, and the constructor automatically provides
    the html output?

That wouldn’t be hard if Graph.new accepts an array, no?

print Graph.new(datapoints).html

I can see people wanting to also pass in .min, .max, .bar_color, and
the rest, although personally I’d probably prefer being able to set
defaults for the class.

Graph.default_bar_image = “/images/bargraph.gif”
Graph.default_bar_color = htmlColors[:yellow]

mmmm. Default symbolic colors…


#19

On 6/5/06, Jeff P. removed_email_address@domain.invalid wrote:

With a vertical bar graph you run off the side of page (even without


Posted via http://www.ruby-forum.com/.

Just throw an exception on errors – let the user/framework deal with
exceptions. They should only be generated on “true” errors.
Personally, I would let questionable data through, ignoring it – this
often simplifies graphing where some of the data can be rough.

pth