This course will help prep you to earn the CompTIA Healthcare IT Technician certification showing that you have the knowledge and skills needed to succeed in installing, managing, and troubleshooting IT systems in medical and clinical settings.

Hey everyone, so I have this graphing program that graphs regression lines. As of now it works well with small numbers, and the size of the picturebox scales with how large the points are. However when dealing with large numbers the graph lags out because it is way to large. I need to be able to scale the graphs coordinates so that it always shows the regression line no matter how big. Default origin is the top left corner (0,0). If i have plot points at like (297400, 10000, etc etc) I need to orgin to change for those numbers. Heres some pictures

This is the graph with small numbers:

screen3up.jpg

Large Numbers - lags out from the graph size being too large

screen4b.jpg

The large numbers being plotted are {69400, 2500, 109000, 5000, 207900, 7500, 297200, 10000, 346500, 12500}

I know those numbers are valid because oither graphing prgrams plot them perfectly, because the coordinate system scales.

Heres my code, if you could give me some tips you would make me very happy, as well as my boss!!

This is the graph with small numbers:

screen3up.jpg

Large Numbers - lags out from the graph size being too large

screen4b.jpg

The large numbers being plotted are {69400, 2500, 109000, 5000, 207900, 7500, 297200, 10000, 346500, 12500}

I know those numbers are valid because oither graphing prgrams plot them perfectly, because the coordinate system scales.

Heres my code, if you could give me some tips you would make me very happy, as well as my boss!!

```
Public Class Form1
'Declare variables
'-----------------------------------------------------
Private Structure PointType
Dim X As Double
Dim Y As Double
End Structure
Dim Reg As New RegressionObject
Private LastEndPoint As New Point(0, 0)
'Graph lines and points
Dim regLine As New Series
Dim points As New Series
'The radius
Const R = 100
'Point
Dim P(0 To 200) As PointType
'Array that holds X and Y values for graphing
Dim MyData() As Single = New Single() {69400, 2500, 109000, 5000, 207900, 7500, 297200, 10000, 346500, 12500}
'Scale graph to stay within the picturebox
Dim HorizontalScaleFactor As Single
'The array for the points on the graph
Dim DataPoints(MyData.Length - 1) As PointF
'Points where the number labels are drawn
Dim labels As PointF
'The font
Dim drawFont As New Font("Arial", 16)
Dim cordFont As New Font("Arial", 8)
'Regression degrees
Dim deg As Integer
Dim flag As Boolean
Dim loaded As Boolean
'FORM LOAD
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
For i As Integer = 1 To 10
degBox.Items.Add(i)
Next
loaded = False
flag = False
degBox.Text = "3"
Reg.Degree = deg
End Sub
'This updates the picturebox everytime it is redrawn
Private Sub picboxPulseCurve_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles picboxPulseCurve.Paint
Dim i As Integer
e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.HighQuality
'e.Graphics.DrawCure(ve(Pens.Blue, DataPoints))
regLine.Name = "Regression Curve"
regLine.ChartType = SeriesChartType.Spline
regLine.Color = Color.Maroon
With Reg
Using pn As New Pen(Color.Red, 2)
For i = 0 To .XYCount
DrawACircle(e, pn, New Point(P(i).X, P(i).Y), R / 10)
Next i
End Using
LastEndPoint = New Point(0, .RegVal(CDbl(Me.ClientRectangle.Height)))
Dim CurrentPoint As Point
For i = 0 To Me.ClientRectangle.Width Step R
CurrentPoint = New Point(i, .RegVal(CDbl(i)))
Using pn As New Pen(Color.BlueViolet, 3)
e.Graphics.DrawLine(pn, LastEndPoint, CurrentPoint)
End Using
e.Graphics.DrawLine(Pens.Red, 0, MyData.Max + 150, 0, 0)
e.Graphics.DrawLine(Pens.Red, MyData.Max + 150, 0, 0, 0)
If (flag = False) Then
regLine.Points.AddXY(-CurrentPoint.X, -CurrentPoint.Y)
End If
LastEndPoint = CurrentPoint
Next i
If (flag = False) Then
graph.Series.Add(regLine)
graph.Series.Add(points)
End If
End With
End Sub
'Draws a circle at the given points
Private Sub DrawACircle(ByVal e As System.Windows.Forms.PaintEventArgs, ByVal P As Pen, ByVal center As Point, ByVal radius As Integer)
' Create a bounding rectangle and make its center the center of our point
' Then make its width 2 * the radius
' Then draw our ellipse
points.Name = "Points"
points.ChartType = SeriesChartType.Point
points.Color = Color.Black
Dim rect As New Rectangle(center, New Size(0, 0))
For i = -3000 To MyData.Max + 150 Step 50
labels = New Point(i, 0)
e.Graphics.DrawString(i.ToString(), drawFont, Brushes.Black, labels)
e.Graphics.DrawLine(Pens.Black, i, 0, i, MyData.Max + 150)
Next
For i = -3000 To MyData.Max + 150 Step 50
labels = New Point(0, i)
e.Graphics.DrawString(i.ToString(), drawFont, Brushes.Black, labels)
e.Graphics.DrawLine(Pens.Black, 0, i, MyData.Max + 150, i)
Next
rect.Inflate(radius, radius)
e.Graphics.DrawEllipse(P, rect)
e.Graphics.DrawString(center.X.ToString() + " " + center.Y.ToString(), cordFont, Brushes.Black, New PointF(center.X + 8, center.Y))
If (flag = False) Then
points.Points.AddXY(-center.X, -center.Y)
End If
End Sub
'This button resets the graphs and data
Private Sub resetBtn_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles resetBtn.Click
flag = False
regLine.Points.Clear()
points.Points.Clear()
graph.Series.Clear()
txtBox.ResetText()
Reg.Init()
MsgBox("Data has been reset!")
End Sub
'This populates the program with graph points that are loaded from a file
'It also resets the graphs and data
Private Sub PopulateDataPointsArray(ByVal PictureBoxWidth As Integer)
'Scale the graph to fit the picture box:
HorizontalScaleFactor = CSng(PictureBoxWidth / DataPoints.Length)
picboxPulseCurve.Width = MyData.Max + 150
picboxPulseCurve.Height = MyData.Max + 150
If (flag = False) Then
regLine.Points.Clear()
points.Points.Clear()
graph.Series.Clear()
End If
txtBox.ResetText()
Reg.Init()
'Populate the DataPoints array:
For i As Integer = 0 To DataPoints.Length - 2
DataPoints(i).X = MyData(i)
DataPoints(i).Y = MyData(i + 1)
txtBox.Text += ("X: " + MyData(i).ToString() + " Y: " + MyData(i + 1).ToString() + vbNewLine)
With Reg
.XYAdd(DataPoints(i).X, DataPoints(i).Y)
P(.XYCount).X = DataPoints(i).X
P(.XYCount).Y = DataPoints(i).Y
End With
Next
Me.Refresh()
End Sub
```

