# Trend lines

> Fit a straight line through each series with trendLine(), read how well it fits, and draw exponential trends on a log axis.

Values go up and down. Is the series growing anyway? `trendLine()` answers with one straight line through it, dashed and in the series' color. It works on the presets and in composed charts, on bars, lines and points. For a fixed goal or limit, see [target lines](https://chartist.dev/packages/essentials/target-lines/).

It comes from `@chartist-js/essentials`, with its stylesheet after Chartist's:

```ts
import 'chartist/styles.css';
import '@chartist-js/essentials/styles.css';
```

## A trend through bars

Presets take extra layers in their `layers` option: `above` draws them on top of the bars or lines. On bar charts, `align: 'center'` lines the trend up with the middle of the bars:

**Bars with a trend line** (runs in the browser):

`src/main.ts`:

```ts
import 'chartist/styles.css';
import '@chartist-js/essentials/styles.css';
import { barChart } from 'chartist';
import { trendLine } from '@chartist-js/essentials';

// Monthly sign-ups with the trend they follow.
barChart(
  '#chart',
  {
    labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug'],
    series: [[42, 38, 51, 47, 58, 54, 66, 63]]
  },
  {
    low: 0,
    // Centered, so the line runs through the middle of the bars.
    layers: { above: [trendLine({ align: 'center' })] }
  }
);
```

`index.html`:

```html
<!doctype html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <script type="module" src="/src/main.ts"></script>
  </head>
  <body>
    <div id="chart" style="height: 50vh"></div>
  </body>
</html>
```

The line runs from the series' first to its last value. Where it ends below or above the values, the Y axis grows to keep it in view. Holes are skipped, and a series with fewer than two values gets no line. Without options, every series gets a line; `series` picks some by name or index.

| Option       | What it does                                                           |
| ------------ | ---------------------------------------------------------------------- |
| `series`     | The series to fit, by name or index; by default all of them            |
| `x`, `y`     | The ids of the axes to draw on, in a composed chart                    |
| `align`      | `'start'` (default) or `'center'` of each step, to line up with bars   |
| `classNames` | `{ series, line }` replace the classes `ct-series` and `ct-trend-line` |

## Points on a scale

The fit is least squares: on a step axis it uses the values' order, on a scale axis their `x`. So a scatter plot gets its regression line:

**A regression line** (runs in the browser):

`src/main.ts`:

```ts
import 'chartist/styles.css';
import '@chartist-js/essentials/styles.css';
import { autoScaleAxis, lineChart } from 'chartist';
import { trendLine } from '@chartist-js/essentials';

// Daily ice cream sales against the day's high, in °C.
const days = [
  [14, 215],
  [16, 325],
  [11, 185],
  [15, 332],
  [18, 406],
  [22, 522],
  [19, 412],
  [25, 614],
  [23, 544],
  [18, 421],
  [22, 445],
  [17, 408],
  [24, 590],
  [27, 621],
  [21, 489],
  [13, 230],
  [20, 470],
  [26, 632]
];

lineChart(
  '#chart',
  { series: [days.map(([x, y]) => ({ x, y }))] },
  {
    // Points only: a scatter plot.
    showLine: false,
    axisX: { type: autoScaleAxis(), onlyInteger: true },
    low: 0,
    // The least-squares line through the points.
    layers: { above: [trendLine()] }
  }
);
```

`index.html`:

```html
<!doctype html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <script type="module" src="/src/main.ts"></script>
  </head>
  <body>
    <div id="chart" style="height: 50vh"></div>
  </body>
</html>
```

## How well it fits

A rising line says little when the values jump around it. Each trend line's node has the line's `slope` and `intercept`, and its `correlation`: Pearson's r, from -1 for values that all lie on a falling line, through 0 for no straight trend, to 1 for a rising one. Its square is the R² that spreadsheets show next to a trendline, the share of the ups and downs the line explains. A listener can read it from the scene:

**Two trends, two fits** (runs in the browser):

`src/main.ts`:

