Sign in Join
Wiki copytemporary

TAChart Tutorial: ListChartSource, Logarithmic Axis, Fitting/ru: what changed

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

OldNewLine
11## Введение
22
33![](/wiki-images/3/3d/TAChart_LogAx_Tutorial15.png)
44
55Вы знаете [Закон Мура](https://ru.wikipedia.org/wiki/Закон_Мура)? Он перед вами...
66
77Возможно, читая это, вы сидите перед своим десктопом или держите на коленях ноутбук, или смартфон в руках. В последние десятилетия произошёл огромный прогресс микроэлектроники и он всё продолжается. Это происходит благодаря минитюаризации электронных устройств, позволяющей упаковывать всё больше функций на один кремниевый чип. И закон Мура именно об этом: количество транзисторов на чипе удваивается примерно каждые два года.
88
99В этом руководстве мы возьмем опубликованные данные крупного производителя микропроцессоров и воспользуемся TAChart для построения графика количества транзисторов в зависимости от года выпуска продуктов на рынок. Этими данными мы попытаемся подтвердить закон Мура.
1010
1111Вы можете найти эти данные на сайте [www.intel.com/pressroom/kits/quickreffam.htm](http://www.intel.com/pressroom/kits/quickreffam.htm), который содержит список микропроцессоров, дату их выхода на рынок и количество транзисторов на чип.
1212
1313При изучении этого примера вы научитесь:
1414
1515- как **вводить данные в фазе разработки формы (designtime)**
1616- как **создать серию точек с метками сверху каждой точки**
1717- как **создать логарифмическую ось**
1818- как **аппроксимировать данные**.
1919
2020Вам нужно иметь базовые знания о том, как работать с TAChart; иначе необходимо просмотреть [[TAChart Tutorial: Getting started/ru|Руководство по началу работы]] TAChart. Конечно, вы должны быть знакомы с [[Lazarus]] и [[Object Pascal]]. И не надо слишком бояться математики, вам понадобятся логарифмы и экспоненциальная функция.
2121
2222## Подготовка
2323
2424### Настройка диаграммы
2525
2626- Создадим новый проект.
2727- Поскольку получается несколько меток по длинной оси, увеличим размер формы примерно до 540 x 320 пикселей.
2828- Добавим компонент `TChart`, выровняем его в режиме `alClient`, установим `BackColor` в `clWhite` и `Grid.Color` каждой оси в `clSilver`.
2929- Добавим имя оси **X** («Year of market introduction» — Год выхода на рынок) и оси **Y** («Number of transistors» — Количество транзисторов).
3030- Используем текст «Progress in Microelectronics» (Прогресс в микроэлектронике) как заголовок диаграммы.
3131- Зададим стиль шрифта `fsBold`.
3232- Дадим ссылку на наши данные в нижнем колонтитуле. Используем для этого свойство диаграммы [[TAChart documentation|Foot]]. Заметьте, что редактор свойства `Foot.Text` (а также `Title.Text`) позволяет вводить многострочные заголовки.
3333
3434![](/wiki-images/1/17/TAChart_LogAx_Tutorial1.png)
3535
3636### Создание серии точек
3737
3838Мы хотим нарисовать каждую запись TDataRecord как единую точку данных — в других программах для построения диаграмм это называется «серией точек». Редактор серии TAChart не имеет такого типа серии потому что это можно сделать с помощью [[TAChart documentation/ru|TLineSeries]]. Нам нужно только установить его свойство `ShowPoints` в `true` и отключить соединительные линии (`LineType` = `ltNone`).Эти символы определены свойством `Pointer`.
3939
4040Итак, добавим LineSeries на форму и установим свойства для создания серии точек. Дополнительно установим `Pointer.Brush.Color` в `clRed`, и `Pointer.Style` в `psCircle`, чтобы нарисовать красный круг в каждой точке.
4141
4242## Ввод данных
4343
4444### Список источников данных (ListChartSource)
4545
4646Есть много способов для ввода данных в диаграмму. Мы будем использовать [[TAChart documentation/ru|ListChartSource]]. Обычно данные загружаются в источник динамически во время выполнения программы, например, после чтения файла. Однако в нашем проекте мы хотим ввести их во время разработки программы с помощью редактора точек ListChartSource. Главное преимущество этого в том, что мы немедленно увидим результат наших действий, не компилируя проект. Однако у этого подхода также есть и свои недостатки.
4747
4848ListChartSource хранит данные для рисования в списке — отсюда и его название. Элементы списка это так называемые `TChartDataItem` объекты, содержащие для каждой точки следующее:
4949
5050- координаты `x` и `y`,
5151- `Text` для метки точки,
5252- `Color`, который перекрывает SeriesColor,
5353- а также `YList`, содержащий дополнительные значения `y`, которые нужны в некоторых специальных типах серий.
5454
5555ListChartSource — это тот же самый тип источника данных, который используется внутри многих классов серий. Однако наличие его в качестве отдельного компонента имеет большое преимущество, заключающееся в том, что тот же источник диаграммы можно снова использовать для других серий — эта функция понадобится нам позже при применении FitSeries.
5656
5757![](/wiki-images/3/3b/TAChart_LogAx_Tutorial2.png) Начнем с добавления TListChartSource в нашу форму. Это вторая иконка в палитре компонентов диаграммы. Привяжем к этой серии наш источник, указав в её свойстве `Source` новый `ListChartSource1`.
5858
5959### Редактор данных в ListChartSource
6060
6161![](/wiki-images/a/af/TAChart_LogAx_Tutorial16.png)
6262
6363При нажатии на кнопку с многоточием рядом со свойством `DataPoints` открывается редактор данных источника диаграммы. Это таблица, в которую мы можем вводить данные. Введём данные с предыдущего изображения. Они взяты с веб-сайта, упомянутого во введении. На этом сайте указано время выхода на рынок по годам и месяцам — для простоты я пропустил месяц и округлил до ближайшего календарного года. Введите год**а** в столбец **X**. Столбец **Y** получит количество транзисторов на чип. Название каждого микропроцессора войдёт в столбец **Text**. Поскольку мы не хотим присваивать каждой точке отдельный цвет, оставляем столбец **Color** в покое, но, конечно, можно поэкспериментировать и с этой функцией.
6464
6565После закрытия редактора данных, серия автоматически обновляется и отображает текущий набор данных. Вау!
6666
6767### Отображение меток точек
6868
6969Почему мы не видим имена процессоров, введённых в таблицу? Потому, что [[TAChart documentation/ru|метки точек]] по умолчанию отключены. Выберем серию и перейдём к `Marks`. Посмотрим на свойство `Style`, оно содержит `smsNone`, что значит «выключено». Откроем раскрывающийся список. Увидим много вариантов маркировки точек. Поиграемся с этими установками чтобы выучить, что они значат. Здесь мы хотим использовать `smsLabel`, отображающий поле `Text` свойства `TChartDataItem`. Чтобы назначить **Marks.Style** через исходный код, нужно добавить `uses ... TAChartUtils`.
7070
7171Между метками и точками существуют также соединительные линии . У них по умолчанию белый цвет, поэтому на белом фоне мы его не видим. Имя свойства для этой линии `LinkPen`. Можно установить `LinkPen.Color` в `clGray`.
7272
7373Позиция метки нас устраивает, но надо знать, что серия имеет свойство [[TAChart documentation|MarkPositions]], чтобы контролировать её положение.
7474
7575![](/wiki-images/a/a4/TAChart_LogAx_Tutorial3.png)
7676
7777В этот момент можно скомпилировать проект.
7878
7979Ничего нового — мы видели всё уже в режиме разработки. Это большое преимущество работы с редактором точек в ListChartSource.
8080
8181Есть две вещи, которые можно улучшить на этом этапе:
8282
8383- Метки точек обрезаются по краям диаграммы. Можно исправить это увеличением `Margin.Left` и `Margin.Right` диаграммы до 24. [[TAChart documentation/ru|Margin]] определяет пространство, окружающее внутреннюю область графика, чтобы оно не содержало точек. Также есть свойство [[TAChart documentation/ru|MarginExternal]], которое определяет окружение внешней границы диаграммы и может использоваться для изменения расстояния до соседних элементов управления.
8484- Поскольку почти все точки сосредоточены в нижней части диаграммы, график не очень удобен. Именно поэтому нам нужна **логарифмическая ось**.
8585
8686## Настройка логарифмической оси
8787
8888Отображение данных на логарифмической оси означает, что на график наносятся логарифмы значений данных, а не сами значения. Например, значения **y** на нашей диаграмме находятся в диапазоне от 2300 до 731 миллиона. Когда мы вычисляем [десятичные](https://ru.wikipedia.org/wiki/Десятичный_логарифм) (log<sub>10</sub>) логарифмы, диапазон составляет примерно от 3,3 до 7,1 — на такой диаграмме данные различить намного проще.
8989
9090### TChartTransformations и LogarithmicAxisTransform
9191
9292![](/wiki-images/3/36/TAChart_LogAx_Tutorial4.png) Вычисление логарифма может быть выполнено TAChart автоматически. Основное преимущество этого заключается в том, что исходные единицы данных отображаются на оси, а логарифмы используются для построения графика.
9393
9494Фактически есть целая группа компонентов для трансформаций осей: [[TAChart documentation/ru|TChartAxisTransformations]]. Преобразование оси это функция, которая сопоставляет данные «реального мира» в единицах, указанных на оси (*«осевые координаты»*) во внутренние единицы, общие для всех серий в той же диаграмме (*«координаты графика»*). Осевая координата количества транзисторов процессора 4004, например, 2300, координата на графике — логарифм этого числа, т.е. log<sub>10</sub>(2300) = 3.36.
9595
9696TAChart предлагает много преобразований. В добавок к логарифмическому преобразованию есть [[TAChart documentation|линейное преобразование]], которое позволяет умножать данные на коэффициент и добавлять смещение. [[TAChart documentation|Автомасштабирующее преобразование]] полезно когда несколько серий надо нарисовать на одной оси. [[TAChart documentation|Пользовательское преобразование]] позволяет применить любое произвольное преобразование.
9797
9898![](/wiki-images/5/55/TAChart_LogAx_Tutorial5.png)
9999
100100Добавим на форму компонент `TAChartTransformations`, дважды кликнем по нему (или кликнем правой клавишей на нём в дереве объектов и выберем «Edit axis transformations»), кликнем на «Add» и выберем «Logarithmic». Создастся компонент `ChartAxisTransformations1LogarithmAxisTransform1` — вот ведь имечко! Хорошо хоть, что скорее всего вам не придётся вводить его руками.
101101
102102В инспекторе объектов мы увидим несколько свойств — самое важное — `Base`. Это основание вычисляемого логарифма. Сменим его на 10, т.к. мы хотим считать [десятичные логарифмы](https://en.wikipedia.org/wiki/Common_logarithm) — это подходит к 99% всех логарифмических диаграмм.
103103
104104Примечание: очень важно **в этом месте сохранить проект**. Почему? Увидите через минуту.
105105
106106Теперь мы должны определить ось, которая должна быть преобразована. Для этого каждая ось имеет свойство `Transformations`. В нашем случае огромные числа отложены по оси **Y**. Итак, переходим к левой оси и устанавливаем ее свойство `Transformations` в `ChartAxisTransformations1`.
107107
108108![](/wiki-images/0/0d/TAChart_LogAx_Tutorial17.png)
109109
110110Чёрт, что это? Выскакивает сообщение об ошибке проверки диапазона. Надеюсь, вы сохранили проект. Если вы нажмете «Отмена», Lazarus выключится, все будет потеряно. Если вы нажмете «ОК», диаграмма внезапно исчезнет, ​​​​она снова появится, когда вы кликните где-нибудь, но неисправная ось будет скрыта.
111111
112112Вы в отчаянии?
113113
114114Это основной недостаток работы в фазе конструирования. Если что-то пойдет не так, то нет отладчика, нет индикации того, что вызвало проблему. Поскольку компоненты компилируются в Lazarus, вам придется отлаживать IDE. Звучит сложно.
115115
116116Давайте сядем и подумаем, что мы сделали. Мы присвоили логарифмическое преобразование оси **Y**. Преобразование пока не имеет никакой связи с данными, поэтому данные пока в «реальных» единицах, их максимум 731 миллион. Но преобразование «думает», что данные уже представлены в графических единицах (логарифмах). Когда оно вычисляет метки осей в осевых единицах, это занимает сотни миллионов в степени 10! Вот что вызывает ошибку проверки диапазона. Однако ситуация не всегда столь драматична; самое меньшее, что может случиться, это то, что данные не трансформируются, а ось трансформируется.
117117
118118Что мы можем с этим сделать? Каждая серия имеет свойства `AxisIndexX` и `AxisIndexY`. Преобразование может использовать эту информацию чтобы вычислить логарифмы правильных координат перед обновлением меток осей. Это решает нашу проблему.
119119
120120Итак, нажмём «Отмена», чтобы выключить Lazarus. Перезапустим и перезагрузим проект. В сохраненном состоянии трансформация еще не связана с осью.
121121
122122Теперь взглянем на дерево объектов над инспектором объектов, и увидим, что левая ось имеет индекс 0. Поэтому установим `AxisIndexY` серии в это значение. Хотя это и не обязательно, может быть хорошей идеей обезвредить также ось **X**, назначив индекс 1 свойству `AxisIndexX` серии — кто может гарантировать, что мы не будем трансформировать ось x в будущем?
123123
124124После этого мы можем установить для `LeftAxis.Transformation` значение `LeftAxis.Transformation` без ошибки проверки диапазона.
125125
126126С активированным логарифмическим преобразованием точки теперь хорошо распределяются по диапазону оси **Y**. Но что не так с метками оси **Y**? А годы на оси абсцисс слишком близки и частично перекрываются.
127127
128128![](/wiki-images/d/d0/TAChart_LogAx_Tutorial6.png)
129129
130130Поиск меток осей — нетривиальная задача, особенно когда активны преобразования, сильно искажающие интервалы осей. К сожалению, логарифмические оси принадлежат к этой группе. По сути, есть два способа управления позиционированием метки: **автоматический** и **ручной**.
131131
132132### Автоматическая расстановка осевых меток
133133
134134Для автоматической расстановки меток ось имеет свойство [[TAChart documentation/ru|Intervals]], которое дает доступ к нескольким, частично взаимоисключающим параметрам — см. пояснение в [[TAChart documentation/ru|документации TAChart]]. В случае логарифмической оси проблема обычно возникает из-за того, что не установлена опция `aipGraphCoordinates`. Этот параметр, если он установлен, принудительно вычисляет интервалы делений для преобразованных данных («координаты графика»), а не для данных «реального мира» («координаты оси»). Итак, установим `aipGraphCoordinates` в `LeftAxis.Intervals.Options`. Метки разместятся более равномерно.
135135
136136![](/wiki-images/f/f1/TAChart_LogAx_Tutorial7.png)
137137
138138В зависимости от размера формы могут получиться очень хорошие или не очень хорошие метки. Изменив размер формы, увидим несколько «кривых» меток.
139139
140140Улучшить внешний вид метки можно следующим образом:
141141
142142- Увеличить `Intervals.Tolerance`. Это позволяет изменять расстояние между делениями.
143143- Отрегулировать диапазон в пикселях, в котором может варьироваться расстояние между метками. Он определяется свойствами `Intervals.MaxLength` и `Intervals.MinLength`. Оптимальное значение зависит от размера диаграммы и диапазона данных. В нашем учебном проекте хорошие метки получаются при установке этих свойств в 100 и 50 соответственно. Обычно `Intervals.MaxLength` обеспечивает лучшие результаты.
144144
145145Таким же образом можно поступить с перекрывающимися метками года оси **X**. Просто увеличим `BottomAxis.Intervals.MaxLength` до 70.
146146
147147Теперь осталась «1», которая появляется на оси **Y** между «10000000» и «1E009». Это связано с ошибкой в некоторых версиях FPC. Если у вас это тоже есть, просто измените свойство `LeftAxis.Marks.Format`. Эта строка передается функции `Format` для преобразования чисел в строки. Спецификатор формата «%0.0n», например, позволяет избежать этой ошибки преобразования и, кроме того, добавляет к меткам разделители тысяч, что делает их намного более читабельными.
148148
149149![](/wiki-images/7/7e/TAChart_LogAx_Tutorial8.png)
150150
151151### Расстановка осевых меток вручную
152152
153153Это лучшее, что мы смогли сделать с автоматическим позиционированием меток. Это не идеально, потому что, когда мы увеличиваем высоту окна или увеличиваем масштаб, могут появиться значения полудекады, или интервал метки может составлять две декады, как на рисунке выше.
154154
155155Если нас это не устраивает, мы должны использовать **ручной выбор осевых меток**. Для этого у каждой оси есть свойство `Source`, которое можно связать с ListChartSource, содержащим только разрешенные метки осей. Поэтому, когда этот источник диаграммы содержит только метки полных декад, нет риска меток полудекад или пропуска всех остальных меток. С другой стороны, когда мы увеличиваем диаграмму, мы можем наткнуться на точку, у которой метки больше не видны.
156156
157157Добавим в форму второй источник ListChartSource. Можно снова использовать редактор DataPoints, чтобы ввести числа полных декад. Это имеет то преимущество, что мы можем выполнить большую часть этого проекта, не написав ни одной строки кода!
158158
159159Но можно также легко заполнить источник списка и в событии `FormCreate`:
160160
161161``` pascal
162162procedure TForm1.FormCreate(Sender: TObject);
163163const
164164 MIN = 0;
165165 MAX = 12;
166166var
167167 i: Integer;
168168 value: double;
169169begin
170170 for i:=MIN to MAX do begin
171171 value := Power(10, i);
172172 ListChartSource2.Add(value, value);
173173 end;
174174end;
175175```
176176
177177Эта процедура добавляет степени 10 в достаточно широком диапазоне в ListChartSource с помощью метода `Add`.
178178
179179Подключим `ListChartSource1` к `LeftAxis.Marks.Source`, чтобы активировать ручные метки ListChartSource. Нам нужно также удалить все флаги из свойства `Options`. В противном случае автоматический поиск делений будет в какой-то степени активен. Если мы не использовали редактор DataPoints, мы должны скомпилировать проект, чтобы увидеть эффект.
180180
181181![](/wiki-images/5/51/TAChart_LogAx_Tutorial9.png)
182182
183183### Мелкие деления
184184
185185Очень часто между крупными делениями располагаются мелкие деления. TAChart позволяет добавить несколько наборов мелких делений на каждую ось. Нам здесь нужен только один. Ищем свойство `LeftAxis` и кликаем кнопку с многоточием рядом со свойством `Minors`. Открывается редактор для `Chart1.AxisList[0].Minors`. Нажимаем «Add» и «М» в списке ниже. Теперь можем настроить параметры в инспекторе объектов, чтобы получить «хорошие» мелкие деления. Если большие деления на логарифмической оси соответствуют полным декадам, то мелкие деления обычно соответствуют 2, 3, 4,..., 8, 9 и, конечно же, десятым степеням. Этого можно легко добиться, отключив все `Intervals.Options`, кроме `aipUseCount`, и установив `Intervals.Count` = 9. Конечно, это имеет смысл только в том случае, если большие метки показывают полные декады, как в описанном выше ручном подходе.
186186
187187Обычно график становится слишком переполненным мелкой сеткой, как сейчас, и нам надо установить для мелкой сетки `Grid.Visible` значение `false`.
188188
189189![](/wiki-images/5/5c/TAChart_LogAx_Tutorial10.png)
190190
191191## Аппроксимация
192192
193193Теперь поищем связь между данными, т. е. мы хотим найти математическую формулу, описывающую зависимость количества транзисторов от года выхода на рынок. Это называется «аппроксимация»: мы выбираем формулу с параметрами и подбираем эти параметры так, чтобы отклонение от данных было как можно меньше.
194194
195195TAChart не содержит полноценного механизма аппроксимации. Он использует процедуры аппроксимации из библиотеки FPC [[numlib]]. Поэтому TAChart не может охватить все варианты аппроксимации, но охватывает самый важный случай — приближение с помощью [полиномов](https://en.wikipedia.org/wiki/Polynomial), используя [метод наименьших квадратов](https://en.wikipedia.org/wiki/Least_squares). Это уровень, доступный пользователям Excel, когда они добавляют «линию тренда» на свой график.
196196
197197### TFitSeries
198198
199199Для аппроксимации TAChart предоставляет специалиальный объект типа [[TAChart documentation|TFitSeries]]. Такая серия имеет свойство `FitEquation`, которое определяет используемую формулу:
200200
201201- `fePolynomial`: y = b<sub>0</sub> + b<sub>1</sub>x + b<sub>2</sub>x<sup>2</sup> + … + b<sub>n</sub>x<sup>n</sup>. Указывает число аппроксимирующих параметров a<sub>i</sub> в свойстве `ParamCount` = n + 1.
202202- `feLinear`: y = a + bx — это частный случай полинома с n = 1 и параметрами аппроксимации a and b. Он доступен как отдельный элемент, поскольку прямые линии определяют наиболее важные условия аппроксимации.
203203- `feExp`: y = a * e<sup>bx</sup> — Эта функция также может быть к полиномиальной, хотя это не так просто заметить. Но взяв натуральный логарифм этой функции, получим ln(y) = a + bx. Теперь, когда мы аппроксимируем ln(y) вместо y, мы снова имеем линейный случай.
204204- `fePower`: y = a * x<sup>b</sup>. Снова это может быть сведено к линейной функции путём логарифмических преобразований обеих осей.
205205
206206![](/wiki-images/b/b5/TAChart_LogAx_Tutorial11.png)
207207
208208Довольно теории. Давайте добавим FitSeries на диаграмму: дважды кликнем по диаграмме и в редакторе серий нажмём «Add» и выберем «Least squares fit series»(аппроксимация методом наименьших квадратов) из выпадающего меню.
209209
210210Во-первых, нам нужно указать серии, где она найдёт свои данные. Для этого мы свяжем свойство серии `Source` с `ListChartSource1`, как мы уже делали с линейной серией. Заметим, что один и тот же источник данных может использоваться несколькими сериями.
211211
212212Надеюсь, вы помните описанную выше катастрофу с AxisIndex. Так что установим в `AxisIndexY` индекс левой оси, как мы делали в линейной серии.
213213
214214Какую из четырёх возможностей `FitEquation` выбрать? Ну, данные выглядят как лежащие на прямой. Так что выберем `feLinear`.
215215
216216![](/wiki-images/0/06/TAChart_LogAx_Tutorial12.png)
217217
218218Блин! Мы видим черную аппроксимирующую кривую, но она совсем не аппроксимирует. Мы хотели прямую линию, а получили изогнутую кривую. Как такое может быть?
219219
220220Причина в логарифмическом преобразовании, которое мы применили к данным оси **Y**. Поэтому на нашем графике показаны логарифмы, но для аппроксимации используются «сырые» данные. Мы эффективно аппроксимируем прямой данные на скриншоте в разделе Отображение меток точек, где логарифмическое преобразование ещё не было введено — понятно, что прямая линия там не подойдёт. И когда аппроксимирующая функция нарисована, логарифмическое преобразование искажает прямую линию в искривленную кривую, которую мы и видим.
221221
222222С другой стороны, если **логарифмизированные данные** находятся на прямой линии, то наша аппроксимирующая функция не линейна, а экспоненциальна. Установим `FitEquation` в `feExp` и попробуем снова.
223223
224224![](/wiki-images/a/ac/TAChart_LogAx_Tutorial13.png)
225225
226226Вот, намного лучше!
227227
228228Теперь мы знаем, что экспоненциальный закон y = a * x<sup>b</sup> — хорошее приближение наших данных. Но как нам получить параметры a и b?
229229
230230### Результаты аппроксимации
231231
232232Аппроксимирующая серия имеет свойство типа массив `Param`, содержащий параметры аппроксимации. `a` это `Params[0]`, и `b` лежит в `Params[1]`. Конечно, эти значения имеют смысл только тогда, когда была произведена удачная аппроксимация. Как мы это узнаем? Ну, аппроксимирующая серия генерирует событие `OnFitComplete`, когда аппроксимация удачно завершается. Вот где мы можем узнать полученные параметры аппроксимации. Например, отобразим результаты аппроксимации в сообщении вместе с аппроксимирующей функцией:
233233
234234``` pascal
235235procedure TForm1.Chart1FitSeries1FitComplete(Sender: TObject);
236236begin
237237 with Chart1FitSeries1 do
238238 ShowMessage(Format(
239239 'Fit result: a = %g, b = %g', [
240240 Param[0], Param[1]
241241 ]));
242242end;
243243```
244244
245245И вот что мы получим:
246246
247247![](/wiki-images/d/d1/TAChart_LogAx_Tutorial14.png)
248248
249249Теперь мы хотим вычислить время T за которое число транзисторов на пластине удваивается. В качестве упражнения попробуйте показать, что
250250
251-`T = ln(2) / b`
251+```text
252+T = ln(2) / b
253+```
252254
253255Было бы неплохо указать время удвоения в виде дополнительной строки в заголовке графика. Для этого модифицируем обработчик события `OnFitComplete` следующим образом:
254256
255257``` pascal
256258procedure TForm1.Chart1FitSeries1FitComplete(Sender: TObject);
257259begin
258260 Chart1.Title.Text.Add(Format(
259261 'The number of transistors doubles every %.0f years',
260262 [ln(2) / Chart1FitSeries1.Param[1]]
261263 ));
262264end;
263265```
264266
265267![](/wiki-images/3/3d/TAChart_LogAx_Tutorial15.png)
266268
267269Вау! Это закон Мура: «Количество транзисторов на пластине удваивается каждые два года».
268270
269271## Исходный код
270272
271273### Файл проекта
272274
273275``` pascal
274276program project1;
275277
276278{$mode objfpc}{$H+}
277279
278280uses
279281 {$IFDEF UNIX}{$IFDEF UseCThreads}
280282 cthreads,
281283 {$ENDIF}{$ENDIF}
282284 Interfaces, // this includes the LCL widgetset
283285 Forms, Unit1, tachartlazaruspkg
284286 { you can add units after this };
285287
286288{$R *.res}
287289
288290begin
289291 //RequireDerivedFormResource := True;
290292 Application.Initialize;
291293 Application.CreateForm(TForm1, Form1);
292294 Application.Run;
293295end.
294296```
295297
296298### Unit1.pas
297299
298300``` pascal
299301unit Unit1;
300302
301303{$mode objfpc}{$H+}
302304
303305interface
304306
305307uses
306308 Classes, SysUtils, FileUtil, TAGraph, TASeries, TASources, Forms, Controls,
307309 Graphics, Dialogs, TACustomSource, TATransformations, TAFuncSeries;
308310
309311type
310312
311313 { TForm1 }
312314
313315 TForm1 = class(TForm)
314316 Chart1: TChart;
315317 Chart1FitSeries1: TFitSeries;
316318 Chart1LineSeries1: TLineSeries;
317319 ChartAxisTransformations1: TChartAxisTransformations;
318320 ChartAxisTransformations1LogarithmAxisTransform1: TLogarithmAxisTransform;
319321 ListChartSource1: TListChartSource;
320322 ListChartSource2: TListChartSource;
321323 procedure Chart1FitSeries1FitComplete(Sender: TObject);
322324 procedure FormCreate(Sender: TObject);
323325 private
324326 { private declarations }
325327 public
326328 { public declarations }
327329 end;
328330
329331var
330332 Form1: TForm1;
331333
332334implementation
333335
334336{$R *.lfm}
335337
336338uses
337339 math;
338340
339341{ TForm1 }
340342
341343procedure TForm1.FormCreate(Sender: TObject);
342344const
343345 MIN = 0;
344346 MAX = 12;
345347var
346348 i: Integer;
347349 value: double;
348350begin
349351 for i:=MIN to MAX do begin
350352 value := IntPower(10, i);
351353 ListChartSource2.Add(value, value);
352354 end;
353355 Chart1FitSeries1.ExecFit;
354356end;
355357
356358procedure TForm1.Chart1FitSeries1FitComplete(Sender: TObject);
357359begin
358360 {
359361 with Chart1FitSeries1 do
360362 ShowMessage(Format(
361363 'Fit result: a = %g, b = %g', [
362364 Param[0], Param[1]
363365 ]));
364366 }
365367 Chart1.Title.Text.Add(Format(
366368 'The number of transistors doubles every %.0f years',
367369 [ln(2) / Chart1FitSeries1.Param[1]]
368370 ));
369371end;
370372
371373end.
372374```
373375
374376### Unit1.lfm
375377
376-``` pascal
378+``` lfm
377379object Form1: TForm1
378380 Left = 244
379381 Height = 356
380382 Top = 193
381383 Width = 552
382384 Caption = 'Form1'
383385 ClientHeight = 356
384386 ClientWidth = 552
385387 OnCreate = FormCreate
386388 LCLVersion = '1.1'
387389 object Chart1: TChart
388390 Left = 0
389391 Height = 356
390392 Top = 0
391393 Width = 552
392394 AxisList = <
393395 item
394396 Grid.Color = clSilver
395397 Marks.Format = '%0:.0n'
396398 Marks.Source = ListChartSource2
397399 Marks.Style = smsCustom
398400 Minors = <
399401 item
400402 Grid.Visible = False
401403 Intervals.Count = 9
402404 Intervals.MinLength = 5
403405 Intervals.Options = [aipUseCount]
404406 end>
405407 Title.LabelFont.Orientation = 900
406408 Title.LabelFont.Style = [fsBold]
407409 Title.Visible = True
408410 Title.Caption = 'Number of transistors'
409411 Transformations = ChartAxisTransformations1
410412 end
411413 item
412414 Grid.Color = clSilver
413415 Intervals.MaxLength = 60
414416 Alignment = calBottom
415417 Minors = <>
416418 Title.LabelFont.Style = [fsBold]
417419 Title.Visible = True
418420 Title.Caption = 'Year of market introduction'
419421 end>
420422 BackColor = clWhite
421423 Foot.Alignment = taLeftJustify
422424 Foot.Brush.Color = clBtnFace
423425 Foot.Font.Color = clBlue
424426 Foot.Text.Strings = (
425427 'Source:'
426428 'http://www.intel.com/pressroom/kits/quickreffam.htm'
427429 )
428430 Foot.Visible = True
429431 Margins.Left = 24
430432 Margins.Right = 24
431433 Title.Brush.Color = clBtnFace
432434 Title.Font.Color = clBlue
433435 Title.Font.Style = [fsBold]
434436 Title.Text.Strings = (
435437 'Progress in Microelectronics'
436438 )
437439 Title.Visible = True
438440 Align = alClient
439441 ParentColor = False
440442 object Chart1LineSeries1: TLineSeries
441443 Marks.Format = '%2:s'
442444 Marks.LinkPen.Color = clGray
443445 Marks.Style = smsLabel
444446 AxisIndexY = 0
445447 LineType = ltNone
446448 Pointer.Brush.Color = clRed
447449 Pointer.Style = psCircle
448450 ShowPoints = True
449451 Source = ListChartSource1
450452 end
451453 object Chart1FitSeries1: TFitSeries
452454 AxisIndexX = 1
453455 AxisIndexY = 0
454456 FitEquation = feExp
455457 OnFitComplete = Chart1FitSeries1FitComplete
456458 ParamCount = 2
457459 Source = ListChartSource1
458460 end
459461 end
460462 object ListChartSource1: TListChartSource
461463 DataPoints.Strings = (
462464 '1972|2300|?|4004'
463465 '1974|6000|?|8080'
464466 '1978|29000|?|8086'
465467 '1982|134000|?|80286'
466468 '1986|275000|?|80386'
467469 '1989|1200000|?|80486'
468470 '1993|3100000|?|Pentium'
469471 '1997|7500000|?|Pentium II'
470472 '2001|42000000|?|Xeon'
471473 '2006|152000000|?|Core Duo'
472474 '2009|731000000|?|Core i7'
473475 )
474476 left = 240
475477 top = 40
476478 end
477479 object ChartAxisTransformations1: TChartAxisTransformations
478480 left = 243
479481 top = 96
480482 object ChartAxisTransformations1LogarithmAxisTransform1: TLogarithmAxisTransform
481483 Base = 10
482484 end
483485 end
484486 object ListChartSource2: TListChartSource
485487 left = 243
486488 top = 176
487489 end
488490end
489491```
490492
491493---
492494*From the Free Pascal wiki, page "TAChart Tutorial: ListChartSource, Logarithmic Axis, Fitting/ru", as it stood on 2023-08-01 after a change by AMXS52, 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