Search code examples
chartslinechartnovacode-docx

Novacode LineChart type


I have a code that implements a Novacode.LineChart. And the LineChart type which is shown by default is this one:

enter image description here

But I dont want this type of chart, I want it without points, like this:

enter image description here

This is the code where I create the chart:

   LineChart c = new LineChart();
   c.AddLegend(ChartLegendPosition.Bottom, false);
   c.Grouping = Grouping.Stacked;

Anyone knows how can I hide thoose points and show only the lines? Thanks to everyone!!


Solution

  • Your question is shown up while I was searching for the exact same feature. It's probably a bit late but I hope it would be useful for other people in need of this feature.

    My so called answer is not more than a few lines of dirty and unmanageable hack so unless you are not in dire need, I do not recommend to follow this way.

    I also do not know if is it an approved approach here but I prefer to write the solution step by step so it may help you to grasp the concept and use better methods.

    After I have realized that I was unable to use DocX to create a line chart without markers, using currently provided API, I wanted to know what were the differences between actual and desired output. So I saved a copy of .docx file with line chart after I manually edited the chart to expected result.

    Before and after the edit

    As you may already know, a .docx is a container format and essentially comprised of a few different folders and files. You can open it up with a .zip archive extractor. I used 7-Zip for this task and found chart file at location of /word/charts/chart1.xml but this may differ depending on the file, but you can easily figure it out.

    Compared both of chart1.xml files and the difference was, the file without the markers had and extra XML tag with an additional attribute;

    <c:marker>
        <c:symbol val="none" />
    </c:marker>
    

    I had to somehow add this segment of code to chart. I added these up to example code provided by DocX. You can follow up from: DocX/ChartSample.cs at master

    This is where the fun begins. Easy part first.

    using System.Xml;
    using System.Xml.Linq;
    using Xceed.Words.NET;
    
    // Create a line chart.
    var line_chart = new LineChart();
    
    // Create the data.
    var PlaceholderData = ChartData.GenerateRandomDataForLinechart();
    
    // Create and add series
    var Series_1 = new Series("Your random chart with placeholder data");
    Series_1.Bind(PlaceholderData, "X-Axis", "Y-Axis");
    line_chart.AddSeries(Series_1);
    
    // Create a new XmlDocument object and clone the actual chart XML
    XmlDocument XMLWithNewTags = new XmlDocument();
    XMLWithNewTags.LoadXml(line_chart.Xml.ToString());
    

    I've used XPath Visualizer Tool to determine the XPath query, which is important to know because you can't just add the marker tag to somewhere and expect it to work. Why do I tell this? Because I appended marker tag on a random line and expected it to work. Naive.

    // Set a namespace manager with the proper XPath location and alias
    XmlNamespaceManager NSMngr = new XmlNamespaceManager(XMLWithNewTags.NameTable);
    
    string XPathQuery = "/c:chartSpace/c:chart/c:plotArea/c:lineChart/c:ser";
    string xmlns = "http://schemas.openxmlformats.org/drawingml/2006/chart";
    
    NSMngr.AddNamespace("c", xmlns);
    XmlNode NewNode = XMLWithNewTags.SelectSingleNode(XPathQuery, NSMngr);
    

    Now create necessary tags on newly created XML Document object with specified namespace

    XmlElement Symbol = XMLWithNewTags.CreateElement("c", "symbol", xmlns);
    Symbol.SetAttribute("val", "none");
    
    XmlElement Marker = XMLWithNewTags.CreateElement("c", "marker", xmlns);
    Marker.AppendChild(Symbol);
    
    NewNode.AppendChild(Marker);
    

    And we should copy the contents of latest changes to actual XML object. But oops, understandably it is defined as private so it is a read-only object. This is where I thought like "Okay, I've fiddled enough with this. I better find another library" but then decided to go on because reasons.

    Downloaded DocX repo, changed this line to

    get; set;
    

    recompiled, copied Xceed.Words.NET.dll to both projectfolder/packages and projectfolder/projectname/bin/Debug folder and finally last a few lines were

    // Copy the contents of latest changes to actual XML object
    line_chart.Xml = XDocument.Parse(XMLWithNewTags.InnerXml);
    
    // Insert chart into document
    document.InsertChart(line_chart);
    
    // Save this document to disk.
    document.Save();
    

    Is it worth it? I'm not sure but I have learned a few things while working on it. There're probably lots of bad programming practises in this answer so please tell me if you see one. Sorry for meh English.