http://www.perlmonks.org?node_id=735506

KianTern has asked for the wisdom of the Perl Monks concerning the following question:

Hi all,
I looking for a way to accomplish the following.
Using a delimited text file, draw a box plot.
Sounds easy but there is a catch.
I need to be able to select one or multiple points in the box plot
and export the data to a new text file, or exclude them from the chart.
In short I need a graphics module that can respond to mouse/keyboard events
and will allow me to reasonably easy draw charts.
The only library I found that somewhat suits me is SDL, but it seems
to be more game oriented and I need scientific precision.
Will SDL work or is there another module available?
I know that Perl is not very well suited for scientific
software but unfortunately all the data parsing modules are
written in Perl and I don't have the time or the knowledge
to write this in another language

Replies are listed 'Best First'.
Re: Graphics Module
by zentara (Archbishop) on Jan 11, 2009 at 14:54 UTC
    It sounds like an easy job for one of the Canvas modules....Tk::Canvas, Tk::Zinc, Gnome2::Canvas, Goo::Canvas, etc. The advantage of the canvas widgets over SDL, is that they give you persistence of items ( sort of as objects) on the screen, whearas SDL requires you to do that yourself.

    See Tk Patio/Office layout designer as a good example of tagging items on a canvas.

    For a simple example of mouse position and the use of tags, this moves lines individually, or as a group if you move the red oval

    #!/usr/bin/perl use warnings; use strict; use Tk; my $dx; my $dy; my $grouptag; my $mw = MainWindow->new; $mw->geometry("700x600"); my $x1 = 50; my $x2 = 100; my $y1 = 50; my $y2 = 200; my $c = $mw->Canvas(-width => 700, -height => 565, -bg => 'black', )->pack; my $closebutton = $mw->Button(-text => 'Exit', -command => sub{Tk::exi +t(0)}) ->pack; my $parent = $c->createOval($x1, $y1, $x2, $y2, -fill => 'red', -tags => ['mover','group1'], ); my @children; for (1..4) { push @children, $c->createLine(($x1 + $x2)/2,$y1, (2 * $x2), (2 * +$y2), # -state =>'disabled', -fill => 'white', -activefill => 'green', -disabledfill => 'white', -tags => ['mover','group1','line','line'.$_], ); $x1 += 15; $x2 += 15; } $c->bind('mover', '<1>', sub {&mobileStart();}); $c->bind('mover', '<B1-Motion>', sub {&mobileMove();}); $c->bind('mover', '<ButtonRelease>', sub {&mobileStop();}); MainLoop; sub mobileStart { my $ev = $c->XEvent; ($dx, $dy) = (0 - $ev->x, 0 - $ev->y); my $curr_object = $c->find('withtag','current'); print "curr->",@$curr_object,"\n"; #array dereference my (@list) = $c->gettags($curr_object); print "movelist->@list\n"; # if( grep /line/, @list){ # ($grouptag) = grep /(line\d+)/, @list; # } else {($grouptag) = grep /(group\d+)/, @list; } # JKrahn correctly observes: #You are grep()ing through @list twice! and using capturing parenthese +s! #this is better unless ( ( $grouptag ) = grep /line\d/, @list ) { ( $grouptag ) = grep /group\d/, @list; } # print "grouptag-> $grouptag\n"; # print "START MOVE-> $dx $dy\n"; } sub mobileMove { my $ev = $c->XEvent; $c->move($grouptag, $ev->x + $dx, $ev->y +$dy); ($dx, $dy) = (0 - $ev->x, 0 - $ev->y); # print "MOVING-> $dx $dy\n"; } sub mobileStop{&mobileMove;} __END__
    If you are more specific in your question, like showing a sample text file, and exactly what you want to do, we might be able to give you a head start on setting up your tags and mouse bindings.

    I'm not really a human, but I play one on earth Remember How Lucky You Are
      Basicly the data looks like
      ITEM_1,ITEM_2,ITEM_3,ITEM_4,ITEM_N
      and so on for millions of lines.

      The best example of what I want to do is SAS JMP software.
      It provides a way to directly interact with charts(select ,exclude and export data) and switch
      back and forth between the charts and the data.
      I don't need the complexity JMP provides but the idea is the same.
        I don't know anything about JMP, but what does ITEM_1 mean? I would expect something like
        ITEM_1 = (100,200); ITEM_2 = (200,150); etc etc
        what are you trying to plot? What shape do you expect the items to be represented as?...a point, a line, a circle?

        I'm not really a human, but I play one on earth Remember How Lucky You Are
