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

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

Dear monks, Can you please guide me to create a graph network in perl Tk canvas where the nodes will be pie charts. There are modules like Tk::Graphitems and Tk::Chart but cannot be cross linked to create what I want. Looking forward for your help. Thanks, Kuntal

Replies are listed 'Best First'.
Re: Creating Pie chart based graph network
by choroba (Cardinal) on Sep 25, 2013 at 12:39 UTC
    What have you tried? Please, provide a sample code that shows how far you have got. Also, try to be more cooperative by providing links to the libraries: [mod://Tk::GraphItems]Tk::GraphItems, [mod://Tk::Chart]Tk::Chart; and by providing more information on what you need: What do you mean by crosslinking? Tk::Canvas is very powerful...
    لսႽ† ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

      I have a file consisting of some nodes (and edges) with the coordinates of the nodes. I also need to map some data specific to the nodes that are in form of pie charts.Here is a cropped snipped of the code.

      my $index = 0; if(open(FH, 'layout_coords')) { while($line = <FH>) { chomp($line); @arr = (); @arr = split('\t', $line ); my $label = $node_labels[$index]; my $x = $arr[0]; my $y = $arr[1]; my $x1 = $x + 20; my $y1 = $y + 20; $canvas->createOval($x,$y, $x1, $y1,-fill => 'green'); ## I need this +oval as a pie (I have the data for each node in form of a fixed array + like (2,3,1,3), etc.) $canvas->createText($x,$y, -text => $label); $index++; } } else { die "can't open file layout_coords: $!"; } close FH;
Re: Creating Pie chart based graph network
by kcott (Archbishop) on Sep 25, 2013 at 13:52 UTC

    G'day KuntalBhusan,

    For creating pie charts in a Tk::Canvas, you'll probably want to use $canvas->createArc(...) with various options, including -style => 'pieslice'. See Tk::Canvas: ARC ITEMS.

    I'm not really sure what you have in mind with respect to a "graph network". Tk::Canvas: LINE ITEMS seems like the obvious choice; however, you're also talking about cross-linking, so perhaps that's not what you want. You'll need to clarify what you mean in this regard.

    -- Ken

      Dear Ken,

      To put it in a more simpler way I need to get the output of the code below in form of a pie. Probably this will be a subroutine with the shown inputs that will be taken dynamically.can you help me in getting the values for $x1, $x2, $y1, $y2 in the code dynamically.

      use strict; use Tk; my $mw = new MainWindow(-title => 'Test'); my $canvas = $mw->Canvas(-width => 512, -height => 512)->pack; ## input ######################### my $start_x = 0; my $stary_y = 0; my $radius = 10; my @data = (4,5,2,6,8); ######################### my $slices = $data; my $slice_angle = 360/$slices; foreach my $this_value (@data) { my $x1 = ?; ## need to get dynamically my $y1 = ?; ## need to get dynamically my $x2 = ?; ## need to get dynamically my $y2 = ?; ## need to get dynamically $canvas->createArc( $x1, $y2, $x2, $y2, -start => 0, -extent => $slice +_angle, -style => 'pieslice', ); } MainLoop;

        Here's a working script that produces pie charts. See the notes at the end (which will probably make more sense after you've read the code and run the script).

        #!/usr/bin/env perl use strict; use warnings; use Tk; use List::Util 'sum'; my $pie_slice_colours = [ map { '#' . $_ } qw{ff0000 ffff00 00ff00 00ffff 0000ff ff00ff} + ]; my @pie_data = ( { centre_x => 50, centre_y => 150, radius => 40, values => [ 1, 2, 5, 3 ], fills => $pie_slice_colours, }, { centre_x => 220, centre_y => 105, radius => 100, values => [ 1, 8, 16, 4, 2 ], fills => $pie_slice_colours, }, { centre_x => 420, centre_y => 75, radius => 75, values => [ 1, 1, 2, 3, 5, 8 ], fills => $pie_slice_colours, }, { centre_x => 60, centre_y => 40, radius => 50, values => [ 32, 16, 8, 4, 2, 1 ], fills => $pie_slice_colours, }, ); my $mw = MainWindow->new; my $ctrl_F = $mw->Frame->pack(-side => 'bottom'); $ctrl_F->Button(-text => 'Quit', -command => sub { exit })->pack; my $canv_F = $mw->Frame->pack(-side => 'top', -fill => 'both', -expand + => 1); my $sc = $canv_F->Scrolled(Canvas => -scrollbars => 'osoe', -bg => '#ffffff', -width => 500, -height => 220, -scrollregion => [0, 0, 500, 220], ); $sc->pack(-fill => 'both', -expand => 1); my $canvas = $sc->Subwidget('canvas'); draw_pie(\$canvas, $_) for @pie_data; MainLoop; sub draw_pie { my ($c_ref, $data) = @_; my @coords = @{_get_pie_coords($c_ref, $data)}; $$c_ref->createArc(@coords, %$_) for @{_get_pie_slices($data)}; return; } sub _get_pie_coords { my ($c_ref, $data) = @_; my ($x, $y, $r) = @$data{qw{centre_x centre_y radius}}; my $h = $$c_ref->cget('-height'); return [$x - $r, $h - $y + $r, $x + $r, $h - $y - $r]; } sub _get_pie_slices { my $data = shift; my @values = @{$data->{values}}; my @fills = @{$data->{fills}}; my $total_values = sum @values; my $start = 90; return [ map { my $extent = 360 * $values[$_] / $total_values; $start -= $extent; +{ -extent => $extent, -start => $start, -fill => $fills[$ +_] } } 0 .. $#values ]; }

        Notes:

        • The Tk::Canvas coordinate system is an upside-down version of Cartesian coordinates. I personally don't like this: mainly because I find it counter-intuitive (x increases along the x-axis but y decreases along the y-axis). _get_pie_coords() takes (x,y) Cartesian coordinates for the centre of the pie chart, as well as the radius for the pie chart, and returns the coordinates required by createArc(). Feel free to revert to the Tk::Canvas coordinate system; however, you'll still need a function like this unless you're happy to specify (x1, y1, x2, y2) for every pie chart (and note those coordinates are outside the pie chart).
        • The placement of the pie slices is also somewhat counter-intuitive (at least, in my opinion). If you take the defaults, -start is called 0° (but, on a compass, it would be east, i.e. 90°); and -extent (whose default value is 90°) increases in an anticlockwise direction such that adding 90° to east results in north (on a compass, that would be south). Anyway, _get_pie_slices() works all that out for you: the first slice starts at 0° (north) and extends proportionally in a clockwise fashion; subsequent slices continue to be added in the same manner.
        • Unless you have a particular reason not to, you probably want (at least optional) scrollbars. Note that Scrolled(Canvas => ...) is actually a composite widget and the Tk::Canvas widget is a component of this accessed with Subwidget('canvas').
        • I've added six colours ($pie_slice_colours) and reused them for each pie chart. You may need more colours. You may not want the same colours for every chart: set the value of the fills key how you want it.
        • Everything else should either be fairly straightforward Perl or documented via links already supplied.

        -- Ken

Re: Creating Pie chart based graph network
by SuicideJunkie (Vicar) on Sep 25, 2013 at 14:54 UTC

    Drawing a simple example manually would probably help a lot.

    My impression is you want something that looks like:

    ClientA _____Master ___Link /\________/ | \ / | \ __Archive \/ |___| |_______| | |_______/ \ | \ | \_|_/ \__/ /\____\/ __ __/ / \/ \__/Client B