I've expanded upon the work of both moot and eric256. It's still pretty basic but adds a few additional features: colored lines, scroll bars, zoom, centering and error trapping/reporting. Since it uses Math::Trig, you can use any of its trigonometric functions.

To zoom in, click the left mouse button over the graph. To zoom out, click the right mouse button over the graph. To center on a point, click the middle mouse button over the spot that be at the center of the graph.

Enjoy!

Update: I've added the ability to redraw the axes based on the values in X Min, X Max, and Step (there is no input validation for these yet). The axes subroutine still needs some work too.

Update: Posted the correct refactoring attempt that doesn't use $x_axis, $y_axis or @ticks.

#!/usr/bin/perl use strict; use warnings; use Tk; use Tk::WorldCanvas; require Tk::Dialog; use Graphics::ColorNames; use Math::Trig; # define our color set my $colors = Graphics::ColorNames->new( 'HTML' ); my %colors = %{ $colors->{SCHEMES}[0] }; delete $colors{fuscia}; # this is the misspelling of fuschia delete $colors{black}; # color of our axes delete $colors{white}; # kind of hard to see delete $colors{silver}; # kind of hard to see delete $colors{gray}; # kind of hard to see my @colors = keys %colors; # array of colors for the lines my $maxcolors = @colors; # mod the line count with this later my @IDs; # store line IDs so that we can delete them without removing +axes # main window my $top = new MainWindow(-width => 800, -height => 600, -title => 'Gra +phing Calculator'); # dialog box for error messages my $d = $top->DialogBox(-title => "Calculation Error", -buttons => ["O +K"]); # scrolled worldcanvas # left mouse click zooms in, middle mouse click centers, right mouse c +lick zooms out my $cvs = $top->Scrolled('WorldCanvas', -scrollbars => 'se', -width => + 800, -height => 550); $cvs->CanvasBind('<1>' => sub { $cvs->zoom(1.25) }); $cvs->CanvasBind('<3>' => sub { $cvs->zoom(0.8) }); $cvs->CanvasBind('<2>' => sub { $cvs->CanvasFocus; $cvs->center($cvs-> +eventLocation) }); # normal canvas with labels and text entries my $frm = $top->Canvas(-width => 800, -height => 20); my $txt_txt = $frm->Label(-text => 'Expression'); my $txt = $frm->Entry(-width => 40); my $min_txt = $frm->Label(-text => 'X Min'); my $min = $frm->Entry(-width => 5); my $max_txt = $frm->Label(-text => 'X Max'); my $max = $frm->Entry(-width => 5); my $stp_txt = $frm->Label(-text => 'Step'); my $stp = $frm->Entry(-width => 5 ); my $redraw = $frm->Button(-text => 'Redraw Axes', -command => [ \&axes + ]); my $clr = $frm->Button(-text => 'Clear', -command => [ sub { $cvs->de +lete(@IDs); @IDs = (); } ]); # bind the enter key to call the evaluate subroutine $txt->bind('<KeyPress-Return>', [ \&evaluate ]); # form up $frm->pack(-side => 'bottom'); $min_txt->pack(-side => 'left'); $min->pack(-side => 'left'); $max_txt->pack(-side => 'left'); $max->pack(-side => 'left'); $stp_txt->pack(-side => 'left'); $stp->pack(-side => 'left'); $redraw->pack(-side => 'left'); $txt_txt->pack(-side => 'left'); $clr->pack(-side => 'right'); $txt->pack(-side => 'right'); $cvs->pack(-side => 'top'); # preload our text boxes $min->insert(0, "0"); $max->insert(0, "100"); $stp->insert(0, "1"); axes(); MainLoop; sub evaluate { my $text = $txt->get(); my $func = lc $text; $func =~ s/(\d+)(pi|x)/$1 * $2/g; $func =~ s/([xy])/\$$1/g; $func =~ s/\^/**/g; my $mini = $min->get(); my $maxi = $max->get(); my $step = $stp->get(); # what's our new color? my $color = $colors->hex($colors[@IDs % $maxcolors], '#'); my @errors; my @points; for ( my $i = $mini ; $i <= $maxi ; $i += $step ) { my $y = 0; my $x = $i; eval "$func"; if ($@) { # do we have an eval error? # strip the ' at (eval XXX) line XXX' part of the error $@ =~ s/ at \(eval \d+\) line \d+//; push @errors, "$@\n"; } # only graph real points if ( $y =~ /i/ ) { push @errors, "Calculation '$text' resulted in y containing an i +maginary number."; } else { push @points, $x, $y; } } if ( @errors ) { # create dialog box with errors # if there are more than 5, only show the first one my $errors = @errors; my $msg; if ( @errors > 5 ) { $msg = "Showing only the first of $errors errors:\n$errors[0]"; } else { $msg = join( "\n", @errors ); } my $DialogRef = $top->Dialog( -title => 'Calculation Error', -text => $msg, -bitmap => 'warning', -buttons => [ 'OK' ], ); my $selected = $DialogRef->Show(); # I don't use $selected but may + in the future } else { # no errors # create the line and grab the ID my $ID = $cvs->createLine( @points, -smooth => 1, -fill => $color +); # keep track of all IDs so that we can delete them push( @IDs, $ID ); $cvs->viewFit( @IDs ); } } sub axes { $cvs->delete('all'); my $minx = $min->get(); my $maxx = $max->get(); my $step = $stp->get(); my $tick = (abs($minx) + abs($maxx)) / 10; my $maxi = 2 * $maxx; my $mini = -$maxi; my $scale = 10 * $step / $tick; $cvs->createLine($mini, 0, $maxi, 0); $cvs->createLine(0, $mini, 0, $maxi); for ( my $i = $mini; $i <= $maxi; $i += $tick ) { $cvs->createLine($i, -$scale, $i, $scale); $cvs->createLine(-$scale, $i, $scale, $i); } }

In reply to Re: Cheap'n'cheerful Graph Drawer by Mr. Muskrat
in thread Cheap'n'cheerful Graph Drawer by moot

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.