Skip to content

Commit

Permalink
chart: add intial support for combined secondary axes
Browse files Browse the repository at this point in the history
  • Loading branch information
jmcnamara committed May 29, 2024
1 parent ae406b3 commit 301db22
Show file tree
Hide file tree
Showing 12 changed files with 241 additions and 17 deletions.
4 changes: 2 additions & 2 deletions examples/doc_chart_axis_set_hidden.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ fn main() -> Result<(), XlsxError> {
chart.add_series().set_values("Sheet1!$A$1:$A$5");

// Hide both axes.
chart.x_axis().set_hidden();
chart.y_axis().set_hidden();
chart.x_axis().set_hidden(true);
chart.y_axis().set_hidden(true);

// Hide legend for clarity.
chart.legend().set_hidden();
Expand Down
66 changes: 54 additions & 12 deletions src/chart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1023,6 +1023,28 @@ impl Chart {
&mut self.y_axis
}

/// Get the chart X2-Axis object in order to set its properties.
///
/// Get a reference to the chart's X2-Axis [`ChartAxis`] object in order to
/// set its properties.
///
/// See the [`chart.x_axis()`][Chart::x_axis] method above.
///
pub fn x2_axis(&mut self) -> &mut ChartAxis {
&mut self.x2_axis
}

/// Get the chart Y2-Axis object in order to set its properties.
///
/// Get a reference to the chart's Y2-Axis [`ChartAxis`] object in order to
/// set its properties.
///
/// See the [`chart.x_axis()`][Chart::x_axis] method above.
///
pub fn y2_axis(&mut self) -> &mut ChartAxis {
&mut self.y2_axis
}

/// Get the chart legend object in order to set its properties.
///
/// Get a reference to the chart's [`ChartLegend`] object in order to set
Expand Down Expand Up @@ -2318,7 +2340,12 @@ impl Chart {

let axis_id = (5000 + chart_id) * 10000 + 1;
self.axis_ids = (axis_id, axis_id + 1);
self.axis2_ids = (axis_id + 2, axis_id + 3);

if self.combined_chart.is_none() {
self.axis2_ids = (axis_id + 2, axis_id + 3);
} else {
self.axis2_ids = (axis_id + 10_000_000, axis_id + 10_000_001);
}
}

// Check for any legend entries that have been hidden/deleted via the
Expand Down Expand Up @@ -2361,7 +2388,14 @@ impl Chart {

// todo
fn check_for_secondary_axis(&mut self) {
// TODO
if let Some(combined_chart) = &self.combined_chart {
for series in &combined_chart.series {
if series.y2_axis {
self.has_secondary_axis = true;
}
}
}

for series in &self.series {
if series.y2_axis {
self.has_secondary_axis = true;
Expand Down Expand Up @@ -3007,6 +3041,7 @@ impl Chart {
// Write the combined chart.
if let Some(combined_chart) = &mut self.combined_chart {
combined_chart.axis_ids = self.axis_ids;
combined_chart.axis2_ids = self.axis2_ids;
combined_chart.series_index = self.series.len();

mem::swap(&mut combined_chart.writer, &mut self.writer);
Expand Down Expand Up @@ -3051,13 +3086,18 @@ impl Chart {
if self.has_secondary_axis {
let mut x_axis = self.x2_axis.clone();
let mut y_axis = self.y2_axis.clone();
let mut chart_group_type = self.chart_group_type;

if let Some(combined_chart) = &self.combined_chart {
chart_group_type = combined_chart.chart_group_type;
}

// Reverse the X and Y axes for Bar charts.
if self.chart_group_type == ChartType::Bar {
if chart_group_type == ChartType::Bar {
std::mem::swap(&mut x_axis, &mut y_axis);
}

match self.chart_group_type {
match chart_group_type {
ChartType::Pie | ChartType::Doughnut => {}

ChartType::Scatter => {
Expand Down Expand Up @@ -3897,8 +3937,7 @@ impl Chart {
// Write the c:crossAx element.
self.write_cross_ax(axis_ids.0);

// Write the c:crosses element. Note, the Y crossing comes from the X
// axis.
// Write the c:crosses element. Note, the Y crossing comes from the X axis.
match x_axis.crossing {
ChartAxisCrossing::Automatic | ChartAxisCrossing::Min | ChartAxisCrossing::Max => {
self.write_crosses(&x_axis.crossing.to_string());
Expand Down Expand Up @@ -3989,8 +4028,7 @@ impl Chart {
// Write the c:crossAx element.
self.write_cross_ax(axis_ids.1);

// Write the c:crosses element. Note, the X crossing comes from the Y
// axis.
// Write the c:crosses element. Note, the X crossing comes from the Y axis.
match y_axis.crossing {
ChartAxisCrossing::Automatic | ChartAxisCrossing::Min | ChartAxisCrossing::Max => {
self.write_crosses(&y_axis.crossing.to_string());
Expand Down Expand Up @@ -11582,6 +11620,10 @@ impl ChartAxis {
///
/// Hide the number or label section of the chart axis.
///
/// # Parameters
///
/// * `enable` - Turn the property on/off.
///
/// # Examples
///
/// A chart example demonstrating hiding the chart axes.
Expand Down Expand Up @@ -11609,8 +11651,8 @@ impl ChartAxis {
/// chart.add_series().set_values("Sheet1!$A$1:$A$5");
///
/// // Hide both axes.
/// chart.x_axis().set_hidden();
/// chart.y_axis().set_hidden();
/// chart.x_axis().set_hidden(true);
/// chart.y_axis().set_hidden(true);
///
/// // Hide legend for clarity.
/// chart.legend().set_hidden();
Expand All @@ -11629,8 +11671,8 @@ impl ChartAxis {
///
/// <img src="https://rustxlsxwriter.github.io/images/chart_axis_set_hidden.png">
///
pub fn set_hidden(&mut self) -> &mut ChartAxis {
self.is_hidden = true;
pub fn set_hidden(&mut self, enable: bool) -> &mut ChartAxis {
self.is_hidden = enable;
self
}
}
Expand Down
Binary file added tests/input/chart_combined04.xlsx
Binary file not shown.
Binary file added tests/input/chart_combined05.xlsx
Binary file not shown.
Binary file added tests/input/chart_gap04.xlsx
Binary file not shown.
2 changes: 1 addition & 1 deletion tests/integration/chart_axis49.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ fn create_new_xlsx_file(filename: &str) -> Result<(), XlsxError> {
chart.add_series().set_values(("Sheet1", 0, 1, 4, 1));
chart.add_series().set_values(("Sheet1", 0, 2, 4, 2));

chart.x_axis().set_hidden();
chart.x_axis().set_hidden(true);

worksheet.insert_chart(8, 4, &chart)?;

Expand Down
2 changes: 1 addition & 1 deletion tests/integration/chart_axis50.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ fn create_new_xlsx_file(filename: &str) -> Result<(), XlsxError> {
chart.add_series().set_values(("Sheet1", 0, 1, 4, 1));
chart.add_series().set_values(("Sheet1", 0, 2, 4, 2));

chart.y_axis().set_hidden();
chart.y_axis().set_hidden(true);

worksheet.insert_chart(8, 4, &chart)?;

Expand Down
2 changes: 1 addition & 1 deletion tests/integration/chart_axis51.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fn create_new_xlsx_file(filename: &str) -> Result<(), XlsxError> {
.set_categories(("Sheet1", 0, 0, 4, 0))
.set_values(("Sheet1", 0, 2, 4, 2));

chart.x_axis().set_hidden();
chart.x_axis().set_hidden(true);

worksheet.insert_chart(8, 4, &chart)?;

Expand Down
57 changes: 57 additions & 0 deletions tests/integration/chart_combined04.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// Test case that compares a file generated by rust_xlsxwriter with a file
// created by Excel.
//
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright 2022-2024, John McNamara, [email protected]

use crate::common;
use rust_xlsxwriter::{
Chart, ChartAxisLabelPosition, ChartEmptyCells, ChartType, Workbook, XlsxError,
};

// Create rust_xlsxwriter file to compare against Excel file.
fn create_new_xlsx_file(filename: &str) -> Result<(), XlsxError> {
let mut workbook = Workbook::new();

let worksheet = workbook.add_worksheet();

// Add some test data for the chart(s).
worksheet.write_column(0, 0, [2, 7, 3, 6, 2])?;
worksheet.write_column(0, 1, [20, 25, 10, 10, 20])?;

let mut chart1 = Chart::new(ChartType::Column);
chart1.add_series().set_values(("Sheet1", 0, 0, 4, 0));

let mut chart2 = Chart::new(ChartType::Line);
chart2
.add_series()
.set_values(("Sheet1", 0, 1, 4, 1))
.set_y2_axis(true);

chart1.show_empty_cells_as(ChartEmptyCells::Gaps);

chart1.combine(&chart2);

chart1
.x2_axis()
.set_label_position(ChartAxisLabelPosition::NextTo);

worksheet.insert_chart(8, 4, &chart1)?;

workbook.save(filename)?;

Ok(())
}

#[test]
fn test_chart_combined04() {
let test_runner = common::TestRunner::new()
.set_name("chart_combined04")
.set_function(create_new_xlsx_file)
.ignore_elements("xl/charts/chart1.xml", "autoZero")
.initialize();

test_runner.assert_eq();
test_runner.cleanup();
}
68 changes: 68 additions & 0 deletions tests/integration/chart_combined05.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Test case that compares a file generated by rust_xlsxwriter with a file
// created by Excel.
//
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright 2022-2024, John McNamara, [email protected]

use crate::common;
use rust_xlsxwriter::{
Chart, ChartAxisCrossing, ChartAxisLabelPosition, ChartEmptyCells, ChartType, Workbook,
XlsxError,
};

// Create rust_xlsxwriter file to compare against Excel file.
fn create_new_xlsx_file(filename: &str) -> Result<(), XlsxError> {
let mut workbook = Workbook::new();

let worksheet = workbook.add_worksheet();

// Add some test data for the chart(s).
worksheet.write_column(0, 0, [2, 7, 3, 6, 2])?;
worksheet.write_column(0, 1, [20, 25, 10, 10, 20])?;

let mut chart1 = Chart::new(ChartType::Bar);
chart1.set_axis_ids(60914304, 78899072);
chart1.set_axis2_ids(85542016, 85183872);

chart1.add_series().set_values(("Sheet1", 0, 0, 4, 0));

let mut chart2 = Chart::new(ChartType::Line);
chart2
.add_series()
.set_values(("Sheet1", 0, 1, 4, 1))
.set_y2_axis(true);

chart1.show_empty_cells_as(ChartEmptyCells::Gaps);

chart1.combine(&chart2);

chart1
.x2_axis()
.set_crossing(ChartAxisCrossing::Max)
.set_hidden(true)
.set_label_position(ChartAxisLabelPosition::NextTo);

chart1
.y2_axis()
.set_crossing(ChartAxisCrossing::Automatic)
.set_hidden(false)
.set_label_position(ChartAxisLabelPosition::NextTo);

worksheet.insert_chart(8, 4, &chart1)?;

workbook.save(filename)?;

Ok(())
}

#[test]
fn test_chart_combined05() {
let test_runner = common::TestRunner::new()
.set_name("chart_combined05")
.set_function(create_new_xlsx_file)
.initialize();

test_runner.assert_eq();
test_runner.cleanup();
}
54 changes: 54 additions & 0 deletions tests/integration/chart_gap04.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Test case that compares a file generated by rust_xlsxwriter with a file
// created by Excel.
//
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright 2022-2024, John McNamara, [email protected]

use crate::common;
use rust_xlsxwriter::{Chart, ChartType, Workbook, XlsxError};

// Create rust_xlsxwriter file to compare against Excel file.
fn create_new_xlsx_file(filename: &str) -> Result<(), XlsxError> {
let mut workbook = Workbook::new();

let worksheet = workbook.add_worksheet();

// Add some test data for the chart(s).
worksheet.write_column(0, 0, [1, 2, 3, 4, 5])?;
worksheet.write_column(0, 1, [6, 8, 6, 4, 2])?;

let mut chart = Chart::new(ChartType::Column);
chart.set_axis_ids(45938176, 59715584);
chart.set_axis2_ids(62526208, 59718272);

chart
.add_series()
.set_values(("Sheet1", 0, 0, 4, 0))
.set_overlap(12)
.set_gap(51);

chart
.add_series()
.set_values(("Sheet1", 0, 1, 4, 1))
.set_overlap(-27)
.set_gap(251)
.set_y2_axis(true);

worksheet.insert_chart(8, 4, &chart)?;

workbook.save(filename)?;

Ok(())
}

#[test]
fn test_chart_gap04() {
let test_runner = common::TestRunner::new()
.set_name("chart_gap04")
.set_function(create_new_xlsx_file)
.initialize();

test_runner.assert_eq();
test_runner.cleanup();
}
3 changes: 3 additions & 0 deletions tests/integration/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,8 @@ mod chart_column13;
mod chart_combined01;
mod chart_combined02;
mod chart_combined03;
mod chart_combined04;
mod chart_combined05;
mod chart_crossing01;
mod chart_crossing02;
mod chart_crossing03;
Expand Down Expand Up @@ -345,6 +347,7 @@ mod chart_format35;
mod chart_gap01;
mod chart_gap02;
mod chart_gap03;
mod chart_gap04;
mod chart_gradient01;
mod chart_gradient02;
mod chart_gradient03;
Expand Down

0 comments on commit 301db22

Please sign in to comment.