Search code examples
perlgraphchartsgtkgtk3

How to show a graph in a Perl Gtk GUI?


Using Perl and Gtk2 (or Gtk3), I'd like to display a graph in a GUI application.

Chart::Clicker looks promising, but it seems to only write to files. Is there a way to get that into a GtkDrawingArea or similar?


Solution

  • After lots of experimentation, I figured it out.

    1. Don't use Gtk::DrawingArea, use Gtk::Image.
    2. $img->set_from_surface($chart->driver->surface);

    Reading through the source to Chart::Clicker, I found that $chart->driver is the Cairo object and ->surface is the actual Cairo surface. A Gtk::Image can be directly drawn based on a Cairo surface.

    Complete program that illustrates how to do this:

    #!/usr/bin/perl -w
    use strict;
    use Gtk3 -init;
    use Chart::Clicker;
    use Chart::Clicker::Data::Series;
    use Chart::Clicker::Data::DataSet;
    my $win = Gtk3::Window->new;
    my $img = Gtk3::Image->new;
    $win->add($img);
    my $chart = Chart::Clicker->new;
    my $dataset = Chart::Clicker::Data::DataSet->new(
            series => [Chart::Clicker::Data::Series->new(
                    keys => [1, 2, 3, 4, 5],
                    values => [2, 3, 5, 7, 11],
            )],
    );
    $chart->add_to_datasets($dataset);
    $chart->draw;
    $img->set_from_surface($chart->driver->surface);
    $win->signal_connect(destroy => sub{Gtk3->main_quit});
    $win->show_all;
    Gtk3::main;
    

    Update

    On Gtk3 < 3.10, replace the line containing set_from_surface with:

    my $loader = Gtk3::Gdk::PixbufLoader->new;
    $chart->driver->surface->write_to_png_stream(sub {
        $loader->write([unpack 'C*', $_[1]]);
    });
    $loader->close;
    $img->set_from_pixbuf($loader->get_pixbuf);