Compact Number Formatting Missing for Negative Axis Intervals

When using compact number formatting (K, M, B) on chart axes, positive axis intervals are formatted correctly (e.g., 1.2K, 3.4M, 2.1B), but negative axis intervals display unformatted values (e.g., -1200, -3400000) instead of compact forms like -1.2K, -3.4M, or -2.1B. And this issue is occurring for both excel and ppt

Added aspose java programs below

Excel:

    public static void main(String[] args) {
        try {
            // Create a new workbook
            Workbook workbook = new Workbook();

            // Get the first worksheet
            Worksheet worksheet = workbook.getWorksheets().get(0);
            Cells cells = worksheet.getCells();

            // Add headers
            cells.get("A1").setValue("Category");
            cells.get("B1").setValue("Value");

            // Sample data for waterfall chart
            String[] categories = {"Start", "Q1 Growth", "Q2 Loss", "Q3 Growth", "Q4 Loss"};
            double[] values = {-15000000, -2500000, 1800000, 32000000, -9500000};

            // Populate data with compact formatting
            for (int i = 0; i < categories.length; i++) {
                cells.get(i + 2, 0).setValue(categories[i]);
                cells.get(i + 2, 1).setValue(values[i]);
                
                Style style = cells.get(i + 2, 1).getStyle();
                style.setCustom("#,##0,,.0\"B\";[>=1000000]#,##0,.0\"M\";#,##0");
                cells.get(i + 2, 1).setStyle(style);
            }

            // Create waterfall chart
            int chartIndex = worksheet.getCharts().add(com.aspose.cells.ChartType.WATERFALL, 8, 2, 20, 12);
            Chart chart = worksheet.getCharts().get(chartIndex);

            // Set data range for chart
            chart.getNSeries().add("B2:B7", true);
            chart.getNSeries().setCategoryData("A2:A7");

            // Configure chart appearance
            chart.getTitle().setText("Simple Waterfall Chart");
            chart.setShowLegend(false);

            // Show data labels
            chart.getNSeries().get(0).getDataLabels().setShowValue(true);
            
            // Configure Y-axis to use compact number formatting
            Axis valueAxis = chart.getValueAxis();
            valueAxis.getTickLabels().setNumberFormat("[>999999999]#.00,,,\"B\";[>999999] #.00,,\"M\"; #.00");
            
            // Save the workbook
            workbook.save("simple_waterfall_chart.xlsx", SaveFormat.XLSX);
            System.out.println("Simple waterfall chart created successfully: waterfall_chart.xlsx");

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Ppt:

public static void main(String[] args) {
    Presentation pres = new Presentation();
    ISlide slide = pres.getSlides().get_Item(0);

    IChart chart = slide.getShapes().addChart(ChartType.Waterfall, 50, 50, 600, 400);
    IChartDataWorkbook wb = chart.getChartData().getChartDataWorkbook();

    // Clear default series/categories
    chart.getChartData().getSeries().clear();
    chart.getChartData().getCategories().clear();

    // Sample categories
    String[] cats = {"Previous Year", "January", "March", "August", "October", "Current Year"};
    for (int i = 0; i < cats.length; i++) {
      chart.getChartData().getCategories().add(wb.getCell(0, i + 1, 0, cats[i]));
    }

    // Sample values
    double[] vals = {83222344.5, 112333333.5, -711111333.5, 2.5, 8.5, 3.5};
    IChartSeries series = chart.getChartData().getSeries().add(wb.getCell(0, 0, 1, "Series1"), chart.getType());
    for (int i = 0; i < vals.length; i++) {
      IChartDataPoint dp = series.getDataPoints().addDataPointForWaterfallSeries(
          wb.getCell(0, i + 1, 1, vals[i]));
      if (i == 0 || i == vals.length - 1) {
        dp.setSetAsTotal(true); // set endpoints as totals
      }
    }
    
    // To Set Max and Min bound
    IAxis yAxis = chart.getAxes().getVerticalAxis();
    yAxis.setNumberFormat("[>999999999]#.00,,,\"B\";[>999999]#.00,,\"M\";#.00");    

    series.setShowConnectorLines(true);

    pres.save("waterfall_slides.pptx", SaveFormat.Pptx);
    pres.dispose();
  }

waterfall-excel.png (18.5 KB)

waterfall-ppt.png (78.8 KB)

@Shivapriya

Issue Summary

  • Positive axis labels are displayed with the compact format (1.2K, 3.4M, 2.1B).
  • Negative axis labels appear as raw numbers (‑1200, ‑3400000, …).

The same behaviour is observed in both:

Product Code snippet used Axis configuration
Aspose.Cells (Excel) valueAxis.getTickLabels().setNumberFormat("[>999999999]#.00,,,\"B\";[>999999] #.00,,\"M\"; #.00"); Axis valueAxis = chart.getValueAxis();
Aspose.Slides (PowerPoint) yAxis.setNumberFormat("[>999999999]#.00,,,\"B\";[>999999]#.00,,\"M\";#.00"); IAxis yAxis = chart.getAxes().getVerticalAxis();

The root cause is that the number‑format string does not contain a separate pattern for negative values.
When a format string has only one or two sections, Excel/PowerPoint (and consequently Aspose) automatically uses the default “‑#,##0” pattern for negatives.
Therefore the compact pattern is applied only to the positive part of the axis.


Solution: Define a negative‑number section in the format string

Excel/PowerPoint number‑format strings can have up to four sections, separated by semicolons (;):

positive ; negative ; zero ; text

To get compact formatting for both positive and negative values you must repeat the same conditional blocks for the negative section (and optionally for zero).

1. Aspose.Cells (Excel)

// ------------------------------------------------------------------
// Build a format that works for both positive and negative numbers
// ------------------------------------------------------------------
String compactFormat =
        // Positive numbers
        "[>999999999]#.00,,,\"B\";[>999999]#.00,,\"M\";#.00" +
        // Negative numbers – same rules, just prepend a minus sign
        ";[>999999999]-#.00,,,\"B\";[>999999]-#.00,,\"M\";-#.00" +
        // Zero (optional, you can omit it)
        ";0";

// Apply it to the value axis
Axis valueAxis = chart.getValueAxis();
valueAxis.getTickLabels().setNumberFormat(compactFormat);

2. Aspose.Slides (PowerPoint)

// ------------------------------------------------------------------
// Same format string, but set on the vertical axis of the chart
// ------------------------------------------------------------------
String compactFormat =
        // Positive numbers
        "[>999999999]#.00,,,\"B\";[>999999]#.00,,\"M\";#.00" +
        // Negative numbers
        ";[>999999999]-#.00,,,\"B\";[>999999]-#.00,,\"M\";-#.00" +
        // Zero (optional)
        ";0";

IAxis yAxis = chart.getAxes().getVerticalAxis();
yAxis.setNumberFormat(compactFormat);

Result – both charts will now display:

-1.2K   -3.4M   -2.1B   …   1.2K   3.4M   2.1B

Why the original code did not work

valueAxis.getTickLabels().setNumberFormat("[>999999999]#.00,,,\"B\";[>999999] #.00,,\"M\"; #.00");
  • The string contains only three sections (positive; negative; zero) but the negative section is empty – Excel/PowerPoint falls back to its default negative format.

  • The same applies to the Slides example.

By explicitly providing a negative‑section (the part after the second semicolon) you tell the rendering engine exactly how negatives should look.


Additional Tips

Topic Recommendation
Zero values If you want 0 to appear as 0 (or ‑0) add the fourth section (e.g., ;0).
Data labels chart.getNSeries().get(0).getDataLabels().setNumberFormat(compactFormat); will also apply the same compact format to the data‑point labels.
Testing Open the generated file in the corresponding Office application to verify the format. The format string is stored verbatim, so any typo will be reflected as “####”.
Documentation Aspose.Cells – Chart Axis Number Formatting
Aspose.Slides – Axis Number Format

If you still see raw negatives

  1. Confirm the exact string saved in the file (inspect the XML in the .xlsx / .pptx file).
  2. Clear any previously applied style on the cells (for Excel) that might override the axis format.
  3. As a last resort, manually set the tick‑label text via valueAxis.getTickLabels().setCustomLabelData(...) (Slides) or chart.getValueAxis().getTickLabels().setCustomLabels(...) (Cells).

TL;DR

Add a negative‑section to the axis number‑format string.
The compact format will then be applied to both positive and negative tick values.

If you need further assistance or a sample project, feel free to let us know!

@Shivapriya,

Thanks for the screenshots and code snippet.

I tested your scenario/case using your sample code snippet regarding rendering Excel spreadsheet using Aspose.Cells for Java. The reason for your mentioned issue is simple: it is due to your custom numbers formatting string that you are setting to the ticket labels on chart value axes, which is not right. Your formatted string is only setting positive axis intervals. That’s why for negative axis intervals, it will still display values e.g., -1200 , -3400000. When you set the custom numbers format as "#,##0,,.0\"B\";[>=1000000]#,##0,.0\"M\";#,##0" that means “#,##0” will always be applied to negative numbers. See the display value in cell B3 (in MS Excel) for example.

e.g., You can try setting the custom numbers formatting for testing as:
valueAxis.getTickLabels().setNumberFormat("#,##0,,.00\"B\";[>=1000000]#,##0,.00\"M\";#,##00,.00\"M\"");

Please note, it’s better that you should find your expected custom numbers format in MS Excel (manually) first (as you maybe need to set different formats for negative numbers) and then use the same custom numbers formatting string when setting the format for tick labels accordingly.

@Shivapriya,
I was unable to apply the expected number format for axis values using Aspose.Slides for Java.

We have opened the following new ticket(s) in our internal issue tracking system and will consider your requirements according to the terms mentioned in Free Support Policies.

Issue ID(s): SLIDESJAVA-39767

@Shivapriya,
Our developers have reviewed your requirements. Unfortunately, PowerPoint charts do not support complex number formats. The only thing that will definitely work is applying a single scale to the entire axis, for example, millions or billions.

Code example:

IAxis yAxis = chart.getAxes().getVerticalAxis();
yAxis.setNumberFormatLinkedToSource(false);
yAxis.setNumberFormat("#,##0\"M\";-#,##0\"M\";0");
yAxis.setDisplayUnit(DisplayUnitType.Millions);

The axis will look as follows: