in reply to Which tk to use and how to show images?

I think you are going to run into problems with this type of script, where you combine Tk and GD.

From the Perldoc for GD::Graph

BUGS GD::Graph objects cannot be reused. To create a new plot, you have to +create a new GD::Graph object.
What that means, is that everytime you update your graph, you will get a memory increase. If it is a long running program, it will become unacceptable.

For something simple like a bar graph, you would be better of making a Tk Canvas, and creating rectangles to show your bars. It won't leak memory when you update, and you would be able to add more color to the bars. Additionally, it will use less memory than a script that uses GD.

In this example, I have it upside down. You can add axis and text if you want. It is also just a "quick demo", and the design can be improved upon.

#!/usr/bin/perl use warnings; use strict; use Tk; use MeM; my $w=20; my $x=0; my $y=0; my %colors = ( 0 => ['black','yellow'], 1 => ['yellow','black'], 2 => ['white','green'], 3 => ['green','white'], 4 => ['grey','red'], 5 => ['red','grey'], 6 => ['blue','white'], 7 => ['white','blue'], 8 => ['orange','grey45'], 9 => ['grey45','orange'], ); my %bardata = ( 0 => rand 200, 1 => rand 200, 2 => rand 200, 3 => rand 200, 4 => rand 200, 5 => rand 200, 6 => rand 200, 7 => rand 200, 8 => rand 200, 9 => rand 200, ); my %bars; my $mw=tkinit; my $c = $mw->Canvas->pack; for (0..9) { $bars{$_} = $c->createRectangle($x,$y,$x+20,$bardata{$_}, -fill=> ${$colors{$_}}[0], ); my $text = $c->createText($x+10,$y+10, -anchor=>'center', -fill => ${$colors{$_}}[1], -text => $_ ); $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; $mw->repeat(2000, sub{ &update }); MainLoop; ########################################################## sub update{ $x=0; $y=0; %bardata = ( 0 => rand 200, 1 => rand 200, 2 => rand 200, 3 => rand 200, 4 => rand 200, 5 => rand 200, 6 => rand 200, 7 => rand 200, 8 => rand 200, 9 => rand 200, ); for (0..9) { $c->delete( $bars{$_} ); $bars{$_} = $c->createRectangle($x,$y,$x+20,$bardata{$_}, -fill=> ${$colors{$_}}[0], ); my $text = $c->createText($x+10,$y+10, -anchor=>'center', -fill => ${$colors{$_}}[1], -text => $_ ); $x+=20; } }

I'm not really a human, but I play one on earth. flash japh

Replies are listed 'Best First'.
Re^2: Which tk to use and how to show images?
by BrowserUk (Patriarch) on Nov 04, 2005 at 15:32 UTC
    I think you are going to run into problems with this type of script, where you combine Tk and GD.

    Hmm. Provided that you disard old things before creating new ones, the space should be reused.

    I haven't put this in a tight loop and run it thousands of times, but I've clicked the button quite a lot (maybe a 100 times) whilst monitoring the memory, and I see no sign of a growth trend (on my system):

    use Tk; use Tk::PNG; use MIME::Base64; use GD::Graph; use GD::Graph::bars; my $data = [ [qw/1st 2nd 3rd 4th 5th 6th 7th 8th 9th/], [qw/ 1 2 5 6 3 1.5 1 3 4/], ]; my $graph = GD::Graph::bars->new(400, 300); $graph->set( x_label => 'X Label', y_label => 'Y label', title => 'Some simple graph', y_max_value => 8, y_tick_number => 8, y_label_skip => 2 ) or die $my_graph->error; my $gd = $graph->plot($data) or die $my_graph->error; my $mw = MainWindow->new; my $png = $mw->Photo(-data => encode_base64($gd->png)); $mw->Button( -text => 'doit', -command => sub{ $data->[ 1 ] = [ map{ rand 5 } 1 .. 9 ]; undef $graph; $graph = GD::Graph::bars->new(400, 300); $graph->set( x_label => 'X Label', y_label => 'Y label', title => 'Some simple graph', y_max_value => 8, y_tick_number => 8, y_label_skip => 2 ) or die $my_graph->error; my $gd = $graph->plot($data) or die $my_graph->error; $png->blank; $png->configure( -data => encode_base64($gd->png) ); $mw->update; } )->pack; $mw->Label(-image => $png)->pack; MainLoop;

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      Yeah, you have it pretty close, by undef'ing $gd. I ran your code with a repeat and it leveled out after about 200 updates, only gaining about 200k, which is probably due to the total area of bar space displayed maxing out eventually. But I still think the plain canvas approach uses less cpu.

      I'm not really a human, but I play one on earth. flash japh
        But I still think the plain canvas approach uses less cpu

        Oh, I totally agree. If the graph is only ever to be displayed in Tk, and not re-used as an image elsewhere, a Canvas does make sense.

        That said, GD::Graph does do some stuff with scaling and ticks, labels and pie-charts that are not trivial to reproduce.


        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        Lingua non convalesco, consenesco et abolesco. -- Rule 1 has a caveat! -- Who broke the cabal?
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
      It would appear you guys are good, I was wondering what would happen to the memory usage. Being new to perl I assumed the garbage collector would cleanup after me (that is what they are for) but I've had problems with programs using to much memory. I'm re-drawing the graph every two seconds over four or five hours and it's been getting a bit slow. I've now added the approiate undef and so far it's looking better.
      Has anyone seen my bint?