Форма с TChart в консольном приложении

Вопросы программирования и использования среды Lazarus.

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

Форма с TChart в консольном приложении

Сообщение mike » 14.08.2025 19:57:41

Всем привет.

Возникла необходимость постройки графиков в консольном приложении (fpWeb), для чего была добавлена невидимая форма с чартами, некоторые модули в uses, и все прекрасно работает под Win.
Однако после сборки под Linux возникла проблема с тулкитом визуализации. При запуске требует GUI-библиотеку, которой на сервере нет. И даже если установить либы GTK или QT, иксов-то все рано нет, и все равно не запускается.
Можно, конечно, установить какой-нибудь Xvfb, который создаст мне фейковый X-сервер, но это уже ИМХО перебор.

Есть какой-то способ заставить работать невидимую форму в Linux без X-сервера?

Пробовал LCLWidgetType = nogui, но он сильно недоделанный, валит ошибки, а в конце еще и не умеет создавать виртуальный дескриптор канвы, что убивает всякую возможность отрисовки чего-либо в битмап. Задница...
mike
новенький
 
Сообщения: 45
Зарегистрирован: 23.02.2007 17:25:00

Re: Форма с TChart в консольном приложении

Сообщение sts » 15.08.2025 09:35:33

sts
постоялец
 
Сообщения: 466
Зарегистрирован: 04.04.2008 12:15:44
Откуда: Тольятти

Re: Форма с TChart в консольном приложении

Сообщение Alexander » 15.08.2025 09:58:39

В вопросе есть противоречие. Консольное приложение и есть не графическое по определению.

Что можно попытаться сделать? Например, использовать GNU/Plot:

Код: Выделить всё
unit GnuPlotUtils;
{$MODE OBJFPC}{$H+}

