File Coverage

blib/lib/Excel/Writer/XLSX/Chart/Pie.pm
Criterion Covered Total %
statement 105 107 98.1
branch 15 20 75.0
condition 7 11 63.6
subroutine 16 16 100.0
pod 1 2 50.0
total 144 156 92.3


line stmt bran cond sub pod time code
1              
2             ###############################################################################
3             #
4             # Pie - A class for writing Excel Pie charts.
5             #
6             # Used in conjunction with Excel::Writer::XLSX::Chart.
7             #
8             # See formatting note in Excel::Writer::XLSX::Chart.
9             #
10             # Copyright 2000-2021, John McNamara, jmcnamara@cpan.org
11             #
12             # Documentation after __END__
13             #
14              
15             # perltidy with the following options: -mbl=2 -pt=0 -nola
16              
17             use 5.008002;
18 37     37   3443 use strict;
  37         111  
19 37     37   180 use warnings;
  37         60  
  37         625  
20 37     37   134 use Carp;
  37         58  
  37         694  
21 37     37   143 use Excel::Writer::XLSX::Chart;
  37         54  
  37         1845  
22 37     37   199  
  37         53  
  37         30573  
23             our @ISA = qw(Excel::Writer::XLSX::Chart);
24             our $VERSION = '1.09';
25              
26              
27             ###############################################################################
28             #
29             # new()
30             #
31             #
32              
33             my $class = shift;
34             my $self = Excel::Writer::XLSX::Chart->new( @_ );
35 60     60 0 1550  
36 60         242 $self->{_vary_data_color} = 1;
37             $self->{_rotation} = 0;
38 60         129  
39 60         106 # Set the available data label positions for this chart type.
40             $self->{_label_position_default} = 'best_fit';
41             $self->{_label_positions} = {
42 60         124 center => 'ctr',
43             inside_end => 'inEnd',
44 60         230 outside_end => 'outEnd',
45             best_fit => 'bestFit',
46             };
47              
48             bless $self, $class;
49             return $self;
50 60         122 }
51 60         172  
52              
53             ###############################################################################
54             #
55             # set_rotation()
56             #
57             # Set the Pie/Doughnut chart rotation: the angle of the first slice.
58             #
59              
60             my $self = shift;
61             my $rotation = shift;
62              
63 5     5 1 27 return if !defined $rotation;
64 5         8  
65             if ( $rotation >= 0 && $rotation <= 360 ) {
66 5 50       10 $self->{_rotation} = $rotation;
67             }
68 5 50 33     28 else {
69 5         11 carp "Chart rotation $rotation outside range: 0 <= rotation <= 360";
70             }
71             }
72 0         0  
73              
74             ##############################################################################
75             #
76             # _write_chart_type()
77             #
78             # Override the virtual superclass method with a chart specific method.
79             #
80              
81             my $self = shift;
82              
83             # Write the c:pieChart element.
84             $self->_write_pie_chart( @_ );
85 48     48   93 }
86              
87              
88 48         142 ##############################################################################
89             #
90             # _write_pie_chart()
91             #
92             # Write the <c:pieChart> element. Over-ridden method to remove axis_id code
93             # since Pie charts don't require val and cat axes.
94             #
95              
96             my $self = shift;
97              
98             $self->xml_start_tag( 'c:pieChart' );
99              
100             # Write the c:varyColors element.
101 48     48   86 $self->_write_vary_colors();
102              
103 48         164 # Write the series elements.
104             $self->_write_ser( $_ ) for @{ $self->{_series} };
105              
106 48         152 # Write the c:firstSliceAng element.
107             $self->_write_first_slice_ang();
108              
109 48         76 $self->xml_end_tag( 'c:pieChart' );
  48         284  
