Recent

Author Topic: TAChartImageList  (Read 11011 times)

wp

  • Hero Member
  • *****
  • Posts: 11916
TAChartImageList
« on: October 30, 2011, 12:49:29 pm »
Sometimes it is necessary to have access to the legend images of a chart's series for displaying series information in listviews, treeviews etc. We already have a ChartListbox in the library, but this quite specialized. Therefore, I decided to extract the image creation code and put it into an ImageList. The image list is populated by assigning its "Chart" property accordingly. The image list can be used also for usual toolbar and menu icons, but make sure to have the chart unassigned when manually adding images. Otherwise image indices will change if additional series are added to the chart at run-time.

Two demo programs are added to show this new component. Use the run-time project first - it does not require an installation into the TAChart package.

The component uses features added to TAChart recently. So it requires one of the more recent svn snapshots to compile.

I would be glad if this component could be added to the TAChart library. I'll need it for the next component that I am currently working on, a TChartGrid.

Ask

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 687
Re: TAChartImageList
« Reply #1 on: October 30, 2011, 05:33:20 pm »
First, thanks for your continued contributions.

Quote
I decided to extract the image creation code and put it into an ImageList.
This is sensible plan.
Before applying your code I'd like to think a little about design:
1) Copying series icons as bitmaps seems a bit wasteful, I would prefer some kind of "virtual image list", where the icons are drawn directly when needed.
This would also solve the problems with non-chart images,
image storing and series updating.
Unfortunately, it seems that TCustomImageList has no provision for
such virtualization. So we are out of luck here.
2) I have minor doubts about OnPopulate event --
it is called whenever the chart broadcasts a change,
so anybody handling this event cold just subscribe to the broadcast?
3) Can you describe what behavior FirstSeriesIndex/SeriesCount are aimed to achieve?
For example, adding new image directly, then adding a new series will
move the series images to the end of the list -- is it intended?
4) Since you are contributing a lot of code, I would appreciate
if you would format it in TAChart style, in particular with spaces after, but not before the colons in variable declarations.

Quote
I am currently working on, a TChartGrid
This is great news, I did contemplate something in this direction.
However, since this component is more complex than your previous
contributions, please let's discuss the design in advance.

I see several options for implementing chart-grid connection:
1) Implement TListSourceDataset and use standard DBGrid
2) Put chart data in TSdfDataset, then use TDbChartSource for chart and standard DBGrid -- this is already possible now
3) Implement ExportToGrid/ImportFromGrid methods in chatrSource and/or chart and let the user call them when needed
4) Implement TGridChartSource and use it to get chart data from the grid
5) Implement TChartSourceLink/TChartGridLink which syncronizes data between the
chart and the grid
6) Implement TChartGrid as a descendant of TStringGrid
7) Implement the grid *inside* the chart. This may allow to synchronize the grid with the chart axis.
8) Maybe you plan something else?

Those methods are not mutually exclusive, but I would like to make
informed choice among them.

wp

  • Hero Member
  • *****
  • Posts: 11916
Re: TAChartImageList
« Reply #2 on: October 30, 2011, 06:39:30 pm »
Quote
I have minor doubts about OnPopulate event --
it is called whenever the chart broadcasts a change,
so anybody handling this event cold just subscribe to the broadcast?
Isn't this a problem of many event handlers, that somebody could do something stupid? BTW: I think we have that same construction in TChartListbox.

Quote
Can you describe what behavior FirstSeriesIndex/SeriesCount are aimed to achieve?
This provides a mechnism to protect the non-series images from deletion when the ImageList is repopulated due to broadcast. See ClearAllSeries.

Quote
adding new image directly, then adding a new series
That's what I tried to describe in the unit header - you just shouldn't do that... I know this is a bit cumbersome, and to my excuse I can say that the ImageList was intentionally intended to provide series images only, but then it came to my mind that it could support regular images also.

Quote
Maybe you plan something else?
The TChartGrid is a TDrawGrid descendant with specialized columns for the series data, no intermediate classes. The columns interface to the series data directly, no additional storage of the cell texts. So far, the grid is working fine with some minor bugs to be fixed and features to be added.

Quote
I would appreciate if you would format it in TAChart style, in particular with spaces after, but not before the colons in variable declarations.
I'll try to adhere to that. Anything else to consider?

Ask

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 687
Re: TAChartImageList
« Reply #3 on: November 02, 2011, 07:29:15 am »
Sorry for the delay. Unfortunately, my Lazarus time is extremely limited now.
I still have some plans to update it's API, especially the part about manual image adding,
but I have no time now.
I have committed your code with only code style changes in r33213 so as to not hold your development efforts.

In addition to my previous comments, I have noticed the following:

* TChartImageList.WriteData will delete series images and not add them back
* heaptrc reports memory leak in TChartImageList

Quote
I'll try to adhere to that. Anything else to consider?
I started the documentation:

http://wiki.lazarus.freepascal.org/TAChart_documentation#Coding_style

wp

  • Hero Member
  • *****
  • Posts: 11916
Re: TAChartImageList
« Reply #4 on: November 02, 2011, 09:05:12 am »
Quote
I have committed your code
Thank you.

Quote
TChartImageList.WriteData will delete series images and not add them back
That's intended. The images are created automatically when the chart is assigned. With the inherited WriteData method every series image will be in the image list twice.

Ask

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 687
Re: TAChartImageList
« Reply #5 on: November 02, 2011, 11:09:58 am »
Quote
That's intended. The images are created automatically when the chart is assigned. With the inherited WriteData method every series image will be in the image list twice.

I understand that. However, immediately after the WriteData call, the chart will be assigned, but the images will be absent. In other words, I think that
"FChart := ch" assignment should be replaced by "Chart := ch".

