Визуализация численных данных

Форум для изучающих FPC и их учителей.

Модератор: Модераторы

Визуализация численных данных

Сообщение gooroong » 08.08.2012 00:08:06

Здравствуйте!

Помогите решить проблему. Есть телеметрия некой модели. Мне надо представить как изменяются параметры визуально (в виде графиков).

Данные хранятся в памяти в виде графа, но преобразовать я смогу его только в массив, т.к. слово "SQL" для меня ничего не значит, в TP6 его особо не было.

Визуализировать массив в лоб не выйдет - он 4-х мерный

На поверхности лежит решение - проекция n-мерного пространства на двумерное. Для этого я создаю два "ползунка" tTrackBar и предлагаю пользователю указать значения. После этого я могу сформировать массив (в минимальном случае [1..2, 1..n], но, лучше если я создам массив [1..4, 1..n])

Теперь надо этот массив нарисовать. В книге "Free Pascal и Lazarus Учебник по программированию" Алексеев, Чеснокова, Кучер достаточно подробно описана схема построения графика при помощи LineTo, что, в принципе, реально, но долго :-). Думаю, что в Lazarus реализованы готовые схемы. Я нашел вкладку Chart и инструмент TChart.

Я не понял как работает эта штука и куда там "пихать" данные, кстати, там на вкладке есть еще много вариантов графиков, может быть среди них есть для трехмерных или n-мерных массивов, было бы прекрасно не изобретать велосипед.
gooroong
новенький
 
Сообщения: 11
Зарегистрирован: 06.08.2012 13:59:42

Re: Визуализация численных данных

Сообщение Oleg_D » 08.08.2012 09:47:36

В Лазарусе с TChart не работал, только в Дельфи. Предположим, что это одно и то же. Основными элементами TChart являются т.н. серии, то есть, графики. Графиков может быть сколько угодно, они создаются либо "вручную" через инспектор, либо в "ран-тайме", динамически. Доступ к графикам (сериям) осуществляется через список Series: Series[0], Series[1],... и т.д. Любой такой график можно создавать и уничтожать, очищать и добавлять к нему точки, скрывать и вновь показывать. Можно настраивать вид графика. Короче, гуглите TChart.
Для вашей задачи можно применить несколько графиков, изображая, таким образом, некоторую поверхность в трёхмерном пространстве, как это обычно принято в технической литературе. Графики создаем и заполняем динамически в соответствии с введёнными пользователем параметрами.
Oleg_D
постоялец
 
Сообщения: 391
Зарегистрирован: 09.05.2011 11:28:36

Re: Визуализация численных данных

Сообщение gooroong » 08.08.2012 10:43:58

Огромное спасибо, но объясните мне тогда, есть ли в лазарусе то, что я нашел для дельфи http://www.beluch.ru/progr/100comp/4_6_1.htm , и существует ли описание tChart для лазаруса на русском, а то все, что я нашел по запросу "tChart Lazarus" для Дельфи
gooroong
новенький
 
Сообщения: 11
Зарегистрирован: 06.08.2012 13:59:42

Re: Визуализация численных данных

Сообщение Oleg_D » 08.08.2012 13:19:20

Повторяю, что сам я в Лазарусе не работаю, но знающие люди тут на форуме утверждают, что дельфовые сведения годятся для лазаря. Так это, или нет? - придётся проверять на практике.
Oleg_D
постоялец
 
Сообщения: 391
Зарегистрирован: 09.05.2011 11:28:36

Re: Визуализация численных данных

Сообщение Ask » 08.08.2012 18:05:54

TChart в Лазарусе немного похож, но не точно повторяет Дельфи.
Для визуализации двумерного массива есть два варианта -- ColorMap либо, если по одному измерению данных немного,
набор столбиков.
Визуализации типа surface на настоящий момент нет.

Документация по TAChart:
http://wiki.lazarus.freepascal.org/TAChart_documentation
Пошаговая инструкция для начинающих:
http://wiki.lazarus.freepascal.org/TAChart_tutorial:_Getting_started
Демонстрационные программы находятся каталоге components\tachart\demo
Ask
постоялец
 
Сообщения: 163
Зарегистрирован: 25.12.2008 03:51:37

Re: Визуализация численных данных

Сообщение gooroong » 09.08.2012 13:11:17

Так, кажется начал разбираться, но все же попрошу помощи, что бы не пыхтеть с английским.

у меня на форме есть чекбоксы (пока их мало - всего 12) в данный момент реакция на изменение одного из них выглядит вот так

