19. НАУЧНАЯ ГРАФИКА

Под научной графикой я понимаю изображение зависимостей одних переменных от других, а также изображение двумерных распределений какой-то величины. Другими словами, изображение одномерных и двумерных функций. Для такого изображения существуют определенные стандарты и достаточно много специальных программ. В использовании ACL, по крайней мере, в моей работе, показ научных графиков является достаточно частой операцией. Соответственно реализовано несколько разных возможностей, описание которых дано в этом разделе. Прежде всего обсудим общую структуру описания осей координат и заголовков на некоторых плоских графиках. Способ рисования осей и заголовков является общим для всех таких графиков. Так полный размер графика в пикселах экрана определяется параметрами [twi] и [the]. При этом x и y размеры прямоугольника из осей координат равны значениям параметров [wid] и [hei]. Левый нижний угол этого прямоугольника имеет координаты [xsh] и [ysh] относительно левого нижнего угла поля графика.

Оси имеют короткие и длинные риски. Размеры этих рисок определяются параметрами [bot] и [top] соответственно. Риски могут смотреть внутрь и наружу от осей. Кроме того, каждая ось может иметь три свойства: отсутствовать, присутсвовать без чисел и с числами. Все эти свойства задаются одним параметром [sty]. В общем случае это пятиразрядное целое число, имеющее структуру "lbrtm". Первые четыре разряда определяют способ рисования осей, "l" для левой оси, "b" для нижней оси, "r" для правой оси и "t" для верхней оси. Если эти разряды равны 0, это означает стандартное появление осей, когда левая и нижняя оси имеют числа, а правая и верхняя оси не имеют чисел. Если эти разряды равны 2, это означает нестандартное появление осей, когда, наоборот, правая и верхняя оси имеют числа, а левая и нижняя не имеют чисел. Если они равны 1, то соответствующая ось вообще не будет нарисована. Последний пятый разряд "m" определяет ориентацию рисок. Если "m" = 0, они смотрят внутрь, а если "m"=1 они смотрят наружу. Вот примеры: [sty=1;] -- это стандартная форма, [sty=11211;] -- это указание на рисование только правой оси с числами. Обратите внимание, что если "m"=0 и [top=max/2;] где max = maximum(wid,hei), то график будет иметь сетку.

Числа на осях будут иметь размер, определяемый параметром [tsi] в пикселах экрана. Кроме того, параметры [tfo] и [tki] позволяют задать фонт и тип текста точно так же, как в команде #g (см. раздел 14). Очевидно необходимо указать какие значения ставить на рисках. Однако, если параметр [uni=0;], то эти значения определяются автоматически из минимального и максимального значений для функции и аргумента. Очень часто этого достаточно. Все же иногда автоматическая разметка осей может быть нежелательной. В этом случае параметр [uni] должен указывать на номер первого элемента реального массива r(), где находится дополнительная информация об осях. Пусть, например, [uni=i;]. Тогда программист должен определить

r(i) = fnor ( единицу для функций, график будет показывать f(x)/fnor )
r(i+1) = xmin (минимальное значение на оси x)
r(i+2) = xmax (максимальное значение на оси x)
r(i+3) = xmf (значение для первой длинной риски на оси x)
r(i+4) = xms (разницу значений между длинными рисками на оси x)
r(i+5) = xni (число коротких рисок в области между длинными рисками на оси x)
r(i+6) = ymin (минимальное значение на оси y)
r(i+7) = ymax (максимальное значение на оси y)
r(i+8) = ymf (значение для первой длинной риски на оси y)
r(i+9) = yms (разницу значений между длинными рисками на оси y)
r(i+10) = yni (число коротких рисок в области между длинными рисками на оси y)

Такой способ позволяет приготовить график произвольной формы.

Что касается заголовков, то число заголовков задается параметром [n], но сами заголовки являются аргументами команд. Структура этих аргументов следующая:   x   y   rts   FT   для каждого заголовка. Здесь   x   и   y  -- положение левого нижнего угла текста заголовка, FT есть форматированный текст соответствующего заголовка (см. описание форматированного текста в команде #print раздела 4),   rts   определяет увеличение или уменьшение размера текста заголовка относительно [tsi]. Стандартное значение есть [tsi=14;]   rts=2.

После такого введения вернемся к командам. Научная графика не выполняется специальными командами, а сделана в виде операций уже рассмотренных выше команд оконной графики. Напомню, что во всех оконных операциях надо задавать параметр [c=1;] если необходимо задержать выполнение программы.

Прежде всего, это дополнительные операции команды #w, а именно

.

 #w [op=pf; file=; form=; c=; b=; le=; mo=; twi=; the=;  wid=; hei=; xsh=; ysh=; sty=; bot=; top=;
   nx=; ny=; sav=; tsi=; tfo=; tki=; uni=;   col=; msi=; mki=; n=;] аргументы

