Recent

Author Topic: How to create a project file to adjust chart and series properties  (Read 4062 times)

barsoom

  • Jr. Member
  • **
  • Posts: 51
Happy new year everyone,

My first question this year is about how to create a "project file" to store the configuration of  a chart (file, series, points, chart items like tittle foot, etc...).

Let me explain in detail. I am working on a program that read date-time vs temperature (1 or more temperatures for the same date-time), and plot it in a chart.

The user is able to change series name, color, with show/hide points and lines, change symbols shape, color, brush,... The user could also change tittle text, font, color,... chart background color, axis properties... and so on.

The idea is to store all this information in a file (like a project file). Then, the next time, the user only need to open this file and the program should read the different properties from that file and then, open the data file/s and assign all the properties such as it was stored. The idea is to allow the user not to work more than once on the chart and series configuration, going back to where they finish last time they were exploring the data.

My main problem is how to create that file (an ASCII file) and how to read the different data from it, to be latter assigned to each corresponding property. What if it imply to use more than one file whith more than  data series each one?

Do you understand what i would like to do?

You can see that i am lost in the concept and how to organize it and how to read it.
Any tip or help?

Thanks in advance!

wp

  • Hero Member
  • *****
  • Posts: 11916
Re: How to create a project file to adjust chart and series properties
« Reply #1 on: January 12, 2020, 12:49:52 am »
Do you have any requirements on the format? Ini, xml? In this case, it's quite a lot of work because of the many properties.

If not, I think the simplest way would be to write/read the chart in the same way as the IDE does in lfm files. You can use WriteComponentAsTextToStream from unit LResources to write the chart, and ReadComponentFromTextStream to read it back. Look at the attached demo.

barsoom

  • Jr. Member
  • **
  • Posts: 51
Re: How to create a project file to adjust chart and series properties
« Reply #2 on: January 12, 2020, 02:26:38 am »
@WP, it is an interesting solution, since i do not have any spetial requirement for that file, just only to make easy the life of the user. I had on mind an INI file, since i do not want to allow to modify ALL the options, but titles, foot fonts properties, and visibility, series properties,..., I know they are still many.

In any case, about your solution, it seems it only works with the chart design, but not with the data series, right?
If i open the program, save the chart, and open the file, the result is perfect. However, once i create the file storing the chart style, if i close the program and open it again, when loading the chart, the new plot show the right design, but without the series... i suposse that i must also connect the chart with the original data file/s, populate a chartsource component,...





« Last Edit: January 12, 2020, 02:35:56 am by barsoom »

wp

  • Hero Member
  • *****
  • Posts: 11916
Re: How to create a project file to adjust chart and series properties
« Reply #3 on: January 13, 2020, 11:08:15 am »
I can consider two use cases for storing charts to file:
  • Creating a template, i.e. use all the settings of a formatted chart when a new data file is loaded.
  • Taking a snapshot, i.e. preserving the format of a chart for the next program run - I think this is what you mean.
How are data stored? In the built-in list source of each series? In a separate list source? In some other way, and you use a user-defined chartsource to access the data?

Should the data values be included in the file? Or is it sufficient to store only the filename, and upon retrieval the filename is passed to the same routine which was used also for initial reading?

wp

  • Hero Member
  • *****
  • Posts: 11916
Re: How to create a project file to adjust chart and series properties
« Reply #4 on: January 13, 2020, 07:43:19 pm »
Now I experimented a bit with the property storage components that come with Lazarus, TXMLPropStorage and TIniPropStorage, and they, in fact, can create a snapshot easily with just a few lines of code and some mouse clicks, in particular, when the chart contains a fixed count of series.

If you want to store the data along with the series you cannot use the the built-in listsource of the series because it cannot be accessed by a published property. Use a separate TChartListSource instead, link it to the Source property of the series and add the data values to it instead of to the series (ListChartSource.Add(x, y)).