You will have to use some easy math to scale the graph before you draw it, and keep the size of the PictureBox constant.

Scaling the ever growing picturebox is a hugely inefficient use of RAM, and as you found out, it doesn't work with large sets.

Lets see, if you keep the picturebox costant at 1000x1000 for example, the math should be:

plotx = 64000

plotwidth = 75000

actualwidth = 1000

scalefactor = actualwidth / 75000

drawx = plotx * scalefactor

do the same for y, and this will give you multipliers that you apply to the variables before you draw them. this way, as far as vb is concerned, you are drawing withing the box, all the math happens BEFORE translation.

oh ya, and as far as the tick marks, you simply draw whatever number you want on the graph, and have it match the MATH numbers, not the pixel numbers.

(question, does it always start at 0,0?, if not, you will need to find the distance away from 0, multiplied by the scale factor, and then REMOVE this amount from the actual graphing of the reg line)

Lot of information here, let me know what you come back with :)

Oh and that scale factor I had in there, wasnt working at all. It would only work if you were plotting only y coordinates for some reason

I'm sure you're well on your way to a much more powerful and robust graphing program, with a much smaller memory footprint.

I'll be back

At lines #81 thru #83, you're creating a new pen instance for every single line drawn! The Pen color/width isn't being changed for any particular line so you should create ONE Pen outside the loop and re-use it the entire time. Move line #81 to #78.5 and line#83 to #90.5.

Make those changes first and see if the performance increases.

Still working on that scaling using the tips themrrobert gave me. No luck yet :(

http://msdn.microsoft.com/en-us/library/zhc2xxtx.aspx

*Leave the scaling at 1:1 to draw the grid and labels first, then scale afterwards to draw the rest of the graph.

so scale transform seems to be working on the line :)

Now i just gotta use themrroberts logic on the pictureBox to scale that accordingly...same with the circles, they need to appear in the right spots.

screen5rx.jpg

It seems you still need to adjust the the labels on the X and Y axis to match the scale, but other than that it looks good. is there anything else that you need?

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.

However, I can help get you there. For starters, you will want to have (in your Window.onResize event)

Ok, at the top, and a new Private variable PB_WIDTH and PB_HEIGHT, this amount will be updated in the routine i'm about to describe:

a route which shrinks or grows the picturebox to match the amount of room left. This should be relatively easy, you can find the new width by taking Form.width - PictureBox.Left (and the same for Top/Height)

Since this is your code, you are best prepared to modify it. With your recently populated PB_WIDTH and PB_HEIGHT variables, you can get the scale as follows (i'm not sure how you want to define the max, perhaps the highest value rounded up to nearest 10,000, you can fill in that yourself)

so you have SCALEY = PB_HEIGHT / SCALEYMAX and SCALEX = PB_WIDTH / SCALEXMAX

(the numbers i just had you find)

this gives you the multiplier you will apply to all numbers to be plotted BEFORE drawing.

hack out all of the code that scales the picturebox, and instead, keep the PB constant, and add in new code in form of (SCALEX * VARTOBEDRAWN) or similar.

Hopefully this gets you where you need. I will check back later to see if you need anymore help :)