§ 15. Построение графиков функций и диаграмм

15.2. Построение диаграмм

Рассмотрим основные принципы построения гистограмм на примерах построения гистограммы и круговой диаграммы. Интерактивность в данном случае обеспечивается данными в файле.

Пример 15.3. Создать проект, в котором необходимо построить гистограмму по данным из массива из n элементов. Значения элементов массива считать из текстового файла. Текстовый файл поместить в папку Win32\Debug. В этом случае для доступа к файлу достаточно прописать имя файла. Если файл хранится в другом месте, то для доступа к файлу необходимо прописать полный путь.

Этапы выполнения задания

  1. Поместить на форму компоненты: изображение (Image) и кнопка (Button).
  2. Изменить свойства Caption у компонента Button1 на «Построить».
  3. Установить размеры Image — 600 × 400.
  4. Написать обработчик события OnClick для компонента Button1, в котором диаграмма строится с помощью прямоугольников.

4.1. Считать данные из файла в массивы: массив d — хранит числа, по которым строится диаграмма; массив s — подписи элементов. Для работы с файлами подключить библиотеку <fstream>. Для чтения строк из файла подключить библиотеку <string>, для работы с. массивами — библиотеку <vector>. Прописать директиву Using NameSpace std для обращения к командам стандартных библиотек.
4.2. Найти максимальный элемент в массиве — элемент, стоящий на месте n_max.
4.3. Рассчитать масштабный коэффициент: . Для того чтобы оставить место для вывода надписей, от высоты формы отнимаем 40.
4.4. В цикле строить n прямоугольников одинаковой ширины. Ширина прямоугольника —   Высота прямоугольника определяется значением , преобразованным к целому типу. Цвет прямоугольников задавать случайно — каждая составляющая цвета изменяется в диапазоне от 1 до 245 (исключаем черный цвет и цвета близкие к белому).
4.5. Вывести надписи над прямоугольниками. Для вывода строк, считанных из файла, их нужно преобразовать так, чтобы можно было вывести на канву. Для этого можно воспользоваться функцией c_str().

Пример 15.4. Создать проект, в котором нужно построить круговую диаграмму по данным из массива. Значения элементов массива считать из текстового файла. Текстовый файл поместить в папку Win32\Debug.

  1. Поместить на форму компоненты: изображение (Image) и кнопка (Button).
  2. Изменить свойства Caption у компонента Button1 на «Построить».
  3. Установить размеры Image — 500 × 500.
  4. Для работы с файлами подключить библиотеку <fstream>. Для чтения строк из файла подключить библиотеку <string>, для работы с массивами — библиотеку <vector>. Для вычислений понадобятся тригонометрические функции, поэтому необходимо подключить библиотеку <cmath>.  Прописать директиву using namespace std для обращения к командам стандартных библиотек.
  5. Написать обработчик события OnClick для компонента Button1, в котором диаграмма строится с помощью секторов.

5.1. Считать данные из файла в массив.
5.2. Найти сумму элементов массива — sum.
5.3. Рассчитать масштабный коэффициент: .
5.4. В цикле строить n  секторов. Цвет сектора задавать случайно — каждая составляющая цвета изменяется в диапазоне от 1 до 245 (исключаем черный цвет и цвета близкие к белому).
5.5. Секторы определяются кругом радиуса R, вписанным в квадрат с координатами диагонали (x1; y1) — (x2; y2). Значения x1 = 50, y1 = 50, x2 = x1 + 2R, y2 = y1 + 2R, R = 200.
5.6. Расчет ключевых точек для построения сектора (см. рисунок).
5.7. Для построения сектора координаты точек (x3; y3) и (x4; y4) нужно преобразовать в экранные: увеличить горизонтальные на , а у вертикальных поменять знак и увеличить на 
5.8. Вывести надписи вверху компонента Image. Для вывода строк, считанных из файла, их нужно преобразовать так, чтобы можно было вывести на канву. Для этого можно воспользоваться функцией c_str(). Местоположение надписи рассчитывается так же и как для гистограммы.

Пример 15.3. Форма на этапе конструирования:

Текстовый файл с данными:

Подключение библиотек:

Обработчик события OnClick для компонента Button1.

void __fastcall TForm1::Button1Click(TObject *Sender)

{

  //чтение данных из файла

  ifstream fin("date.txt");

  int n;

  fin >> n;

  vector <int> d(n);

  vector <string> s(n);

  for(int i = 0; i < n; i++)

    fin >> s[i] >> d[i];

  //поииск максимального

  int n_max = 0;

  for (int i = 0; i < n; i++)

    if (d[i] > d[n_max])

      n_max = i;

  //коэффициент масштабирования

  int  h = Image1 -> Height - 40;

  double k = 1. * h / d[n_max];

  //ширина столбца

  int w = Image1 -> Width/(2 * n + 1);

  int x = w;

  for (int i = 0; i < n; i++) {

    //цвет

    int cr = rand()245 + 1;

    int cg = rand()245 + 1;

    int cb = rand()245 + 1;

    TColor c = TColor (RGB(cr, cg, cb));

    Image1 -> Canvas -> Brush -> Color = c;

    Image1 -> Canvas -> Rectangle

    (x, h + 40, x + w, h - (int)(k * d[i]) + 30);

    //надпись

    Image1 -> Canvas -> Brush -> Color = clWhite;

    Image1 -> Canvas -> Font -> Color = c;

    Image1 -> Canvas -> TextOut

      (x + 33, s[i].c_str());

    //переход к следующему столбцу

    x += 2 * w;

  }

}

Работающее приложение:

Пример 15.4. Форма на этапе конструирования:

Расчет ключевых точек для построения сектора:

Величина угла u2 соответствует текущему значению данных из массива и равна . Величина угла u1 — суммарное значение углов для уже построенных секторов. Вначале u1 = 0.

Значения x3 и y3 — катеты прямоугольного треугольника с углом u1 и гипотенузой равной радиусу круга, поэтому x3 = cos u1, y3 = sin u1.

Аналогично определяем x4 и y4:  y4 = cos (u1 + u2), y4 = sin (u1 + u2).

Обработчик события OnClick для компонента Button1.

void __fastcall TForm1::Button1Click
               (TObject *Sender)

{

  //чтение данных из файла

  ifstream fin("date.txt");

  int n;

  fin >> n;

  vector <int> d(n);

  vector <string> s(n);

  for(int i = 0; i < n; i++)

    fin >> s[i] >> d[i];

  //поииск суммы

  int sum = 0;

  for (int i = 0; i < n; i++)

    sum += d[i];

  //коэффициент масштабирования

  double pi = acos(-1.);

  double k = 2 * pi / sum;

  //определение круга

  double u1 = 0;

  int w = Image1 -> Width/(2 * n + 1);

  int x = w ;

  int R = 200;

  int x1 = 50, y1 = 50;

  int x2 = x1 + 2 * R, y2 = y1 + 2 * R;

  //центр области построения

  int c_X = Image1 -> Width / 2;

  int c_Y = Image1 -> Height / 2;

  for (int i = 0; i < n - 1; i++){

    double u2 = k * d[i];

    int x3 = int (R * cos(u1)) + c_X;

    int y3 = c_Y - int (R * sin(u1));

    int x4 = int (R * cos(u1 + u2)) + c_X;

    int y4 = c_Y - int (R * sin(u1 + u2));

    //цвет

    int cr = rand()255 + 1;

    int cg = rand()255 + 1;

    int cb = rand()255 + 1;

    TColor c = TColor (RGB(cr, cg, cb));

    Image1 -> Canvas -> Brush -> Color = c;

    //сектор

    Image1 -> Canvas -> Pie

    (x1, y1, x2, y2, x3, y3, x4, y4);

    //переход к следующему сектору

    u1 += u2;

    //надпись

    Image1 -> Canvas -> Brush -> Color = clWhite;

    Image1 -> Canvas -> Font -> Color = c;

    Image1 -> Canvas -> 

    TextOut(x + 33, s[i].c_str());

    //переход к следующей надписи

    x += 2 * w;

 Работающее приложение: