http://qs1969.pair.com?node_id=1219241

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

Hi Perl Monks

I want to have a doughnut chart for Hard Disk. It should display Used space, Free Space and Total etc.. Now, I wrote a code for it. It's a pie chart.. How can I get a doughnut for it. I want to display with CGI.

Here's my code

#!/usr/bin/perl use CGI ':standard'; use strict; use warnings; use GD::Graph::pie; my $cmd_1 = "sudo df -h |grep /var |awk '{print \$2}' | sed -e 's/.\$/ +/'"; my $cmd_2 = "sudo df -h |grep /var |awk '{print \$3}' | sed -e 's/.\$/ +/'"; my $result_used = qx/ $cmd_1 /; #$result_used shows 1.4 my $result_free = qx/ $cmd_2 /; #$result_free shows 85 # Both the arrays should same number of entries. my @data = (['Used', 'Free'], [$result_used, $result_free]); my $mygraph = GD::Graph::pie->new(300, 300); $mygraph->set( title => '/var Partition, Size in GB', '3d' => 0, #'3d' => 1, ) or warn $mygraph->error; $mygraph->set_value_font(GD::gdMediumBoldFont); my $myimage = $mygraph->plot(\@data) or die $mygraph->error; print "Content-type: image/png\n\n"; print $myimage->png;

I think Doughnut chart is NICER. But, I can't find many docs for them.

Can U guys help me? Better methods are also welcome...

Replies are listed 'Best First'.
Re: doughnut charts with gd:graph
by hippo (Bishop) on Jul 25, 2018 at 10:23 UTC
    use CGI ':standard';

    You don't appear to be using this anywhere in your script. Why not remove it?

    my $cmd_1 = "sudo df -h |grep /var |awk '{print \$2}' | sed -e 's/.\$/ +/'"; my $cmd_2 = "sudo df -h |grep /var |awk '{print \$3}' | sed -e 's/.\$/ +/'"; my $result_used = qx/ $cmd_1 /; #$result_used shows 1.4 my $result_free = qx/ $cmd_2 /; #$result_free shows 85

    You shell out, sudo and pipe through a grep an awk and a sed from perl! Twice. Let's try another way.

    my @df = `df /var`; my ($used, $free) = (split (/\s+/, $df[1]))[2,3];

    Don't pass -h to df when using a script. You can easily end up with MB vs GB and then you'll have real confusion. Better yet, use something like Linux::Info::DiskUsage to avoid shelling out entirely.

    I think Doughnut chart is NICER. But, I can't find many docs for them.

    You already have the image as a pie so why not just overlay a background-coloured circle on the middle?

      Thanks for your reply since I want to complete this

      I understand the below code

      my @df = `df /var`;

      I can print df in this way..

      print @df;

      it shows in this way

      Filesystem 1K-blocks Used Available Use% Mounted on /dev/mapper/vg_mail-lv_var 94959436 1415576 88713448 2% /var

      Pls explain this below code? I think you split 2 things. (i.e - white spaces and another). Difficult to understand. Sir, Pls explain in detail. Your effort will NOT got to waste.

      my ($used, $free) = (split (/\s+/, $df[1]))[2,3]; #HOW TO PRINT THE OU +TPUT?

      Finally, How to print $used and $free

      the below lines will NOT?

      print $used; print $free;
      I think the above one line can be written in these 2 lines? AM I RIGHT?
      my $used = (split (/\s+/, $df[1]))[2]; my $free = (split (/\s+/, $df[1]))[3];

      Waiting for yor REPLY...

        Filesystem 1K-blocks Used Available Use% Mounted on /dev/mapper/vg_mail-lv_var 94959436 1415576 88713448 2% /var

        That explains why the scalars are not set for you. If your Filesystem paths are so long as to overflow like this you will need to use -P. That will avoid the wrapping and hence the assignment errors. Note that this is a demonstrably good reason not to shell out but to use a module instead.

        Here is an SSCCE demonstrating this use of -P:

        #!/usr/bin/env perl use strict; use warnings; my @df = `df -P /var`; my ($used, $free) = (split (/\s+/, $df[1]))[2,3]; print "used $used, free $free\n";

        The split acts on $df[1] (which is the second line returned by df) and splits it on whitespace (like awk does). You then want only the 3rd and 4th fields for your used and free figures but indexing in Perl starts at zero hence the slice of [2,3]. Hopefully that makes it clear enough?

      You already have the image as a pie so why not just overlay a background-coloured circle on the middle?

      I can draw a circle separately. Here's the separate code. I use GD::Simple

      #!/usr/bin/perl use CGI ':standard'; use strict; use warnings; use GD::Simple; # create a new image (width, height) my $img = GD::Simple->new(200, 100); $img->bgcolor('white'); $img->fgcolor('blue'); $img->moveTo(60, 50); # (x, y) $img->ellipse(80, 80); binmode STDOUT; print "Content-type: image/png\n\n"; print $img->png;

      How can I insert it to the Pie chart code... Can you help me?

      Can I use like this?

      my $img = (GD::Simple->new(200, 100), GD::Graph::pie->new(500, 600));

        >> You already have the image as a pie so why not just overlay a background-coloured circle on the middle?

        This time I used GD::Image to draw a circle and inserted it to the pie chart.

        Here's the code. It works...

        #!/usr/bin/perl use CGI ':standard'; use strict; use warnings; use GD; use GD::Graph::pie; my @df = `df -P /var`; my ($used, $free) = (split (/\s+/, $df[1]))[2,3]; # Both the arrays should have same number of entries. my @data = (['Used', 'Free'], [$used, $free]); my $mygraph = GD::Graph::pie->new(175, 175); $mygraph->set( title => '/var Partition' , '3d' => 0, #'3d' => 1, #label => 'Label', transparent => 1, ) or warn $mygraph->error; $mygraph->set_value_font(GD::gdMediumBoldFont); my $myimage = $mygraph->plot(\@data) or die $mygraph->error; my $circleImg = new GD::Image( 100,100 ); # allocate some colors my $green = $circleImg->colorAllocate(0,255,0); my $white = $circleImg->colorAllocate(255,255,255); my $blue = $circleImg->colorAllocate(0,0,255); #$circleImg->transparent($green); #$circleImg->interlaced('true'); # Draw a blue circle $circleImg->arc(50,50,100,100,0,360,$blue); # And fill it with color $circleImg->fill(50,50,$white); $myimage->copy($circleImg,38,46,0,0,100,100); print "Content-type: image/png\n\n"; binmode STDOUT; print $myimage->png;

        Hv a Nice day to all perl Monks...

Re: doughnut charts with gd:graph
by marto (Cardinal) on Jul 25, 2018 at 10:34 UTC

    Here's an old reference from IBM developerworks that I had bookmarked, it may still be relevant.

Re: doughnut charts with gd:graph
by roboticus (Chancellor) on Jul 25, 2018 at 13:28 UTC

    theravadamonk:

    I was going to suggest using a transparent background and draw a pie chart with different sizes for each donut, then stacking the images together. While reviewing the thread, I noticed that marto posted a link to an IBM developerworks article that shows how to customize pie charts. I think stacking transparent pie charts with the customization bits (such as hollowing out the pie chart and annotating it) in the IBM article should be able to get you where you want to go.

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

Re: doughnut charts with gd:graph
by anonymized user 468275 (Curate) on Jul 26, 2018 at 13:18 UTC
    It might be better to codegen and/or pipe to a specialised interpreter, e.g. gnuplot or matplotlib. The latter is also more freely integrated in Perl6.

    One world, one people