Article Options
Recently Viewed
Premium Sponsor
Premium Sponsor

 »  Home  »  .NET Newbie  »  Chart Success Part 5 - Line Graph  »  Drawing The Line(s)
 »  Home  »  Windows Development  »  Graphics  »  Chart Success Part 5 - Line Graph  »  Drawing The Line(s)
Chart Success Part 5 - Line Graph
by Ged Mead | Published  06/06/2006 | .NET Newbie Graphics | Rating:
Drawing The Line(s)

Calculate Lengths

   The code for drawing the lines will be contained in a separate procedure called DrawTheLine.   The first task is to calculate the length of each segment of the overall graph line.   By this I mean that each month's sales figure is to be represented by a line segment; we need to calculate how much of the available width of the PictureBox is to be given to each of those monthly segments.

   It's fairly simple math:

           '  Calculate length of baseline drawn by the previous procedure
        BaseLineLength = PBLineChart.Width - (LeftMargin + RightMargin)
        '  Calculate the width of each line segment
        LineWidth = (BaseLineLength / Sales.Length)

   Sales.Length is of course the number of elements in the array that holds the Sales figures.  We work out the total available width of the baseline and divide it by the number of segments that we want to fit into it.

Calculate Vertical Scale

    The line segments that we draw are going to rise or fall to represent the rise or fall in sales figures from month to month.   These values are fixed.   However, the length of the vertical axis can be changed (as we demonstrated previously by resizing the form and seeing that the PictureBox size also changed).         In order to ensure that the height rise or fall is drawn proportionately to the current size of the PictureBox we must calculate the scale, i.e. how many Sales are represented by a single pixel up that vertical line.    This measurement will be used to ensure that the line segments are drawn proportionately within the overall height available.

   This may sound complicated.  It really isn’t and the calculation itself is very simple.  We divide the total number of pixels in that vertical line by the maximum value we set for the axis:

    Dim VertScale As Double
   VertScale = VertLineLength / 1000
  

    and that provides us with a scaling value that will be valid no matter how many times we resize the form.

Create and Draw the First Line Segment

   The first line segment will of course represent the sales figure for Jan (which will be start of the line segment) and the sales figure for Feb (the end of the line segment).  We know that the start and end points of lines each have an X and a Y value.   The best way to draw the series of line segments is to create four variables, one each for the two X values and one each for the two Y values.

   Here's the code that does that:

        Dim XPosStart As Integer = CInt(LeftMargin + 30)
        Dim XPosEnd As Integer = CInt(XPosStart + LineWidth)

        Dim YPosStart As Integer = CInt(Sales(0) * VertScale)
        Dim YPosEnd As Integer = CInt(Sales(1) * VertScale)

   The names of the four variables are self-explanatory.   The arithmetic is straightforward:

XPosStart is the X value of the start of the line segment and is placed 30 pixels in from the left margin.   

XPosEnd is the X value of the end of the line segment and is calculated by adding the line segment width (or length, if you prefer to think of it that way) to the start point value.

YPosStart is the Y value of the start of the line segment.  It is equal to the value of the first Sales figure (Jan) multiplied by that vertical scaling factor that we created a moment ago.

YPosEnd is the Y value of the end of the line segment.  It is equal to the value of next Sales figure, which in the code above happens to be Feb's figure, the second element in the array.