I am attaching a demo which was created from these steps:
  • Click on the '...' next to the "SessionProperties" property of the form which contains the chart.
  • The "Properties of ..." dialog opens. You see all components on the form in the left list. Click on the chart - the right list is populated with its (published) properties. For simplicity select all these properties (i.e., click on the first property and SHIFT-click on the last one). This adds all these properties to the bottom list "Selected properties". Repeat with the series and with the ListChartSources. Of course, you can remove properties which you do not want to be stored, and you can add other properties, such as checkbox or radiobutton checks. Very flexible. Click OK to close the dialog.
  • Now add a TXMLPropStorage to the form. This component reads/writes all the properties specified by the "SessionProperties" in the step above. In property "FileName" give the name of the file in which the chart will be saved. Set "Active" to false to avoid to automatically store the settings at program end and to automatically restore them at program start.
  • Instead of the TXMLPropStorage you can also use a TIniPropStorage which works with an INI file instead an XML file. As I noticed, however, the IniPropStorage appears to be slower noticably.
  • Provide a button, menu item etc to store the snapshot. Add the following OnClick code:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.btnSaveClick(Sender: TObject);
  2. begin
  3.   XmlPropStorage1.Active := true;
  4.   XmlPropStorage1.Save;
  5.   XmlPropStorage1.Active := false;
  6. end;
  • Do the same for loading, replace the .Save by .Restore.


barsoom

  • Jr. Member
  • **
  • Posts: 51
Re: How to create a project file to adjust chart and series properties
« Reply #5 on: January 13, 2020, 10:44:49 pm »
Thanks @wp  lot,

About your first answer, my idea was the second on, to create a snapshot that could be restored the next time the user want to work with the same datafile without to adjust again all the properties of the chart and the series, but without to store the data, just the filename to be called and loaded, and then applied the stored properties again to each series and the final chart.

About your second solution, it is not obvius to me, so i need to read your answer with care to be sure i understand every step. I will also study you example to see if i could adjunt it to my case.
In really you helped to me not long ago with this topic: https://forum.lazarus.freepascal.org/index.php/topic,47074.0.html
It is the same project. Once the user load the data into the chart, then, it could want to save the adjustments on the series and chart properties.

Thanks a lot for to explore these ways!
« Last Edit: January 13, 2020, 10:48:02 pm by barsoom »

wp

  • Hero Member
  • *****
  • Posts: 11916
Re: How to create a project file to adjust chart and series properties
« Reply #6 on: January 13, 2020, 11:14:33 pm »
About your first answer, my idea was the second on, to create a snapshot that could be restored the next time the user want to work with the same datafile without to adjust again all the properties of the chart and the series, but without to store the data, just the filename to be called and loaded, and then applied the stored properties again to each series and the final chart.
if you don't want to store the data you either stay with the built-in chart source (i.e. add data directly to the series: Series.AddXY(x, y, ..)) or you simply do not add the external chart source to the SessionProperties of the form. You can use the StoredValues property of the XMLProperty to store the filename (as described in principle in the wiki article).

About your second solution, it is not obvius to me, so i need to read your answer with care to be sure i understand every step.
I should have added the link to TXMLPropStorage: https://wiki.lazarus.freepascal.org/TXMLPropStorage

In really you helped to me not long ago with this topic:
My memory is getting shorter and shorter...

barsoom

  • Jr. Member
  • **
  • Posts: 51
Re: How to create a project file to adjust chart and series properties
« Reply #7 on: January 14, 2020, 01:34:40 am »
Thanks again @wp,
It seems to see easy, except for the datafile name, but i need to check it by myself to see how it works, because i can point to the datafile, but, how know the program how to read it? In my program, as you helped to me, the data from the csv file is readed into a stringgrid and from it to a chartsource...

I need to check this component what is completely new to me.
Thanks!


lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: How to create a project file to adjust chart and series properties
« Reply #8 on: January 14, 2020, 01:44:04 pm »
You can save anything to the XMLPropStorage; if it's something that is not easily saved as a property of some control/component, then you have to add handlers for the events OnSavingProperties and OnRestoringProperties.

For example, to save a filename stored, say, in a field FDatafileName: String· you'd do:

Code: Pascal  [Select][+][-]
  1. {XMLStore is a TXMLPropStorage}
  2. procedure TMain.RestoreProperties(Sender: TObject);
  3. begin
  4.   FDatafileName := XMLStore.ReadString('DataFile', '');
  5.   if (FDatafileName <> '') and FileExists(FDatafileName) then
  6.     {Do whatever you need to load the file}
  7. end;
  8.  
  9. procedure TMain.SaveProperties(Sender: TObject);
  10. begin
  11.   XMLStore.WriteString('DataFile', FDatafileName);
  12. end;

As easy as that ;)
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

barsoom

  • Jr. Member
  • **
  • Posts: 51
Re: How to create a project file to adjust chart and series properties
« Reply #9 on: January 14, 2020, 11:13:54 pm »
thanks @wp and @lucamar,

I tried to apply your solutions... but without good results.

I followed the steps marked by @wp above and adding the lines of code from @lucamar. These are the pieces of code:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.SaveProjectExecute(Sender: TObject);
  2. var
  3.   wasActive: Boolean;
  4. begin
  5.   wasActive := XmlPropStorage1.Active;
  6.   XmlPropStorage1.Active := true;
  7.   XmlPropStorage1.Save;
  8.   XMLStore.WriteString('DataFile', FDatafileName); // Should i change here "datafile" by the real name of the file?
  9.   XmlPropStorage1.Active := false;
  10. end;

Code: Pascal  [Select][+][-]
  1. procedure TForm1.LoadProjectExecute(Sender: TObject);
  2. var
  3.   wasActive: Boolean;
  4. begin
  5.   wasActive := XmlPropStorage1.Active;
  6.   XmlPropStorage1.Active := true;
  7.   XmlPropStorage1.Restore;
  8.   FDatafileName := XMLStore.ReadString('DataFile', 'test.xml'); // I dont know if i shuld wirte here the name of the datafile. The idea is to take the filename from a variable that store the filename of the opened datafile.
  9.   if (FDatafileName <> 'test.xml') and FileExists(FDatafileName) then
  10.     {Do whatever you need to load the file}
  11.   XmlPropStorage1.Active := wasActive;
  12. end;

I am sure i am not doing it correctly... in fact i have all these error messages when trying to compile:
Quote
unit1.pas(475,3) Error: Identifier not found "FDatafileName"
unit1.pas(475,20) Error: Identifier not found "XMLStore"
unit1.pas(476,7) Error: Identifier not found "FDatafileName"
unit1.pas(476,51) Error: Identifier not found "FDatafileName"
unit1.pas(504,3) Error: Identifier not found "XMLStore"
unit1.pas(504,36) Error: Identifier not found "FDatafileName"

wp

  • Hero Member
  • *****
  • Posts: 11916
Re: How to create a project file to adjust chart and series properties
« Reply #10 on: January 15, 2020, 12:09:08 am »
No this is wrong. You cannot call the ReadString and WriteString methods of a PropStorage yourself. When the XMLPropStorage writes the properties to a file it generates an event OnSaveProperties, and this is where these methods are executed. And the same happens for reading, the event is called OnRestoreProperties.

I completed my demo for this case. Instead of adding the datapoints to the chart by code it now reads some dummy data file (in fact, I added two of them). The filename is stored in an internal variable. When the xml storage saves the chart the filename is written along with the chart properties. And when the storage is restored the filename is read back, and the file loading procedure is called with loads the data from this particular file into the series.

I am still not 100% clear if this example exactly suits your requirements. It assumes that the series is created at designtime because you must add its properties to the Sessionproperties of the form. Of course you can use several series, but then each one of them must be precreated and included in the Sessionproperties.

