C# draws statistical chart [radar chart] in Pdf (taking pentagon as an example)

Preface

Tools: PdfSharpCore or Pdfsharp
Knowledge: Basic trigonometric function
ideas: Draw coordinates and determine points --------> Draw multiple regular polygons with gradient radius -------> Determine the value of the radar chart based on the data Location

StepOne: Draw a regular pentagon

First draw an auxiliary coordinate axis,
and then use trigonometric functions to confirm the coordinates of each point. Here is a picture to show.
Insert image description here
Because the default origin of pdfsharp is the upper left corner, and the positive value is the fourth quadrant,
in order to better determine the coordinates of each point ,
you need to move the position of the origin and rotate the coordinate axis to set it to familiar common coordinates. Fortunately,
pdfsharpcore provides a ready-made method, and it is relatively simple to adjust
. Code:

const double PAI = Math.PI;
        static void Main(string[] args)
        {
    
    
            PdfDocument doc = new PdfDocument();

            PdfPage page = new PdfPage(doc);

            XGraphics graphics = XGraphics.FromPdfPage(page);
		    //这个方法用来移动坐标原点的位置
            graphics.TranslateTransform(200, 200);
			//这个方法用来旋转坐标轴
            graphics.RotateTransform(180);

            graphics.DrawLine(new XPen(XBrushes.AliceBlue), new XPoint(-200,0), new XPoint(200,0));

            graphics.DrawLine(new XPen(XBrushes.AliceBlue), new XPoint(0,200), new XPoint(0,-200));


            double radius = 60;

            XPoint[] points = new XPoint[6]
            {
    
    
                new XPoint(){
    
     X = 0,Y = radius },
                new XPoint(){
    
     X = Math.Sin(72*PAI/180)*radius,Y = Math.Sin(18*PAI/180)*radius },
                new XPoint(){
    
     X = Math.Sin(36*PAI/180)*radius,Y = -1*Math.Sin(54*PAI/180)*radius },
                new XPoint(){
    
     X = -1*Math.Sin(36*PAI/180)*radius,Y = -1*Math.Sin(54*PAI/180)*radius },
                new XPoint(){
    
     X = -1*Math.Sin(72*PAI/180)*radius,Y = Math.Sin(18*PAI/180)*radius},
                new XPoint(){
    
     X = 0,Y = radius }
            };

            graphics.DrawLines(new XPen(XColors.RoyalBlue),points);

            graphics.Save();


            doc.AddPage(page);

            doc.Save("../../../wdnmd.pdf");

You can get it after running
Insert image description here

StepTwo: Take the origin as the center and draw several pentagons with equal radii.

With the above code, you only need to prepare a radius array
as follows:

const double PAI = Math.PI;
        static void Main(string[] args)
        {
    
    
            PdfDocument doc = new PdfDocument();

            PdfPage page = new PdfPage(doc);

            XGraphics graphics = XGraphics.FromPdfPage(page);

            graphics.TranslateTransform(200, 200);

            graphics.RotateTransform(180);

            graphics.DrawLine(new XPen(XBrushes.AliceBlue), new XPoint(-200,0), new XPoint(200,0));

            graphics.DrawLine(new XPen(XBrushes.AliceBlue), new XPoint(0,200), new XPoint(0,-200));

            //等差/或等比都行
            double[] radius_list = new double[5]
            {
    
    
              60,75,90,105,120
            };

            radius_list.ToList<double>().ForEach(item=> {
    
    

                XPoint[] points = new XPoint[6]
                {
    
    
                     new XPoint(){
    
     X = 0,Y = item },
                     new XPoint(){
    
     X = Math.Sin(72*PAI/180)*item,Y = Math.Sin(18*PAI/180)*item },
                     new XPoint(){
    
     X = Math.Sin(36*PAI/180)*item,Y = -1*Math.Sin(54*PAI/180)*item },
                     new XPoint(){
    
     X = -1*Math.Sin(36*PAI/180)*item,Y = -1*Math.Sin(54*PAI/180)*item },
                     new XPoint(){
    
     X = -1*Math.Sin(72*PAI/180)*item,Y = Math.Sin(18*PAI/180)*item},
                     new XPoint(){
    
     X = 0,Y = item }
                };

                graphics.DrawLines(new XPen(XColors.RoyalBlue), points);

            });

            graphics.Save();


            doc.AddPage(page);

            doc.Save("../../../wdnmd.pdf");

        }

Insert image description here

StepThree: fill in data

Suppose there is a set of data as follows

[100,20,66,33,55]
[44,77,30,100,88]
[66,88,77,50,20]

Then you have to choose one of the following two methods
: 1. Fixed vertex value
2. Use the maximum value of the alignment in the group as the vertex value (can draw more fully)

The second option is chosen here. The
next step is to determine the position of each point in the group in the graph
. Because the point must be on the line connecting the origin to the polygon vertex, and the length is self/Max*R
, the specific coordinates of the point can be determined.

The calculation steps are omitted directly here, and the coordinate points of the three groups are obtained as

[(0,100/100*R),
(-1*20/88*R*sin72,20/88*R*sin18),
(-1*66/77*R*sin36,-1*66/77*R*sin54),
(33/100*R*sin36,-1*33/100*R*sin54),
(55/88*R*sin72,55/88*R*sin18)
]
[(0,44/100*R),
(-1*77/88*R*sin72,77/88*R*sin18),
(-1*30/77*R*sin36,-1*30/77*R*sin54),
(100/100*R*sin36,-1*100/100*R*sin54),
(88/88*R*sin72,88/88*R*sin18)
]
[(0,66/100*R),
(-1*88/88*R*sin72,88/88*R*sin18),
(-1*77/77*R*sin36,-1*77/77*R*sin54),
(50/100*R*sin36,-1*50/100*R*sin54),
(20/88*R*sin72,20/88*R*sin18)
]

StepFour: Draw polygons

After determining the coordinate position of each point, just call the graphics.DrawPolygon method directly.
The code is as follows:

const double PAI = Math.PI;
        static void Main(string[] args)
        {
    
    
            PdfDocument doc = new PdfDocument();

            PdfPage page = new PdfPage(doc);

            XGraphics graphics = XGraphics.FromPdfPage(page);

            graphics.TranslateTransform(200, 200);

            graphics.RotateTransform(180);

            graphics.DrawLine(new XPen(XBrushes.AliceBlue), new XPoint(-200,0), new XPoint(200,0));

            graphics.DrawLine(new XPen(XBrushes.AliceBlue), new XPoint(0,200), new XPoint(0,-200));


            /* double radius = 60;

             XPoint[] points = new XPoint[6]
             {
                 new XPoint(){ X = 0,Y = radius },
                 new XPoint(){ X = Math.Sin(72*PAI/180)*radius,Y = Math.Sin(18*PAI/180)*radius },
                 new XPoint(){ X = Math.Sin(36*PAI/180)*radius,Y = -1*Math.Sin(54*PAI/180)*radius },
                 new XPoint(){ X = -1*Math.Sin(36*PAI/180)*radius,Y = -1*Math.Sin(54*PAI/180)*radius },
                 new XPoint(){ X = -1*Math.Sin(72*PAI/180)*radius,Y = Math.Sin(18*PAI/180)*radius},
                 new XPoint(){ X = 0,Y = radius }
             };

             graphics.DrawLines(new XPen(XColors.RoyalBlue),points);*/

            //等差/或等比都行
            double[] radius_list = new double[5]
            {
    
    
              60,75,90,105,120
            };

            radius_list.ToList<double>().ForEach(item=> {
    
    

                XPoint[] points = new XPoint[6]
                {
    
    
                     new XPoint(){
    
     X = 0,Y = item },
                     new XPoint(){
    
     X = Math.Sin(72*PAI/180)*item,Y = Math.Sin(18*PAI/180)*item },
                     new XPoint(){
    
     X = Math.Sin(36*PAI/180)*item,Y = -1*Math.Sin(54*PAI/180)*item },
                     new XPoint(){
    
     X = -1*Math.Sin(36*PAI/180)*item,Y = -1*Math.Sin(54*PAI/180)*item },
                     new XPoint(){
    
     X = -1*Math.Sin(72*PAI/180)*item,Y = Math.Sin(18*PAI/180)*item},
                     new XPoint(){
    
     X = 0,Y = item }
                };

                graphics.DrawLines(new XPen(XColors.RoyalBlue), points);

            });


		
			//假设以下是数据
            List<double[]> doubles = new List<double[]>()
            {
    
    
                new double[]{
    
    100,20,66,33,55},
                new double[]{
    
    44,77,30,100,88},
                new double[]{
    
     66, 88, 77, 50, 20 }
            };

			//寻找数据中每一列的最大值
            double maxOne = 0;
            double maxTwo = 0;
            double maxThree = 0;
            double maxFour = 0;
            double maxFive = 0;
            foreach(double[] temp in doubles){
    
    
                maxOne = Math.Max(temp[0],maxOne);
                maxTwo = Math.Max(temp[1], maxTwo);
                maxThree = Math.Max(temp[2], maxThree);
                maxFour = Math.Max(temp[3], maxFour);
                maxFive = Math.Max(temp[4], maxFive);
            }

            doubles.ForEach(item => {
    
    
				//根据同上的三角函数,确定各点的坐标
                XPoint[] points = new XPoint[6]
                {
    
    
                    new XPoint(0,item[0]/maxOne*120),
                    new XPoint(-1*item[1]/maxTwo*120*Math.Sin(72*PAI/180),item[1]/maxTwo*120*Math.Sin(18*PAI/180)),
                    new XPoint(-1*item[2]/maxThree*120*Math.Sin(36*PAI/180),-1*item[2]/maxThree*120*Math.Sin(54*PAI/180)),
                    new XPoint(item[3]/maxFour*120*Math.Sin(36*PAI/180),-1*item[3]/maxFour*120*Math.Sin(54*PAI/180)),
                    new XPoint(item[4]/maxFive*120*Math.Sin(72*PAI/180),item[4]/maxFive*120*Math.Sin(18*PAI/180)),
                    new XPoint(0,item[0]/maxOne*120)
                };

                graphics.DrawPolygon(new XPen(XColors.Red, 1), points);
            });

            
            


            graphics.Save();


            doc.AddPage(page);

            doc.Save("../../../wdnmd.pdf");



        }

The effect is as follows
Insert image description here

StepFive: Summary

PdfSharp/Core's drawing methods are very rich and can be used to draw more precise graphics.
At the same time, if you want to draw further, it is best to fix the data Model and create a fixed format, which can also be used to display more information.
Finally, please note that the calculation of coordinate points requires the use of some trigonometric functions, please don’t forget them.

Guess you like

Origin blog.csdn.net/jamenu/article/details/127646622