The Inverted and Disappearing Lines Problem

   You would expect that we could now simply draw a set of lines one after the other using the standard DrawLine method.   We could, but you wouldn't get the results you expected.   The reason is that when we view graphs we expect the start point of the graph (that is, Point 0,0) to be in the bottom left hand corner.   This is standard and you will be familiar with this expectation, I'm sure. 

  The problem is that the PictureBox control has its 0,0 point in the Top Left corner.   So if we were to draw a line, say from 0,0  to 100,100 this line would angle downwards from the top left hand corner.   This is the opposite of what we would expect - we actually want a line that extends from the bottom left corner and goes upwards.    

   There are several ways of solving this problem.   The fix we will use in this article is to create the series of line segments in memory which we will store in a Drawing class object called the GraphicsPath.   We will then rotate and adjust the starting position of the "upside down" lines in this GraphicsPath so that they appear in the way we want them. 

   The GraphicsPath object is quite versatile and is not difficult to use.   The transformations and rotations, however, are not quite so easy to understand.  In fact, they can be quite mind boggling unless you have the mind of a mathematician (which I don't).   For the purposes of this graph creation article, therefore, I am going to show you the code needed but will sidestep the mechanics of just how it works.     In a later article I will come back to this thorny subject and try and explain a step at a time in non-mathematician terms just what is involved.   If you have tried transformations yourself, you will probably have already come up against the problem of the invisible line - that is, you rotate a line and it simply disappears!  

    The code that we use will resolve all the above difficulties.   Create a new GraphicsPath object:

        Dim MyPath As New GraphicsPath

The First Line Segment

   As you will see, we will iterate through each of the elements in the Sales array - that's to say, each of the sales figures - in turn.   As we come upon each new figure, we will use it to change the end point for the next line segment.  

    The first segment, however, we have to set up individually in order to get the ball rolling:

      MyPath.AddLine(XPosStart, YPosStart, XPosEnd, YPosEnd)

   Note that the AddLine method takes just the four parameters - two X values and two Y values.  We don't need to specify a pen to draw the line with; this will be taken care of when we finally come to draw the complete Path.   AddLine does what the name suggests; it adds the details of this line segment to the GraphicsPath.

The Remaining Line Segments

   Now that the first segment is created and stored, we can iterate through the Sales array and add the remaining line segments to the GraphicsPath:

            For i As Integer = 1 To UBound(Sales) - 1
                '  Update the X and Y positions for the next value:
                '  Move start point one line width to the right
                XPosStart = XPosEnd
                '  Move end point one line width to the right
                XPosEnd = CInt(XPosStart + LineWidth)
                ' Assign YPosStart the 'old' value of Y
                YPosStart = YPosEnd
                ' Assign YPosEnd the next the next scaled Sales figure
                YPosEnd = CInt(Sales(i + 1) * VertScale)

                '  Add this line segment to the GraphicsPath
                MyPath.AddLine(XPosStart, YPosStart, XPosEnd, YPosEnd)
            Next

   That's all the line segments created and stored in the GraphicsPath.  Now for that tricky Transformation bit.

Transformations

   Here is the code that rotates and flips the complete line and also moves its start location to the correct position.   I have included some commenting to give an indication of what each line does.

         '  We want the line to go in opposite direction, so rotate by 180 degrees
        g.RotateTransform(180)

        '  Because the rotation also moves the line out of view (to the left), so
        '  we need to scale the x so that it is on the (plus) side of the
        '  vertical axis.
        '  The Y value remains unchanged, so a "scale" of 1 is used.
        '  (i.e. no change made)

        g.ScaleTransform(-1, 1)

        ' Move the start point down to the bottom left corner
        ' The X value remains the same
        ' Y is shifted down to the end of the vertical axis, adjusted by
        ' a fudge factor of 10 to compensate for the vertical scaling.

        g.TranslateTransform(0, VertLineLength + 10, MatrixOrder.Append)

Draw the Transformed Line

   Drawing the complete line that we have just created and transformed is a simple matter of drawing the GraphicsPath on to the Graphics Object.   The GraphicsPath, of course, contains all the data we entered for the line segments.

        Dim MyPen As Pen = New Pen(Color.Blue, 3)
        g.DrawPath(MyPen, MyPath)

   One final, but very important task remains.   We have to reset or roll back the Transformations that have been applied to the Graphics Object.   Failure to do so will mean that any future drawing task using this Graphics Object will have the same Transformations applied to them.   The results would then almost certainly not be what you wanted.

        g.ResetTransform()

Check It Out

   Once again, we can check that everything is going to plan.  In the click event of the button code, enter this:

    Private Sub btnDraw_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDraw.Click
        DrawOutline()
        DrawTheLine()
        TempDisplay()
    End Sub

   Run the project and click the button.   You should now see the chart line that represents the Sales figures.

Comments    Submit Comment

Comment #1  (Posted by an unknown user on 06/19/2006)
Rating
Thank you for this aricle, it was of great help to me. One question:
I am able to draw lines with the mouse on the graph and these must stay there, even after the graph is updated. How to go about?
Thanks!
 
Comment #2  (Posted by an unknown user on 06/19/2006)
Rating
Thank you for this aricle, it was of great help to me. One question:
I am able to draw lines with the mouse on the graph and these must stay there, even after the graph is updated. How to go about?
Thanks!
 
Comment #3  (Posted by Ged Mead on 06/19/2006)
Rating
Hi, You can continue in the same way by drawing your lines using DrawLine methods on the bitmap that is used and assigned to the PictureBox. If it is a single simple line you can update the bitmap on the mouse up event. If it is more complex you may need to use the DrawPath method again, saving the various mouse clicks along the way (it's fiddly but can be done).
There is a recent FAQ by Sp!ke on Persistence which you might also find of interest. You can read it here: http://www.vbcity.com/forums/faq.asp?fid=41&cat=Graphics&#TID128254
 
Comment #4  (Posted by Mike Brewster on 06/21/2006)
Rating
Thank Mr. Mead for a great tutorial. As a newbie to .NET, I am enjoying the difficulties from unlearning old school to learn new school stuff, such as this. ;-)

With that said, I may not fully understand some of your build notes. Are you in indicating that a class object be created called GraphicsPath with only the for interation in it?

Do you happen to have a ZIP build of this? I ask as the chart shows only a horizontal line at 1000 with the respective "points" as specified. I'm sure I'm missing something writing the code for DrawTheLine.

Any insight or comments is greatly appreciated. Thank you!
 
Comment #5  (Posted by an unknown user on 06/21/2006)
Rating
Hi Mike, Thanks for the feedback. I will upload a zipped sample solution by the end of the week, so you can see how the whole thing comes together.
 
Comment #6  (Posted by Ged Mead on 06/22/2006)
Rating
I have now uploaded a demo solution using VB.NET 2003. I hope this will help you to analyze the code in the article.
 
Comment #7  (Posted by Mike Brewster on 06/22/2006)
Rating
Thank Mr Mead! It is what I expected, I had the DrawTheLine coded incorrectly. I also notice your use of "try", though i didn't see it commented in the writing, is this strictly to catch the exception?. Also, if I wanted to have an additional line plotted, I assume referencing additional Sales arrays will do the trick. Again, thank you for a great tutorial!
 
Comment #8  (Posted by an unknown user on 06/27/2006)
Rating
high quality work, no shortcuts
 
Comment #9  (Posted by an unknown user on 06/30/2006)
Rating
Thanks Ged Meat for a wonderful Tutorial. I have one problem. When i am saving the chart. it not getting displayed. Can u suggest any solution for this

 
Comment #10  (Posted by Vimal Raj on 07/03/2006)
Rating
Wonderful Tutorial.When I am saving the graph in Jpeg,or any format the graph is not showing properly. In background fully its black. Can u help me out.
 
Comment #11  (Posted by Jimmie Missfeldt on 07/12/2006)
Rating
Great post. I had alot of help with it to draw my graph.

I translated all of it into C# though and came across a few problems with the VertScale on drawing the line.

I am still not quite sure from where in the translation the problem came but I got a flat line in the bottom of my graph. am using a hard size on the graph so I took the Scaling to Sales[1] * scaling (where scaling = 0.2) and it all came out good.

just a tip for you C# nerds out there who couldn't find any other graph tutorial ;)
 
Comment #12  (Posted by Bob Goh on 07/24/2006)
Rating
Excellent and well wriiten. Although my current job require me to build a complex time-distance diagram, after going through your article (1-5), it really equip me with some essential knowledges to kick start the develpoment. Thanks
 
Comment #13  (Posted by an unknown user on 08/01/2006)
Rating
Thank you!
 
Comment #14  (Posted by an unknown user on 09/29/2006)
Rating
excellent !!
 
Comment #15  (Posted by Cesar Parrales on 05/22/2007)
Rating
Mr. Mead. I having the problem that Mike say in his comment #5. You said in your comment #6 you uploaded a demo solution using VB.NET 2003.

My point is, haw can I get this solution?

I appreciate you help,

Thanks in advance.
 
Comment #16  (Posted by az on 05/31/2007)
Rating
Ok, however the chart lines fail to draw express edtion.
 
Comment #17  (Posted by an unknown user on 06/16/2007)
Rating
i am new in vb.net and this is very nicely created method for line grid

thanks
 
Comment #18  (Posted by an unknown user on 07/04/2007)
Rating
Very nice ! Thank You
 
Comment #19  (Posted by Julia Andrea Rodriguez Amaro on 07/28/2007)
Rating
Hello, I need to know where do you uploaded the sample for VB 2003. Thanks a lot!
 
Comment #20  (Posted by an unknown user on 10/05/2007)
Rating
Best C# tutorial, hands down! Please make more :)
 
Comment #21  (Posted by Nerea007 on 10/16/2007)
Rating
Thanks so much for the articles - I was struggling so much to find a good, comprehensive source for charts and graphics.

I'm having a little trouble with this section. My X-axis was not showing up and I was getting an error, so I changed 'PBBarChart' to 'PBLineChart' in these lines:

Dim StartPoint As New Point(LeftMargin, PBBarChart.Height - BaseMargin)

Dim VertLineLength As Integer = PBBarChart.Height - (BaseMargin + TopMargin)

g.DrawLine(LinePen, LeftMargin, PBBarChart.Height - BaseMargin, _
PBBarChart.Width - RightMargin, PBBarChart.Height - BaseMargin)

And the X-axis appeared just like in your screen shot, but then I went to make the procedure DrawTheLine() and it just didn't work - I got a blue horizontal line at the 1000 mark.

Could you give me any pointers as to where I'm going wrong? There was some mention in the comments about a zip file of the code - maybe you can refer me to the link and I can compare what I have written to see where my mistake is.

Thanks!
 
Comment #22  (Posted by Ged Mead on 10/16/2007)
Rating
Hi, If you navigate to the final page of the article and then page down to the bottom you will see there a link to a zip file named Chart5.zip. This is the downloadable sample. (It is placed between the "Related Articles" section and the start of the Comments.)

 
Comment #23  (Posted by an unknown user on 02/11/2008)
Rating
Very, very helpful article. I'm trying to create graphical statistics for a call management package, the next step is to connect to a SQL server table for input. Thanks for the tutorial!
 
Comment #24  (Posted by an unknown user on 03/25/2008)
Rating
Great tutorial ... thousands of thanks cast to u ... =)
 