barsoom

  • Jr. Member
  • **
  • Posts: 51
Re: How to create a project file to adjust chart and series properties
« Reply #11 on: January 15, 2020, 12:47:00 am »
Thanks @wp,

i will check your example.
However, no, i don´t know how many series contains the datafiles.. so the series are created on runtime. Anyway, i am going to explore you example to see how it works and learn from it.
Thanks.

wp

  • Hero Member
  • *****
  • Posts: 11916
Re: How to create a project file to adjust chart and series properties
« Reply #12 on: January 15, 2020, 12:49:39 am »
Will the run-time created series always be the same type, e.g. a line series, or a bar series? Or will there be mixed series types within the same chart?

barsoom

  • Jr. Member
  • **
  • Posts: 51
Re: How to create a project file to adjust chart and series properties
« Reply #13 on: January 15, 2020, 12:57:42 am »
I just tested the example and seems to be what i want... But to ask the user for the project file name... but i think i am able to do it. Looks great the example.

About your question, i think that the series will be always line series. I readed your code in the example, and i think it fits what i want, but i need to test in my program to see if i am able to adapt the ideas.

Thanks @wp

Edited 1:

My only concert at this point is how to call to the restored file. I mean... in your example, you create a unique xml file (chart.xml) independty of the datafile showed in the chart. However, i want to use different files, for different datafiles.
I understand that i could allow the user to change the name of the xml file, by the use of a savefiledialog, and latter select among different xml files by the use of a open filedialog, right?
So, i could adjunt the file in this way:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.btnLoadClick(Sender: TObject);
  2. var
  3.   wasActive: Boolean;
  4. begin
  5.   wasActive := XmlPropStorage1.Active;
  6.   XmlPropStorage1.Active := true;
  7.   xmlPropStorage1.FileName:= XXXXX; // xxx if the file that the user can select in a OpenFile dialog, right?
  8.   XmlPropStorage1.Restore;
  9.   XmlPropStorage1.Active := wasActive;
  10. end;

Am i right?

Edited 2:
I tested to save and load the xml files, using different names by the use of Savedialog and openfiledialog components. It works nicely.

This is what i did for the moment:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.SaveProjectExecute(Sender: TObject);
  2. var
  3.   wasActive: Boolean;
  4. begin
  5.   if SaveDialog1.Execute then
  6.     begin
  7.       XmlPropStorage1.FileName := SaveDialog1.Filename;
  8.       wasActive := XmlPropStorage1.Active;
  9.       XmlPropStorage1.Active := true;
  10.       XmlPropStorage1.Save;
  11.       XmlPropStorage1.Active := false;
  12.     end;
  13. end;

Code: Pascal  [Select][+][-]
  1. procedure TForm1.LoadProjectExecute(Sender: TObject);
  2. var
  3.   wasActive: Boolean;
  4.   filename: string;
  5. begin
  6.   if OpenDialog2.Execute then
  7.     begin
  8.       filename := OpenDialog2.Filename;
  9.       XmlPropStorage1.FileName := filename;
  10.       wasActive := XmlPropStorage1.Active;
  11.       XmlPropStorage1.Active := true;
  12.       XmlPropStorage1.Restore;
  13.       XmlPropStorage1.Active := wasActive;
  14.   end;
  15. end;    

By this, the user can save a different project for each datafile.

For the moment, it only works for the chart properties, because i still did not "imported" the datafile issue from @wp example. I need to do some changes in the present code i have to allow a nice working like in the example, but it seems it will work very good. Thanks @wp.

I will inform ASAP of the results.
Thanks!
« Last Edit: January 15, 2020, 03:24:17 am by barsoom »

wp

  • Hero Member
  • *****
  • Posts: 11916
Re: How to create a project file to adjust chart and series properties
« Reply #14 on: January 15, 2020, 01:28:21 am »
correct

 

TinyPortal © 2005-2018