Search code examples
c#plotzedgraph

Unable to draw a vertical line in ZedGraph


The following source code is supposed to draw a vertical line using the ZedGraph library.

AddVerticalLine() function is supposed to be able to handle both linear scale and log scale.

However, for some reason it is unable to draw the line, and I am seeing a blank graph pane.

What am I doing incorrectly?

enter image description here

class Program
{
    static void Main(string[] args)
    {
        DataPlotter plotter = new DataPlotter();
        plotter.IsLogX = true;
        plotter.IsLogY = true;
        
        plotter.AddVerticalLine("Vertical Line at 10^2.2", 2.2);
        plotter.ShowDialog();
    }
}
using ZedGraph;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Drawing2D;
using System.IO;
using System.Windows.Forms;

public class DataPlotter
{
    private GraphPane myPane_;
    private int curveCounter_ = 0;

    #region [Single line properties]
    public ZedGraphControl ZedGraphCtrl { get; set; }
    public SymbolType DefaultSymbolType { get; set; } = SymbolType.Circle;
    public float DefaultSymbolSize { get; set; } = 7;
    public Color DefaultLineColor { get; set; } = Color.Blue;

    public DashStyle DefaultLineDashStyle { get; set; } = DashStyle.Solid;
    public float DefaultLineWidth { get; set; } = 1;

    public Color? CurveColor { get; set; }
    public SymbolType? CurveSymbolType { get; set; }
    public float? CurveSymbolSize { get; set; }
    public DashStyle? CurveDashStyle { get; set; }
    #endregion

    #region [Multi-line properties]
    public string ImageTitle
    {
        get => myPane_.Title.Text;
        set => myPane_.Title.Text = value;
    }

    public string XAxisTitle
    {
        get => myPane_.XAxis.Title.Text;
        set => myPane_.XAxis.Title.Text = value;
    }

    public string YAxisTitle
    {
        get => myPane_.YAxis.Title.Text;
        set => myPane_.YAxis.Title.Text = value;
    }

    public int Width
    {
        get => ZedGraphCtrl.Width;
        set => ZedGraphCtrl.Width = value;
    }

    public int Height
    {
        get => ZedGraphCtrl.Height;
        set => ZedGraphCtrl.Height = value;
    }

    public bool IsLogX
    {
        get => myPane_.XAxis.Type == AxisType.Log;
        set => myPane_.XAxis.Type = value ? AxisType.Log : AxisType.Linear;
    }

    public bool IsLogY
    {
        get => myPane_.YAxis.Type == AxisType.Log;
        set => myPane_.YAxis.Type = value ? AxisType.Log : AxisType.Linear;
    }

    private bool _isSymbolVisible = true;

    public bool IsSymbolVisible
    {
        get => _isSymbolVisible;
        set
        {
            _isSymbolVisible = value;
            foreach (CurveItem curve in myPane_.CurveList)
            {
                if (curve is LineItem lineItem)
                {
                    lineItem.Symbol.IsVisible = value;
                }
            }
            ZedGraphCtrl.Invalidate();
        }
    }

    public bool IsLegendVisible
    {
        get => myPane_.Legend.IsVisible;
        set
        {
            myPane_.Legend.IsVisible = value;
            ZedGraphCtrl.Invalidate();
        }
    }
    #endregion

    #region [ctor]
    public DataPlotter()
    {
        ZedGraphCtrl = new ZedGraphControl();
        ZedGraphCtrl.Size = GetDisplayScreenResolution();
        myPane_ = ZedGraphCtrl.GraphPane;

        ImageTitle = "Image Title";
        XAxisTitle = "X Axis";
        YAxisTitle = "Y Axis";
        IsLogX = false;
        IsLogY = false;
        IsLegendVisible = true;
        IsSymbolVisible = false;
        ZedGraphCtrl.Dock = System.Windows.Forms.DockStyle.Fill;
    }
    #endregion



    // Method to bring the specified curve to the front
    private void BringCurveToFront(LineItem curve)
    {
        myPane_.CurveList.Remove(curve);
        myPane_.CurveList.Insert(0, curve);
        ZedGraphCtrl.Invalidate();
    }

