Equation Graphing (#176)

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

The three rules of Ruby Q. 2:

  1. Please do not post any solutions or spoiler discussion for this
    quiz until 48 hours have passed from the time on this message.

  2. Support Ruby Q. 2 by submitting ideas as often as you can! (A
    permanent, new website is in the works for Ruby Q. 2. Until then,
    please visit the temporary website at

    http://splatbang.com/rubyquiz/.

  3. Enjoy!

Suggestion: A [QUIZ] in the subject of emails about the problem
helps everyone on Ruby T. follow the discussion. Please reply to
the original quiz message, if you can.

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

This week’s quiz idea provided and written by Martin DeMello.

Equation Graphing (#176)

Back when the world was shiny and new, and BBC Basic my language of
choice and necessity, one of the fun little programs I wrote was a
simple equation grapher. Two things that made it simple were (i) the
ever-useful EVAL function, and (ii) the almost trivial ability to pick
a colour and a pair of coordinates and put a friendly glowing pixel
onto the screen. Instant gratification writ large. Well, anything that
Basic can do, Ruby should be able to, so your task this week is to
whip out your favourite graphics toolkit or library and write a
program that

  1. Asks for a function of one variable, x
  2. Asks for the region of the graph to display (xmin, xmax, ymin, ymax)
  3. Plots the graph

You can trust the user to input a syntactically correct function, but
don’t forget that it might behave badly for certain values of x (e.g.
1/x where x=0). Style points for making the main loop look trivial :slight_smile:

Here’s a neat little online grapher you can use to visually check your
output: http://www.walterzorn.com/grapher/grapher_e.htm.

Equation Graphing (#176)

You can trust the user to input a syntactically correct function, but
don’t forget that it might behave badly for certain values of x (e.g.
1/x where x=0). Style points for making the main loop look trivial :slight_smile:

I went for style points. :slight_smile:
1/x where x = 0 is handled nicely too.

graph.rb:
#!/usr/bin/ruby

def usage
puts "USAGE: #{File.basename($0)}
"
exit 42
end

eq = ARGV.shift || usage
usage unless ARGV.length == 4

cmd = “set xr [%f:%f]; set yr [%f:%f]; set tit ‘%s’; plot %s w li
notitle”

IO.popen(“gnuplot -persist”, “w”) do |plot|
plot.puts cmd % [ARGV.collect { |a| a.to_f }, eq, eq].flatten
end

On Fri, Sep 5, 2008 at 10:01 AM, Matthew M. [email protected]
wrote:

whip out your favourite graphics toolkit or library and write a
program that

  1. Asks for a function of one variable, x
  2. Asks for the region of the graph to display (xmin, xmax, ymin, ymax)
  3. Plots the graph

I didn’t follow the requirements, but inspired by the quiz did a
little bit using my favorite graphics (none;-):

def grapher xmin, ymin, xmax, ymax, &function
ymax.downto(ymin) do |y|
xmin.upto(xmax) do |x|
begin
print (function.call(x, y) ? ‘#’ : ‘+’)
rescue
print “X”
end
end
print “\n”
end
print “\n”
end

grapher(0, 0, 40, 10){|x,y| x == y}
grapher(0, 0, 40, 10){|x,y| 2 >= y2 / x}
grapher(0, -5, 60, 10){|x,y| y == (5 + Math.sin(x) * 5).to_i}
grapher(-10, -5, 70, 10){|x,y| y
2 == x}

Output:

++++++++++#++++++++++++++++++++++++++++++
+++++++++#+++++++++++++++++++++++++++++++
++++++++#++++++++++++++++++++++++++++++++
+++++++#+++++++++++++++++++++++++++++++++
++++++#++++++++++++++++++++++++++++++++++
+++++#+++++++++++++++++++++++++++++++++++
++++#++++++++++++++++++++++++++++++++++++
+++#+++++++++++++++++++++++++++++++++++++
++#++++++++++++++++++++++++++++++++++++++
+#+++++++++++++++++++++++++++++++++++++++
#++++++++++++++++++++++++++++++++++++++++

X+++++++++++++++++++++++++++++++++#######
X+++++++++++++++++++++++++++#############
X+++++++++++++++++++++###################
X++++++++++++++++########################
X++++++++++++############################
X++++++++################################
X+++++###################################
X+++#####################################
X+#######################################
X########################################
X########################################

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+##+++++#+++++#+++++##+++++#+++++#+++++#+++++##+++++#+++++#++
+++++++#+++++++#++++++++++#+++++++++++++#++++++++++#+++++++#+
+++++++++#+++#++++++++++++++++++#+#++++++++++++++++++++++#+++
++++++++++++++++++++++++++++#+++++++++#++++++++++++++#+++++++
#++#+++++++++++++++#++++++++++++++++++++++++#++#+++++++++++++
++++++++++++++++++++++#++#+++++++++++++++#+++++++++++++++++++
++++++#+++++++++#+++++++++++++++++++++++++++++++++#+++++++++#
++++++++++#+#++++++++++++++++++#+++#++++++++++++++++++#+#++++
++++#+++++++++++++#++++++++++#+++++++#++++++++++#++++++++++++
+++++#+++++#+++++#+++++##+++++#+++++#+++++##+++++#+++++#+++++
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#++++++
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++#+++++++++++++++++++++
++++++++++++++++++++++++++++++++++++++++++++++#++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++#+++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++#++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
++++++++++++++++++++++++++#++++++++++++++++++++++++++++++++++++++++++++++++++++++
+++++++++++++++++++++++++++++++++++#+++++++++++++++++++++++++++++++++++++++++++++

http://github.com/fjc/rubyquiz/tree/master/176.rb

Here’s my solution, using _why’s wonderful little shoes toolkit. Run
like

shoes graph.rb “x*x; -5; 5; 0; 25”

The args are “fn; xmin; xmax; ymin; ymax”

I tried to make the code as straightforward as possible, to recapture
the feel of the old Basic days. A few inevitable complications, due to
shoes being a work in progress: the Grapher class is to work around
scoping quirks, and the range check is due to a bug that doesn’t let
the exception handler catch an overflowing Bignum -> long conversion
in the canvas code (it would’ve been nice to simply draw to a point
off-canvas and let the drawing engine cope). Also shoes’s argv
handling code puts the filename in ARGV[0] and doesn’t like negative
numbers as plain command line args (they are treated as shoes args),
so a single quoted string was the simplest thing that worked.

#------------------------------------------------------------------------------------------------------

ARGV[0] is the filename, since we launch via shoes graph.rb args

ARGV.shift
args = ARGV[0].split(";").map {|i| i.chomp}
F = args.shift
Xmin, Xmax, Ymin, Ymax = args.map {|i| i.to_f}

X = Y = 800

XScale = X * 1.0/(Xmax - Xmin)
YScale = Y * 1.0/(Ymax - Ymin)

class Grapher
def at(x,y)
[((x -Xmin)* XScale).to_i, Y - ((y - Ymin) * YScale).to_i] rescue
nil
end

def bounded?(x,y)
x && y && 0 <= x && x <= X && 0 <= y && y <= Y
end

def fn(x)
y = eval(F)
end
end

Shoes.app :height => Y, :width => X do
g = Grapher.new
background rgb(255, 255, 255)

fill white
stroke black
strokewidth 1
u, v = nil
Xmin.step(Xmax, (Xmax - Xmin)/(X*1.0)) {|i|
begin
x0, y0 = g.at(u,v)
u, v = i, g.fn(i)
x, y = g.at(u,v)
if g.bounded?(x,y) and g.bounded?(x0,y0)
line(x0, y0, x, y)
end
rescue
end
}
end

Hello

I think this is the time to show what RubyX11 can do.

You need the X11 directory from the RubyX11-0.6.pre1, ruby 1.8, and an X
server.

The program is not as simple as with Shoes but it requires no binary
extension - you could run it in JRuby as well.

Unfortunately RubyX11 is not complete, and likely will never be. As I
understand it people went from server-side font rendering to
client-side font rendering for X11 applications. This means that you
cannot do the font rendering effectively to a remote display, the
letters rendered by different applications suck in different ways, and
you cannot write a simple client library for X that would also render
text reasonably.

OK, enough complaints about lack of design in X protocols.

You can find the program attached. If you run it without parameters it
asks for them interactively in the terminal.

It is sort of a cheat - the X11 interfacing is merged form two RubyX11
examples, I only had to write the method that calculates the points of
the graph and fix window resizing.

Thanks

Michal