```ts
import 'chartist/styles.css';
import '@chartist-js/essentials/styles.css';
import './style.css';
import { alphaNumerate, findAll, lineChart } from 'chartist';
import { trendLine } from '@chartist-js/essentials';

const fit = document.querySelector('#fit')!;
const shops = ['Basel', 'Bern'];

// Two shops over twelve weeks: one grows steadily, one jumps around. Both
// trend lines rise, but only one fits its values well.
lineChart(
  '#chart',
  {
    labels: Array.from({ length: 12 }, (_, week) => `${week + 1}`),
    series: [
      {
        name: shops[0],
        data: [20, 22, 25, 24, 28, 30, 31, 34, 33, 37, 39, 41]
      },
      { name: shops[1], data: [18, 34, 15, 29, 40, 22, 38, 19, 44, 27, 35, 46] }
    ]
  },
  {
    showPoint: false,
    lineSmooth: false,
    layers: { above: [trendLine()] },
    on: {
      // Each trend line's node knows its slope and its correlation r; r²
      // is the share of the ups and downs the line explains.
      scene: ({ scene }) => {
        fit.replaceChildren(
          ...findAll(scene, { role: 'trendLine' }).map(({ ctx }) => {
            const row = document.createElement('span');
            // The series class gives the name its series' color.
            row.className = `ct-series-${alphaNumerate(ctx.seriesIndex)}`;
            const r2 = (ctx.correlation ?? 0) ** 2;
            row.textContent = `${shops[ctx.seriesIndex]}: +${ctx.slope.toFixed(1)} a week, R² ${r2.toFixed(2)}`;
            return row;
          })
        );
      }
    }
  }
);
```

`src/style.css`:

```css
#fit {
  display: grid;
  gap: 0.25em;
  margin: 0.5em 0 0;
  font-size: 13px;
}

#fit span {
  color: var(--ct-color);
}
```

`index.html`:

```html
<!doctype html>
<html>
  <head>
    <meta charset="UTF-8" />
    <script type="module" src="/src/main.ts"></script>
  </head>
  <body>
    <div id="chart" class="ct-golden-section"></div>
    <p id="fit"></p>
  </body>
</html>
```

Both shops grow, but only Basel's line describes its weeks. With two values r is always 1 or -1, so a fit needs a few values before it means much. A [tooltip](https://chartist.dev/packages/tooltips/content-and-styling/) can show the same numbers on hover.

## Exponential growth

On a [log axis](https://chartist.dev/packages/essentials/log-axis/), the line is fitted to the logarithms of the values, so it's straight there: an exponential trend on a log Y axis, a power law on two log axes. Here an animal's metabolic rate grows with its mass to the power of about ¾:

**A power law** (runs in the browser):

`src/main.ts`:

```ts
import 'chartist/styles.css';
import '@chartist-js/essentials/styles.css';
import { axisGrid, axisLabels, cartesianAxes, chart, line } from 'chartist';
import { logAxis, trendLine } from '@chartist-js/essentials';

// Body mass (kg) and resting metabolic rate (W) from a mouse to an
// elephant. The rate grows with the mass to the power of about 3/4
// (Kleiber's law): on two log axes that's a straight line, and the trend
// line fitted to the logarithms finds it.
const animals = [
  { x: 0.02, y: 0.17, meta: 'Mouse' },
  { x: 0.3, y: 1.45, meta: 'Rat' },
  { x: 4, y: 9.1, meta: 'Cat' },
  { x: 30, y: 46, meta: 'Dog' },
  { x: 70, y: 80, meta: 'Human' },
  { x: 600, y: 395, meta: 'Horse' },
  { x: 4000, y: 1800, meta: 'Elephant' }
];

chart('#chart', {
  data: { series: [animals] },
  axes: cartesianAxes([
    { id: 'mass', side: 'bottom', type: logAxis({ minorTicks: true }) },
    { id: 'rate', side: 'left', type: logAxis({ minorTicks: true }) }
  ]),
  layers: [axisGrid(), trendLine(), line({ showLine: false }), axisLabels()],
  // Room for the last X label, which starts at its tick.
  padding: { right: 32 }
});
```

`index.html`:

```html
<!doctype html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <script type="module" src="/src/main.ts"></script>
  </head>
  <body>
    <div id="chart" style="height: 50vh"></div>
  </body>
</html>
```

The `slope` is then in powers of the base per step, here about 0.75: the rate grows by a factor of 10 to the 0.75 for every tenfold mass.

## Styling

A trend line takes its series' color. Its width and dash pattern are custom properties:

```css
.ct-chart {
  --ct-trend-line-width: 1px;
  --ct-trend-line-dasharray: 2px 2px;
}
```

The markup: a `line.ct-trend-line` in a series group (`g.ct-series.ct-series-a`) per line. In listeners and plugins, find them by the role `trendLine`, as in [events and plugins](https://chartist.dev/docs/events-and-plugins/). Importing `@chartist-js/essentials` declares the role, so TypeScript knows its context.
