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

Hi

Using Excel::Writer::XLSX::Chart::Pie, does anyone know how to explode a pie chart (to create a gap between the pie slices, ala excels setting: 'Format Data Series' -> 'Pie Explosion')? I had a look through the docs but couldn't see anything.

Thanks!

Replies are listed 'Best First'.
Re: XLSX::Chart::Pie -> Exploding
by NetWallah (Canon) on Oct 12, 2021 at 04:44 UTC
    You could try to convert this VBA code into the equivalent perl.

                    "If you had better tools, you could more effectively demonstrate your total incompetence."

Re: XLSX::Chart::Pie -> Exploding
by pryrt (Abbot) on Oct 12, 2021 at 15:46 UTC

    The Excel::Writer::XLSX::Chart or Excel::Writer::XLSX::Chart::Pie add_series method don't seem to expose the explosion attribute for a chart series.

    So, to see if I could work around it: I used the example in the SYNOPSIS of Excel::Writer::XLSX::Chart::Pie to create chart.xlsx without exploding pie pieces. I unzipped the chart1.xml from the original for reference. Then I used Excel to edit chart.xlsx to explode the pie to 5%, and extracted its chart1.xml. Looking at the differences, I think the critical point is at original:

    <c:ser> <c:idx val="0"/> <c:order val="0"/> <c:cat> <c:numRef> <c:f>Sheet1!$A$2:$A$7</c:f>
    vs modified:
    <c:ser> <c:idx val="0"/> <c:order val="0"/> <c:explosion val="5"/> <c:cat> <c:numRef> <c:f>Sheet1!$A$2:$A$7</c:f>
    ... The modified version adds the <c:explosion val="5"/> empty tag.

    I dug in a little, and unsuccessfully tried to monkey-patch things to include that extra xml tag (but I discovered after a lot of work I was patching in the wrong place). It looks like what needs to happen is the Excel::Writer::Chart::add_series method needs to be taught the explosion attribute; or similarly, Excel::Writer::Chart::Pie needs to define a wrapper around the parent add_series method which calls the parent, then appends the explosion attribute; and then whichever module is patched would have to also define _write_explosion to call $self->xml_empty_tag('c:explosion', val => $value;. If I find time later today, I might look into that more... but no guarantees (I think the best bet is to add the add_series-wrapper in ::Pie, and defining the _write_explosion() method in ::Pie as well).

    Whatever happens, it is also a good idea to put in a feature request for Excel-Writer-XLSX to officially add the explosion attribute for charts (or at least pie charts) and the individual per-data-point explosion attribute as well (since you can explode individual slices). That is a feature that would be good to support natively, without monkey-patching.

      Okay, with the following code, I was able to make an exploding pie chart.

      #!perl use 5.012; # strict, // use warnings; use Excel::Writer::XLSX; ################ patch methods into ::Pie ################ package Excel::Writer::XLSX::Chart::Pie { sub add_series { my $self = shift; my %args = @_; $self->SUPER::add_series(@_); if(exists $args{explosion}) { $self->{_series}[-1]{_explosion} = $args{explosion}; # +add explosion attribute to last-added series } } sub _write_explosion { my $self = shift; my $val = shift; if(defined $val) { my @attributes = ( 'val' => $val ); $self->xml_empty_tag( 'c:explosion', @attributes ); } } sub _write_ser { # copied from https://metacpan.org/dist/Excel-Writer-XLSX/sour +ce/lib/Excel/Writer/XLSX/Chart.pm; violates D.R.Y. # ideally, there should be a way to run the ...::Chart::_write +_ser but just insert my one additional element from ::Chart::Pie::_wr +ite_ser(), but I don't know how to do that. my $self = shift; my $series = shift; my $index = $self->{_series_index}++; $self->xml_start_tag( 'c:ser' ); # Write the c:idx element. $self->_write_idx( $index ); # Write the c:order element. $self->_write_order( $index ); # Write the series name. $self->_write_series_name( $series ); # Write the c:spPr element. $self->_write_sp_pr( $series ); # Write the c:marker element. $self->_write_marker( $series->{_marker} ); # Write the c:invertIfNegative element. $self->_write_c_invert_if_negative( $series->{_invert_if_neg} +); # Write the c:dPt element. $self->_write_d_pt( $series->{_points} ); # Write the c:dLbls element. $self->_write_d_lbls( $series->{_labels} ); # Write the c:trendline element. $self->_write_trendline( $series->{_trendline} ); # Write the c:errBars element. $self->_write_error_bars( $series->{_error_bars} ); # Write the c:explosion element. # added by [pryrt] $self->_write_explosion( $series->{_explosion} ); # Write the c:cat element. $self->_write_cat( $series ); # Write the c:val element. $self->_write_val( $series ); # Write the c:smooth element. if ( $self->{_smooth_allowed} ) { $self->_write_c_smooth( $series->{_smooth} ); } $self->xml_end_tag( 'c:ser' ); } } ################ /end: patch methods into ::Pie ################ ################ back to the example from ::Pie SYNOPSIS, with added e +xplosion attribute ################ my $workbook = Excel::Writer::XLSX->new('chart.xlsx'); my $worksheet = $workbook->add_worksheet(); my $chart = $workbook->add_chart( type => 'pie' ); # Configure the chart. $chart->add_series( categories => '=Sheet1!$A$2:$A$7', values => '=Sheet1!$B$2:$B$7', explosion => 5, ); # Add the worksheet data the chart refers to. my $data = [ [ 'Category', 2, 3, 4, 5, 6, 7 ], [ 'Value', 1, 4, 5, 2, 1, 5 ], ]; $worksheet->write( 'A1', $data ); __END__

      There are things here that I'm not happy with. Ideally, the ...::Pie::_write_ser should mostly just run the ::Chart::_write_ser but somehow insert the call to _write_explosion; I didn't know how to do that. It may be that the "right" answer is for ::Chart::_write_ser to include the call to _write_explosion itself, rather than having the ::Pie do it... Maybe then having ::Chart::_write_explosion be empty but ::Chart::Pie::_write_explosion be defined as in my code. But for the v1.00 and v1.09 of Excel::Writer:::XLSX, the code I shared worked.

      Again, really, it should be incorporated into the distribution with a feature request -- if you do create such a feature request, you have my permission to point the author to this post, and the author may include the code I presented here with whatever fixes or adaptations are necessary to make it work with the distro as a whole.