Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Graphs and arrays - do they work for beginners? 1

Status
Not open for further replies.

cluelessC

Programmer
Jul 20, 2001
10
0
0
GB
Hello, everybody!
My problem might seem quite trivial, but I'd give my right hand to solve it!
Basically, I need to represent a range of short intergers, read from a file, in a shape of a histogramm. I am only a beginner and so far I only managed to get my "programm" to read the file and count the occurences of certain numbers. But when I attempt to use Canvas->MoveTo/LineTo to draw my simple graph by going through the range (20-80) of numbers (that would give it the coordinates on the x-axis), it is only the first number that my method returns the corresponding y-axis value for. How does it happen that the "for"-loop just does not seem to execute beyond its first step?
I also tried looking up some info on the TGraph component. In Help they say that it has to be a two-dimensional array, so even if I take the Number (x-axis)
for one dimension, and its occurences - for another dimension, how do I get my graph to recognize that Number should be "ThisPoint" and ItsOccurences - "ThisSet"? And what on earth does := mean? They used it to illustrate their examples in the Help menu, but then there is nothing on this operator(?) in the Index section!
Oh, dear, I am out of breath already! I hope somebody will take pity and spare a couple of minutes to help me out! Any answer would be much appreciated!

Thank you,
Victoria :cool:
 
Create a new application (I used Builder 4.0 for the following code.) Insert the following into the Unit1 header file (Unit1.h):
Code:
  int x,y;
  int xMin,xMax;
  int yMin,yMax;
and
Code:
  int __fastcall scaleX(int x);
  int __fastcall scaleY(int y);
  void __fastcall drawHistogram();
as shown below:
Code:
//---------------------------------------------------------------------------
#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE-managed Components
        void __fastcall FormShow(TObject *Sender);
        void __fastcall FormResize(TObject *Sender);
private:	// User declarations
        int x,y;
        int xMin,xMax;
        int yMin,yMax;
public:		// User declarations
        __fastcall TForm1(TComponent* Owner);
    int __fastcall scaleX(int x);
    int __fastcall scaleY(int y);
    void __fastcall drawHistogram();
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
Add the math library reference (needed for abs()) just before #include &quot;Unit1.h&quot; as below:
Code:
#include <math.h>
#include &quot;Unit1.h&quot;
Now add the data array to be plotted immediately before the constructor:
Code:
// Data to be plotted in the histogram
int counts[]= {1,2,4,8,16,32,64,96,112,120,124,126,127,
               126,124,120,112,96,64,32,16,8,4,2,1};
NOTE: You could enter any data into the counts array that you would like, just follow the format I used above.

Next add the following functions to Unit1.cpp just after the constructor:

Code:
//---------------------------------------------------------------------------
int  __fastcall TForm1::scaleX(int x) {
  if(x < xMin) x= xMin;
  else if(x > xMax) x= xMax;
  return (ClientWidth * x) / (xMax - xMin);
  }
//---------------------------------------------------------------------------
int  __fastcall TForm1::scaleY(int y) {
  if(y < yMin) y= yMin;
  else if(y > yMax) y= yMax;
  return ClientHeight - (ClientHeight * y) / (yMax - yMin);
  }
//---------------------------------------------------------------------------
void __fastcall TForm1::drawHistogram() {
  xMin= xMax= 0;
  yMin= yMax= 0;
  // find maximums
  xMax= sizeof(counts)/sizeof(int);   // Simply calculate the # of buckets
  yMin= xMin= 0;                      // Always zero for histograms
  if(xMax <= 0) {
    ShowMessage(&quot;Nothing to plot!&quot;);
    return;
    }
  yMax= 0;                            // Presume 0 is the minimum
  for(int ii=0;ii<xMax;ii++)
    if(abs(counts[ii]) > yMax) yMax= abs(counts[ii]);

  // Calculate the width of each bar of the histogram
  int xWidth= ClientWidth / xMax;
  // Set up the pen  
  Canvas->Pen->Width= 1;
  Canvas->Pen->Color= clBlack;
  Canvas->Pen->Style= psSolid;

  // Clear the canvas
  Canvas->FillRect(Rect(0,0,Width,Height));

  // At last we can plot!
  Canvas->MoveTo(scaleX(0),scaleY(0));                     // Move to (0,0)
  for(int ii=0;ii<xMax;ii++) {
    Canvas->LineTo(scaleX(ii),scaleY(counts[ii]));         // Up
    Canvas->LineTo(scaleX(ii)+xWidth,scaleY(counts[ii]));  // Over
    Canvas->LineTo(scaleX(ii)+xWidth,scaleY(0));  // Down
    }
  }