Re: Graphics Module
by zentara (Archbishop) on Jan 11, 2009 at 15:27 UTC
    This code may interest you. It interfaces Gtk2 and the GD graphing module to give mouse interactivity.
    #!/usr/bin/perl use strict; use warnings; use Gtk2::Ex::Graph::GD; use GD::Graph::Data; use Gtk2 -init; use Glib qw /TRUE FALSE/; use Data::Dumper; my $graph = Gtk2::Ex::Graph::GD->new(500, 300, 'bars'); # All the properties set here go straight into the GD::Graph::* object + created inside. # Therefore, any property acceptable to the GD::Graph::* object can be + passed through here $graph->set ( title => 'Mice, Fish and Lobsters', x_labels_vertical => TRUE, bar_spacing => 1, shadowclr => 'dred', transparent => 0, # cumulate => TRUE, type => ['lisen', 'bars', 'bars'], ); my @legend_keys = ('Field Mice Population', 'Fish Population', 'Lobste +r Growth in millions'); $graph->set_legend(@legend_keys); my $data = GD::Graph::Data->new([ [ 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,], [ 1, 2, 5, 8, 3, 4.5, 1, 3, 4], [1.4, 4, 15, 6, 13, 1.5, 11, 3, 4], [11.4, 14, 22, 16, 1.3, 15, 1, 13, 14], ]) or die GD::Graph::Data->error; $graph->signal_connect ('mouse-over' => sub { #print Dumper @_; } ); $graph->signal_connect ('clicked' => sub { print Dumper @_; } ); # This actually returns an eventbox instead of an image. # But you don't <really> care either way, do you ? my $image = $graph->get_image($data); my $window = Gtk2::Window->new; $window->signal_connect(destroy => sub { Gtk2->main_quit; }); $window->set_default_size(700, 500); $window->add($image); $window->show_all; Gtk2->main;

    I'm not really a human, but I play one on earth Remember How Lucky You Are
Re: Graphics Module
by planetscape (Chancellor) on Jan 12, 2009 at 06:17 UTC
Re: Graphics Module
by Bloodnok (Vicar) on Jan 11, 2009 at 17:09 UTC
    Sorry to interrupt the flow of excellent help zentara is providing, but altho' I can't be of much assistance WRT your question (graphics isn't my 'bag' either), I'm guessing it would be more help to those who can [assist you], if you were to identify at least the OS/platform & perl version (perl -V) that you are using ... or indeed, intend, to use to acheive your goal.

    A user level that continues to overstate my experience :-))
Re: Graphics Module
by KianTern (Acolyte) on Jan 12, 2009 at 07:43 UTC
    Thanks for your advice, zentara, I'll check it out.
    I'm using perl 5.10 on Ubuntu 8.10
    Basicly the data is
    ---------------- | Name | Value | |--------------- | A | 1 | | A | 2 | |___A__|___1___|
    Now I need to generate box plot with "Name" as X Axis and "Value" as Y axis
    which will allow me to select individual points by clicking them on the box plot itself. I hope I was clear enough this time.
      Here is a basic Tk::Canvas script to do it. You can do what ever you want in the callback. I just print the x,y position, and the x axis label.
      #!/usr/bin/perl use warnings; use strict; use Tk; my $w=20; my $x=0; my $y=0; my %colors = ( 0 => ['black','yellow'], 1 => ['yellow','black'], 2 => ['green','white'], 3 => ['lightgreen','white'], 4 => ['grey','red'], 5 => ['red','grey'], 6 => ['lightsteelblue','white',], 7 => ['blue','white',], 8 => ['orange','grey45'], 9 => ['grey45','orange'], ); my %bardata = ( 0 => 100 + rand 200, 1 => 100 +rand 200, 2 => 100 +rand 200, 3 => 100 +rand 200, 4 => 100 +rand 200, 5 => 100 +rand 200, 6 => 100 +rand 200, 7 => 100 +rand 200, 8 => 100 +rand 200, 9 => 100 +rand 200, ); my %bars; my $mw=tkinit; my $c = $mw->Canvas(-bg=>'white')->pack(-expand=>1,-fill=>'both'); foreach my $key(sort keys %bardata) { $bars{$key} = $c->createRectangle($x,$y,$x+20,$bardata{$key}, -fill=> ${$colors{$key}}[0], -tags=>[ $key] ); my $text = $c->createText($x+10,$y+10, -anchor=>'center', -fill => ${$colors{$key}}[1], -text => $key ); $x+=20; } $mw->Button( -text => "Save", -command => [sub { $c->update; my @capture=(); my ($x0,$y0,$x1,$y1)=$c->bbox('all'); @capture=('-x'=>$x0,'-y'=>$y0,-height=>$y1-$y0,-width=>$x1-$x +0); $c -> postscript(-colormode=>'color', -file=>$0.'.ps', -rotate=>90, -width=>800, -height=>500, @capture); } ] )->pack; $c->Tk::bind("<Button-1>", [ \&print_xy, Ev('x'), Ev('y') ]); # adjust canvas size to show all my ($x0,$y0,$x1,$y1)=$c->bbox('all'); $c->configure( -width=>($x1-$x0)+20, -height=>($y1-$y0)+20 ); MainLoop; ########################################################## sub print_xy { #print "@_\n"; my ($canv, $x, $y) = @_; print "(x,y) = ", $canv->canvasx($x), ", ", $canv->canvasy($y), "\t" +; my $current = $canv->find(qw/withtag current/); my (@tags) = $canv->gettags($current); print "for @tags\n\n"; }

      I'm not really a human, but I play one on earth Remember How Lucky You Are
Re: Graphics Module
by zentara (Archbishop) on Jan 12, 2009 at 20:23 UTC
    Here is a little better, Tk version, with vertical text, and scrolling to accomodate alot of data. It may need some font spacing adjustments, but works fine with the default system font here on linux. See Tk Canvas Interactive bar graph

    I'm not really a human, but I play one on earth Remember How Lucky You Are