Author Topic: A simple chart class  (Read 1011 times)

SteveDee

  • Newbie
  • *
  • Posts: 33
A simple chart class
« on: December 04, 2009, 05:22:19 PM »
I needed to graph simple quantities, so tried to use the gb.Chart component. Unfortunately (at the time of writing) this does not appear to work.

So, inspired by an old paper chart pen recorder, I created this simple chart class.

To play with this, just create a new Gambas project, add a new (blank) class and name it "clsPaperChart", then copy & paste the class code at the bottom of this post.

On the main project form, add a Timer and a DrawingArea.

In the main form:-

Code: [Select]
'Declare a new chart object
PUBLIC myChart AS NEW clsPaperChart


PUBLIC SUB Form_Open()
  WITH myChart
    .DrawArea = DrawingArea1
    .intMarkerWidth = 3
    .intMaxYaxis = 100
    .fAlarmLevel = 90
    .blnSelfTest=TRUE
  END WITH
  Timer1.Delay=1000
  Timer1.Start()
END

PUBLIC SUB Timer1_Timer()
  myChart.PlotPoint(0)
  ME.Caption = myChart.strLastDataPoint
END


When you run this program, myChart will generate its own random data. If you set blnSelfTest=FALSE you will need to supply your own data via the PlotPoint method.

Depending upon the size of your Drawing Area and the number of data points (intMaxPoints) you may find the plot does not reach the bottom of the drawing area. You can adjust this by changing the bar width (intMarkerWidth) or increasing the number of data points ((intMaxPoints). You could also modify the class to scale this automatically.

The clsPaperChart class:-

Code: [Select]
' Gambas class file
'
'clsPaperChart
'++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
'A simple class to plot a chart similar to a paper chart pen recorder.
'
'Steve Davis
'December 2009
'++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

PROPERTY DrawArea AS DrawingArea  'where we draw our chart
PRIVATE dArea AS DrawingArea

PROPERTY intMaxYaxis AS Integer   'chart scale
PRIVATE intMaxY AS Integer

PROPERTY strUnits AS String     'examples; "%", "kHz"
PRIVATE strUnitType AS String

PROPERTY intMarkerWidth AS Integer  'chart data marker or bar width
PRIVATE intMarkWidth AS Integer

PROPERTY intMaxPoints AS Integer    'max number of data points
PRIVATE intMaxPts AS Integer

PROPERTY fAlarmLevel AS Float   'value=0 to disable
PRIVATE fAlarm AS Float

PROPERTY blnSelfTest AS Boolean   'generate random data for chart
PRIVATE bTest AS Boolean

PROPERTY READ strLastDataPoint AS String  'Data point + units + timestamp
PRIVATE strLastPoint AS String

PRIVATE fPoints AS Float[] 'array of data points

PRIVATE intPoints AS Integer  'number of data points

PRIVATE CONST FULL_SCALE AS Float = 1 'using full chart width

PUBLIC SUB _new()
 
  fPoints = NEW Float[]
  'set defaults
  intMaxPts = 100 
  intMaxY = 100
END


PUBLIC SUB PlotPoint(fData AS Float)
DIM index AS Integer
DIM fScale AS Float   'use to scale data to plot
DIM fAlarming AS Float  'scaled alarm level

  fScale = FULL_SCALE * dArea.Width / CFloat(intMaxY)
  fAlarming = fscale * fAlarm
  fPoints.Resize(intPoints + 1)
  IF fPoints.Max > intMaxPts THEN fPoints.Resize(intMaxPts)
  FOR index = fPoints.Max TO 1 STEP -1
    fPoints[index] = fPoints[index - 1]
  NEXT
  IF bTest THEN 'use random test data
    fData = Rnd(0, intMaxY)
  ENDIF
  fPoints[0] = fscale * fData
  INC intPoints
  strLastPoint = "Last: " & Round(fData, 0) & strUnitType & " @" & Format(Now(), "hh:mm:ss")
'   lblRange.Text = intRange & strUnits
  dArea.Clear
  draw.Begin(dArea) 
  draw.LineWidth = 1
  IF intMarkWidth < 1 THEN intMarkWidth = 1
  IF fAlarming > 0 THEN 'create a red alarm line
    draw.ForeColor = Color.Red
    draw.Line(fAlarming, 0, fAlarming, dArea.ClientH)
  ENDIF
  draw.ForeColor = Color.LightGray
  draw.Line(0.75 * FULL_SCALE * dArea.ClientWidth, 0, 0.75 * FULL_SCALE * dArea.ClientWidth, dArea.ClientH) 
  draw.Line(0.5 * FULL_SCALE * dArea.ClientWidth, 0, 0.5 * FULL_SCALE * dArea.ClientWidth, dArea.ClientH) 
  draw.Line(0.25 * FULL_SCALE * dArea.ClientWidth, 0, 0.25 * FULL_SCALE * dArea.ClientWidth, dArea.ClientH) 
  'Plot data
  FOR index = 0 TO fPoints.Max
    IF fAlarming > 0 AND fPoints[index] > fscale * fAlarm THEN
      draw.ForeColor = color.Red  'red bars
    ELSE
      draw.ForeColor = color.Blue  'blue bars
    ENDIF
    draw.LineWidth = intMarkWidth
    draw.Line(0, (index + 1) * intMarkWidth, fPoints[index], (index + 1) * intMarkWidth)
  NEXT
  Draw.End
END

'++++Class Properties+++++++++++++++++++++++++++++++++

PRIVATE FUNCTION DrawArea_Read() AS DrawingArea
  RETURN dArea
END

PRIVATE SUB DrawArea_Write(Value AS DrawingArea)
  dArea = Value
  dArea.Cached = TRUE
  dArea.Border = 2
END

PRIVATE FUNCTION intMaxYaxis_Read() AS Integer
  RETURN intMaxY
END

PRIVATE SUB intMaxYaxis_Write(Value AS Integer)
  intMaxY = Value
END

PRIVATE FUNCTION strUnits_Read() AS String
  RETURN strUnitType
END

PRIVATE SUB strUnits_Write(Value AS String)
  strUnitType = Value
END

PRIVATE FUNCTION intMarkerWidth_Read() AS Integer
  RETURN intMarkWidth
END

PRIVATE SUB intMarkerWidth_Write(Value AS Integer)
  intMarkWidth = Value
END

PRIVATE FUNCTION intMaxPoints_Read() AS Integer
  RETURN intMaxPts
END

PRIVATE SUB intMaxPoints_Write(Value AS Integer)
  intMaxPts = Value
END

PRIVATE FUNCTION blnSelfTest_Read() AS Boolean
  RETURN bTest
END

PRIVATE SUB blnSelfTest_Write(Value AS Boolean)
  bTest = Value
END

PRIVATE FUNCTION strLastDataPoint_Read() AS String
  RETURN strLastPoint
END

PRIVATE FUNCTION fAlarmLevel_Read() AS Float
  RETURN fAlarm
END

PRIVATE SUB fAlarmLevel_Write(Value AS Float)
  fAlarm = Value
END

Linux Basic

A simple chart class
« on: December 04, 2009, 05:22:19 PM »