    public void SavePlot(string outputPath, string outputFileName)
    {
        try
        {
            if (!Directory.Exists(outputPath))
            {
                Directory.CreateDirectory(outputPath);
            }

            string fullPath = Path.Combine(outputPath, outputFileName);

            ZedGraphCtrl.AxisChange();
            ZedGraphCtrl.Invalidate();

            using (Bitmap bmp = new Bitmap(ZedGraphCtrl.Width, ZedGraphCtrl.Height))
            {
                ZedGraphCtrl.DrawToBitmap(bmp, new Rectangle(0, 0, ZedGraphCtrl.Width, ZedGraphCtrl.Height));
                bmp.Save(fullPath, ImageFormat.Png);
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("An error occurred while saving the plot: " + ex.Message);
        }
    }

    private Size GetDisplayScreenResolution()
    {
        // PrimaryScreen represents the primary display monitor
        Rectangle resolution = Screen.PrimaryScreen.Bounds;

        // Create a Size structure to hold the width and height of the primary screen
        Size screenSize = new Size(resolution.Width, resolution.Height);

        return screenSize;
    }

    public void Clear()
    {
        myPane_.CurveList.Clear();
        ZedGraphCtrl.Invalidate();
    }

    public void ShowDialog()
    {
        DataPlotterForm f = new DataPlotterForm();
        ZedGraphCtrl.Dock = DockStyle.Fill;
        f.Controls.Add(ZedGraphCtrl);
        f.WindowState = FormWindowState.Maximized;
        f.ShowDialog();
    }


    #region [AddVerticalLine]
    public void AddVerticalLine(string curveName, double xValue, Color? curveColor = null)
    {
        Color actualCurveColor = curveColor ?? DefaultLineColor;

        if (IsLogX)
        {
            xValue = Math.Pow(10, xValue);
        }

        PointPairList list = new PointPairList();
        double minY = myPane_.YAxis.Scale.Min;
        double maxY = myPane_.YAxis.Scale.Max;

        if (myPane_.YAxis.Type == AxisType.Log)
        {
            minY = Math.Max(minY, 1.0); 
            maxY = Math.Max(maxY, minY * 10); 
        }

        list.Add(xValue, minY); 
        list.Add(xValue, maxY); 

        LineItem myCurve = myPane_.AddCurve(curveName, list, actualCurveColor, SymbolType.None);

        myCurve.Line.IsVisible = true;
        myCurve.Line.Style = DashStyle.Solid;
        myCurve.Line.Width = 2.0F;

        myCurve.Symbol.IsVisible = false;

        ZedGraphCtrl.Invalidate();
    }
    #endregion
}

Solution

  • As suggested by @dlr the line is being plotted, you just can't see it because your XScale is not set (so it defaults from 0.0 to 1.2) and your line is being plotted in X=10^2.2.

    You can modify AddVerticalLine method like this:

    public void AddVerticalLine(string curveName, double xValue, Color? curveColor = null)
    {
        Color actualCurveColor = curveColor ?? DefaultLineColor;
    
        if (IsLogX)
        {
            xValue = Math.Pow(10, xValue);
        }
        // IsLogX is true, so xValue becomes 10^2.2 (~158.49)
        // But your XAxis is being displayed from 0.0 to 1.0
        // So the line is plotted correctly, it's just out of scale
        // To fix we just change the scale of the graph
        myPane_.XAxis.Scale.Min = xValue - 10.0d;
        myPane_.XAxis.Scale.Max = xValue + 10.0d;
        ////////////////////////////////////////////////////
    
    
        PointPairList list = new PointPairList();
        double minY = myPane_.YAxis.Scale.Min;
        double maxY = myPane_.YAxis.Scale.Max;
    
        if (myPane_.YAxis.Type == AxisType.Log)
        {
            minY = Math.Max(minY, 1.0);
            maxY = Math.Max(maxY, minY * 100);
        }
    
    
        list.Add(xValue, minY);
        list.Add(xValue, maxY);
    
        LineItem myCurve = myPane_.AddCurve(curveName, list, actualCurveColor, SymbolType.None);
    
        myCurve.Line.IsVisible = true;
        myCurve.Line.Style = DashStyle.Solid;
        myCurve.Line.Width = 2.0F;
    
        myCurve.Symbol.IsVisible = false;
    
        ZedGraphCtrl.Invalidate();
    }