{
    Gnu Plot visualizator.
    For GNU/Linux 64 bit version. Root priveleges or kernel patch needed.
    Version: 1.
    Written on FreePascal (https://freepascal.org/).
    Copyright (C) 2024-2025  Artyomov Alexander
    http://self-made-free.ru/
    aralni@mail.ru

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU Affero General Public License as
    published by the Free Software Foundation, either version 3 of the
    License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Affero General Public License for more details.

    You should have received a copy of the GNU Affero General Public License
    along with this program.  If not, see <https://www.gnu.org/licenses/>.
}

interface

uses
  SysUtils, Classes, Process, DataTypes;

procedure SaveDataForPlot(const FileName: String;
                         const Data: TDoubleMatrix;
                         const Labels: TIntegerArray);
procedure PlotKMeansClusters(const DataFile, CentroidFile: String;
                           K: Integer);
procedure PlotGBPredictions(const DataFile, PredictionsFile: String);

implementation

procedure SaveDataForPlot(const FileName: String;
                         const Data: TDoubleMatrix;
                         const Labels: TIntegerArray);
var
  f: TextFile;
  i: Integer;
begin
  AssignFile(f, FileName);
  Rewrite(f);
  try
    for i := 0 to High(Data) do
    begin
      if (Length(Labels) > 0) and (i <= High(Labels)) then
        WriteLn(f, Format('%g %g %d', [Data[i][0], Data[i][1], Labels[i]]))
      else
        WriteLn(f, Format('%g %g', [Data[i][0], Data[i][1]]));
    end;
  finally
    CloseFile(f);
  end;
end;

procedure PlotKMeansClusters(const DataFile, CentroidFile: String;
                           K: Integer);
var
  gnuplot: TProcess;
  script: TStringList;
  scriptFile: String;
begin
  script := TStringList.Create;
  try
script.Add('set size square');
script.Add('set grid');
script.Add('set key outside');

    script.Add('set title "KMeans Clustering (K=' + IntToStr(K) + ')"');
    script.Add('set xlabel "Feature 1"');
    script.Add('set ylabel "Feature 2"');
    script.Add('set palette defined (0 "red", 1 "blue", 2 "green", 3 "purple")');
    script.Add('plot "' + DataFile + '" using 1:2:3 with points pt 7 ps 1 palette title "Data", \');
    script.Add('     "' + CentroidFile + '" with points pt 2 ps 3 lc black title "Centroids"');
    script.Add('pause -1 "Press Enter to continue"');
   
    scriptFile := ChangeFileExt(DataFile, '.plt');
    script.SaveToFile(scriptFile);
   
    gnuplot := TProcess.Create(nil);
    try
      gnuplot.Executable := 'gnuplot';
      gnuplot.Parameters.Add(scriptFile);
      gnuplot.Execute;
    finally
      gnuplot.Free;
    end;
  finally
    script.Free;
  end;
end;

procedure PlotGBPredictions(const DataFile, PredictionsFile: String);
var
  gnuplot: TProcess;
  script: TStringList;
  scriptFile: String;
begin
  script := TStringList.Create;
  try
    script.Add('set title "Gradient Boosting Predictions"');
    script.Add('set xlabel "Feature"');
    script.Add('set ylabel "Target"');
    script.Add('plot "' + DataFile + '" using 1:2 with points pt 7 title "Actual", \');
    script.Add('     "' + PredictionsFile + '" using 1:2 with lines lw 2 title "Predicted"');
    script.Add('pause -1 "Press Enter to continue"');
   
    scriptFile := ChangeFileExt(DataFile, '_gb.plt');
    script.SaveToFile(scriptFile);
   
    gnuplot := TProcess.Create(nil);
    try
      gnuplot.Executable := 'gnuplot';
      gnuplot.Parameters.Add(scriptFile);
      gnuplot.Execute;
    finally
      gnuplot.Free;
    end;
  finally
    script.Free;
  end;
end;

end.


Код: Выделить всё
procedure VisualizeKMeans;
var
  dataFile, centroidFile: String;
  emptyLabels: TIntegerArray;
begin
  if not isDataLoaded or (Length(kmeansModel.centroids) = 0) then
  begin
    ShowError('Данные не загружены или модель не обучена');
    Exit;
  end;
  if Length(x[0]) <> 2 then
  begin
    ShowError('Визуализация доступна только для 2D данных');
    Exit;
  end;
  try
    dataFile := 'kmeans_data.dat';
    centroidFile := 'kmeans_centroids.dat';
    // Создаем пустой массив меток для центроидов
    SetLength(emptyLabels, 0);
    // Сохраняем данные с метками кластеров
    GnuPlotUtils.SaveDataForPlot(dataFile, x, kmeansModel.labels);
    // Сохраняем центроиды (без меток)
    GnuPlotUtils.SaveDataForPlot(centroidFile, kmeansModel.centroids, emptyLabels);
    // Визуализируем
    GnuPlotUtils.PlotKMeansClusters(dataFile, centroidFile, Length(kmeansModel.centroids));
    ShowSuccess('Визуализация завершена. Проверьте окно GNU Plot.');
  except
    on E: Exception do
      ShowError('Ошибка визуализации: ' + E.Message);
  end;
end;
Аватара пользователя
Alexander
энтузиаст
 
Сообщения: 840
Зарегистрирован: 18.12.2005 19:10:00
Откуда: оттуда

Re: Форма с TChart в консольном приложении

Сообщение mike » 15.08.2025 14:53:43

sts писал(а):чтото похожее
https://forum.lazarus.freepascal.org/in ... ic=56262.0

Да, ситуация в точности та же, и предлагаемое решение работает.
Но, блин, настраивать чарт в рантайме -- это же адская боль! Один из самых сложных компонентов в истории...
Я для того и использовал форму, чтобы не приходилось этой трахолюдией заниматься.

Придется еще и парсер lfm прикручивать...
mike
новенький
 
Сообщения: 45
Зарегистрирован: 23.02.2007 17:25:00


Вернуться в Lazarus

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

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

Рейтинг@Mail.ru