Using the Object Inspector on Form1: TForm1 click on Events then double click on OnResize and insert the following line of code:
Code:
  drawHistogram();
Again, using the Object Inspector on Form1: TForm1 click on Events then double click on OnShow and insert the following line of code:
Code:
  drawHistogram();
Your code should now look similar to the following Unit1.cpp code from the project I created.
Code:
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop

#include <math.h>

#include &quot;Unit1.h&quot;
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource &quot;*.dfm&quot;
TForm1 *Form1;

// Data to be plotted in the histogram
int counts[]= {1,2,4,8,16,32,64,96,112,120,124,126,127,
               126,124,120,112,96,64,32,16,8,4,2,1};
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) {
  }
//---------------------------------------------------------------------------
int  __fastcall TForm1::scaleX(int x) {
  if(x < xMin) x= xMin;
  else if(x > xMax) x= xMax;
  return (ClientWidth * x) / (xMax - xMin);
  }
//---------------------------------------------------------------------------
int  __fastcall TForm1::scaleY(int y) {
  if(y < yMin) y= yMin;
  else if(y > yMax) y= yMax;
  return ClientHeight - (ClientHeight * y) / (yMax - yMin);
  }
//---------------------------------------------------------------------------
void __fastcall TForm1::drawHistogram() {
  xMin= xMax= 0;
  yMin= yMax= 0;
  // find maximums
  xMax= sizeof(counts)/sizeof(int);   // Simply calculate the # of buckets
  yMin= xMin= 0;                      // Always zero for histograms
  if(xMax <= 0) {
    ShowMessage(&quot;Nothing to plot!&quot;);
    return;
    }
  yMax= 0;                            // Presume 0 is the minimum
  for(int ii=0;ii<xMax;ii++)
    if(abs(counts[ii]) > yMax) yMax= abs(counts[ii]);

  // Calculate the width of each bar of the histogram
  int xWidth= ClientWidth / xMax;
  // Set up the pen  
  Canvas->Pen->Width= 1;
  Canvas->Pen->Color= clBlack;
  Canvas->Pen->Style= psSolid;

  // Clear the canvas
  Canvas->FillRect(Rect(0,0,Width,Height));

  // At last we can plot!
  Canvas->MoveTo(scaleX(0),scaleY(0));                     // Move to (0,0)
  for(int ii=0;ii<xMax;ii++) {
    Canvas->LineTo(scaleX(ii),scaleY(counts[ii]));         // Up
    Canvas->LineTo(scaleX(ii)+xWidth,scaleY(counts[ii]));  // Over
    Canvas->LineTo(scaleX(ii)+xWidth,scaleY(0));  // Down
    }
  }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormShow(TObject *Sender) {
  drawHistogram();
  }
//---------------------------------------------------------------------------
void __fastcall TForm1::FormResize(TObject *Sender) {
  drawHistogram();
  }
//---------------------------------------------------------------------------
This simple application demonstrates much of the power of C++ Builder graphing capabilities and concepts. Hope it helps.

-mark-
 
Thanks very much - ten out of ten for going into such detail! To be honest, I've solved my problem myself, but in a different way - it was good to get a different view on the problem from your solution. Besides, I never knew of the drawHistogram() function - something knew to try out!

So, thanks again for responding!:)
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top