Sign in Join
Wiki copytemporary

TAChart Tutorial: BarSeries: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11## Introduction
22
33![](/wiki-images/b/b1/BarSeries_finished.png%E2%80%8E)
44
55The `TAChart` library can create a variety of charts in Lazarus. But in comparison with other series types, bar series appear to be more difficult, mostly because there is a wide range of possibilities:
66
77- side-by-side bar series
88- stacked bar series
99- stacked bar series normalized to 100%
1010- vertical bar series
1111- horizontal bar series
1212
1313In this tutorial we want to show you the basic idea of how to create a chart with several bar series arranged in a side-by-side manner. A [[TAChart Tutorial: Stacked BarSeries|follow-up tutorial]] will teach you how to stack bars above each other.
1414
1515Besides bar series this tutorial will also introduce [[TAChart documentation|TRandomChartSource]] which is a convenient data source to design and test a chart without needing to compile the application.
1616
1717You'll need some basic knowledge of Pascal and Lazarus. Have a look at the [[TAChart Tutorial: Getting started]] to learn some basic skills for working with `TAChart` if this library is new to you. We also recommend to study the [[TAChart documentation]].
1818
1919## Preparation
2020
2121### Setting up the chart
2222
2323Create a new project, save it.
2424
2525Add a `TChart` component from Lazarus' component palette to `Form1`, scale it to fill a given region of the form.
2626
2727### Data for plotting
2828
2929Before continuing let's think about which data we want to plot. Maybe you could use the balance of your checking and saving accounts, or the business results of large companies found somewhere in the internet, or something completely different...
3030
3131Let's go a different way this time: why don't we plot just random data? Of course, they don't mean anything, but they are simple and very convenient for exercising. In particular, `TAChart` contains the [[TAChart documentation|TRandomChartSource]] component which provides random data to be plugged into a series seamlessly at design-time. This means you can follow this tutorial without a need to write a line of code and without a need to compile the demo application. Later, when the layout work is done, you could remove the RandomChartSources and replace them with the ChartSources containing our data.
3232
3333As you will see shortly, there will be three series in the chart, each of them with - say - four bars. For each series, you'll need a `RandomChartSource`. To add a `RandomChartSource` have a look at the "Chart" component palette - it is the fourth icon in the palette highlighted by red in the screenshot below:
3434
3535![](/wiki-images/8/8b/TChart_Palette_RandomChartSource.png)
3636
3737Add three RandomChartSources to the form - one per series. Rename them as `RedChartSource`, `BlueChartSource`, and `YellowChartSource` since they will be linked to "red", "blue" and "yellow" bar series to be created immediately (you should always prefer to use "speaking" variable names.)
3838
3939Before doing so, we need to set up the RandomChartSources because they do not provide any data by default. We want to have four bars per series. Therefore, set the property `PointsNumber` to 4. In order to get the axis labels in sync with the bars the `x` axis must range between 1 and 4 (or between 0 and 3, or between 0 and 39, whatever you like - we'll come across axis labels later in more details): `XMin = 1, XMax = 4`. And finally we also have to specify the `y` axis range, maybe select `YMin = 0` and `YMax = 100`.
4040
4141## Bar series
4242
4343### Adding series
4444
4545Now that all preparations are done we can add the bar series to the chart. Double-click on the chart to open the series editor. Click "Add" and select "Bar series" from the list. Repeat twice. In the end, we have three bar series in the chart. We don't see them in the chart since they are not yet linked to our data. In the object tree of the Object Inspector, however, the series appear as children of the Chart node.
4646
4747Click at the first series in the object tree, and - in the Object Inspector - go to the property `Source` and pick `RedChartSource` from the list. Now the series becomes visible in the chart. To make it "red" go to its property `SeriesColor` and select the color `clRed`. Rename the series to "RedBarSeries", and change its title to "red". The latter is for the legend which we turn on by setting the chart's `Legend.Visible` to `true`.
4848
4949Repeat with the other two series correspondingly.
5050
5151![](/wiki-images/2/28/AllBarSeries.png)
5252
5353Now the chart displays the bar series. However, the bars are located at the same value of the `x` axis, the yellow bars are partly covered by the other bars. Let's fix this.
5454
5555### Side-by-side arrangement of bars
5656
5757In oder to arrange the bars of each group (i.e. bars corresponding to the same `x` value) side-by-side, we have to shift them horizontally. `TBarSeries` offers two properties for this purpose:
5858
5959- `BarWidthPercent`
6060- `BarOffsetPercent`
6161
6262Both numbers are expressed as a percentage of the distance to the next bar group. (In some charts, the bars are not equidistant and therefore get varying bar widths. To achieve a constant bar thickness in such a case, set the property `BarWidthStyle` to `bwPercentMin`.)
6363
6464The basic idea is that the space between the bar groups (100%) is divided by the bars and some empty space to the next group. If we want to leave a gap of - say - one bar width between the groups, we have to divide 100% by 4 (3 bars plus gap), i.e. each bar can occupy a width of 25%.
6565
6666So, let's set the `BarWidthPercent` to 25% and see what happens. Oh - not quite what we wanted: The bars did get narrower, but they are still overlapping. Of course, this happens because we did not change the `BarOffsetPercent` parameter.
6767
6868Currently, `BarOffsetPercent` is zero which means that the center of each bar is exactly at the position of the axis tick mark. We have to shift the red bars to the left and the yellow bars to the right such that they touch the blue bars which remain in the center. The shift difference is one bar width, i.e. 25%. For moving the red bars to the left their `BarOffsetPercent` has to be negative.
6969
7070In summary, we use the following values:
7171
7272- `RedBarSeries: BarOffsetPercent = -25, BarWidthPercent = 25`
7373- `BlueBarSeries: BarOffsetPercent = 0, BarWidthPercent = 25`
7474- `YellowBarSeries: BarOffsetPercent = 25, BarWidthPercent = 25`
7575
7676![](/wiki-images/0/09/AllBarSeries-side-by-side.png)
7777
7878## Axis
7979
8080### Using text labels
8181
8282The next issue to be addressed is the `x` axis. Usually bar charts are considered to display categories of some data sets which often requires text labels underneath each bar group. But so far, we only have numerical labels, and the intermediate labels at half integers are particularly annoying.
8383
8484The best way to get this right is to use an additional ChartSource for assigning the strings to the axis values, it is a `TListChartSource` this time to be found as the second icon in the chart component palette. Add it to the form and rename is as `LabelsChartSource`.
8585
8686The ListChartSource has a built-in data editor which allows to enter data at design-time. Select the `LabelsChartSource` and go to the property `DataPoints`. Click on "..." at the right to open the data points editor, and enter the following data:
8787
8888![](/wiki-images/3/36/LabelsSource_DataPoints_Editor.png)
8989
9090In the "X" column we enter the values of the `x` coordinates of each bar group. We could omit the "Y" column, but as we'll see later that it is conventient to have the same data in this column as well because labels are retained after rotation of the bars to an horizontal arrangement. In the column "Text" we specify the texts that will appear for each bar group along the axis as axis marks. Let us assume that our data represent some seasonal values and use the abbreviations "Q1", "Q2", "Q3", and "Q4" for "quarter 1" etc. Column "Color" can be left empty.
9191
9292In order to activate these labels we have to assign this ChartSource to the `Source` property of the `Marks` of the bottom axis, and we have to set the property `Style` of the `Marks` to `smsLabel`.
9393
9494Voila - here's what we get:
9595
9696![](/wiki-images/a/a5/BarSeries_with_Axis_Marks.png%E2%80%8E)
9797
9898### Showing grid lines & ticks between groups
9999
100100A minor issue can be improved: the chart would be clearer if the axis tick marks and grid lines were not at the center of the bar groups, but right between them.
101101
102102At first, we turn off the grid of the bottom axis: `BottomAxis.Grid.Visible = false`. To remove the ticks, we can set the `TickLength` and the `TickInnerLength` to `0`.
103103
104104But how to add grid lines between the chart groups? This can be done by creating a "minor" axis to the bottom axis. This is another set of ticks and gridlines in addition to the "major" axis. Go to the bottom axis and click on `Minors` to open the corresponding editor. Click "Add" and the select the `0 - M` in the list. Back in the normal Object Inspector, activate `Visible`, increase the `TickLength` to 4, and finally, set `Intervals.Count` to `1` - we only want one minor tick between the major ticks. Check the `Grid` settings - `Visible` should be `true`.
105105
106106This leads to the final result. Final? Not quite! There is an annoying little gap underneath the bars. This originates from the chart's `Margins` property which leaves some distance between the series and the axes. Just set `Chart.Margins.Bottom` to `0` to remove the gap.
107107
108108![](/wiki-images/3/3a/BarSeries_no_bottom_margins.png)
109109
110110## Horizontal bar series
111111
112112Before closing this lesson we'd like to quickly modify this project and create a plot with horizontal bars. This kind of diagram is often preferred when the axis labels consist of lengthy texts, and the chart is in a landscape orientation.
113113
114114`TAChart` does not offer a dedicated "`THorizontalBarSeries`", but the standard `TBarSeries` can easily be modified to obtain horizontal bars. Like any other descendant of `TChartSeries` it has properties `AxisIndexX` and `AxisIndexY` to indicate which axis is responsible for `x` and `y` coordinates. Just set `AxisIndexX` to the index of the `LeftAxis` (usually `0`) and `AxisIndexY` to that of the `BottomAxis` in order to rotate the bar direction.
115115
116116And, of course, the `LabelsChartSource` has to be linked to the `Marks.Source` of the `LeftAxis` this time. And the minor axis has to be handled accordingly.
117117
118118Essentially, that's all that's needed to create a chart with horizontal bars.
119119
120120![](/wiki-images/9/9b/Horizontal_BarSeries.png%E2%80%8E)
121121
122122## Summary
123123
124124Steps to create a side-by-side bar chart:
125125
126126- Every bar requires a separate BarSeries.
127127- Use the BarSeries' properties `BarWidthPercent` and `BarOffsetPercent` to arrange the bars side-by-side with or without overlapping. The percentages refer to the distance between the center of the bar groups.
128128- For horizontal bar series, set the series' `AxisIndexX` to the index of the chart's `LeftAxis` (usually `0`) and `AxisIndexY` to the index of the `BottomAxis` (usually `1`).
129129
130130## Source code
131131
132132The source code of this tutorial is available in the folder `components/tachart/tutorials/bar_series` of your TAChart installation of newer Lazarus versions.
133133
134134### Project file
135135
136136``` pascal
137137program project1;
138138
139139{$mode objfpc}{$H+}
140140
141141uses
142142 {$IFDEF UNIX}{$IFDEF UseCThreads}
143143 cthreads,
144144 {$ENDIF}{$ENDIF}
145145 Interfaces, // this includes the LCL widgetset
146146 Forms, tachartlazaruspkg, Unit1
147147 { you can add units after this };
148148
149149{$R *.res}
150150
151151begin
152152 RequireDerivedFormResource := True;
153153 Application.Initialize;
154154 Application.CreateForm(TForm1, Form1);
155155 Application.Run;
156156end.
157157```
158158
159159### Unit1.pas
160160
161161``` pascal
162162unit Unit1;
163163
164164{$mode objfpc}{$H+}
165165
166166interface
167167
168168uses
169169 Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, TAGraph,
170170 TASeries, TASources;
171171
172172type
173173
174174 { TForm1 }
175175
176176 TForm1 = class(TForm)
177177 Chart1: TChart;
178178 LabelsChartSource: TListChartSource;
179179 RedBarSeries: TBarSeries;
180180 BlueBarSeries: TBarSeries;
181181 YellowBarSeries: TBarSeries;
182182 RedChartSource: TRandomChartSource;
183183 BlueChartSource: TRandomChartSource;
184184 YellowChartSource: TRandomChartSource;
185185 private
186186 { private declarations }
187187 public
188188 { public declarations }
189189 end;
190190
191191var
192192 Form1: TForm1;
193193
194194implementation
195195
196196{$R *.lfm}
197197
198198end.
199199```
200200
201201### Unit1.lfm (vertical bars)
202202
203-``` pascal
203+``` lfm
204204object Form1: TForm1
205205 Left = 381
206206 Height = 272
207207 Top = 444
208208 Width = 429
209209 Caption = 'Form1'
210210 ClientHeight = 272
211211 ClientWidth = 429
212212 LCLVersion = '1.3'
213213 object Chart1: TChart
214214 Left = 0
215215 Height = 272
216216 Top = 0
217217 Width = 384
218218 AxisList = <
219219 item
220220 Minors = <>
221221 Title.LabelFont.Orientation = 900
222222 end
223223 item
224224 Grid.Visible = False
225225 TickLength = 0
226226 Alignment = calBottom
227227 Marks.Format = '%2:s'
228228 Marks.Source = LabelsChartSource
229229 Marks.Style = smsLabel
230230 Minors = <
231231 item
232232 Intervals.Count = 1
233233 Intervals.MinLength = 5
234234 Intervals.Options = [aipUseCount, aipUseMinLength]
235235 TickLength = 4
236236 end>
237237 end>
238238 Foot.Brush.Color = clBtnFace
239239 Foot.Font.Color = clBlue
240240 Legend.Visible = True
241241 Margins.Bottom = 0
242242 Title.Brush.Color = clBtnFace
243243 Title.Font.Color = clBlue
244244 Title.Text.Strings = (
245245 'TAChart'
246246 )
247247 ParentColor = False
248248 object RedBarSeries: TBarSeries
249249 Title = 'red'
250250 BarBrush.Color = clRed
251251 BarOffsetPercent = -25
252252 BarWidthPercent = 25
253253 Source = RedChartSource
254254 end
255255 object BlueBarSeries: TBarSeries
256256 Title = 'blue'
257257 BarBrush.Color = clBlue
258258 BarWidthPercent = 25
259259 Source = BlueChartSource
260260 end
261261 object YellowBarSeries: TBarSeries
262262 Title = 'yellow'
263263 BarBrush.Color = clYellow
264264 BarOffsetPercent = 25
265265 BarWidthPercent = 25
266266 Source = YellowChartSource
267267 end
268268 end
269269 object RedChartSource: TRandomChartSource
270270 PointsNumber = 4
271271 RandSeed = 1
272272 XMax = 4
273273 XMin = 1
274274 YMax = 100
275275 YMin = 0
276276 left = 360
277277 top = 72
278278 end
279279 object BlueChartSource: TRandomChartSource
280280 PointsNumber = 4
281281 RandSeed = 2
282282 XMax = 4
283283 XMin = 1
284284 YMax = 100
285285 YMin = 0
286286 left = 360
287287 top = 120
288288 end
289289 object YellowChartSource: TRandomChartSource
290290 PointsNumber = 4
291291 RandSeed = 3
292292 XMax = 4
293293 XMin = 1
294294 YMax = 100
295295 YMin = 0
296296 left = 360
297297 top = 168
298298 end
299299 object LabelsChartSource: TListChartSource
300300 DataPoints.Strings = (
301301 '1|1|?|Q1'
302302 '2|2|?|Q2'
303303 '3|3|?|Q3'
304304 '4|4|?|Q4'
305305 )
306306 left = 361
307307 top = 220
308308 end
309309end
310310```
311311
312312### Unit1.lfm (horizontal bars)
313313
314-``` pascal
314+``` lfm
315315object Form1: TForm1
316316 Left = 381
317317 Height = 272
318318 Top = 444
319319 Width = 429
320320 Caption = 'Form1'
321321 ClientHeight = 272
322322 ClientWidth = 429
323323 LCLVersion = '1.3'
324324 object Chart1: TChart
325325 Left = 0
326326 Height = 272
327327 Top = 0
328328 Width = 384
329329 AxisList = <
330330 item
331331 Grid.Visible = False
332332 TickLength = 0
333333 Marks.Format = '%2:s'
334334 Marks.Source = LabelsChartSource
335335 Marks.Style = smsLabel
336336 Minors = <
337337 item
338338 Intervals.Count = 1
339339 Intervals.MinLength = 5
340340 Intervals.Options = [aipUseCount, aipUseMinLength]
341341 TickLength = 4
342342 end>
343343 Title.LabelFont.Orientation = 900
344344 end
345345 item
346346 Alignment = calBottom
347347 Minors = <>
348348 end>
349349 Foot.Brush.Color = clBtnFace
350350 Foot.Font.Color = clBlue
351351 Legend.Visible = True
352352 Margins.Bottom = 0
353353 Title.Brush.Color = clBtnFace
354354 Title.Font.Color = clBlue
355355 Title.Text.Strings = (
356356 'TAChart'
357357 )
358358 ParentColor = False
359359 object RedBarSeries: TBarSeries
360360 Title = 'red'
361361 AxisIndexX = 0
362362 AxisIndexY = 1
363363 BarBrush.Color = clRed
364364 BarOffsetPercent = -25
365365 BarWidthPercent = 25
366366 Source = RedChartSource
367367 end
368368 object BlueBarSeries: TBarSeries
369369 Title = 'blue'
370370 AxisIndexX = 0
371371 AxisIndexY = 1
372372 BarBrush.Color = clBlue
373373 BarWidthPercent = 25
374374 Source = BlueChartSource
375375 end
376376 object YellowBarSeries: TBarSeries
377377 Title = 'yellow'
378378 AxisIndexX = 0
379379 AxisIndexY = 1
380380 BarBrush.Color = clYellow
381381 BarOffsetPercent = 25
382382 BarWidthPercent = 25
383383 Source = YellowChartSource
384384 end
385385 end
386386 object RedChartSource: TRandomChartSource
387387 PointsNumber = 4
388388 RandSeed = 1
389389 XMax = 4
390390 XMin = 1
391391 YMax = 100
392392 YMin = 0
393393 left = 360
394394 top = 72
395395 end
396396 object BlueChartSource: TRandomChartSource
397397 PointsNumber = 4
398398 RandSeed = 2
399399 XMax = 4
400400 XMin = 1
401401 YMax = 100
402402 YMin = 0
403403 left = 360
404404 top = 120
405405 end
406406 object YellowChartSource: TRandomChartSource
407407 PointsNumber = 4
408408 RandSeed = 3
409409 XMax = 4
410410 XMin = 1
411411 YMax = 100
412412 YMin = 0
413413 left = 360
414414 top = 168
415415 end
416416 object LabelsChartSource: TListChartSource
417417 DataPoints.Strings = (
418418 '1|1|?|Q1'
419419 '2|2|?|Q2'
420420 '3|3|?|Q3'
421421 '4|4|?|Q4'
422422 )
423423 left = 361
424424 top = 220
425425 end
426426end
427427```
428428
429429---
430430*From the Free Pascal wiki, page "TAChart Tutorial: BarSeries", as it stood on 2022-12-30 after a change by Wp, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history