Код: Выделить всё
procedure TBG.CBS1BeltChange(Sender: TObject);
begin
  if CBS1BeltChange.Checked then begin
    {создаем слой на BGChart с именем BGChartSim1Belt}
  end else begin
    {удаляем слой на BGChart с именем BGChartSim1Belt}
  end;
end;


очень хочется что бы комментарии были перед кодом, который бы исполнял вышеописанное :-) спасибо!

в частности я уже сделал процедуру, которая наполняет некий массив данных [1..2,1..n] из структуры
(мне друг на все это сказал вот так "М-да, вот он, настоящий ОлдСкул!")
Код: Выделить всё
sigma----t3-----t2----Data--Simulation1...3
|        |      |
|        |      t2--- Data--Simulation1..3
|        |      |
|        |      .....
|        |         
|        t3-----t2----Data--Simulation1...3
|        |      |
|        |      t2--- Data--Simulation1..3
|        |      |
|        |      .....
|       ....
|
Sigma---...
|
... 


Добавлено спустя 1 час 19 минут 30 секунд:
вот, курица слепая, такую вещь не найти http://www.freepascal.ru/forum/viewtopic.php?f=5&t=2923
gooroong
новенький
 
Сообщения: 11
Зарегистрирован: 06.08.2012 13:59:42

Re: Визуализация численных данных

Сообщение Ask » 09.08.2012 14:55:54

gooroong писал(а):у меня на форме есть чекбоксы ... в данный момент реакция на изменение одного из них выглядит вот так
...создаем слой на BGChart с именем BGChartSim1Belt...
...удаляем слой на BGChart с именем BGChartSim1Belt...

См. демку "basic". Вообще если есть трудности с пониманием документации, рекомендую посмотреть на демки --
их довольно много, и большинство фич в них показаны.
В то же время, если количество серий известно заранее, Я бы их не создавал динамически, а создал бы заранее
и просто делал Active := true/false.

в частности я уже сделал процедуру, которая наполняет некий массив данных [1..2,1..n]

Я честно говоря не до конца понял, почему всего лишь 1..2?
Если размерность так мала, то не надо никакого 3d, достаточно просто двух серий.


В принципе там всё правильно, но это *очень* старый тред, с тех пор код TAChart был полностью переписан.
Возможно, есть мелкие несовместимости -- рекомендую всё-таки посмотреть на демки.
Ask
постоялец
 
Сообщения: 163
Зарегистрирован: 25.12.2008 03:51:37

Re: Визуализация численных данных

Сообщение gooroong » 09.08.2012 18:42:13

господа, в чем ошибка?

Код: Выделить всё
  TBG = class(TForm)
    BGChartS1Belt2: TLineSeries;
    BGChartS2Umdl4: TLineSeries;
    итд...


Код: Выделить всё
    tmpArray:=GetArray(i,1,5); {array[1..2] of double;}
    BGChartS1Belt1.AddXY(tmpArray[1],tmpArray[2]);

при трассировке возникает ошибка "проект вызвал класс исключения 'external: SIGSEGV'" при запуске exe-шника говорит, что "произошло corruption"
в массиве значения "нормальные" т.к. побовал вот так
Код: Выделить всё
    BGChartS1Belt1.AddXY(3,3);
gooroong
новенький
 
Сообщения: 11
Зарегистрирован: 06.08.2012 13:59:42

Re: Визуализация численных данных

Сообщение Pavia » 09.08.2012 19:02:58

Код: Выделить всё

tmpArray:=GetArray(i,1,5); {array[1..2] of double;}
BGChartS1Belt1.AddXY(tmpArray[1],tmpArray[2]);


Где объявление tmpArray?
Где функция GetArray?
Где создание BGChartS1Belt1?
Где создание tmpArray?
Аватара пользователя
Pavia
постоялец
 
Сообщения: 290
Зарегистрирован: 07.01.2011 12:46:51

Re: Визуализация численных данных

Сообщение gooroong » 09.08.2012 21:10:41

там модуль на 800 строк, ладно, терпите :-)

вначале покажу заголовок с определением типов
Код: Выделить всё
unit buildgraphics;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  ComCtrls, TAGraph, TASeries, gsc, types, TACustomSeries;

