Построение графиков
График является самым наглядным способом представления экспериментальных данных, отображения зависимости, полученной в результате численного моделирования и т.п. Поэтому построение различных графиков является одним из важных этапов решения многих прикладных задач. Графики бывают разных видов: точечные, линейные (в виде ломаной линии, соединяющей отдельные точки), полигоны, графики в виде столбиковой диаграммы (гистограммы), в виде секторной диаграммы и т.д.
Рассмотрим в качестве примера задачу построения линейного графика произвольной функции в заданном диапазоне изменения аргумента. Исходными данными в этой задаче являются: функция, график которой строится, диапазоны изменения аргумента a и b, и количество точек N, отображаемых на графике (или шаг изменения аргумента dx). При решения поставленной задачи желательно придерживаться следующей последовательности действий:
1. ввод исходных данных;
2. табулирование функции (вычисление значений функции при изменении аргумента от a до b с шагом dx);
3. определение минимального и максимального значений функции на заданном интервале;
4. определение мировой системы координат;
5. построение осей координат;
6. построение графика функции.
Рассмотрим реализацию некоторых из перечисленных действий и оформим их в виде отдельных процедур и функций. В основной программе опишем следующие константы и переменные:
CONST
N = 50;
VAR
X, Y : array[1..N] of real;
Константа N задает число точек отображаемых на графике. В массивы X и Y мы поместим результаты табулирования функции.
Кроме этого, будем подразумевать, что в программу включено описание:
· целочисленных переменных XWmin, XWmax, YWmin и YWmax, определяющих координаты окна вывода (см. выше);
· вещественных переменных xmin, xmax, ymin, ymax, определяющих математическую систему координат;
· процедур SetWindow и SetWorldCoords (см. выше);
· двух функций преобразования координат Xs и Ys;
· целочисленных переменных GrDr и GrMd, необходимых для процедуры инициализации графики.
Табулирование функции:
PROCEDURE TablFunc( a, b : real );
VAR
i : integer;
function F( x : real ) : real;
begin
F := выражение для функции, график которой нужно построить;
end;
BEGIN
for i:=1 to N do begin
X[i] := a + (b-a)/(N-1)*(i-1);
Y[i] : F( X[i] );
end;
END;
Определение минимального и максимального значений функции:
Определение минимального и максимального значения функции в данном случае сводится к поиску минимального и максимального элемента в массиве Y, который получен на этапе табулирования функции. Оформим эту операцию в виде отдельных функций для минимального и максимального значений, соответственно:
FUNCTION MinY : real;
VAR i : integer;
m : real;
BEGIN
m := Y[1];
for i:=2 to N do if Y[i]<m then m := Y[i];
MinY := m
END;
FUNCTION MaxY : real;
VAR i : integer;
m : real;
BEGIN
m := Y[1];
for i:=2 to N do if Y[i]>m then m := Y[i];
MaxY := m
END;
Оси координат:
Основой для построения любых графиков и диаграмм является система координат. Ниже приведена процедура построения на экране декартовой системы координат с изображением осей и разметкой по периметру. Процедура имеет два параметра nx и ny, которые определяют количество штрихов на оси OX и OY, соответственно.
PROCEDURE BuildCoords( nx, ny : Byte );
VAR
i : Byte;
v : real;
s : string;
BEGIN
SetColor( White );
Rectangle( XWmin, YWmin, XWmax, YWmax ); { область графика }
Line( Xs(xmin), Ys(0), Xs(xmax), Ys(0) ); { ось ОХ }
Line( Xs(0), Ys(ymax), Xs(0), Ys(ymin) ); { ось OY }
SetTextStyle(SmallFont,0,5); { выбор шрифта Small }
SetTextJustify(CenterText,CenterText); { выравнивание текста }
{ Разметка оси Х }
for i:=0 to nx-1 do begin
v := xmin + (xmax-xmin)/(nx-1)*i; { координата i-го штриха }
Str(v:5:2,s); { преобразование числа в строку }
Line(Xs(v), YWmax, Xs(v), YWmax+5); { черчение i-го штриха }
OutTextXY(Xs(v), YWmax+15, s); { вывод числа }
end;
{ Разметка оси Y }
for i:=0 to ny-1 do begin
v := ymin + (ymax-ymin)/(ny-1)*i;
Str(v:5:2,s);
Line(XWmin, Ys(v), XWmin-5, Ys(v));
OutTextXY(XWmin-30, Ys(v), s);
end;
END;
Построение графика:
PROCEDURE Graphic( Color : word );
VAR i : integer;
BEGIN
SetColor( Color );
MoveTo( Xs(X[1]), Ys(Y[1]) );
Circle( Xs(X[1]), Ys(Y[1]), 2);
FOR i:=2 TO N DO begin
LineTo( Xs(X[i]), Ys(Y[i]) );
Circle( Xs(X[i]), Ys(Y[i]), 2);
end;
END;
Процедура Graphic строит точечно-линейный график по точкам, хранящимся в массивах X и Y. Параметр Color определяет цвет линии.
Таким образом, с учетом рассмотренных выше подпрограмм, программа построения графиков функций будет иметь следующую структуру:
PROGRAM Graphic_of_Function;
USES CRT, Graph;
CONST
N = 50;
VAR
X, Y : array[1..N] of real;
VAR
Описание переменных XWmin, XWmax, YWmin, YWmax;
Описание переменных xmin, xmax, ymin, ymax;
Описание процедуры SetWorldCoords;
Описание процедуры SetWindow;
Описание функции Xs;
Описание функции Ys;
Описание процедуры TablFunc;
Описание функции MinY;
Описание функции MaxY;
Описание процедуры BuildCoords;
Описание процедуры Graphic;
VAR
a, b : real;
GrDr, GrMd : integer;
BEGIN
ClrScr;
Write(‘Введите пределы изменения аргумента [a, b]: ’);
ReadLn(a, b);
TablFunc( a, b );
GrDr := detect;
InitGraph( GrDr, GrMd, ‘C:\TP7\BGI’ );
SetWindow( 100, 50, 500, 400 );
SetWorldCoords( a, MinY, b, MaxY );
BuildCoords( 5, 5 );
Graphic( Yellow );
ReadKey;
CloseGraph;
END.
Эту программу легко изменить с тем, что бы она строила график по заданным точкам, полученным, например, в результате некоторого эксперимента. Собственно говоря, ничего менять для этого не нужно. Необходимо написать новую процедуру заполнения массивов X и Y. Напомним, что раньше этим занималась процедура TablFunc. Процедура ввода данных может быть оформлена следующим образом:
PROCEDURE ReadDATA;
VAR
i : integer;
BEGIN
WriteLn(‘Введите попарно координаты точек X, Y: ’);
FOR i:=1 TO N DO begin
Write(i,‘-я точка: ’);
ReadLn( X[i], Y[i] )
end
END;
После чего в основном блоке программы вместо вызова процедуры TablFunc нужно поставить вызов процедуры ReadDATA.
На первый взгляд, рассмотренная выше программа построения линейных графиков может показаться несколько сложной (хотя это только кажущаяся сложность) и перегруженной различными процедурами и функциями. Основное достоинство рассмотренного подхода и программы в их относительной универсальности: какую бы Вы функцию не задали, какие бы Вы не ввели пределы изменения аргумента, программа обязательно построит желаемый график. Причем все изображение графика будет точно умещаться в рамках отведенного окна. Безусловно за универсальность приходится платить, и в данном случае, ценой введения разнообразных переменных и подпрограмм. Зато используя арсенал этих подпрограмм можно с одинаковой легкостью построить на экране как один график, так и целых десять, каждый из которых будет иметь свои оси координат. При желании описание некоторых подпрограмм (таких, как SetWindow, SetWorldCoords, Xs, Ys), а также переменных XWmin, XWmax, YWmin, YWmax, xmin, xmax, ymin и ymax можно оформить в виде отдельного модуля. Можно также добавить процедуры построения графиков других видов. Все это позволит в дальнейшим значительно упростить написание программ, предусматривающих построение графиков.
4. Когда нет времени…
При решении различных задач, например, связанных с компьютерным моделированием тех или иных процессов, часто возникает необходимость отобразить получаемые результаты графически. При этом возможно, что к оформлению предъявляются самые минимальные требования, особенно если результаты являются промежуточными. В этом случае, конечно же, нет необходимости писать универсальную программу для построения графиков, и поэтому многие вещи, рассмотренные ранее, можно существенно упростить.
Для примера рассмотрим простую задачу:
Камень брошен вверх под углом ά к горизонт с начальной скоростью. Требуется построить на экране траектории движения камня при разных значениях угла бросания .
Уравнения движения для координат камня x и y в неподвижной инерциальной системе отсчета имеют вид:
При заданных значения и максимальная высота подъема камня над горизонтом и максимальная дальность полета определяются соответственно:
,
.
Для построения траектории движения камня при заданных значения и
необходимо, изменяя значение t с некоторым шагом
, вычислять координаты x и y и отображать их на экране. Для того чтобы на экране “уместились” все траектории с различными значениями угла бросания необходимо сначала определить максимальную дальность полета и высоту подъема при заданном значении
. Очевидно, что максимальная дальность полета будет равна
(при
), а максимальная высота подъема
(при
).
Определим декартову систему координат (мировые координаты) относительно которой будем строить траектории движения камня:
xmin = 0, xmax = , ymin = 0, ymax =
.
С учетом формул (1) экранные координаты будут определятся следующими выражениями:
,
,
где введены обозначения: и
.
Ниже приведена соответствующая программа.
PROGRAM Stone;
USES CRT, Graph;
CONST
g = 9.8;
VAR
x, y, t, dt,
v0, alpha,
gx, gy : real;
xs, ys,
GrDr, GrMd : integer;
BEGIN
ClrScr;
Write(‘Введите начальную скорость камня Vo [м/с]: ’);
ReadLn(v0);
{ Инициализация графического режима }
GrDr := detect;
InitGraph(GrDr, GrMd, ‘C:\TP7\BGI’);
Line(0, GetMaxY, GetMaxX, GetMaxY ); { ось OX (поверхность Земли) }
{ Масштабные множители }
gx := GetMaxX / ( sqr(v0)/g );
gy := GetMaxY / ( sqr(v0)/(2*g) );
{ Начальный угол бросания }
alpha := 10;
REPEAT
{ Шаг по времени = 1/1000 от времени полета }
dt := (2*v0*sin(alpha*pi/180)/g)/1000;
t := 0;
REPEAT
x := v0*cos(alpha*pi/180)*t;
y := v0*sin(alpha*pi/180)*t-g*sqr(t)/2;
{ Вычисляем экранные координаты и ставим желтую точку }
xs := round( gx*x );
ys := GetMaxY - round( gy*y );
PutPixel( xs, ys, Yellow );
t := t + dt;
UNTIL (y<0);
alpha := alpha + 5; { Увеличиваем угол бросания на 5 градусов }
UNTIL (alpha>90);
ReadKey;
CloseGraph;
END.