Comment #25  (Posted by kishore on 04/10/2008)
Rating
Excellent work. How can i show value of the sales near the elliptical region. Any solution is apreciable

thnx
 
Comment #26  (Posted by an unknown user on 06/25/2008)
Rating
It was of great help
 
Comment #27  (Posted by Heruki Otsasori on 10/12/2008)
Rating
no matter which site you set as your default. ,
 
Comment #28  (Posted by Nick on 10/12/2008)
Rating
It works because reputable writers make links to things ,
 
Comment #29  (Posted by an unknown user on 11/19/2008)
Rating
A minor mistake in the article, the VertLineLength variable is Dimmed twice which causes the graph line to be drawn incorrectly. Otherwise an excellent article and very useful.
 
Comment #30  (Posted by an unknown user on 12/01/2008)
Rating
this is something i was looking for...
a beginners guide.. thanks!
 
Comment #31  (Posted by an unknown user on 01/19/2009)
Rating
Easy to follow and gives a good illustration of the concepts involved
 
Comment #32  (Posted by Naresh Kumar Prajapati on 03/17/2009)
Rating
Excellent Article yaar , good job. but i think u missed one line in ur DrawTheLine() subroutine which is
VertLineLength = PictureBox1.Height - (BaseMargin + TopMargin)
please have a look
 
Comment #33  (Posted by an unknown user on 05/09/2009)
Rating
i went through this artical,how ever i ddint use it so far but i m going to use it surely...

Thanks Man
 
Comment #34  (Posted by an unknown user on 08/25/2009)
Rating
Great work! Thank you.
 
Comment #35  (Posted by an unknown user on 09/23/2009)
Rating
i have searched many websites for source code of showing but none of these are good like this
 
Comment #36  (Posted by knockNrod on 09/24/2009)
Rating
First, excellent tutorial, thank you. Wished I had seen this a long time ago when I was first getting into GDI+.

The reason I came to this site was to look for a way to add points to a line graph, rather than line segments. The reason being that line segments tend to re-initialize the dots in a dotted line. Too many line segments converts a dotted line into a solid one.

I doubt you still monitor this article, given the date, although it's as relevant today as then, so if you are, do you have any suggestions on how to draw a many-point, dotted line graph?
 
Comment #37  (Posted by Ged on 09/25/2009)
Rating
Hi, I do try and monitor my articles, although I don't often find the time to respond to all the queries.
Yours, however, might be a relatively easy one.
You can set the dash pattern on the Pen object that you use for the DrawLine method.
Something like:
Dim DashPen as New Pen
DashPen = New Pen(Color.Black, 2)
DashPen.DashStyle = DashStyle.DashDotDot

g.DrawLine(DashPen, New Point(12,12), New Point(45,76))

NB. This is Air Code, but I think it's fairly accurate.
Give that a try and see if it works for you.
 
Sponsored Links