Эта операция называется plain figure. Она выполняет научный график, на котором показаны некоторые зависимости в виде кривых. Этот график имеет оси и заголовки. Каждая кривая является зависимостью одной величины от другой величины. Кривые показываются внутри прямоугольника из осей. Числовые данные берутся из файла, имя которого задает параметр [file]. Данные должны быть записаны в файл как реальные числа в компьютерном коде (длиной 4 байта) одна кривая за другой кривой. Данные другого формата могут быть предварительно прочитаны командой #io [file=;]. Здесь также есть особый случай. Если [file=here;], то числа берутся из реального массива r(), начиная с первого индекса, задаваемого параметром [b]. Значения массива r() могут быть определены предварительно разными способами. Как и в других операциях, файл может иметь заголовок. Размер заголовка определяется параметром [le]. Число точек на одну кривую задается параметром [nx] и оно может рассматриваться как размер одной колонки в обычном представлении функций матрицей чисел. Число колонок в файле определяется параметром [ny]. Однако смысл колонок может быть разным в зависимости от значения параметра [mo]. Если [mo=0;], все колонки есть функции. Аргумент для этих функций вычисляется из минимального и максимального значений Xmin и Xmax с постоянным шагом. Значения Xmin и Xmax являются аргументами команды, которые должны стоять перед любыми другими аргументами. Если [mo=1;], то первая колонка -- аргумент, а все остальные -- функции. Число функций равно [ny]-1. Если [mo=2;], то нечетные колонки есть аргументы, а четные колонки есть функции, то есть каждая функция имеет свои аргументы. Число функций равно [ny]/2.

В случае [uni=0;] разметка осей производится из минимального и максимального значений всех аргументов и всех функций. В противном случае она должна быть указана, как описано в начале этого раздела. Первая кривая рисуется цветом, задаваемым элементом массива цветов с индексом задаваемым параметром [col]. В случае нескольких кривых каждая следующая кривая рисуется цветом, задаваемым следующим элементом массива цветов. Массив цветов определяется командой #col (см. раздел 14). Тип представления кривой зависит от значения параметра [msi], который определяет размер маркера в пикселах. Если [msi=0;], все кривые рисуются линиями единичной толщины. Если [msi] > 0, то параметр [mki] определяет тип маркера для первых 5 кривых. Это есть 5-разрядное целое число, в котором каждый разряд может иметь значения от 0 до 4. Все 5 разрядов необходимо задавать, причем левый (старший) разряд относится к первой кривой, следующий слева - к второй кривой и так далее. Например, [mki=1234;] означает линию для первой кривой (левый разряд = 0), пустой прямоугольник для второй кривой, сплошной прямоугольник для третьей кривой, пустой круг для четвертой кривой, и сплошной круг для пятой кривой. Остальные кривые задаются теми же маркерами в цикле. Полученный рисунок будет либо показан, либо спасен в память или в файл в зависимости от значения параметра [sav] и [c] точно так же как и в других операциях с окнами, например, #w [op=im;]. Не забывайте, что все параметры являются элементами массива s(). Соответствие имен и индексов указано ниже:
[n](7), [c](8), [b](9), [le](10), [mo](11), [twi](12), [the](13), [wid](14), [hei](15), [xsh](16), [ysh](17), [sty](18), [bot](19), [top](20), [nx](21), [ny](22), [sav](23), [tsi](24), [uni](25), [col](29), [tfo](30), [tki](31), [msi](32), [mki](33).
Вот пример части возможной программы

 # x=-2; i=102; j=304; k=1; l=203;
 #rep 101 # r(i)=100*exp(-x^2); i=i+1; r(j)=80*exp(-(x-0,5)^2);
   j=j+1; r(k)=x; k=k+1; r(l)=x; l=l+1; x=x+0,04;
 #end #io [n=404; fir=r(1); op=wd; file=test.dat; mo=1;]
 #d 3 i(1) 255 0 0 #col [b=2; le=1; fir=i(1);]
 #d 19 s(7) 2 1 0 0  2 240 320 200 220 30 60  0 3 6 101 4 0 14 0 
 #d 5 s(29) 1 3 0 0 0 
 #w [op=pf; file=test.dat; form=test;] 128 20 2 Distance [mm]\E
 15 300 2 Gaussians [arb. units]\E

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

