Skip to content

Commit

Permalink
cond format: add multi-range conditional format example
Browse files Browse the repository at this point in the history
  • Loading branch information
jmcnamara committed Nov 10, 2023
1 parent 3be31d7 commit 1b6f98c
Show file tree
Hide file tree
Showing 4 changed files with 291 additions and 9 deletions.
39 changes: 38 additions & 1 deletion examples/app_conditional_formatting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ fn main() -> Result<(), XlsxError> {

worksheet.add_conditional_format(2, 1, 11, 10, &conditional_format)?;

// Invert the duplicate conditional format to show uniques values in the
// Invert the duplicate conditional format to show unique values in the
// same range.
let conditional_format = ConditionalFormatDuplicate::new()
.invert()
Expand Down Expand Up @@ -213,6 +213,43 @@ fn main() -> Result<(), XlsxError> {

worksheet.add_conditional_format(2, 1, 11, 10, &conditional_format)?;

// -----------------------------------------------------------------------
// Example 6. Cell conditional formatting in non-contiguous range.
// -----------------------------------------------------------------------
let caption = "Cells with values >= 50 are in light red. Values < 50 are in light green. Non-contiguous ranges.";

// Add a worksheet to the workbook.
let worksheet = workbook.add_worksheet();

// Write the caption.
worksheet.write(0, 1, caption)?;

// Write the worksheet data.
worksheet.write_row_matrix(2, 1, data)?;

// Set the column widths for clarity.
for col_num in 1..=10u16 {
worksheet.set_column_width(col_num, 6)?;
}

// Write a conditional format over a non-contiguous range.
let conditional_format = ConditionalFormatCell::new()
.set_criteria(ConditionalFormatCellCriteria::GreaterThanOrEqualTo)
.set_value(50)
.set_multi_range("B3:D6 I3:K6 B9:D12 I9:K12")
.set_format(&format1);

worksheet.add_conditional_format(2, 1, 11, 10, &conditional_format)?;

// Write another conditional format over the same range.
let conditional_format = ConditionalFormatCell::new()
.set_criteria(ConditionalFormatCellCriteria::LessThan)
.set_value(50)
.set_multi_range("B3:D6 I3:K6 B9:D12 I9:K12")
.set_format(&format2);

worksheet.add_conditional_format(2, 1, 11, 10, &conditional_format)?;

// -----------------------------------------------------------------------
// Save and close the file.
// -----------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion examples/doc_conditional_format_duplicate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ fn main() -> Result<(), XlsxError> {

worksheet.add_conditional_format(2, 1, 11, 10, &conditional_format)?;

// Invert the duplicate conditional format to show uniques values.
// Invert the duplicate conditional format to show unique values.
let conditional_format = ConditionalFormatDuplicate::new()
.invert()
.set_format(format2);
Expand Down
71 changes: 71 additions & 0 deletions examples/doc_conditional_format_multi_range.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// SPDX-License-Identifier: MIT OR Apache-2.0
//
// Copyright 2022-2023, John McNamara, [email protected]

//! Example of adding a cell type conditional formatting to a worksheet over a
//! non-contiguous range. Cells with values >= 50 are in light red. Values < 50
//! are in light green. Note that the cells outside the selected ranges do not
//! have any conditional formatting.
use rust_xlsxwriter::{
ConditionalFormatCell, ConditionalFormatCellCriteria, Format, Workbook, XlsxError,
};

fn main() -> Result<(), XlsxError> {
// Create a new Excel file object.
let mut workbook = Workbook::new();
let worksheet = workbook.add_worksheet();

// Add some sample data.
let data = [
[90, 80, 50, 10, 20, 90, 40, 90, 30, 40],
[20, 10, 90, 100, 30, 60, 70, 60, 50, 90],
[10, 50, 60, 50, 20, 50, 80, 30, 40, 60],
[10, 90, 20, 40, 10, 40, 50, 70, 90, 50],
[70, 100, 10, 90, 10, 10, 20, 100, 100, 40],
[20, 60, 10, 100, 30, 10, 20, 60, 100, 10],
[10, 60, 10, 80, 100, 80, 30, 30, 70, 40],
[30, 90, 60, 10, 10, 100, 40, 40, 30, 40],
[80, 90, 10, 20, 20, 50, 80, 20, 60, 90],
[60, 80, 30, 30, 10, 50, 80, 60, 50, 30],
];
worksheet.write_row_matrix(2, 1, data)?;

// Set the column widths for clarity.
for col_num in 1..=10u16 {
worksheet.set_column_width(col_num, 6)?;
}

// Add a format. Light red fill with dark red text.
let format1 = Format::new()
.set_font_color("9C0006")
.set_background_color("FFC7CE");

// Add a format. Green fill with dark green text.
let format2 = Format::new()
.set_font_color("006100")
.set_background_color("C6EFCE");

// Write a conditional format over a non-contiguous range.
let conditional_format = ConditionalFormatCell::new()
.set_criteria(ConditionalFormatCellCriteria::GreaterThanOrEqualTo)
.set_value(50)
.set_multi_range("B3:D6 I3:K6 B9:D12 I9:K12")
.set_format(format1);

worksheet.add_conditional_format(2, 1, 11, 10, &conditional_format)?;

// Write another conditional format over the same range.
let conditional_format = ConditionalFormatCell::new()
.set_criteria(ConditionalFormatCellCriteria::LessThan)
.set_value(50)
.set_multi_range("B3:D6 I3:K6 B9:D12 I9:K12")
.set_format(format2);

worksheet.add_conditional_format(2, 1, 11, 10, &conditional_format)?;

// Save the file.
workbook.save("conditional_format.xlsx")?;

Ok(())
}
188 changes: 181 additions & 7 deletions src/conditional_format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,195 @@
//
// Copyright 2022-2023, John McNamara, [email protected]

//! Working with Conditional Formats
//! # Working with Conditional Formats
//!
//! TODO Add intro to conditional formats
//! Conditional formatting is a feature of Excel which allows you to apply a
//! format to a cell or a range of cells based on certain criteria. For example
//! you might apply rules like the following to highlight cells in different
//! ranges.
//!
//! <img
//! src="https://rustxlsxwriter.github.io/images/conditional_format_dialog.png">
//!
//! With `rust_xlsxwriter` we could emulate this by creating [`Format`]
//! instances and applying them to conditional format rules, like this:
//!
//! ```
//! # // This code is available in examples/doc_conditional_format_cell1.rs
//! #
//! # use rust_xlsxwriter::{
//! # ConditionalFormatCell, ConditionalFormatCellCriteria, Format, Workbook, XlsxError,
//! # };
//! #
//! # fn main() -> Result<(), XlsxError> {
//! # // Create a new Excel file object.
//! # let mut workbook = Workbook::new();
//! # let worksheet = workbook.add_worksheet();
//! #
//! # // Add some sample data.
//! # let data = [
//! # [90, 80, 50, 10, 20, 90, 40, 90, 30, 40],
//! # [20, 10, 90, 100, 30, 60, 70, 60, 50, 90],
//! # [10, 50, 60, 50, 20, 50, 80, 30, 40, 60],
//! # [10, 90, 20, 40, 10, 40, 50, 70, 90, 50],
//! # [70, 100, 10, 90, 10, 10, 20, 100, 100, 40],
//! # [20, 60, 10, 100, 30, 10, 20, 60, 100, 10],
//! # [10, 60, 10, 80, 100, 80, 30, 30, 70, 40],
//! # [30, 90, 60, 10, 10, 100, 40, 40, 30, 40],
//! # [80, 90, 10, 20, 20, 50, 80, 20, 60, 90],
//! # [60, 80, 30, 30, 10, 50, 80, 60, 50, 30],
//! # ];
//! # worksheet.write_row_matrix(2, 1, data)?;
//! #
//! # // Set the column widths for clarity.
//! # for col_num in 1..=10u16 {
//! # worksheet.set_column_width(col_num, 6)?;
//! # }
//! #
//! // Add a format. Light red fill with dark red text.
//! let format1 = Format::new()
//! .set_font_color("9C0006")
//! .set_background_color("FFC7CE");
//!
//! // Add a format. Green fill with dark green text.
//! let format2 = Format::new()
//! .set_font_color("006100")
//! .set_background_color("C6EFCE");
//!
//! // Write a conditional format over a range.
//! let conditional_format = ConditionalFormatCell::new()
//! .set_criteria(ConditionalFormatCellCriteria::GreaterThanOrEqualTo)
//! .set_value(50)
//! .set_format(format1);
//!
//! worksheet.add_conditional_format(2, 1, 11, 10, &conditional_format)?;
//!
//! // Write another conditional format over the same range.
//! let conditional_format = ConditionalFormatCell::new()
//! .set_criteria(ConditionalFormatCellCriteria::LessThan)
//! .set_value(50)
//! .set_format(format2);
//!
//! worksheet.add_conditional_format(2, 1, 11, 10, &conditional_format)?;
//!
//! # // Save the file.
//! # workbook.save("conditional_format.xlsx")?;
//! #
//! # Ok(())
//! # }
//! ```
//!
//! Which would produce an output like the following. Cells with values >= 50
//! are in light red. Values < 50 are in light green.
//!
//! <img
//! src="https://rustxlsxwriter.github.io/images/conditional_format_cell1.png">
//!
//! # Excel's limitations on conditional format properties
//!
//! Not all of Excel's cell format properties can be modified with a conditional
//! format. Properties that **cannot** be modified in a conditional format are
//! font name, font size, superscript and subscript, diagonal borders, all
//! alignment properties and all protection properties.
//! format.
//!
//! For example see the limited number of font properties that can be set in the
//! Excel conditional format dialog. The available properties are highlighted
//! with green.
//!
//! <img
//! src="https://rustxlsxwriter.github.io/images/conditional_format_limitations.png">
//!
//! Properties that **cannot** be modified in a conditional format are font
//! name, font size, superscript and subscript, diagonal borders, all alignment
//! properties and all protection properties.
//!
//! # Selecting a non-contiguous range
//!
//! In Excel it is possible to select several non-contiguous cells or ranges
//! like `"A1:A3 A5 B3:K6 B9:K12"` and apply a conditional format to them.
//!
//! It is possible to achieve a similar effect with `rust_xlsxwriter` by using
//! repeated calls to
//! [`Worksheet::add_conditional_format()`](crate::Worksheet::add_conditional_format).
//! However this approach results in multiple identical conditional formats
//! applied to different cell ranges rather than one conditional format applied
//! to a multiple range selection.
//!
//! If this distinction is important to you then you can get the Excel multiple
//! selection effect using the `set_multi_range()` which is provided for all the
//! `ConditionalFormat` types. See the example below and note that the cells
//! outside the selected ranges do not have any conditional formatting.
//!
//! ```
//! # // This code is available in examples/doc_conditional_format_multi_range.rs
//! #
//! # use rust_xlsxwriter::{
//! # ConditionalFormatCell, ConditionalFormatCellCriteria, Format, Workbook, XlsxError,
//! # };
//! #
//! # fn main() -> Result<(), XlsxError> {
//! # // Create a new Excel file object.
//! # let mut workbook = Workbook::new();
//! # let worksheet = workbook.add_worksheet();
//! #
//! # // Add some sample data.
//! # let data = [
//! # [90, 80, 50, 10, 20, 90, 40, 90, 30, 40],
//! # [20, 10, 90, 100, 30, 60, 70, 60, 50, 90],
//! # [10, 50, 60, 50, 20, 50, 80, 30, 40, 60],
//! # [10, 90, 20, 40, 10, 40, 50, 70, 90, 50],
//! # [70, 100, 10, 90, 10, 10, 20, 100, 100, 40],
//! # [20, 60, 10, 100, 30, 10, 20, 60, 100, 10],
//! # [10, 60, 10, 80, 100, 80, 30, 30, 70, 40],
//! # [30, 90, 60, 10, 10, 100, 40, 40, 30, 40],
//! # [80, 90, 10, 20, 20, 50, 80, 20, 60, 90],
//! # [60, 80, 30, 30, 10, 50, 80, 60, 50, 30],
//! # ];
//! # worksheet.write_row_matrix(2, 1, data)?;
//! #
//! # // Set the column widths for clarity.
//! # for col_num in 1..=10u16 {
//! # worksheet.set_column_width(col_num, 6)?;
//! # }
//! #
//! # // Add a format. Light red fill with dark red text.
//! # let format1 = Format::new()
//! # .set_font_color("9C0006")
//! # .set_background_color("FFC7CE");
//! #
//! # // Add a format. Green fill with dark green text.
//! # let format2 = Format::new()
//! # .set_font_color("006100")
//! # .set_background_color("C6EFCE");
//! #
//! // Write a conditional format over a non-contiguous range.
//! let conditional_format = ConditionalFormatCell::new()
//! .set_criteria(ConditionalFormatCellCriteria::GreaterThanOrEqualTo)
//! .set_value(50)
//! .set_multi_range("B3:D6 I3:K6 B9:D12 I9:K12")
//! .set_format(format1);
//!
//! worksheet.add_conditional_format(2, 1, 11, 10, &conditional_format)?;
//!
//! // Write another conditional format over the same range.
//! let conditional_format = ConditionalFormatCell::new()
//! .set_criteria(ConditionalFormatCellCriteria::LessThan)
//! .set_value(50)
//! .set_multi_range("B3:D6 I3:K6 B9:D12 I9:K12")
//! .set_format(format2);
//!
//! worksheet.add_conditional_format(2, 1, 11, 10, &conditional_format)?;
//!
//! # // Save the file.
//! # workbook.save("conditional_format.xlsx")?;
//! #
//! # Ok(())
//! # }
//! ```
//!
//! Output file:
//!
//! <img
//! src="https://rustxlsxwriter.github.io/images/conditional_format_multi_range.png">
//!
#![warn(missing_docs)]

mod tests;
Expand Down Expand Up @@ -575,7 +749,7 @@ impl ConditionalFormatCell {
///
/// worksheet.add_conditional_format(2, 1, 11, 10, &conditional_format)?;
///
/// // Invert the duplicate conditional format to show uniques values.
/// // Invert the duplicate conditional format to show unique values.
/// let conditional_format = ConditionalFormatDuplicate::new()
/// .invert()
/// .set_format(format2);
Expand Down

0 comments on commit 1b6f98c

Please sign in to comment.