110             }
111              
112 48         153  
113             ##############################################################################
114 48         119 #
115             # _write_plot_area().
116             #
117             # Over-ridden method to remove the cat_axis() and val_axis() code since
118             # Pie/Doughnut charts don't require those axes.
119             #
120             # Write the <c:plotArea> element.
121             #
122              
123             my $self = shift;
124             my $second_chart = $self->{_combined};
125              
126             $self->xml_start_tag( 'c:plotArea' );
127              
128             # Write the c:layout element.
129 57     57   102 $self->_write_layout( $self->{_plotarea}->{_layout}, 'plot' );
130 57         103  
131             # Write the subclass chart type element.
132 57         167 $self->_write_chart_type();
133              
134             # Configure a combined chart if present.
135 57         377 if ( $second_chart ) {
136              
137             # Secondary axis has unique id otherwise use same as primary.
138 57         200 if ( $second_chart->{_is_secondary} ) {
139             $second_chart->{_id} = 1000 + $self->{_id};
140             }
141 57 100       171 else {
142             $second_chart->{_id} = $self->{_id};
143             }
144 2 50       6  
145 0         0 # Shart the same filehandle for writing.
146             $second_chart->{_fh} = $self->{_fh};
147              
148 2         4 # Share series index with primary chart.
149             $second_chart->{_series_index} = $self->{_series_index};
150              
151             # Write the subclass chart type elements for combined chart.
152 2         4 $second_chart->_write_chart_type();
153             }
154              
155 2         4 # Write the c:spPr element for the plotarea formatting.
156             $self->_write_sp_pr( $self->{_plotarea} );
157              
158 2         5 $self->xml_end_tag( 'c:plotArea' );
159             }
160              
161              
162 57         207 ##############################################################################
163             #
164 57         164 # _write_legend().
165             #
166             # Over-ridden method to add <c:txPr> to legend.
167             #
168             # Write the <c:legend> element.
169             #
170              
171             my $self = shift;
172             my $legend = $self->{_legend};
173             my $position = $legend->{_position} || 'right';
174             my $font = $legend->{_font};
175             my @delete_series = ();
176             my $overlay = 0;
177              
178 57     57   102 if ( defined $legend->{_delete_series}
179 57         131 && ref $legend->{_delete_series} eq 'ARRAY' )
180 57   100     255 {
181 57         113 @delete_series = @{ $legend->{_delete_series} };
182 57         112 }
183 57         117  
184             if ( $position =~ s/^overlay_// ) {
185 57 100 66     262 $overlay = 1;
186             }
187              
188 1         3 my %allowed = (
  1         7  
189             right => 'r',
190             left => 'l',
191 57 100       185 top => 't',
192 1         2 bottom => 'b',
193             top_right => 'tr',
194             );
195 57         316  
196             return if $position eq 'none';
197             return unless exists $allowed{$position};
198              
199             $position = $allowed{$position};
200              
201             $self->xml_start_tag( 'c:legend' );
202              
203 57 100       210 # Write the c:legendPos element.
204 56 50       156 $self->_write_legend_pos( $position );
205              
206 56         104 # Remove series labels from the legend.
207             for my $index ( @delete_series ) {
208 56         179  
209             # Write the c:legendEntry element.
210             $self->_write_legend_entry( $index );
211 56         317 }
212              
213             # Write the c:layout element.
214 56         184 $self->_write_layout( $legend->{_layout}, 'legend' );
215              
216             # Write the c:overlay element.
217 1         7 $self->_write_overlay() if $overlay;
218              
219             # Write the c:spPr element.
220             $self->_write_sp_pr( $legend );
221 56         262  
222             # Write the c:txPr element. Over-ridden.
223             $self->_write_tx_pr_legend( 0, $font );
224 56 100       171  
225             $self->xml_end_tag( 'c:legend' );
226             }
227 56         176  
228              
229             ##############################################################################
230 56         195 #
231             # _write_tx_pr_legend()
232 56         134 #
233             # Write the <c:txPr> element for legends.
234             #
235              
236             my $self = shift;
237             my $horiz = shift;
238             my $font = shift;
239             my $rotation = undef;
240              
241             if ( $font && exists $font->{_rotation} ) {
242             $rotation = $font->{_rotation};
243             }
244 56     56   166  
245 56         105 $self->xml_start_tag( 'c:txPr' );
246 56         103  
247 56         94 # Write the a:bodyPr element.
248             $self->_write_a_body_pr( $rotation, $horiz );
249 56 50 66     170  
250 1         3 # Write the a:lstStyle element.
251             $self->_write_a_lst_style();
252              
253 56         177 # Write the a:p element.
254             $self->_write_a_p_legend( $font );
255              
256 56         281 $self->xml_end_tag( 'c:txPr' );
257             }
258              
259 56         234  
260             ##############################################################################
261             #
262 56         226 # _write_a_p_legend()
263             #
264 56         132 # Write the <a:p> element for legends.
265             #
266              
267             my $self = shift;
268             my $font = shift;
269              
270             $self->xml_start_tag( 'a:p' );
271              
272             # Write the a:pPr element.
273             $self->_write_a_p_pr_legend( $font );
274              
275             # Write the a:endParaRPr element.
276 56     56   89 $self->_write_a_end_para_rpr();
277 56         96  
278             $self->xml_end_tag( 'a:p' );
279 56         149 }
280              
281              
282 56         188 ##############################################################################
283             #
284             # _write_a_p_pr_legend()
285 56         299 #
286             # Write the <a:pPr> element for legends.
287 56         132 #
288              
289             my $self = shift;
290             my $font = shift;
291             my $rtl = 0;
292              
293             my @attributes = ( 'rtl' => $rtl );
294              
295             $self->xml_start_tag( 'a:pPr', @attributes );
296              
297             # Write the a:defRPr element.
298             $self->_write_a_def_rpr( $font );
299 56     56   96  
300 56         107 $self->xml_end_tag( 'a:pPr' );
301 56         124 }
302              
303 56         165  
304             ##############################################################################
305 56         192 #
306             # _write_vary_colors()
307             #
308 56         278 # Write the <c:varyColors> element.
309             #
310 56         144  
311             my $self = shift;
312             my $val = 1;
313              
314             my @attributes = ( 'val' => $val );
315              
316             $self->xml_empty_tag( 'c:varyColors', @attributes );
317             }
318              
319              
320             ##############################################################################
321             #
322 59     59   100 # _write_first_slice_ang()
323 59         93 #
324             # Write the <c:firstSliceAng> element.
325 59         160 #
326              
327 59         196 my $self = shift;
328             my $val = $self->{_rotation};
329              
330             my @attributes = ( 'val' => $val );
331              
332             $self->xml_empty_tag( 'c:firstSliceAng', @attributes );
333             }
334              
335             1;
336              
337              
338              
339 59     59   113  
340 59         126 =head1 NAME
341              
342 59         133 Pie - A class for writing Excel Pie charts.
343              
344 59         169 =head1 SYNOPSIS
345              
346             To create a simple Excel file with a Pie chart using Excel::Writer::XLSX:
347              
348             #!/usr/bin/perl
349              
350             use strict;
351             use warnings;
352             use Excel::Writer::XLSX;
353              
354             my $workbook = Excel::Writer::XLSX->new( 'chart.xlsx' );
355             my $worksheet = $workbook->add_worksheet();
356              
357             my $chart = $workbook->add_chart( type => 'pie' );
358              
359             # Configure the chart.
360             $chart->add_series(
361             categories => '=Sheet1!$A$2:$A$7',
362             values => '=Sheet1!$B$2:$B$7',
363             );
364              
365             # Add the worksheet data the chart refers to.
366             my $data = [
367             [ 'Category', 2, 3, 4, 5, 6, 7 ],
368             [ 'Value', 1, 4, 5, 2, 1, 5 ],
369             ];
370              
371             $worksheet->write( 'A1', $data );
372              
373             __END__
374              
375             =head1 DESCRIPTION
376              
377             This module implements Pie charts for L<Excel::Writer::XLSX>. The chart object is created via the Workbook C<add_chart()> method:
378              
379             my $chart = $workbook->add_chart( type => 'pie' );
380              
381             Once the object is created it can be configured via the following methods that are common to all chart classes:
382              
383             $chart->add_series();
384             $chart->set_title();
385              
386             These methods are explained in detail in L<Excel::Writer::XLSX::Chart>. Class specific methods or settings, if any, are explained below.
387              
388             =head1 Pie Chart Methods
389              
390             =head2 set_rotation()
391              
392             The C<set_rotation()> method is used to set the rotation of the first segment of a Pie/Doughnut chart. This has the effect of rotating the entire chart:
393              
394             $chart->set_rotation( 90 );
395              
396             The angle of rotation must be C<< 0 <= rotation <= 360 >>.
397              
398              
399             =head2 User defined colors
400              
401             It is possible to define chart colors for most types of Excel::Writer::XLSX charts via the add_series() method. However, Pie/Doughnut charts are a special case since each segment is represented as a point so it is necessary to assign formatting to each point in the series:
402              
403             $chart->add_series(
404             values => '=Sheet1!$A$1:$A$3',
405             points => [
406             { fill => { color => '#FF0000' } },
407             { fill => { color => '#CC0000' } },
408             { fill => { color => '#990000' } },
409             ],
410             );
411              
412             See the main L<Excel::Writer::XLSX::Chart> documentation for more details.
413              
414             Pie charts support leader lines:
415              
416             $chart->add_series(
417             name => 'Pie sales data',
418             categories => [ 'Sheet1', 1, 3, 0, 0 ],
419             values => [ 'Sheet1', 1, 3, 1, 1 ],
420             data_labels => {
421             series_name => 1,
422             percentage => 1,
423             leader_lines => 1,
424             position => 'outside_end'
425             },
426             );
427              
428             Note: Even when leader lines are turned on they aren't automatically visible in Excel or Excel::Writer::XLSX. Due to an Excel limitation (or design) leader lines only appear if the data label is moved manually or if the data labels are very close and need to be adjusted automatically.
429              
430             =head2 Unsupported Methods
431              
432             A Pie chart doesn't have an X or Y axis so the following common chart methods are ignored.
433              
434             $chart->set_x_axis();
435             $chart->set_y_axis();
436              
437             =head1 EXAMPLE
438              
439             Here is a complete example that demonstrates most of the available features when creating a chart.
440              
441             #!/usr/bin/perl
442              
443             use strict;
444             use warnings;
445             use Excel::Writer::XLSX;
446              
447             my $workbook = Excel::Writer::XLSX->new( 'chart_pie.xlsx' );
448             my $worksheet = $workbook->add_worksheet();
449             my $bold = $workbook->add_format( bold => 1 );
450              
451             # Add the worksheet data that the charts will refer to.
452             my $headings = [ 'Category', 'Values' ];
453             my $data = [
454             [ 'Apple', 'Cherry', 'Pecan' ],
455             [ 60, 30, 10 ],
456             ];
457              
458             $worksheet->write( 'A1', $headings, $bold );
459             $worksheet->write( 'A2', $data );
460              
461             # Create a new chart object. In this case an embedded chart.
462             my $chart = $workbook->add_chart( type => 'pie', embedded => 1 );
463              
464             # Configure the series. Note the use of the array ref to define ranges:
465             # [ $sheetname, $row_start, $row_end, $col_start, $col_end ].
466             $chart->add_series(
467             name => 'Pie sales data',
468             categories => [ 'Sheet1', 1, 3, 0, 0 ],
469             values => [ 'Sheet1', 1, 3, 1, 1 ],
470             );
471              
472             # Add a title.
473             $chart->set_title( name => 'Popular Pie Types' );
474              
475             # Set an Excel chart style. Colors with white outline and shadow.
476             $chart->set_style( 10 );
477              
478             # Insert the chart into the worksheet (with an offset).
479             $worksheet->insert_chart( 'C2', $chart, 25, 10 );
480              
481             __END__
482              
483              
484             =begin html
485              
486             <p>This will produce a chart that looks like this:</p>
487              
488             <p><center><img src="http://jmcnamara.github.io/excel-writer-xlsx/images/examples/pie1.jpg" width="483" height="291" alt="Chart example." /></center></p>
489              
490             =end html
491              
492              
493             =head1 AUTHOR
494              
495             John McNamara jmcnamara@cpan.org
496              
497             =head1 COPYRIGHT
498              
499             Copyright MM-MMXXI, John McNamara.
500              
501             All Rights Reserved. This module is free software. It may be used, redistributed and/or modified under the same terms as Perl itself.