Search code examples
c#openxmlepplusepplus-4

EPPlus Line chart cannot align axis to tick marks


I'm using C# and EPPlus to import csv files and make line charts. Everything works great except:

In Excel, aligning the axis position "on tick marks" is easy but I cannot figure out how to do it in C#/EPPlus.

It may have something to do with the XAxis importing(?) as a Value axis rather than a Category axis, as explained in the RemoveGridlines() function.

Pics for reference

Link to sample.csv

Lots of comments in the code:

using System;
using System.IO;
using System.Xml;
using System.Drawing;
using OfficeOpenXml;
using OfficeOpenXml.Drawing.Chart;

namespace ConsoleApp1
{    
    class Program
    {
        static void Main(string[] args)
        {
            // Create the xlsx and add a sheet
            FileInfo book = new FileInfo(@"C:\Users\Meter2\Desktop\test.xlsx");
            ExcelPackage package = new ExcelPackage(book);
            ExcelWorksheet sheet = package.Workbook.Worksheets.Add("sheet1");

            // Load the csv file into the workbook/sheet
            FileInfo csvFileName = new FileInfo(@"C:\Users\Meter2\Desktop\sample.csv");

            var csvText = sheet.Cells.LoadFromText(csvFileName, format);

            // This is probably where the fix needs to be but I can't figure it out.
            var chart = sheet.Drawings.AddChart("chart1", eChartType.Line);
            for (int col = 1; col <= 6; col++)
            {
                chart.Series.Add(csvText.Offset(1, col, 32, 1), csvText.Offset(1, 0, 32, 1));
            }

            chart.Title.Text = "Chart Title";
            chart.SetSize(800, 400);
            chart.DisplayBlanksAs = eDisplayBlanksAs.Gap;
            chart.Legend.Remove();

            chart.XAxis.MajorTickMark = eAxisTickMark.In;
            chart.XAxis.MinorTickMark = eAxisTickMark.None;
            chart.XAxis.MajorUnit = 2;
            chart.XAxis.MinValue = 0;
            chart.XAxis.MaxValue = 32;
            chart.XAxis.CrossesAt = -1.4;
            chart.XAxis.Title.Text = "Frequency (MHz)";
            chart.XAxis.Title.Font.Size = 12;

            chart.YAxis.MinorTickMark = eAxisTickMark.None;
            chart.YAxis.MajorUnit = 0.2;
            chart.YAxis.MinValue = -1.4;
            chart.YAxis.MaxValue = 1.4;
            chart.YAxis.Format = "0.0";
            chart.YAxis.Title.Text = "Error (dB)";
            chart.YAxis.Title.Font.Size = 11;

            RemoveGridlines(chart);

            package.Save();
        }

        // I extracted this from StackOverflow user https://stackoverflow.com/users/1324284/ernie
        //    from this question: https://stackoverflow.com/questions/40804346/epplus-charts-without-gridlines-in-c-sharp-its-a-web-application 
        static void RemoveGridlines(ExcelChart chart)
        {
            var chartXml = chart.ChartXml;
            var nsuri = chartXml.DocumentElement.NamespaceURI;
            var nsm = new XmlNamespaceManager(chartXml.NameTable);
            nsm.AddNamespace("c", nsuri);

            //me// uncommented, this part removes the gridlines, hence XAxis is a Value Axis
            //ernie// XY Scatter plots have 2 value axis and no category
            var valAxisNodes = chartXml.SelectNodes("c:chartSpace/c:chart/c:plotArea/c:valAx", nsm);
            if (valAxisNodes != null && valAxisNodes.Count > 0)
            {
                foreach (XmlNode valAxisNode in valAxisNodes)
                {
                    var major = valAxisNode.SelectSingleNode("c:majorGridlines", nsm);
                    if (major != null)
                        valAxisNode.RemoveChild(major);

                    var minor = valAxisNode.SelectSingleNode("c:minorGridlines", nsm);
                    if (minor != null)
                        valAxisNode.RemoveChild(minor);
                }
            }

            //me// whether commented or not, nothing happens to the gridlines, hence XAxis is not a Category Axis 
            //ernie// Other charts can have a category axis
            var catAxisNodes = chartXml.SelectNodes("c:chartSpace/c:chart/c:plotArea/c:catAx", nsm);
            if (catAxisNodes != null && catAxisNodes.Count > 0)
            {
                foreach (XmlNode catAxisNode in catAxisNodes)
                {
                    var major = catAxisNode.SelectSingleNode("c:majorGridlines", nsm);
                    if (major != null)
                        catAxisNode.RemoveChild(major);

                    var minor = catAxisNode.SelectSingleNode("c:minorGridlines", nsm);
                    if (minor != null)
                        catAxisNode.RemoveChild(minor);
                }
            }
        }
    }
}

Solution

  • All you should have to do is add this line when setting the YAxis:

    chart.YAxis.CrossBetween = eCrossBetween.MidCat;
    

    Which gives me this:

    enter image description here