Следующая операция этой же команды называется multi-plain figure

.

 #w [op=mp; file=; form=; c=; b=; le=; twi=; the=; wid=; hei=; xsh=; ysh=; 
  bot=; top=; nx=; ny=; trx=; try=; sav=; tsi=; tfo=; tki=;] xmi xma ymi yma

Этот тип графика в некотором роде похож на предыдущий тип и иногда он даже показывает тот же самый график. Однако его главная цель -- это показывать двумерный массив данных как квази-трехмерный график. Этот график получает данные в виде матрицы чисел и показывает каждую строку матрицы как отдельную функцию. Но плоскость графика для каждой следующей кривой (строки) смещается по сравнению с предыдущей горизонтально и вертикально и каждая предыдущая кривая имеет смысл непрозрачного щита, так что невидимые части следующих кривых не рисуются. Соответственно третья наклонная ось справа показывает значение второго аргумента. Как обычно данные в компьютерном коде (реальные длиной 4 байта) берутся из файла с именем [file], где [le] байт определяют заголовок. Если [file=here;], то данные берутся из массива r(), в котором индекс первого элемента есть [b]. Полные размеры графика равны [twi] и [the]. Размеры горизонтальных и вертикальных осей есть [wid] и [hei]. Параметры [bot] и [top] определяют размер рисок. Размеры матрицы чисел равны [nx] and [ny]. Файл содержит только значения функции f(x,y) без аргументов. Предполагается, что сетка точек задается с постоянным шагом. Минимальные и максимальные значения на осях x и y являются аргументами команды. Сдвиг плоскостей графика определяется параметрами [trx] и [try] но в разных единицах. Параметр [trx] измеряется в шагах аргумента на оси х, то есть это есть целое число, указывающее число шагов. Обычно [trx=1;]. Параметр [try] измеряется в Fmax/1000, где Fmax -- максимальное значение функции f(x,y). То есть, если [try=30;], то это означает 0.03*Fmax. Параметры [tsi], [tfo] и [tki] определяют стиль текста для чисел на осях. Наконец, параметр [sav] задает способ сохранения картинки так же как во всех оконных операциях. Оси данная операция не подписывает. Если необходимо, то это можно сделать более сложным ACL кодом. Например, спасти рисунок в память и затем продолжить его с командой #g, в которой можно поставить тексты на заданные позиции. Разметка осей делается на этом графике автоматически.

Следующая операция этой же команды называется mathematical map

.

 #w [op=mm; file=; form=; c=; b=j; mo=; sav=; twi=; the=; wid=; hei=; xsh=; ysh=; 
  sty=; bot=; top=; tsi=;    uni=; tfo=; tki=; n=;] аргументы

Этот тип графика показывает картинку, помещенную в прямоугольник из осей с заголовками. Картинка из файла должна быть реальной картинкой, а не числовой матрицей. Данные могут быть предварительно конвертированы в картинку операцией #w [op=im;]. Если [file=here;] картинка берется из памяти компьютера как спасенная с индексом, определяемым параметром [mo]. Картинка помещается полностью и устанавливается симметрично относительно прямоугольника осей. См. выше как задаются оси. Если [uni=0;], то разметка осей производится автоматически из минимального и максимального значений на осях. Последние значения берутся из r(j),..,r(j+3), где j равно значению параметра [b]. Если [uni] > 0, то параметр указывает на индекс массива r(), где задается разметка горизонтальной и вертикальной оси, но первым элементом стоит значение на которое нормируется функция. То есть надо указывать 10 чисел, начиная с какого-то индекса j. Тогда [uni=j-1;] и первый параметр в данной программе не используется. Это не вполне логично, но так получилось. Поэтому j не может быть равным 1. Оси можно задавать только с j=2. Новая картинка (уже с осями) может быть записана в файл с именем [form] или в память согласно значению параметра [sav].

Кроме того, у этой команды есть операция, называемая final figure

.

 #w [op=ff; file=here; form=; sav=; n=; c=; b=j;] FT 

