From 110af3ff4df4e0947dc0a268e586f193e6ea7ff6 Mon Sep 17 00:00:00 2001 From: John McNamara Date: Fri, 2 Oct 2020 20:44:38 +0100 Subject: [PATCH] Fix for ignored position in chart custom data labels. Fix issue where custom chart data labels didn't inherit the position for the data labels in the series.` --- src/chart.c | 8 +++ .../functional/src/test_chart_data_labels48.c | 53 ++++++++++++++++++ .../functional/src/test_chart_data_labels49.c | 53 ++++++++++++++++++ .../functional/src/test_chart_data_labels50.c | 53 ++++++++++++++++++ test/functional/test_chart_data_labels.py | 9 +++ .../xlsx_files/chart_data_labels48.xlsx | Bin 0 -> 9400 bytes .../xlsx_files/chart_data_labels49.xlsx | Bin 0 -> 9391 bytes .../xlsx_files/chart_data_labels50.xlsx | Bin 0 -> 9426 bytes 8 files changed, 176 insertions(+) create mode 100644 test/functional/src/test_chart_data_labels48.c create mode 100644 test/functional/src/test_chart_data_labels49.c create mode 100644 test/functional/src/test_chart_data_labels50.c create mode 100644 test/functional/xlsx_files/chart_data_labels48.xlsx create mode 100644 test/functional/xlsx_files/chart_data_labels49.xlsx create mode 100644 test/functional/xlsx_files/chart_data_labels50.xlsx diff --git a/src/chart.c b/src/chart.c index 2124d2cc..a43f01b9 100644 --- a/src/chart.c +++ b/src/chart.c @@ -2317,6 +2317,10 @@ _chart_write_custom_label_formula(lxw_chart *self, lxw_chart_series *series, _chart_write_custom_label_format_only(self, data_label); + /* Write the c:dLblPos element. */ + if (series->label_position) + _chart_write_d_lbl_pos(self, series->label_position); + /* Write the c:showVal element. */ if (series->show_labels_value) _chart_write_show_val(self); @@ -2356,6 +2360,10 @@ _chart_write_custom_label_str(lxw_chart *self, lxw_chart_series *series, _chart_write_sp_pr(self, data_label->line, data_label->fill, data_label->pattern); + /* Write the c:dLblPos element. */ + if (series->label_position) + _chart_write_d_lbl_pos(self, series->label_position); + /* Write the c:showVal element. */ if (series->show_labels_value) _chart_write_show_val(self); diff --git a/test/functional/src/test_chart_data_labels48.c b/test/functional/src/test_chart_data_labels48.c new file mode 100644 index 00000000..71125585 --- /dev/null +++ b/test/functional/src/test_chart_data_labels48.c @@ -0,0 +1,53 @@ +/***************************************************************************** + * Test cases for libxlsxwriter. + * + * Test to compare output against Excel files. + * + * Copyright 2014-2020, John McNamara, jmcnamara@cpan.org + * + */ + +#include "xlsxwriter.h" + +int main() { + + lxw_workbook *workbook = workbook_new("test_chart_data_labels48.xlsx"); + lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL); + lxw_chart *chart = workbook_add_chart(workbook, LXW_CHART_COLUMN); + + /* For testing, copy the randomly generated axis ids in the target file. */ + chart->axis_id_1 = 61160832; + chart->axis_id_2 = 61167104; + + uint8_t data[5][3] = { + {1, 2, 3}, + {2, 4, 6}, + {3, 6, 9}, + {4, 8, 12}, + {5, 10, 15} + }; + + int row, col; + for (row = 0; row < 5; row++) + for (col = 0; col < 3; col++) + worksheet_write_number(worksheet, row, col, data[row][col], NULL); + + lxw_chart_data_label data_label1 = {.value = "31"}; + lxw_chart_data_label data_label2 = {.value = "32"}; + lxw_chart_data_label *data_labels1[] = {&data_label1, NULL}; + lxw_chart_data_label *data_labels2[] = {&data_label2, NULL}; + + lxw_chart_series *series1 = chart_add_series(chart, NULL, "=Sheet1!$A$1:$A$5"); + lxw_chart_series *series2 = chart_add_series(chart, NULL, "=Sheet1!$B$1:$B$5"); + chart_add_series(chart, NULL, "=Sheet1!$C$1:$C$5"); + + chart_series_set_labels(series1); + chart_series_set_labels(series2); + chart_series_set_labels_position(series2, LXW_CHART_LABEL_POSITION_INSIDE_BASE); + chart_series_set_labels_custom(series1, data_labels1); + chart_series_set_labels_custom(series2, data_labels2); + + worksheet_insert_chart(worksheet, CELL("E9"), chart); + + return workbook_close(workbook); +} diff --git a/test/functional/src/test_chart_data_labels49.c b/test/functional/src/test_chart_data_labels49.c new file mode 100644 index 00000000..bea63908 --- /dev/null +++ b/test/functional/src/test_chart_data_labels49.c @@ -0,0 +1,53 @@ +/***************************************************************************** + * Test cases for libxlsxwriter. + * + * Test to compare output against Excel files. + * + * Copyright 2014-2020, John McNamara, jmcnamara@cpan.org + * + */ + +#include "xlsxwriter.h" + +int main() { + + lxw_workbook *workbook = workbook_new("test_chart_data_labels49.xlsx"); + lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL); + lxw_chart *chart = workbook_add_chart(workbook, LXW_CHART_COLUMN); + + /* For testing, copy the randomly generated axis ids in the target file. */ + chart->axis_id_1 = 59202176; + chart->axis_id_2 = 60966784; + + uint8_t data[5][3] = { + {1, 2, 3}, + {2, 4, 6}, + {3, 6, 9}, + {4, 8, 12}, + {5, 10, 15} + }; + + int row, col; + for (row = 0; row < 5; row++) + for (col = 0; col < 3; col++) + worksheet_write_number(worksheet, row, col, data[row][col], NULL); + + lxw_chart_data_label data_label1 = {.value = "=Sheet1!$B$1"}; + lxw_chart_data_label data_label2 = {.value = "=Sheet1!$B$2"}; + lxw_chart_data_label *data_labels1[] = {&data_label1, NULL}; + lxw_chart_data_label *data_labels2[] = {&data_label2, NULL}; + + lxw_chart_series *series1 = chart_add_series(chart, NULL, "=Sheet1!$A$1:$A$5"); + lxw_chart_series *series2 = chart_add_series(chart, NULL, "=Sheet1!$B$1:$B$5"); + chart_add_series(chart, NULL, "=Sheet1!$C$1:$C$5"); + + chart_series_set_labels(series1); + chart_series_set_labels(series2); + chart_series_set_labels_position(series2, LXW_CHART_LABEL_POSITION_INSIDE_BASE); + chart_series_set_labels_custom(series1, data_labels1); + chart_series_set_labels_custom(series2, data_labels2); + + worksheet_insert_chart(worksheet, CELL("E9"), chart); + + return workbook_close(workbook); +} diff --git a/test/functional/src/test_chart_data_labels50.c b/test/functional/src/test_chart_data_labels50.c new file mode 100644 index 00000000..89d76751 --- /dev/null +++ b/test/functional/src/test_chart_data_labels50.c @@ -0,0 +1,53 @@ +/***************************************************************************** + * Test cases for libxlsxwriter. + * + * Test to compare output against Excel files. + * + * Copyright 2014-2020, John McNamara, jmcnamara@cpan.org + * + */ + +#include "xlsxwriter.h" + +int main() { + + lxw_workbook *workbook = workbook_new("test_chart_data_labels50.xlsx"); + lxw_worksheet *worksheet = workbook_add_worksheet(workbook, NULL); + lxw_chart *chart = workbook_add_chart(workbook, LXW_CHART_COLUMN); + + /* For testing, copy the randomly generated axis ids in the target file. */ + chart->axis_id_1 = 84605184; + chart->axis_id_2 = 84639744; + + uint8_t data[5][3] = { + {1, 2, 3}, + {2, 4, 6}, + {3, 6, 9}, + {4, 8, 12}, + {5, 10, 15} + }; + + int row, col; + for (row = 0; row < 5; row++) + for (col = 0; col < 3; col++) + worksheet_write_number(worksheet, row, col, data[row][col], NULL); + + + + lxw_chart_line line = {.color = LXW_COLOR_RED}; + lxw_chart_font font = {.bold = LXW_TRUE, .italic = LXW_TRUE, .color = LXW_COLOR_RED, .baseline = -1}; + + lxw_chart_data_label data_label1 = {.line = &line, .font = &font}; + lxw_chart_data_label *data_labels[] = {&data_label1, NULL}; + + lxw_chart_series *series = chart_add_series(chart, NULL, "=Sheet1!$A$1:$A$5"); + chart_series_set_labels_custom(series, data_labels); + chart_series_set_labels_position(series, LXW_CHART_LABEL_POSITION_CENTER); + + chart_add_series(chart, NULL, "=Sheet1!$B$1:$B$5"); + chart_add_series(chart, NULL, "=Sheet1!$C$1:$C$5"); + + worksheet_insert_chart(worksheet, CELL("E9"), chart); + + return workbook_close(workbook); +} diff --git a/test/functional/test_chart_data_labels.py b/test/functional/test_chart_data_labels.py index d61983d0..b275c6eb 100644 --- a/test/functional/test_chart_data_labels.py +++ b/test/functional/test_chart_data_labels.py @@ -149,3 +149,12 @@ class TestCompareXLSXFiles(base_test_class.XLSXBaseTest): def test_chart_data_labels47(self): self.run_exe_test('test_chart_data_labels47') + + def test_chart_data_labels48(self): + self.run_exe_test('test_chart_data_labels48') + + def test_chart_data_labels49(self): + self.run_exe_test('test_chart_data_labels49') + + def test_chart_data_labels50(self): + self.run_exe_test('test_chart_data_labels50') diff --git a/test/functional/xlsx_files/chart_data_labels48.xlsx b/test/functional/xlsx_files/chart_data_labels48.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..251c47a9cd580d9c6bb5302ab37a8e42934d9644 GIT binary patch literal 9400 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 E4`k0pHUIzs literal 0 HcmV?d00001 diff --git a/test/functional/xlsx_files/chart_data_labels49.xlsx b/test/functional/xlsx_files/chart_data_labels49.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..f3b62bd7668ba4411a634540ba46a14af13e347a GIT binary patch literal 9391 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≷5_VX)hVJ(}1 z?!6>esal>e5Ti8NF(4FC&_iF)YHl#SQe;> zQ21W2DC)I-%T02O&e;Zxy#%V$2R%GE(Z>r9s;!P+`l z*$5qQ^XVy;f2ndeBRX#vQc*a-hc4N4HR7>kuF_yk=j+GY29?t@!0~`yI_Y zZwqX$PBugBmvvaZimgJb9an&!92yauByGLV54u$?(4ff82jG^8Yd?zAO0m zG234SO<|qE|2%ZNi*t7z^9$(%?8T8g!2CY=F2LRL_ZNUCtbT$4{3?d; zir%fYeu;u`e~SL2^16#~H=+B5Ku>V@IDVyfcTxVHDEz{JC5eQvy8dq3a98~Ap8l`m e5aPdx|LOM?WZ+>e{?RHx2bjPNL7D8w)BgY;H(*cz literal 0 HcmV?d00001