From 21559718f4c94333d1e101d640422e6d31f7495a Mon Sep 17 00:00:00 2001 From: John McNamara Date: Sun, 26 Jul 2020 00:25:40 +0100 Subject: [PATCH] Additional custom chart data labels features and tests. Issue #343 --- examples/chart_data_labels.py | 240 ++++++++++++++++++ xlsxwriter/chart.py | 82 +++--- .../comparison/test_chart_data_labels26.py | 2 +- .../comparison/test_chart_data_labels27.py | 2 +- .../comparison/test_chart_data_labels28.py | 2 +- .../comparison/test_chart_data_labels29.py | 2 +- .../comparison/test_chart_data_labels30.py | 2 +- .../comparison/test_chart_data_labels31.py | 56 ++++ .../comparison/test_chart_data_labels32.py | 56 ++++ .../comparison/test_chart_data_labels33.py | 56 ++++ .../comparison/test_chart_data_labels34.py | 56 ++++ .../xlsx_files/chart_data_labels31.xlsx | Bin 0 -> 9414 bytes .../xlsx_files/chart_data_labels32.xlsx | Bin 0 -> 9437 bytes .../xlsx_files/chart_data_labels33.xlsx | Bin 0 -> 9404 bytes .../xlsx_files/chart_data_labels34.xlsx | Bin 0 -> 9470 bytes 15 files changed, 508 insertions(+), 48 deletions(-) create mode 100644 examples/chart_data_labels.py create mode 100644 xlsxwriter/test/comparison/test_chart_data_labels31.py create mode 100644 xlsxwriter/test/comparison/test_chart_data_labels32.py create mode 100644 xlsxwriter/test/comparison/test_chart_data_labels33.py create mode 100644 xlsxwriter/test/comparison/test_chart_data_labels34.py create mode 100644 xlsxwriter/test/comparison/xlsx_files/chart_data_labels31.xlsx create mode 100644 xlsxwriter/test/comparison/xlsx_files/chart_data_labels32.xlsx create mode 100644 xlsxwriter/test/comparison/xlsx_files/chart_data_labels33.xlsx create mode 100644 xlsxwriter/test/comparison/xlsx_files/chart_data_labels34.xlsx diff --git a/examples/chart_data_labels.py b/examples/chart_data_labels.py new file mode 100644 index 000000000..378481dc6 --- /dev/null +++ b/examples/chart_data_labels.py @@ -0,0 +1,240 @@ +####################################################################### +# +# A demo of an various Excel chart data label features that are available +# via an XlsxWriter chart. +# +# Copyright 2013-2020, John McNamara, jmcnamara@cpan.org +# +import xlsxwriter + +workbook = xlsxwriter.Workbook('chart_data_labels.xlsx') +worksheet = workbook.add_worksheet() +bold = workbook.add_format({'bold': 1}) + +# Add the worksheet data that the charts will refer to. +headings = ['Number', 'Data', 'Text'] + +data = [ + [2, 3, 4, 5, 6, 7], + [20, 10, 20, 30, 40, 30], + ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'], +] + +worksheet.write_row('A1', headings, bold) +worksheet.write_column('A2', data[0]) +worksheet.write_column('B2', data[1]) +worksheet.write_column('C2', data[2]) + +####################################################################### +# +# Example with standard data labels. +# + +# Create a Column chart. +chart1 = workbook.add_chart({'type': 'column'}) + +# Configure the first series with a polynomial trendline. +chart1.add_series({ + 'categories': '=Sheet1!$A$2:$A$7', + 'values': '=Sheet1!$B$2:$B$7', + 'data_labels': {'value': True}, +}) + +# Add a chart title. +chart1.set_title({'name': 'Chart with standard data labels'}) + +# Turn off the chart legend. +chart1.set_legend({'none': True}) + +# Insert the chart into the worksheet (with an offset). +worksheet.insert_chart('D2', chart1, {'x_offset': 25, 'y_offset': 10}) + +####################################################################### +# +# Example with value and category data labels. +# + +# Create a Column chart. +chart2 = workbook.add_chart({'type': 'column'}) + +# Configure the first series with a polynomial trendline. +chart2.add_series({ + 'categories': '=Sheet1!$A$2:$A$7', + 'values': '=Sheet1!$B$2:$B$7', + 'data_labels': {'value': True, 'category': True}, +}) + +# Add a chart title. +chart2.set_title({'name': 'Category and Value data labels'}) + +# Turn off the chart legend. +chart2.set_legend({'none': True}) + +# Insert the chart into the worksheet (with an offset). +worksheet.insert_chart('D18', chart2, {'x_offset': 25, 'y_offset': 10}) + +####################################################################### +# +# Example with standard data labels with different font. +# + +# Create a Column chart. +chart3 = workbook.add_chart({'type': 'column'}) + +# Configure the first series with a polynomial trendline. +chart3.add_series({ + 'categories': '=Sheet1!$A$2:$A$7', + 'values': '=Sheet1!$B$2:$B$7', + 'data_labels': {'value': True, + 'font': {'bold': True, + 'color': 'red', + 'rotation': -30}}, +}) + +# Add a chart title. +chart3.set_title({'name': 'Data labels with user defined font'}) + +# Turn off the chart legend. +chart3.set_legend({'none': True}) + +# Insert the chart into the worksheet (with an offset). +worksheet.insert_chart('D34', chart3, {'x_offset': 25, 'y_offset': 10}) + +####################################################################### +# +# Example with custom string data labels. +# + +# Create a Column chart. +chart4 = workbook.add_chart({'type': 'column'}) + +# Some custom labels. +custom_labels = [ + {'value': 'Amy'}, + {'value': 'Bea'}, + {'value': 'Eva'}, + {'value': 'Fay'}, + {'value': 'Liv'}, + {'value': 'Una'}, +] + +# Configure the first series with a polynomial trendline. +chart4.add_series({ + 'categories': '=Sheet1!$A$2:$A$7', + 'values': '=Sheet1!$B$2:$B$7', + 'data_labels': {'value': True, 'custom': custom_labels}, +}) + +# Add a chart title. +chart4.set_title({'name': 'Chart with custom string data labels'}) + +# Turn off the chart legend. +chart4.set_legend({'none': True}) + +# Insert the chart into the worksheet (with an offset). +worksheet.insert_chart('D50', chart4, {'x_offset': 25, 'y_offset': 10}) + +####################################################################### +# +# Example with custom data labels from cells. +# + +# Create a Column chart. +chart5 = workbook.add_chart({'type': 'column'}) + +# Some custom labels. +custom_labels = [ + {'value': '=Sheet1!$C$2'}, + {'value': '=Sheet1!$C$3'}, + {'value': '=Sheet1!$C$4'}, + {'value': '=Sheet1!$C$5'}, + {'value': '=Sheet1!$C$6'}, + {'value': '=Sheet1!$C$7'}, +] + +# Configure the first series with a polynomial trendline. +chart5.add_series({ + 'categories': '=Sheet1!$A$2:$A$7', + 'values': '=Sheet1!$B$2:$B$7', + 'data_labels': {'value': True, 'custom': custom_labels}, +}) + +# Add a chart title. +chart5.set_title({'name': 'Chart with custom data labels from cells'}) + +# Turn off the chart legend. +chart5.set_legend({'none': True}) + +# Insert the chart into the worksheet (with an offset). +worksheet.insert_chart('D66', chart5, {'x_offset': 25, 'y_offset': 10}) + +####################################################################### +# +# Example with custom and default data labels. +# + +# Create a Column chart. +chart6 = workbook.add_chart({'type': 'column'}) + +# Some custom labels. The undef items will get the default value. +# We also set a font for the custom items as an extra example. +custom_labels = [ + {'value': '=Sheet1!$C$2', 'font': {'color': 'red'}}, + None, + {'value': '=Sheet1!$C$4', 'font': {'color': 'red'}}, + {'value': '=Sheet1!$C$5', 'font': {'color': 'red'}}, +] + +# Configure the first series with a polynomial trendline. +chart6.add_series({ + 'categories': '=Sheet1!$A$2:$A$7', + 'values': '=Sheet1!$B$2:$B$7', + 'data_labels': {'value': True, 'custom': custom_labels}, +}) + +# Add a chart title. +chart6.set_title({'name': 'Mixed custom and default data labels'}) + +# Turn off the chart legend. +chart6.set_legend({'none': True}) + +# Insert the chart into the worksheet (with an offset). +worksheet.insert_chart('D82', chart6, {'x_offset': 25, 'y_offset': 10}) + + +####################################################################### +# +# Example with deleted custom data labels. +# + +# Create a Column chart. +chart7 = workbook.add_chart({'type': 'column'}) + +# Some deleted custom labels and defaults (undef). This allows us to +# highlight certain values such as the minimum and maximum. +custom_labels = [ + {'delete': True}, + None, + {'delete': True}, + {'delete': True}, + None, + {'delete': True}, +] + +# Configure the first series with a polynomial trendline. +chart7.add_series({ + 'categories': '=Sheet1!$A$2:$A$7', + 'values': '=Sheet1!$B$2:$B$7', + 'data_labels': {'value': True, 'custom': custom_labels}, +}) + +# Add a chart title. +chart7.set_title({'name': 'Chart with deleted data labels'}) + +# Turn off the chart legend. +chart7.set_legend({'none': True}) + +# Insert the chart into the worksheet (with an offset). +worksheet.insert_chart('D98', chart7, {'x_offset': 25, 'y_offset': 10}) + +workbook.close() diff --git a/xlsxwriter/chart.py b/xlsxwriter/chart.py index bf8fc8e48..e95bdba8e 100644 --- a/xlsxwriter/chart.py +++ b/xlsxwriter/chart.py @@ -1173,6 +1173,8 @@ def _get_labels_properties(self, labels): data_id = self._get_data_id(formula, label.get('data')) label['data_id'] = data_id + label['font'] = self._convert_font_args(label.get('font')) + return labels def _get_area_properties(self, options): @@ -2682,7 +2684,7 @@ def _write_legend(self): self._write_overlay() if font: - self._write_tx_pr(None, font) + self._write_tx_pr(font) # Write the c:spPr element. self._write_sp_pr(legend) @@ -2810,7 +2812,7 @@ def _write_title_formula(self, title, data_id, is_y_axis, font, layout, self._write_overlay() # Write the c:txPr element. - self._write_tx_pr(is_y_axis, font) + self._write_tx_pr(font, is_y_axis) self._xml_end_tag('c:title') @@ -2820,7 +2822,7 @@ def _write_tx_rich(self, title, is_y_axis, font): self._xml_start_tag('c:tx') # Write the c:rich element. - self._write_rich(title, is_y_axis, font) + self._write_rich(title, font, is_y_axis, is_data_label=False) self._xml_end_tag('c:tx') @@ -2848,7 +2850,7 @@ def _write_tx_formula(self, title, data_id): self._xml_end_tag('c:tx') - def _write_rich(self, title, is_y_axis, font): + def _write_rich(self, title, font, is_y_axis, is_data_label): # Write the element. if font and font.get('rotation'): @@ -2865,36 +2867,7 @@ def _write_rich(self, title, is_y_axis, font): self._write_a_lst_style() # Write the a:p element. - self._write_a_p_rich(title, font) - - self._xml_end_tag('c:rich') - - def _write_rich_label(self, title, font): - # Write the element for data labels. - - if font and font.get('rotation'): - rotation = font['rotation'] - else: - rotation = None - - self._xml_start_tag('c:rich') - - # Write the a:bodyPr element. - self._write_a_body_pr(rotation, None) - - # Write the a:lstStyle element. - self._write_a_lst_style() - - self._xml_start_tag('a:p') - - # Write the a:pPr element. - if font: - self._write_a_p_pr_rich(font) - - # Write the a:r element. - self._write_a_r(title, font) - - self._xml_end_tag('a:p') + self._write_a_p_rich(title, font, is_data_label) self._xml_end_tag('c:rich') @@ -2924,13 +2897,14 @@ def _write_a_lst_style(self): # Write the element. self._xml_empty_tag('a:lstStyle') - def _write_a_p_rich(self, title, font): + def _write_a_p_rich(self, title, font, is_data_label): # Write the element for rich string titles. self._xml_start_tag('a:p') # Write the a:pPr element. - self._write_a_p_pr_rich(font) + if not is_data_label: + self._write_a_p_pr_rich(font) # Write the a:r element. self._write_a_r(title, font) @@ -3046,7 +3020,7 @@ def _write_a_t(self, title): self._xml_data_element('a:t', title) - def _write_tx_pr(self, is_y_axis, font): + def _write_tx_pr(self, font, is_y_axis=False): # Write the element. if font and font.get('rotation'): @@ -3539,7 +3513,7 @@ def _write_d_lbls(self, labels): # Write the custom c:dLbl elements. if labels.get('custom'): - self._write_custom_labels(labels['custom']) + self._write_custom_labels(labels, labels['custom']) # Write the c:numFmt element. if labels.get('num_format'): @@ -3583,7 +3557,7 @@ def _write_d_lbls(self, labels): self._xml_end_tag('c:dLbls') - def _write_custom_labels(self, labels): + def _write_custom_labels(self, parent, labels): # Write the element. index = 0 @@ -3602,12 +3576,30 @@ def _write_custom_labels(self, labels): if delete_label: self._write_delete(1) + elif label.get('formula'): self._write_custom_label_formula(label) - self._write_show_val() + + if parent.get('value'): + self._write_show_val() + if parent.get('category'): + self._write_show_cat_name() + if parent.get('series_name'): + self._write_show_ser_name() + elif label.get('value'): self._write_custom_label_str(label) - self._write_show_val() + + if parent.get('value'): + self._write_show_val() + if parent.get('category'): + self._write_show_cat_name() + if parent.get('series_name'): + self._write_show_ser_name() + else: + if label['font']: + self._xml_empty_tag('c:spPr') + self._write_tx_pr(label['font']) self._xml_end_tag('c:dLbl') @@ -3622,7 +3614,7 @@ def _write_custom_label_str(self, label): self._xml_start_tag('c:tx') # Write the c:rich element. - self._write_rich_label(title, font) + self._write_rich(title, font, is_y_axis=False, is_data_label=True) self._xml_end_tag('c:tx') @@ -3645,6 +3637,10 @@ def _write_custom_label_formula(self, label): self._xml_end_tag('c:tx') + if label['font']: + self._xml_empty_tag('c:spPr') + self._write_tx_pr(label['font']) + def _write_show_legend_key(self): # Write the element. val = '1' @@ -3770,7 +3766,7 @@ def _write_d_table(self): if table['font']: # Write the table font. - self._write_tx_pr(None, table['font']) + self._write_tx_pr(table['font']) self._xml_end_tag('c:dTable') diff --git a/xlsxwriter/test/comparison/test_chart_data_labels26.py b/xlsxwriter/test/comparison/test_chart_data_labels26.py index ac49a37b5..9cfb90540 100644 --- a/xlsxwriter/test/comparison/test_chart_data_labels26.py +++ b/xlsxwriter/test/comparison/test_chart_data_labels26.py @@ -43,7 +43,7 @@ def test_create_file(self): chart.add_series({ 'values': '=Sheet1!$A$1:$A$5', - 'data_labels': {'value': 1, 'custom': [{'value': 33}]} + 'data_labels': {'value': True, 'custom': [{'value': 33}]} }) chart.add_series({'values': '=Sheet1!$B$1:$B$5'}) diff --git a/xlsxwriter/test/comparison/test_chart_data_labels27.py b/xlsxwriter/test/comparison/test_chart_data_labels27.py index 9ebbb262f..7fef0e11a 100644 --- a/xlsxwriter/test/comparison/test_chart_data_labels27.py +++ b/xlsxwriter/test/comparison/test_chart_data_labels27.py @@ -43,7 +43,7 @@ def test_create_file(self): chart.add_series({ 'values': '=Sheet1!$A$1:$A$5', - 'data_labels': {'value': 1, 'custom': [{'value': '=Sheet1!$D$1'}]} + 'data_labels': {'value': True, 'custom': [{'value': '=Sheet1!$D$1'}]} }) chart.add_series({'values': '=Sheet1!$B$1:$B$5'}) diff --git a/xlsxwriter/test/comparison/test_chart_data_labels28.py b/xlsxwriter/test/comparison/test_chart_data_labels28.py index 1fd474b17..b283e7453 100644 --- a/xlsxwriter/test/comparison/test_chart_data_labels28.py +++ b/xlsxwriter/test/comparison/test_chart_data_labels28.py @@ -51,7 +51,7 @@ def test_create_file(self): chart.add_series({ 'values': '=Sheet1!$A$1:$A$5', - 'data_labels': {'value': 1, 'custom': custom} + 'data_labels': {'value': True, 'custom': custom} }) chart.add_series({'values': '=Sheet1!$B$1:$B$5'}) diff --git a/xlsxwriter/test/comparison/test_chart_data_labels29.py b/xlsxwriter/test/comparison/test_chart_data_labels29.py index 39a05ce41..8ae2995a5 100644 --- a/xlsxwriter/test/comparison/test_chart_data_labels29.py +++ b/xlsxwriter/test/comparison/test_chart_data_labels29.py @@ -41,7 +41,7 @@ def test_create_file(self): chart.add_series({ 'values': '=Sheet1!$A$1:$A$5', - 'data_labels': {'value': 1, 'custom': [{'delete': 1}]} + 'data_labels': {'value': True, 'custom': [{'delete': 1}]} }) chart.add_series({'values': '=Sheet1!$B$1:$B$5'}) diff --git a/xlsxwriter/test/comparison/test_chart_data_labels30.py b/xlsxwriter/test/comparison/test_chart_data_labels30.py index 6c729cf7a..92e881097 100644 --- a/xlsxwriter/test/comparison/test_chart_data_labels30.py +++ b/xlsxwriter/test/comparison/test_chart_data_labels30.py @@ -42,7 +42,7 @@ def test_create_file(self): chart.add_series({ 'values': '=Sheet1!$A$1:$A$5', 'data_labels': { - 'value': 1, + 'value': True, 'custom': [{'delete': True}, None, {'delete': True}, None, {'delete': True}] } }) diff --git a/xlsxwriter/test/comparison/test_chart_data_labels31.py b/xlsxwriter/test/comparison/test_chart_data_labels31.py new file mode 100644 index 000000000..6450c523a --- /dev/null +++ b/xlsxwriter/test/comparison/test_chart_data_labels31.py @@ -0,0 +1,56 @@ +############################################################################### +# +# Tests for XlsxWriter. +# +# Copyright (c), 2013-2019, John McNamara, jmcnamara@cpan.org +# + +from ..excel_comparison_test import ExcelComparisonTest +from ...workbook import Workbook + + +class TestCompareXLSXFiles(ExcelComparisonTest): + """ + Test file created by XlsxWriter against a file created by Excel. + + """ + + def setUp(self): + + self.set_filename('chart_data_labels31.xlsx') + + def test_create_file(self): + """Test the creation of a simple XlsxWriter file.""" + + workbook = Workbook(self.got_filename) + + worksheet = workbook.add_worksheet() + chart = workbook.add_chart({'type': 'column'}) + + chart.axis_ids = [71248896, 71373568] + + data = [ + [1, 2, 3, 4, 5], + [2, 4, 6, 8, 10], + [3, 6, 9, 12, 15], + [10, 20, 30, 40, 50], + ] + + worksheet.write_column('A1', data[0]) + worksheet.write_column('B1', data[1]) + worksheet.write_column('C1', data[2]) + worksheet.write_column('D1', data[3]) + + chart.add_series({ + 'values': '=Sheet1!$A$1:$A$5', + 'data_labels': {'value': True, 'category': True, 'series_name': True, 'custom': [{'value': 33}]} + }) + + chart.add_series({'values': '=Sheet1!$B$1:$B$5'}) + chart.add_series({'values': '=Sheet1!$C$1:$C$5'}) + + worksheet.insert_chart('E9', chart) + + workbook.close() + + self.assertExcelEqual() diff --git a/xlsxwriter/test/comparison/test_chart_data_labels32.py b/xlsxwriter/test/comparison/test_chart_data_labels32.py new file mode 100644 index 000000000..aa2c6a7a6 --- /dev/null +++ b/xlsxwriter/test/comparison/test_chart_data_labels32.py @@ -0,0 +1,56 @@ +############################################################################### +# +# Tests for XlsxWriter. +# +# Copyright (c), 2013-2019, John McNamara, jmcnamara@cpan.org +# + +from ..excel_comparison_test import ExcelComparisonTest +from ...workbook import Workbook + + +class TestCompareXLSXFiles(ExcelComparisonTest): + """ + Test file created by XlsxWriter against a file created by Excel. + + """ + + def setUp(self): + + self.set_filename('chart_data_labels32.xlsx') + + def test_create_file(self): + """Test the creation of a simple XlsxWriter file.""" + + workbook = Workbook(self.got_filename) + + worksheet = workbook.add_worksheet() + chart = workbook.add_chart({'type': 'column'}) + + chart.axis_ids = [71374336, 71414144] + + data = [ + [1, 2, 3, 4, 5], + [2, 4, 6, 8, 10], + [3, 6, 9, 12, 15], + [10, 20, 30, 40, 50], + ] + + worksheet.write_column('A1', data[0]) + worksheet.write_column('B1', data[1]) + worksheet.write_column('C1', data[2]) + worksheet.write_column('D1', data[3]) + + chart.add_series({ + 'values': '=Sheet1!$A$1:$A$5', + 'data_labels': {'value': True, 'custom': [{'value': 33, 'font': {'bold': True, 'italic': True, 'color': 'red', 'baseline': -1}}]} + }) + + chart.add_series({'values': '=Sheet1!$B$1:$B$5'}) + chart.add_series({'values': '=Sheet1!$C$1:$C$5'}) + + worksheet.insert_chart('E9', chart) + + workbook.close() + + self.assertExcelEqual() diff --git a/xlsxwriter/test/comparison/test_chart_data_labels33.py b/xlsxwriter/test/comparison/test_chart_data_labels33.py new file mode 100644 index 000000000..33ebb043d --- /dev/null +++ b/xlsxwriter/test/comparison/test_chart_data_labels33.py @@ -0,0 +1,56 @@ +############################################################################### +# +# Tests for XlsxWriter. +# +# Copyright (c), 2013-2019, John McNamara, jmcnamara@cpan.org +# + +from ..excel_comparison_test import ExcelComparisonTest +from ...workbook import Workbook + + +class TestCompareXLSXFiles(ExcelComparisonTest): + """ + Test file created by XlsxWriter against a file created by Excel. + + """ + + def setUp(self): + + self.set_filename('chart_data_labels33.xlsx') + + def test_create_file(self): + """Test the creation of a simple XlsxWriter file.""" + + workbook = Workbook(self.got_filename) + + worksheet = workbook.add_worksheet() + chart = workbook.add_chart({'type': 'column'}) + + chart.axis_ids = [65546112, 70217728] + + data = [ + [1, 2, 3, 4, 5], + [2, 4, 6, 8, 10], + [3, 6, 9, 12, 15], + [10, 20, 30, 40, 50], + ] + + worksheet.write_column('A1', data[0]) + worksheet.write_column('B1', data[1]) + worksheet.write_column('C1', data[2]) + worksheet.write_column('D1', data[3]) + + chart.add_series({ + 'values': '=Sheet1!$A$1:$A$5', + 'data_labels': {'value': 1, 'custom': [{'font': {'bold': 1, 'italic': 1, 'baseline': -1}}]} + }) + + chart.add_series({'values': '=Sheet1!$B$1:$B$5'}) + chart.add_series({'values': '=Sheet1!$C$1:$C$5'}) + + worksheet.insert_chart('E9', chart) + + workbook.close() + + self.assertExcelEqual() diff --git a/xlsxwriter/test/comparison/test_chart_data_labels34.py b/xlsxwriter/test/comparison/test_chart_data_labels34.py new file mode 100644 index 000000000..75e11913d --- /dev/null +++ b/xlsxwriter/test/comparison/test_chart_data_labels34.py @@ -0,0 +1,56 @@ +############################################################################### +# +# Tests for XlsxWriter. +# +# Copyright (c), 2013-2019, John McNamara, jmcnamara@cpan.org +# + +from ..excel_comparison_test import ExcelComparisonTest +from ...workbook import Workbook + + +class TestCompareXLSXFiles(ExcelComparisonTest): + """ + Test file created by XlsxWriter against a file created by Excel. + + """ + + def setUp(self): + + self.set_filename('chart_data_labels34.xlsx') + + def test_create_file(self): + """Test the creation of a simple XlsxWriter file.""" + + workbook = Workbook(self.got_filename) + + worksheet = workbook.add_worksheet() + chart = workbook.add_chart({'type': 'column'}) + + chart.axis_ids = [48497792, 48499712] + + data = [ + [1, 2, 3, 4, 5], + [2, 4, 6, 8, 10], + [3, 6, 9, 12, 15], + [10, 20, 30, 40, 50], + ] + + worksheet.write_column('A1', data[0]) + worksheet.write_column('B1', data[1]) + worksheet.write_column('C1', data[2]) + worksheet.write_column('D1', data[3]) + + chart.add_series({ + 'values': '=Sheet1!$A$1:$A$5', + 'data_labels': {'value': 1, 'custom': [{'value': '=Sheet1!$D$1', 'font': {'bold': 1, 'italic': 1, 'color': 'red', 'baseline': -1}}]} + }) + + chart.add_series({'values': '=Sheet1!$B$1:$B$5'}) + chart.add_series({'values': '=Sheet1!$C$1:$C$5'}) + + worksheet.insert_chart('E9', chart) + + workbook.close() + + self.assertExcelEqual() diff --git a/xlsxwriter/test/comparison/xlsx_files/chart_data_labels31.xlsx b/xlsxwriter/test/comparison/xlsx_files/chart_data_labels31.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..fe5201ff37c837d4d154a796716dfacbc0b976de GIT binary patch literal 9414 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 WX+#){f0PF>0j98xAW8A#>wf^GdrmR{ literal 0 HcmV?d00001 diff --git a/xlsxwriter/test/comparison/xlsx_files/chart_data_labels32.xlsx b/xlsxwriter/test/comparison/xlsx_files/chart_data_labels32.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..42aebd2d2be6ad08524f5d974778457fa6b4c3e1 GIT binary patch literal 9437 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 HkEj0uV}MK- literal 0 HcmV?d00001 diff --git a/xlsxwriter/test/comparison/xlsx_files/chart_data_labels34.xlsx b/xlsxwriter/test/comparison/xlsx_files/chart_data_labels34.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..e754705046d72ad49ec998df2cc888ce40c73406 GIT binary patch literal 9470 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 literal 0 HcmV?d00001