---
title: Build line charts with Kibana
description: Instructions and best practices for building line charts with Kibana Lens in Elastic.
url: https://www.elastic.co/docs/explore-analyze/visualize/charts/line-charts
products:
  - Elastic Cloud Enterprise
  - Elastic Cloud Hosted
  - Elastic Cloud Serverless
  - Elastic Cloud on Kubernetes
  - Elastic Stack
  - Kibana
applies_to:
  - Elastic Cloud Serverless: Generally available
  - Elastic Stack: Generally available
---

# Build line charts with Kibana
Line charts are ideal for visualizing how metrics evolve over time, spotting seasonal patterns, and detecting spikes or regressions at a glance. Use them for KPIs like response time, error rate, throughput, or utilization, and compare multiple series or previous periods on the same chart. You can create line charts from any numeric data using aggregations (for example, `Average`, `Percentile`, `Counter rate`) or with custom [formulas](/docs/explore-analyze/visualize/lens#lens-formulas).
You can create line charts in Kibana using [**Lens**](https://www.elastic.co/docs/explore-analyze/visualize/lens).
![Example Lens line chart](https://www.elastic.co/docs/explore-analyze/images/kibana-line-new.png)

## Build a line chart

Before you start, make sure you have data [indexed into Elasticsearch](https://www.elastic.co/docs/manage-data/ingest) or [install sample data](https://www.elastic.co/docs/manage-data/ingest/sample-data). By default, Lens uses [data views](https://www.elastic.co/docs/explore-analyze/find-and-organize/data-views) to access your Elasticsearch data. Data views are created automatically in most cases when you ingest data. You can also [create one manually](https://www.elastic.co/docs/explore-analyze/find-and-organize/data-views) to select just the data that you want. Alternatively, you can use the [ES|QL query mode](https://www.elastic.co/docs/explore-analyze/visualize/esorql) to query your Elasticsearch data directly.
To build a line chart:
<stepper>
  <step title="Access Lens">
    **Lens** is Kibana's main visualization editor. You can access it:
    - From a dashboard: On the **Dashboards** page, open or create the dashboard where you want to add a line chart, then add a new visualization.
    - From the **Visualize library** page by creating a new visualization.
  </step>

  <step title="Set the visualization to Line">
    Make sure that the visualization type is set to **Line**.<applies-to>Elastic Stack: Generally available since 9.4</applies-to> <applies-to>Elastic Cloud Serverless: Generally available</applies-to> When you drag a date or time field (such as `@timestamp`) onto an empty workspace, **Line** is automatically selected.
  </step>

  <step title="Define the data to show">
    1. Select the data view that contains your data.
    2. Drag a [time field](https://www.elastic.co/docs/reference/elasticsearch/mapping-reference/date) to the **Horizontal axis** and a numeric field to the **Vertical axis**. Kibana automatically selects an appropriate aggregation function compatible with the selected field.
    Optionally:
    - Add more numeric fields to create additional series, or drag a categorical field to **Break down by** to split the series.
    - You can click the **Add layer** icon `plus_in_square` to integrate additional visualizations, [annotations](/docs/explore-analyze/visualize/lens#add-annotations), or a [reference line](/docs/explore-analyze/visualize/lens#add-reference-lines).
    The chart preview updates to show one or more lines plotted over time. Each line represents a series, and data points are connected to show trends.
  </step>

  <step title="Customize the chart to follow best practices">
    You can tweak the appearance of your chart by adjusting axes, legends, and series styles from the chart settings. Consider the following best practices:
    <definitions>
      <definition term="Use color wisely">
        Assign colors that match your users' expectations and consider your specific context.
        <applies-to>Elastic Cloud Serverless: Generally available</applies-to> <applies-to>Elastic Stack: Generally available since 9.4</applies-to> Lens automatically applies the **Elastic (line optimized)** palette to line charts, which reorders colors for better contrast between adjacent series. You can override this by manually selecting a different palette.
      </definition>
      <definition term="Provide context">
        Add a legend and descriptive axis titles, or remove them for obvious axes.
      </definition>
    </definitions>
    For layout, hierarchy, and color guidance on dashboards, check EUI’s [Dashboard good practices](https://eui.elastic.co/docs/dataviz/dashboard-good-practices/).
    For more chart configuration options, go to the [Line chart settings](#settings) section.
  </step>

  <step title="Save the chart">
    - If you accessed Lens from a dashboard, select **Save and return** to save the visualization and add it to that dashboard, or select **Save to library** to add the visualization to the Visualize library.
    - If you accessed Lens from the Visualize library, select **Save**. The Save menu also lets you add the visualization to a dashboard and the Visualize library.
  </step>
</stepper>


## Advanced line scenarios


### Compare current versus previous period with time shift

In line charts, you can enable time shift to compare the current value with a prior time range and identify deltas.
![Example Lens line chart current previous](https://www.elastic.co/docs/explore-analyze/images/kibana-line-current-previous.png)
1. Create a line chart with a time-based **Horizontal axis** and your main metric on **Vertical axis**, for example: `bytes`.
2. Duplicate the layer:
   - <applies-to>Elastic Cloud Serverless: Generally available</applies-to> <applies-to>Elastic Stack: Generally available since 9.3</applies-to> Select `copy` **Duplicate layer** from the visualization editor.
- <applies-to>Elastic Stack: Generally available from 9.0 to 9.2</applies-to> Open the `boxes_vertical` contextual menu of the visualization editor and select `copy` **Duplicate layer**.
3. From the duplicated layer settings, select the field defined as vertical axis to open its details. Expand its **Advanced** options and set **Time shift** to `1w` or to the time value of your choice.
   Check [Compare differences over time](/docs/explore-analyze/visualize/lens#compare-data-with-time-offsets) for more details.
4. Optionally, customize the appearance of the layer to adjust how it looks on the chart. When you duplicate a layer, Kibana automatically assigns a different **Series color** to the new layer. You can for example change this color, or adjust the layer's name and axis position. This name is used for the chart's legend.

<tip>
  You can also compute the relative change by defining the axis data with a [formula](/docs/explore-analyze/visualize/lens#lens-formulas), for example:
  `(average(bytes) - average(bytes, shift='1w')) / average(bytes, shift='1w')`
</tip>


### Highlight thresholds with reference lines

Use reference lines to indicate important thresholds, such as SLOs or alert limits.
![Example Lens line chart reference lines](https://www.elastic.co/docs/explore-analyze/images/kibana-line-reference-lines.png)
1. In the chart settings, add a static value reference line to mark your target or threshold visually.
2. Use the **Text decoration** setting to provide a name, for example, `Target` or `SLO`, choose a color, and optionally a band.


## Line chart settings

Customize your line chart to display exactly the information you need, formatted the way you want.

### Horizontal axis settings

<definitions>
  <definition term="Data">
    - **Functions**:
      - **Top values**: Create separate lines for the most common values in a field.
      - **Field**: Select the field to group by. You can add up to 4 fields. When multiple fields are selected, each line represents a unique combination of values across those fields. You can reorder the fields by dragging them to change their priority.
    - **Number of values**: How many top values to display. The default number of values depends on your environment:
      - <applies-to>Elastic Cloud Serverless: Generally available</applies-to> <applies-to>Elastic Stack: Generally available since 9.4</applies-to> Defaults to 9.
    - <applies-to>Elastic Stack: Generally available from 9.0 to 9.3</applies-to> Defaults to 5.
      - **Rank by**: Specifies the dimension the top values are ranked by. Available options:
      - **Count of records**: Rank by the number of documents containing each value. This is the default when a metric is defined.
      - **Alphabetical**: Rank by the term key alphabetically. This is the default when no metric is defined.
      - **Rarity**: Find terms that appear in very few documents, using a [rare terms aggregation](https://www.elastic.co/docs/reference/aggregations/search-aggregations-bucket-rare-terms-aggregation). You can configure the **Max doc count** to set the maximum number of documents a term can appear in to be considered rare (default: 1, max: 100). Only available for non-numeric fields and single-field terms.
      - **Significance**: Find statistically unusual terms compared to the overall data set, using a [significant terms aggregation](https://www.elastic.co/docs/reference/aggregations/search-aggregations-bucket-significantterms-aggregation). Only available for `keyword` fields and single-field terms.
      - **Custom**: Define a custom metric aggregation to rank by (for example, rank by the sum of a numeric field rather than by count).
      - **Rank direction**: Ascending or descending order. Disabled when **Rank by** is set to **Rarity** or **Significance**.
      <dropdown title="Advanced settings">
      Several advanced options allow you to refine the behavior of the breakdown:
      - **Include documents without the selected field**: Off by default.
      - **Group remaining values as "Other"**: On by default.
      - **Enable accuracy mode**: This option improves results for high-cardinality data, but increases the load on the Elasticsearch cluster.
      - **Include values**: Values from the breakdown dimension to always show a tile for.
      - **Exclude values**: Values from the breakdown dimension to always exclude from the displayed tiles.
      </dropdown>
    - **Date histogram**: Group data points into time-based buckets (for example, hourly, daily, weekly).
      - **Field**: Select the date field to use for the time-based grouping.
      - **Include empty rows**: This option is on by default. Turn it off to exclude empty rows from the data.
      - **Bind to global time picker**: Associate the selected field to the Lens or dashboard main time selector.
      - **Minimum interval**: Define the time interval for aggregating the data. For example, `30s`, `20m`, `24h`, `2d`, `1w`, `1M`
      - **Drop partial intervals**: Exclude incomplete intervals from the data. This option is off by default.
    - **Intervals**: Create numeric ranges for continuous data. You can define the interval granularity or specify custom ranges.
      - **Field**: Select the numeric field to create intervals from.
    - **Filters**: Allow you to segment your data based on specific conditions, creating separate lines for each filter.
  </definition>
  <definition term="Appearance">
    **Name**: By default, the chart uses the function or formula as title. It's a best practice to customize this with a meaningful title.
  </definition>
</definitions>


### Vertical axis settings

<definitions>
  <definition term="Data">
    To represent the metrics or values you want to visualize, you can use quick functions like `Average`, `Count`, `Percentile`, `Counter rate`, or create custom calculations with formulas. Refer to [Lens > Use formulas to perform math](/docs/explore-analyze/visualize/lens#lens-formulas) for examples, or to the `documentation` **Formula reference** available from Lens.
    <dropdown title="Advanced settings">
      Depending on the data you defined, several options allow you to apply additional filtering to the data taken into account to compute the final value to show.Based on the type of visualization you're creating, only some of the following options can be available:
      - **Normalize by unit**: Normalize the metric values to show per unit of time.
      - **Filter by**: Specify a query.
      - **Reduced time range**: Reduce the time range specified on the dashboard's time filter by the specified duration.
      - **Time shift**: Shift the time range by the specified duration. This is useful if the value should use a different time range than the one selected on the dashboard.
      - **Hide zero values**: Don't show values equal to zero. This option is on by default.
    </dropdown>
  </definition>
</definitions>

**Appearance**
- **Name**: Customize the legend label with a descriptive name.
- **Value format**: Control how numeric values are displayed on the vertical axis of your visualization.
- **Series color**: Select a palette or specific color per series.
- **Axis side**: Control where axis labels and tick marks appear.


### Breakdown settings

Breakdown functions segment your data into multiple lines on the same chart, with each line representing a different value of a categorical field. You can specify the following options:
<definitions>
  <definition term="Data">
    - **Functions**:
      - **Top values**: Create separate lines for the most common values in a field.
      - **Field**: Select the field to group by. You can add up to 4 fields. When multiple fields are selected, each line represents a unique combination of values across those fields. You can reorder the fields by dragging them to change their priority.
    - **Number of values**: How many top values to display. The default number of values depends on your environment:
      - <applies-to>Elastic Cloud Serverless: Generally available</applies-to> <applies-to>Elastic Stack: Generally available since 9.4</applies-to> Defaults to 9.
    - <applies-to>Elastic Stack: Generally available from 9.0 to 9.3</applies-to> Defaults to 3.
      - **Rank by**: Specifies the dimension the top values are ranked by. Available options:
      - **Count of records**: Rank by the number of documents containing each value. This is the default when a metric is defined.
      - **Alphabetical**: Rank by the term key alphabetically. This is the default when no metric is defined.
      - **Rarity**: Find terms that appear in very few documents, using a [rare terms aggregation](https://www.elastic.co/docs/reference/aggregations/search-aggregations-bucket-rare-terms-aggregation). You can configure the **Max doc count** to set the maximum number of documents a term can appear in to be considered rare (default: 1, max: 100). Only available for non-numeric fields and single-field terms.
      - **Significance**: Find statistically unusual terms compared to the overall data set, using a [significant terms aggregation](https://www.elastic.co/docs/reference/aggregations/search-aggregations-bucket-significantterms-aggregation). Only available for `keyword` fields and single-field terms.
      - **Custom**: Define a custom metric aggregation to rank by (for example, rank by the sum of a numeric field rather than by count).
      - **Rank direction**: Ascending or descending order. Disabled when **Rank by** is set to **Rarity** or **Significance**.
      <dropdown title="Advanced settings">
      Several advanced options allow you to refine the behavior of the breakdown:
      - **Include documents without the selected field**: Off by default.
      - **Group remaining values as "Other"**: On by default.
      - **Enable accuracy mode**: This option improves results for high-cardinality data, but increases the load on the Elasticsearch cluster.
      - **Include values**: Values from the breakdown dimension to always show a tile for.
      - **Exclude values**: Values from the breakdown dimension to always exclude from the displayed tiles.
      </dropdown>
    - **Date histogram**: Group data points into time-based buckets (for example, hourly, daily, weekly).
      - **Field**: Select the date field to use for the time-based grouping.
      - **Include empty rows**: This option is on by default. Turn it off to exclude empty rows from the data.
      - **Bind to global time picker**: Associate the selected field to the Lens or dashboard main time selector.
      - **Minimum interval**: Define the time interval for aggregating the data. For example, `30s`, `20m`, `24h`, `2d`, `1w`, `1M`
      - **Drop partial intervals**: Exclude incomplete intervals from the data. This option is off by default.
    - **Intervals**: Create numeric ranges for continuous data. You can define the interval granularity or specify custom ranges.
      - **Field**: Select the numeric field to create intervals from.
    - **Filters**: Allow you to segment your data based on specific conditions, creating separate lines for each filter.
  </definition>
  <definition term="Appearance">
    Allow you to customize how your breakdown data is displayed in line charts, including:
    - **Name**: It's a best practice to customize this with a meaningful title.
    - **Value format**: Control how numeric values are displayed in your visualization.
    - **Color mapping**: Determine how colors are assigned to your breakdown series.
  </definition>
</definitions>


### General layout

When creating or editing a visualization, you can adjust the following settings.
<dropdown title="Style">
  Adjust the visual appearance of your line chart to control how the data series are labeled and displayed alongside your chart. Click `brush` to open the **Style** panel.
  <definitions>
    <definition term="Appearance">
      Allow you to customize to overall chart appearance:
    </definition>
  </definitions>

  - **Point visibility**: Use this option to show or hide data points. Set to **Auto** by default: Points are visible unless the distance between them is too short.
    - **Line interpolation**: Choose how to interpolate the line between data points from the available options: **Straight** (default), **Smooth**, and **Step**.
  - **Missing values**: Choose between **Hide**, **Zero**, **Linear**, **Last**, and **Next**. This option controls how gaps in data appear on the chart. By default, gaps are hidden. Missing values include empty buckets and metrics: Buckets without documents or metrics that returned `null` due to their operation and data content.
    <note>
    You can only use this option when the **Include empty rows** option of the chart is enabled or when a metric produces a null bucket. For example, if a moving average finds empty buckets.
    </note>
    - **Hide**: Don't show gaps in data.
  - **Zero**: Fill gaps by connecting starting and ending data points to zero.
  - **Linear**: Fill gaps by connecting related starting and ending data points together with a direct line.
  - **Last**: Fill gaps between data points with a horizontal or vertical line that uses the last ending point value, when available, to determine its position.
  - **Next**: Fill gaps between data points with a horizontal or vertical line that uses the next starting point value, when available, to determine its position.
  - <definitions>
    <definition term="End values">
    If you've chosen to show missing values, you can also decide to extend data series to the edge of the chart. By default, end values are hidden.
    </definition>
    </definitions>
    - **Hide**: Don't extend series to the edge of the chart.
    - **Zero**: Extend series as zero to the edge of the chart.
  - **Nearest**: Extend series with their first or last value to the edge of the chart.
  - <definitions>
    <definition term="Show as dotted line">
    If you've chosen to show missing values, you can turn on this option to show gaps as a dotted line.
    </definition>
    </definitions>

  <definitions>
    <definition term="Left axis">
      Allow you to customize the Y-axis appearance.
    </definition>
  </definitions>

  - **Axis Title**. Show, hide or add a custom title.
    - **Gridlines**. Show or hide gridlines.
  - **Tick labels**. Show or hide tick labels.
  - **Orientation**. Choose the tick labels orientation.
  - **Axis scale**. Choose an axis scale type. Options include: Linear (default), Logarithmic, and Square root.
  - **Bounds**. Use Bounds to set the minimum and maximum values for the Y-axis. Options include: Full, Data, and Custom
  - **Round to nice value**. Axis labels can be rounded to more readable numbers.

  <definitions>
    <definition term="Bottom axis">
      Allow you to customize the bottom axis appearance:
    </definition>
  </definitions>

  - **Axis Title**. Show, hide or add a custom title.
    - **Gridlines**. Show/hide gridlines.
  - **Tick labels**. Show/hide tick labels.
  - **Show partial data markers**: indicate data points where Data collection is incomplete (the time bucket is still open and actively collecting events), or data may change (the values represented might increase as more data arrives).
  - **Show current time marker**: Add a vertical line on your chart that represents the current time.
</dropdown>

<dropdown title="Legend">
  You can customize the way the legend is displayed and the data it shows. Click ![Legend icon](https://www.elastic.co/docs/explore-analyze/images/kibana-legend-icon.svg) to open the **Legend** panel.With the **Visibility**, **Position**, and **Width** options, you can adjust the way the legend appears in or next to the visualization.
  <definitions>
    <definition term="Layout Elastic Stack: Generally available since 9.4 Elastic Cloud Serverless: Generally available">
      For legends positioned outside the chart at the top or bottom, choose how series labels are arranged:
      - **List**: A compact layout that flows series labels to fit the available space. List is the default for new charts when the legend is at the top or bottom.
      - **Grid**: A table-style layout that aligns series labels and statistics into rows and columns.
      Visualizations created before this setting was introduced keep their previous layout until you change it.
    </definition>
    <definition term="Statistics">
      To make your legends as informative as possible, you can show some additional statistics. All statistics are computed based on the selected time range and the aggregated data points shown in the chart, rather than the original data coming from Elasticsearch. For example, if the metric plotted in the chart is Median(system.memory) and the time range is last 24 hours, when you show the Max statistic in the Legend, the value that shows corresponds to the Max[Median(system.memory)] for the last 24 hours.
    </definition>
  </definitions>

  - **Average**: Average value considering all data points in the chart.
    - **Median**: Median value considering all data points in the chart.
  - **Minimum**: Minimum value considering all data points in the chart.
  - **Maximum**: Maximum value considering all data points in the chart.
  - **Range**: Difference between min and max values.
  - **Last value**: Last value considering all data points in the chart.
  - **Last non-null value**: Last non-null value.

  <definitions>
    <definition term="Label truncation">
      For legends positioned inside the chart, outside on the side, or outside at the top or bottom with the **Grid** layout, choose whether to truncate long series labels and set the maximum number of lines for each label.
    </definition>
  </definitions>
</dropdown>


## Line chart examples

<definitions>
  <definition term="Average RAM per host">
    Monitoring the average of RAM over time for the first four hosts:
  </definition>
</definitions>

1. Drag `@timestamp` to the **Horizontal axis** and set the following settings:
   - **Functions**: `Date histogram`
- **Minimum interval**: `Hour`
2. Drag `machine.ram` to the **Vertical axis** and set the following settings:
   - **Functions**: : `Moving average`
- **Value format**: `Bytes`
3. In the **Breakdwon** panel, set the following settings:
   - **Functions**: `Top values`
- **Fields**: `host.keyword`
- **Number of values**: `4`
4. Save your chart.

![Average RAM per host](https://www.elastic.co/docs/explore-analyze/images/kibana-lens-average-ram-host.png)
<dropdown title="Create this chart using the API" applies-to="Elastic Cloud Serverless: Preview, Elastic Stack: Preview since 9.4">
  Send the following request to create a line chart that plots the moving average of RAM, broken down by the top 4 hosts.
  <tab-set>
    <tab-item title="Console">
      ```json

      {
        "type": "xy",
        "title": "Average RAM per host",
        "filters": [],
        "query": { "expression": "" },
        "legend": { "visibility": "visible", "placement": "outside", "position": "bottom" },
        "axis": {},
        "layers": [
          {
            "type": "line",
            "x": {
              "operation": "date_histogram",
              "field": "timestamp",
              "suggested_interval": "1h"
            },
            "y": [
              {
                "operation": "moving_average", <1>
                "of": {
                  "operation": "average",
                  "field": "machine.ram",
                  "format": { "type": "bytes", "decimals": 0 },
                  "filter": { "expression": "" }
                },
                "label": "Moving average of RAM",
                "format": { "type": "bytes", "decimals": 0 },
                "filter": { "expression": "" },
                "color": {
                  "type": "static",
                  "color": "#6092c0"
                }
              }
            ],
            "breakdown_by": { <2>
              "operation": "terms",
              "fields": ["host.keyword"],
              "limit": 4,
              "rank_by": { "type": "alphabetical", "direction": "asc" } <3>
            },
            "data_source": {
              "type": "data_view_spec",
              "index_pattern": "kibana_sample_data_logs",
              "time_field": "timestamp"
            }
          }
        ],
        "styling": {
          "fitting": { "type": "linear" }
        }
      }
      ```
    </tab-item>

    <tab-item title="curl">
      ```bash
      curl -X POST "${KIBANA_URL}/api/visualizations" \
        -H "Authorization: ApiKey ${API_KEY}" \
        -H "kbn-xsrf: true" \
        -H "Content-Type: application/json" \
        -d '{
        "type": "xy",
        "title": "Average RAM per host",
        "filters": [],
        "query": { "expression": "" },
        "legend": { "visibility": "visible", "placement": "outside", "position": "bottom" },
        "axis": {},
        "layers": [
          {
            "type": "line",
            "x": {
              "operation": "date_histogram",
              "field": "timestamp",
              "suggested_interval": "1h"
            },
            "y": [
              {
                "operation": "moving_average", 
                "of": {
                  "operation": "average",
                  "field": "machine.ram",
                  "format": { "type": "bytes", "decimals": 0 },
                  "filter": { "expression": "" }
                },
                "label": "Moving average of RAM",
                "format": { "type": "bytes", "decimals": 0 },
                "filter": { "expression": "" },
                "color": {
                  "type": "static",
                  "color": "#6092c0"
                }
              }
            ],
            "breakdown_by": { 
              "operation": "terms",
              "fields": ["host.keyword"],
              "limit": 4,
              "rank_by": { "type": "alphabetical", "direction": "asc" } 
            },
            "data_source": {
              "type": "data_view_spec",
              "index_pattern": "kibana_sample_data_logs",
              "time_field": "timestamp"
            }
          }
        ],
        "styling": {
          "fitting": { "type": "linear" }
        }
      }'
      ```
    </tab-item>
  </tab-set>
  For more information, refer to the [Visualizations API](https://www.elastic.co/docs/api/doc/kibana/group/endpoint-visualizations).
</dropdown>

<definitions>
  <definition term="Unique IPs over time">
    Visualize the number of unique client IPs throughout the day to identify traffic patterns and peak usage periods:
  </definition>
</definitions>

1. Drag `timestamp` to the **Horizontal axis** and set **Functions** to `Date histogram` with **Minimum interval** set to `Hour`.
2. Drag `clientip` to the **Vertical axis** and set the following settings:
   - **Functions**: `Unique count`
- **Value format**: `Number`
- **Decimals**: `0`
3. In the **Visual options**, set **Missing values** to `Linear` to connect gaps in the line.
4. Save your chart.

![Unique IPs throughout the day](https://www.elastic.co/docs/explore-analyze/images/kibana-lens-unique-ip-throughout-day.png)
<dropdown title="Create this chart using the API" applies-to="Elastic Cloud Serverless: Preview, Elastic Stack: Preview since 9.4">
  Send the following request to create a line chart that plots the unique count of client IPs over time, with linear interpolation for missing values.
  <tab-set>
    <tab-item title="Console">
      ```json

      {
        "type": "xy",
        "title": "Unique IPs over time",
        "filters": [],
        "query": { "expression": "" },
        "legend": { "visibility": "auto" },
        "axis": {},
        "layers": [
          {
            "type": "line",
            "x": {
              "operation": "date_histogram",
              "field": "timestamp",
              "suggested_interval": "1h" <1>
            },
            "y": [
              {
                "operation": "unique_count", <2>
                "field": "clientip",
                "label": "Unique IPs",
                "format": {
                  "type": "number",
                  "decimals": 0
                },
                "filter": { "expression": "" }
              }
            ],
            "data_source": {
              "type": "data_view_spec",
              "index_pattern": "kibana_sample_data_logs",
              "time_field": "timestamp"
            }
          }
        ],
        "styling": {
          "fitting": {
            "type": "linear" <3>
          }
        }
      }
      ```
    </tab-item>

    <tab-item title="curl">
      ```bash
      curl -X POST "${KIBANA_URL}/api/visualizations" \
        -H "Authorization: ApiKey ${API_KEY}" \
        -H "kbn-xsrf: true" \
        -H "Content-Type: application/json" \
        -d '{
        "type": "xy",
        "title": "Unique IPs over time",
        "filters": [],
        "query": { "expression": "" },
        "legend": { "visibility": "auto" },
        "axis": {},
        "layers": [
          {
            "type": "line",
            "x": {
              "operation": "date_histogram",
              "field": "timestamp",
              "suggested_interval": "1h" 
            },
            "y": [
              {
                "operation": "unique_count", 
                "field": "clientip",
                "label": "Unique IPs",
                "format": {
                  "type": "number",
                  "decimals": 0
                },
                "filter": { "expression": "" }
              }
            ],
            "data_source": {
              "type": "data_view_spec",
              "index_pattern": "kibana_sample_data_logs",
              "time_field": "timestamp"
            }
          }
        ],
        "styling": {
          "fitting": {
            "type": "linear" 
          }
        }
      }'
      ```
    </tab-item>
  </tab-set>
  For more information, refer to the [Visualizations API](https://www.elastic.co/docs/api/doc/kibana/group/endpoint-visualizations).
</dropdown>

---