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 strongm 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
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