Эта операция собирает сложную картинку из нескольких картинок, сохраненных в памяти компьютера. Такую же работу могут выполнять команды #g и #eg, но данная операция была сделана раньше и работала еще в тех версиях языка ACL, в которых команд графики не существовало. Предполагается, что спасенная в память компьютера картинка с номером 1 является базовой картинкой и имеет максимальные размеры. Все другие картинки, если они существуют, будут помещены поверх первой. Они будут сдвинуты из начала первой картинки на вектор (x,y), координаты которого берутся из целого массива i() как i(j),i(j+1) для второй картинки, i(j+2),i(j+3) для следующей картинки и так далее, где j - это значение параметра [b]. Полное число картинок задается параметром [n]. Чтобы избежать сообщения об ошибке необходимо указать [file=here;], так как этого требует грамматика. Аргумент FT определяет название полной картинки. Типичное применение -- комбинация карты почернений и шкалы почернений. Но могут быть и более сложные случаи, например полная картина и ее сечения.

Научную графику, кроме того, можно выполнить специальными операциями команды #g. Это относится, в первую очередь, к графику типа plain figure. Но в отличие от #w [op=pf;] с помощью команды #g такой график делается в несколько операций.

.

 #g [op=rfun; file=; mo=; n=; le=; nx=; ny=; b=;]

Эта операция прочитывает значения функций, которые могут быть показаны затем внутри прямоугольника осей. Это делается точно так же, как и в команде #win [op=pf;] (см. выше в этом разделе). После чтения данных минимальное и максимальное значения аргументов и функций будет возвращено программисту в элементах реального массива r() начиная с первого номера равного значению параметра [n]. Поэтому при автоматической разметке осей эту операцию надо выполнить раньше, чем рисовать оси. А при рисовании осей использовать информацию о минимальных и максимальных значениях.

.

 #g [op=axes; col=; b=; wid=; hei=; xsh=; ysh=; bot=; top=; sty=; tfo=; tki=; tsi=; uni=; n=;] аргументы

Эта операция позволяет добавить на график прямоугольник осей координат и заголовки к нему. Размеры прямоугольника осей равны [wid] и [hei]. Цвет линий и текстов задается параметром [col] как номер элемента массива цветов. Центральная точка прямоугольника осей имеет координаты [xsh] и [ysh]. В остальном оси и заголовки определяются точно так же, как в команде #w [op=pf;] (см. выше в этом разделе). При автоматической разметке осей информация о минимальном и максимальном значениях аргумента и функции xmi xma fmi fma берется из реального массива r(), в котором номер первого элемента определяется параметром [b].

.

 #g [op=dfun; col=; nx=; ny=; mo=; b=; msi=; mki=;]

Эта операция позволяет программисту начертить функции внутри прямоугольника осей. Значения функций должны быть предварительно прочитаны операцией [rfun]. Цвет задается параметром [col]. Параметры [nx], [ny] и [mo] имеют тот же самый смысл, что и выше. Параметр [b] определяет индекс реального массива r(), где находятся значения xmi, xma, fmi, fma, используемые для рисования осей. Замечу, что эти значения должны быть точно теми же самыми, как они были определены операцией [rfun]. Однако [rfun] возвращает их в индекс [n], а здесь тот же самый индекс определяется параметром [b]. К сожалению это отличие не может быть исправлено, потому что [b] используется в операции [rfun] для других целей. Будьте внимательны при задании всех параметров в явном виде. Функции рисуются точно так же как в команде #win [op=pf;]. Вообще, комбинация операций [rfun] [axes] [dfun] способна делать ту же работу, что и команда #w [op=pf;], но здесь есть дополнительные возможности, потому что можно рисовать различные функции разными цветами. Кроме того, область осей может не совпадать с областью функций.

В команде #g реализована дополнительная новая операция, которая рисует однозначную функцию двух переменных как аксонометрическую проекцию поверхности некоторого трехмерного объекта, описываемую однозначной функцией z(x,y) где x, y, z есть трехмерные координаты. Объект рисуется линиями через x-z и y-z сечения одновременно или раздельно. Невидимые линии не показываются. Объект помещается в координатные оси, которые показывают значения x, y и z координат. Аксонометрическая проекция строится используя точку зрения как направление между (0,0,0) точкой объекта и точкой зрения и отдельно расстояние между этими точками. Алгоритм устранения невидимых линий предполагает положительные координаты направления точки зрения около [1,1,1]. Данная операция имеет следующую структуру

