User Tools

Site Tools


Action disabled: source
blog:2024-09-30_002



2024-09-30 Share: Polar Graph with ZedGraph in C#

Code

  • I was surprised that ZedGraph doesn't support polar graphs out-of-the-box and there are very few examples online. Using this guildline, I created my own polar graph with ZedGraph in C#. I hope that WillKraemer has solved his problem already (4 years passed) and someone else finds my implementation useful.
  • First is the ZedGraphControl initialization:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    myZg = new ZedGraphControl();
    GraphPane myPane = myZg.GraphPane;
     
    // Init lists
    RadarPointList dseries1 = new RadarPointList();
    RadarPointList dseries2 = new RadarPointList();
     
    // Maximize available space in pane
    myPane.Legend.Position = LegendPos.InsideTopLeft;
    myPane.Title.IsVisible = false;
    myPane.XAxis.IsVisible = false;
    myPane.YAxis.IsVisible = false;
    myPane.Border.IsVisible = false;
    myPane.Chart.Border.IsVisible = false;
    myPane.Margin.All = 0;
     
    // Create concentric grid with 30 degrees spacing & add corresponding labels
    for (double i = 0; i < 36; i+=3.0)
    {
        TextObj gridlbs = new TextObj((i * 10.0).ToString("0°"), (radius + 10.0) * Math.Cos((i * 10.0 * Math.PI) / 180.0), (radius + 10.0) * Math.Sin((i * 10.0 * Math.PI) / 180.0));
        gridlbs.FontSpec.Border.IsVisible = false;
        LineObj gridlns = new LineObj(0, 0, radius * Math.Cos((i * 10.0 * Math.PI) / 180.0), radius * Math.Sin((i * 10.0 * Math.PI) / 180.0));
     
        myPane.GraphObjList.Add(gridlbs);
        myPane.GraphObjList.Add(gridlns);
    }
     
    // Draw circular grid, 5 should look okay
    for (double i = (radius / 5.0); i <= radius; i += (radius / 5.0))
    {
        EllipseObj gridcrl = new EllipseObj(-i, i, 2.0 * i, 2.0 * i);
        gridcrl.ZOrder = ZOrder.E_BehindCurves;
        myPane.GraphObjList.Add(gridcrl);
    }
     
    // Make sure the pane is big enough to fit the labels around the polar plot
    myPane.XAxis.Scale.Min = -(radius + 20.0);
    myPane.XAxis.Scale.Max = (radius + 20.0);
    myPane.YAxis.Scale.Min = -(radius + 20.0);
    myPane.YAxis.Scale.Max = (radius + 20.0);
     
    _selectedRadius = radius;
    // Keep X & Y axis in the correct ratio to avoid distorting polar circle
    myZg_Resize((object)"Startup", EventArgs.Empty);
    myZg.Resize += new EventHandler(myZg_Resize);
    myZg.ZoomEvent  += new ZedGraphControl.ZoomEventHandler(myZg_ZoomEvent2);
     
    // Draw snailly curves (example)
    for (int i = 0; i < 360; i++)
    {
        double r = (double)i/360.0 * radius;
        PointPair pt = new PointPair(PointPair.Missing, r, null);
        dseries1.Add(pt);
        PointPair pt2 = new PointPair(PointPair.Missing, radius - r, null);
        dseries2.Add(pt2);
    }
     
    // Curves are somple LineItem
    FirstCurve = myPane.AddCurve("Snail", dseries1, Color.Blue, SymbolType.None);
    SecondCurve = myPane.AddCurve("antiSnail", dseries2, Color.Red, SymbolType.None);
     
    // Rotate the lists to aling with labels
    dseries1.Rotation = 0;
    dseries2.Rotation = 0;
  • I had to make sure that the graph is not distorted when the form/control resizes, so I added this in the Resize Event:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    protected void myZg_Resize(object sender, EventArgs e)
    {
        GraphPane pane = myZg.GraphPane;
        myZg.AxisChange();
        bool IsXMin = ( pane.Rect.Width < pane.Rect.Height ) ? true : false;
        if (IsXMin)
        {  
            // Scale based on X (width)
            pane.XAxis.Scale.Max = (radius + 20.0); pane.XAxis.Scale.Min = -(radius + 20.0);
            double xPixPerUnit = (double)pane.Chart.Rect.Width / (pane.XAxis.Scale.Max - pane.XAxis.Scale.Min);
            pane.YAxis.Scale.Max = (double)pane.Chart.Rect.Height / xPixPerUnit / 2.0;
            pane.YAxis.Scale.Min = -pane.YAxis.Scale.Max;
            myZg.AxisChange();
        }
        else
        {
            // Scale based on Y (height)
            pane.YAxis.Scale.Max = (radius + 20.0); pane.YAxis.Scale.Min = -(radius + 20.0);
            double yPixPerUnit = (double)pane.Chart.Rect.Height / (pane.YAxis.Scale.Max - pane.YAxis.Scale.Min);
            pane.XAxis.Scale.Max = (double)pane.Chart.Rect.Width / yPixPerUnit / 2.0;
            pane.XAxis.Scale.Min = -pane.XAxis.Scale.Max;
            myZg.AxisChange();
        }
    }
  • Also, I decided to block the user from any zooming actions:
    1
    2
    3
    4
    protected void myZg_ZoomEvent2(ZedGraphControl sender, ZoomState oldState, ZoomState newState)
    {
        myZg_Resize("zoomevent", EventArgs.Empty);
    }
  • The output looks like the picture below:

TAGS

  • 2 person(s) visited this page until now.

blog/2024-09-30_002.txt · Last modified: 2024/09/30 16:04 (external edit)