[QUIZ] Equation Graphing (#176)

## 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)} <equation> <xmin> <xmax> <ymin>
<ymax>"
  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

···

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

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 >= y**2 / 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:

···

On Fri, Sep 5, 2008 at 10:01 AM, Matthew Moss <matthew.moss@gmail.com> 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

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

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

q176.rb (4.71 KB)