type

  { TBG }
  TPointArray=array[1..2] of double;

  TBG = class(TForm)
    BGChartS1Belt2: TLineSeries;
    BGChartS2Umdl4: TLineSeries;
    BGChartS2Y2: TLineSeries;
    BGChartS2Y3: TLineSeries;
    BGChartS2Y4: TLineSeries;
    BGChartS2Z2: TLineSeries;
    BGChartS2Z3: TLineSeries;
    BGChartS2Z4: TLineSeries;
    BGChartS3Belt2: TLineSeries;
    BGChartS3Umdl2: TLineSeries;
    BGChartS3Y2: TLineSeries;
    BGChartS1Umdl2: TLineSeries;
    BGChartS3Z2: TLineSeries;
    BGChartS1Y2: TLineSeries;
    BGChartS1Z2: TLineSeries;
    BGChartS2Belt2: TLineSeries;
    BGChartS2Belt3: TLineSeries;
    BGChartS2Belt4: TLineSeries;
    BGChartS2Umdl2: TLineSeries;
    BGChartS2Umdl3: TLineSeries;
    BGChartS1Umdl1: TLineSeries;
    BGChartS3Y1: TLineSeries;
    BGChartS3Z1: TLineSeries;
    BGChartS1Y1: TLineSeries;
    BGChartS1Z1: TLineSeries;
    BGChartS2Belt1: TLineSeries;
    BGChartS2Umdl1: TLineSeries;
    BGChartS2Y1: TLineSeries;
    BGChartS2Z1: TLineSeries;
    BGChartS3Belt1: TLineSeries;
    BGChartS3Umdl1: TLineSeries;
    BGChartS1Belt1: TLineSeries;
    BGLabelSigmaValue: TLabel;
    CBOne: TCheckBox;
    CBS2Belt: TCheckBox;
    CBS3Belt: TCheckBox;
    CBS1Umdl: TCheckBox;
    CBS2Umdl: TCheckBox;
    CBS3Umdl: TCheckBox;
    CBS1Y: TCheckBox;
    CBS2Y: TCheckBox;
    CBS3Y: TCheckBox;
    CBS1Z: TCheckBox;
    CBS2Z: TCheckBox;
    CBS3Z: TCheckBox;
    CBSim1: TCheckBox;
    CBSim2: TCheckBox;
    CBSim3: TCheckBox;
    CBS1Belt: TCheckBox;
    BGChart: TChart;
    Label1: TLabel;
    Label2: TLabel;
    BGLabelSigma: TLabel;
    Label4: TLabel;
    Labelt2_t3: TLabel;
    BGLabelTValue: TLabel;
    stopT2: TRadioButton;
    stopT3: TRadioButton;
    BSTrackSigma: TTrackBar;
    BSTrack_t: TTrackBar;
    procedure BGChartS1Belt1DrawPointer(ASender: TChartSeries;
      ACanvas: TCanvas; AIndex: Integer; ACenter: TPoint);
    procedure CBS1BeltChange(Sender: TObject);
    procedure CBS1UmdlChange(Sender: TObject);
    procedure CBS1YChange(Sender: TObject);
    procedure CBS1ZChange(Sender: TObject);
    procedure CBS2BeltChange(Sender: TObject);
    procedure CBS2UmdlChange(Sender: TObject);
    procedure CBS2YChange(Sender: TObject);
    procedure CBS2ZChange(Sender: TObject);
    procedure CBS3BeltChange(Sender: TObject);
    procedure CBS3UmdlChange(Sender: TObject);
    procedure CBS3YChange(Sender: TObject);
    procedure CBS3ZChange(Sender: TObject);
    function GetArray(Step, key1, key2: integer): TPointArray;
    procedure BSTrackSigmaChange(Sender: TObject);
    procedure BSTrack_tChange(Sender: TObject);
    procedure CBSim1Change(Sender: TObject);
    procedure CBSim2Change(Sender: TObject);
    procedure CBSim3Change(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure Label2Click(Sender: TObject);
    procedure stopT2Change(Sender: TObject);
    procedure stopT3Change(Sender: TObject);
    procedure RedrawIntervals(redraw_all:integer);
    procedure MakeGraph;
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  BG: TBG;
  BGHeadStructure,
  BGSigma:TSigma;
  BGt2:Tt2;
  BGt3:Tt3;
  BGA:TData;
  BGSim1,
  BGSim2,
  BGSim3:TSim;
  BGInterval_t2,
  BGInterval_t3,
  BGInterval_Sigma: integer;
  BGSigmaStep,
  BGt3Step,
  BGt2Step: real;
  PointArray: TPointArray;
  SeriesCounter: integer;


implementation

{$R *.lfm}


Код: Выделить всё
{тут надо отследить, какие флажи поставлены и создать массивы
я не вижу варианто отличных от "если - то"}
procedure TBG.MakeGraph;
var
  i: integer;
  tmpArray: TPointArray;
begin
  BGSigma:=BGHeadStructure;
  while BGSigma^.Counter<>BSTrackSigma.Position do BGSigma:=BGSigma^.Up;
  BGt3:=BGSigma^.Link;
  for i:=1 to BSTrack_t.Max do begin
    {общее правило выглядит так: если стоит галочка на поле и
    включена галочка "искать только одно решение" то
    сохраняем 5й вариант, иначе в цикле выводим все варианты}
    if CBS1Belt.Checked then begin
      if CBOne.Checked then begin
        tmpArray:=GetArray(i,1,5);
        BGChartS1Belt1.AddXY(tmpArray[1],tmpArray[2]);
      end else begin
        tmpArray:=GetArray(i,1,1);
        BGChartS1Belt1.AddXY(3,3); {тут я как бы говорю, что этой процедуре пофиг на то, что ей кормят - будет ошибка}
        tmpArray:=GetArray(i,1,2);
        BGChartS1Belt2.AddXY(tmpArray[1],tmpArray[2]);
      end;
    end;
   
тут достаточно однообразно

    BGt3:=BGt3^.Up;
  end;
end;


Код: Выделить всё
{щписание ключа 1
симуляция 1
1 - бельта
2 - U среднее
3 - Y
4 - Z-Y
симуляция 2
11 - бельта
12 - U среднее
13 - Y
14 - Z-Y
симуляция 3
21 - бельта
22 - U среднее
23 - Y
24 - Z-Y
ключ 2 отвечает за выбор "варианта" каждого из значений

а как это работает
нам нужно пробежаться по гафу и собрать значения в массив
для этого мы определяем какоевремя закреплено и у нас есть два пути
1 простой нам надо прийти по указанной ветке сигма - т3 - т2 и
  перемещаясь по т2 собрать все нужные знчения
2 не просто мы идем на ветку т3, переходим на т2,
  далее по ветке спускаемся до закрепленного значения и собираем его
  затем спускаемся на следующее т3}
function TBG.GetArray(Step, key1, key2: integer): TPointArray;
begin
  if stopT3.Checked then begin
    while BGt3^.Counter<>BSTrack_t.Position do BGt3:=BGt3^.Up;
    BGt2:=BGt3^.Link;
    while BGt2^.Counter<>Step do BGt2:=BGt2^.Up;
    PointArray[1]:=BGt2^.Value;
    BGA:=BGt2^.Link;
    BGSim1:=BGA^.Sim1;
    BGSim2:=BGA^.Sim2;
    BGSim3:=BGA^.Sim3;
    case key1 of
      1 : PointArray[2]:=BGSim1^.Belt[Key2];
      2 : PointArray[2]:=BGSim1^.Umdl[Key2];
      3 : PointArray[2]:=BGSim1^.Y_i[Key2];
      4 : PointArray[2]:=BGSim1^.Z_y[Key2];
     11 : PointArray[2]:=BGSim2^.Belt[Key2];
     12 : PointArray[2]:=BGSim2^.Umdl[Key2];
     13 : PointArray[2]:=BGSim2^.Y_i[Key2];
     14 : PointArray[2]:=BGSim2^.Z_y[Key2];
     21 : PointArray[2]:=BGSim3^.Belt[Key2];
     22 : PointArray[2]:=BGSim3^.Umdl[Key2];
     23 : PointArray[2]:=BGSim3^.Y_i[Key2];
     24 : PointArray[2]:=BGSim3^.Z_y[Key2];
    end;
  end else begin
    while BGt3^.Counter<>Step do BGt3:=BGt3^.Up;
    PointArray[1]:=BGt3^.Value;
    BGt2:=BGt3^.Link;
    while BGt2^.Counter<>BSTrack_t.Position do BGt2:=BGt2^.Up;
    BGA:=BGt2^.Link;
    BGSim1:=BGA^.Sim1;
    BGSim2:=BGA^.Sim2;
    BGSim3:=BGA^.Sim3;
    case key1 of
      1 : PointArray[2]:=BGSim1^.Belt[Key2];
      2 : PointArray[2]:=BGSim1^.Umdl[Key2];
      3 : PointArray[2]:=BGSim1^.Y_i[Key2];
      4 : PointArray[2]:=BGSim1^.Z_y[Key2];
     11 : PointArray[2]:=BGSim2^.Belt[Key2];
     12 : PointArray[2]:=BGSim2^.Umdl[Key2];
     13 : PointArray[2]:=BGSim2^.Y_i[Key2];
     14 : PointArray[2]:=BGSim2^.Z_y[Key2];
     21 : PointArray[2]:=BGSim3^.Belt[Key2];
     22 : PointArray[2]:=BGSim3^.Umdl[Key2];
     23 : PointArray[2]:=BGSim3^.Y_i[Key2];
     24 : PointArray[2]:=BGSim3^.Z_y[Key2];
    end;
  end;
end; 


Создание BGChartS1Belt1 я создал искусственно нажав на TChar, затем в окне edit series в поле на "+"
Возможно я что то не доделал?

Cоздание tmpArray в первом фрагменте представленного кода.
gooroong
новенький
 
Сообщения: 11
Зарегистрирован: 06.08.2012 13:59:42

Re: Визуализация численных данных

Сообщение Pavia » 10.08.2012 20:08:19

Очевидных ошибок не видно.
А в какой строчке вылетает не ясно так?
Где-то указатель убежал и повредил данные, повреждённые данные после вызывают сбой в самом не предсказуемом месте и времени.
Тогда дедовский способ комментируем определённые участки программа и проверяем где появляется ошибка.

Хотя тут лучше включить обнаружения выхода указателя за диапазон отведённой памяти.Range Check. И в менеджере памяти включить отладочный режим.
http://www.gunsmoker.ru/2009/05/blog-post_24.html
Лучше вот по этой ссылке
http://www.gunsmoker.ru/2009/05/access-violation.html

Правда в вашем случае у меня есть сомнения что эти утилиты помогут. А вот дедовский метод точно.
Аватара пользователя
Pavia
постоялец
 
Сообщения: 290
Зарегистрирован: 07.01.2011 12:46:51

Re: Визуализация численных данных

Сообщение gooroong » 10.08.2012 23:07:34

я уже писал, что ошибка происходит при исполнении вот этой строки, т.е. никаких выходов за пределы ссылок быть не может
я ставил прерывание и проводил трассировку

Код: Выделить всё
BGChartS1Belt1.AddXY(3,3);
gooroong
новенький
 
Сообщения: 11
Зарегистрирован: 06.08.2012 13:59:42

Re: Визуализация численных данных

Сообщение Pavia » 11.08.2012 10:24:55

Код: Выделить всё
BGChartS1Belt1.AddXY(3,3);

Здесь вылетать нечему. Разве только у вас BGChartS1Belt1=nil.
Значит это одно Вы где-то напортачили с указателями они попортили чужие данные. Ошибка прожила ещё какое-то время пока не наткнулась на вашу строчку.
Код: Выделить всё
BGChartS1Belt1.AddXY(3,3);

Это трудно обнаруживаемая ошибка, так как проявляется не сразу.
Аватара пользователя
Pavia
постоялец
 
Сообщения: 290
Зарегистрирован: 07.01.2011 12:46:51

Re: Визуализация численных данных

Сообщение Ask » 11.08.2012 10:46:08

Лучше всего в таких случаях постить не куски кода, а полный проект, желательно урезанный до минимального,
на котором ошибка ещё проявляется.
Это существенно сэкономит время людей, пытающихся помочь -- отладка с полным проектом может занять 5 минут,
а так гадать можно неделями.
Ask
постоялец
 
Сообщения: 163
Зарегистрирован: 25.12.2008 03:51:37

Re: Визуализация численных данных

Сообщение gooroong » 11.08.2012 13:36:40

Господа, прошу прощения у меня в процедуре инициализации моLуля был сюрприз, который я сам себе подложил, т.к. вначале собирался создавать серии динамически, и поставил такую вот процедуры xxx.series.clean вот такой я молодец!

Ладно. попробую дальше колупаться, во всяком случае ошибка не вылетает, но пока не рисует :-) ДВА ДНЯ ЕЖЕДНЕВНОЙ ТРАССИРОВКИ

Добавлено спустя 2 часа 30 минут 36 секунд:
Господа, практически финальный рывок!

Все рисуется, не скажу, что красиво, но верно

Вопрос: возможно ли что бы был не единый масштаб, а для каждой серии свой? Цифры выводить не надо
gooroong
новенький
 
Сообщения: 11
Зарегистрирован: 06.08.2012 13:59:42

След.

Вернуться в Обучение Free Pascal

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 2

Рейтинг@Mail.ru