wp

  • Hero Member
  • *****
  • Posts: 11916
Re: TAChartImageList
« Reply #6 on: November 02, 2011, 12:18:00 pm »
You are right.

wp

  • Hero Member
  • *****
  • Posts: 11916
Re: TAChartImageList
« Reply #7 on: November 02, 2011, 12:48:32 pm »
Coming back to your suggestions for my work on TChartGrid, let me ask a question on the design of the TAChart library.

The ChartGrid, as it is being implemented now, will get its data directly from the ChartSource of the series. This means that the series must inherit from TChartSeries at least since it is the first series class that has a ChartSource; its predecessors, TCustomChartSeries and TBasicChartSeries will not work, and I will be raising an exception to prevent using them with TChartGrid.

Of course, direct descendants of TCustomChartSeries and TBasicChartSeries will have access to their data in some kind as well. So if I'd want to allow these series in the TChartGrid I'd have to write some kind of interfacing class, such as a "TSeriesColumnLink" which transfers the data from the series to the grid column.

But is this really necessary? As far as I can overlook the library all series inherit from TChartSeries. Will the entire library work with non-TChartSeries at all?


Ask

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 687
Re: TAChartImageList
« Reply #8 on: November 02, 2011, 12:50:52 pm »
Quote
* TChartImageList.WriteData will delete series images and not add them back
* heaptrc reports memory leak in TChartImageList

Fixed both problems in r33217

wp

  • Hero Member
  • *****
  • Posts: 11916
Re: TAChartImageList
« Reply #9 on: November 02, 2011, 01:05:28 pm »
Quote
Fixed both problems in r33217
Thank you - you are faster than the speed of light...

Ask

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 687
Re: TAChartImageList
« Reply #10 on: November 02, 2011, 02:41:55 pm »
Quote
all series inherit from TChartSeries
At least TFuncSeries, TConstantLineSeries and TColorMapSeries do not.

I am not strictly against your design, but IMHO a TChartGridLink component
would have some advantages -- for example, it can potentially work
with any TDrawGrid descendant.
Such component may have:
1) "Direction" property, indicating either row-per-series or column-per-series
2) "SeriesLinks" property, which would be a collection of TSeriesGridLink objects
3) Some properties to specify if and how per-series legend is displayed
4) Some properties to specify what is displayed in the column/row headers
5) Some properties to synchronize grid position with chart extent

TSeriesGridLink object may have:
1) SeriesIndex and GridIndex properties
2) Some properties to specify how data values are displayed
  (either using series format or a separate format)
3) Some properties to specify if and how per-data item legend is displayed

wp

  • Hero Member
  • *****
  • Posts: 11916
Re: TAChartImageList
« Reply #11 on: November 02, 2011, 04:55:33 pm »
Most of the properties that you mention are added to descendants of TGridColumn and TGridColumns which are available already in the most basic grid, TCustomGrid (--> TChartGridColum). Each TChartGridColumn displays data from a special data element of each series (property Kind = ckX, ckY, ckYIndex, ckText, ckMark). There is also a NumFormat property to format numbers in a special way.

I see a need for a link component only with respect to data transfer. Since my design is column-based, the "Direction" property - to draw data in rows -, however, is difficult to accomplish.

After fixing some remaining bugs, I'll just post my current version in the next days for you to have a look.

wp

  • Hero Member
  • *****
  • Posts: 11916
Re: TAChartImageList
« Reply #12 on: November 04, 2011, 10:52:30 am »
Quote
Copying series icons as bitmaps seems a bit wasteful, I would prefer some kind of "virtual image list", where the icons are drawn directly when needed. This would also solve the problems with non-chart images, image storing and series updating. Unfortunately, it seems that TCustomImageList has no provision for such virtualization. So we are out of luck here.

Instead of using the local variable "legendItems" in the "Populate" method we could store the legend items permanently in a member FLegendItems of TChartImageList. Then we could override the DrawXXXX and GetBitmap methods of the TImageList by directly calling the drawing routines of the LegendItems, either by painting directly on the provided canvas or on that of temporary bitmaps. Also, normal icons and series icons would be separated because adding the former ones would go into the inherited ImageList while the latter ones would go into the FLegendIems.

Unfortunately, the DrawXXXX methods are not virtual, but my impression is that they are not called internally. Another obstacle might be that the drawing methods use some GraphicsDrawEffects which are obained from the widgetset. So far, I don't know how to access these directly.

Would that work? Also, I have the impression that this is quite some overhead which easily might eat up the memory benefits for saving a few bitmaps.

Ask

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 687
Re: TAChartImageList
« Reply #13 on: November 04, 2011, 12:44:16 pm »
Quote
we could override the DrawXXXX and GetBitmap methods

Yes, this was my first idea too. Unfortunately, there are also GetRawImage and GetFullRawImage which are not virtual too.

I think the correct design should be: keep TCustomImageList
as an interface class, declare all relevant functions virtual,
and introduce an additional class between TCustomImageList and TImageList.
I'll ask on the mailing list, but I am afraid the compatibility reasons may
prevent such a change.

Quote
quite some overhead which easily might eat up the memory benefits for saving a few bitmaps
I am worried not so much about memory consumption, but about the fact that bitmaps
will be deleted and recreated on every series update, for example on adding the data point.

wp

  • Hero Member
  • *****
  • Posts: 11916
Re: TAChartImageList
« Reply #14 on: November 04, 2011, 03:31:30 pm »
Quote
the fact that bitmaps will be deleted and recreated on every series update, for example on adding the data point.
Wouldn't it help if the broadcaster had information on the reason for the update? All broadcasts due to adding points can be ignored by the TChartImageList.

 

TinyPortal © 2005-2018