.

 #g [op=axon; col=; n=; c=; b=; wid=; hei=; xsh=; ysh=; tsi=; tfo=; tki=;]

Ниже шаг за шагом описываются все параметры графика. Цвет определяется [col]. Полные размеры картинки задаются параметрами [wid] и [hei]. Положение левого нижнего угла имеет координаты [xsh], [ysh]. Параметры фонта для значений на осях определяются [tfo], [tki], [tsi] аналогично операции [op=text;]. Функция z(x,y) задается в реальном массиве r(), начиная с первого индекса [b]. Другие реальные параметры должны быть указаны в массиве r(), стартуя с элемента с индексом [n]. Эти параметры имеют следующую структуру:
xmi, xma, xfm, xdm, ymi, yma, yfm, ydm, zmi, zma, zfm, zdm, vp1, vp2, vp3, vpm, hx, hy.
Здесь [xmi] и [xma] минимальные и максимальные значения на оси x; [xfm] значение для установки первой короткой риски; [xdm] значение для разности между короткими рисками. Параметры, у которых имена начинаются с y и z, означают то же самое для y и z осей. Значения [vp1], [vp2], [vp3] описывают направление точки зрения для аксонометрической проекции. Три координаты используются для удобства. Реально вектор нормируется на единицу. Расстояние до точки зрения задается отдельно значением [vpm], которое является десятичным логарифмом для избежания ввода очень больших чисел. Будьте осторожными и не вводите большие числа, так как 3 означает 1000, 5 означает 100000 и так далее. Обычно [hx]=1 и [hy]=1. Эти параметры удобны, если вместо реального трехмерного объекта желательно рисовать некую зависимость f(a,b) где [f], [a] и [b] могут иметь произвольные значения. В этом случае для получения разумной формы необходимо вводить истинные значения и затем подбирать масштабирующие коэффициенты [hx] и [hy] для x и y осей таким образом, что [da]*[hx] и [db]*[hy] имели бы значения близкие к [df] где da = [a]max - [a]min, и то же самое для [b] и [f]. Кроме того, задаются целые параметры как элементы целого массива i(), начиная с индекса [c]. Эти параметры имеют следующую структуру:
nx, ny, ngv, bot, top, nxfm, nxsm, nyfm, nysm, nzfm, nzsm, nax
Здесь [nx] число точек на оси x; [ny] то же самое для оси y. Массив значений функций содержит только значения без аргументов как матрица [nx][ny]. Параметр [ngv] должен быть равен 1 (для x-z сечений) 2 (для y-z сечений) 3 (для обоих сечений одновременно). Параметры [bot] и [top] описывают длину коротких и длинных рисок в единицах, которые равны 0.001 части диагонали для x и y осей соответственно спроектированных. Может быть сделана некоторая коррекция, если [vp1] отличается от [vp2]. Параметр [nxfm] -- это номер первой короткой риски, которая преобразуется в длинную риску и получает значение. Параметр [nxsm] есть число коротких рисок между длинными рисками. Другие параметры означают то же самое для y и z осей. Последний параметр [nax] описывает появление вертикальной осей. Если [nax] = 0, левая и правая вертикальные оси появятся вместе со средней осью и горизонтальными линиями уровней. Если [nax] = 1, только правая вертикальная ось появится около оси x. Если [nax] = 2, только левая вертикальная ось появится около оси y.
Вот пример готовой программы для рисования гауссовой поверхности

 # y=-9; d=0.2; j=21;
 #rep 91  # x=-9;
  #rep 91  # r(j)=exp(-0.03*(x*x+y*y)); j=j+1; x=x+d; #end # y=y+d;
 #end 
 #p [trx=0; try=0; sca=100;] #d 6 i(1) 255 255 255 0 0 0 
 #col [b=1;le=2;fir=i(1);] #g [op=open; twi=800; the=600; col=1;]
 #d 12 i(1) 91 91 3 7 12 2 3 2 3 1 1 0
 #d 18 r(1) -0,9 0,9 -0,9 0,1 -0,9 0,9 -0,9 0,1 0 1 0 0,1 1 1 0.5 3 1 1
 #p [tfo=3; tki=0; tsi=14; col=2;]
 #g [op=axon; n=1; c=1; b=21; wid=600; hei=500; xsh=100; ysh=60;]
 #g [op=clos; sav=0;] Test of Graphics\E

В этой программе функция двух переменных предварительно вычисляется и затем рисуется операцией axon после задания всех параметров графика.