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

# Build treemap charts with Kibana
Treemap charts display hierarchical data as nested rectangles, where each rectangle's size represents a quantitative value. They are ideal for showing part-to-whole relationships within hierarchies, comparing relative sizes of categories, and visualizing how data is distributed across multiple levels.
You can create treemap charts in Kibana using [**Lens**](https://www.elastic.co/docs/explore-analyze/visualize/lens).
![Example Lens treemap charts based on sample data](https://www.elastic.co/docs/explore-analyze/images/treemap-example.png)

## Build a treemap 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 treemap 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 treemap chart, then add a new visualization.
    - From the **Visualize library** page by creating a new visualization.
  </step>

  <step title="Set the visualization to Treemap">
    New visualizations often start as **Bar** charts.Using the **Visualization type** dropdown, select **Treemap**.
  </step>

  <step title="Define the data to show">
    1. Select the data view that contains your data.
    2. Configure the [**Group by**](#group-by-settings) dimension to define how the rectangles are grouped. Add multiple **Group by** dimensions to create a hierarchy.
    3. Configure the [**Metric**](#metric-settings) dimension to define the size of each rectangle.
    The chart preview updates to show rectangles sized by your metric. If you added multiple **Group by** dimensions, smaller rectangles appear nested inside the top-level categories.
  </step>

  <step title="Customize the chart to follow best practices">
    Tweak the appearance of the chart to your needs. Consider the following best practices:
    <definitions>
      <definition term="Limit hierarchy depth">
        Keep your treemap to 2-3 levels of hierarchy. Deeper nesting becomes difficult to read and interpret.
      </definition>
      <definition term="Order categories by size">
        Arrange rectangles by size (largest first) to make comparisons easier. This is the default behavior in Lens.
      </definition>
      <definition term="Use color meaningfully">
        Apply colors to distinguish top-level categories or to represent an additional metric (such as growth rate or status).
      </definition>
      <definition term="Ensure readable labels">
        Labels are automatically hidden on rectangles that are too small to fit them. If too many labels are missing, reduce the number of categories or increase the panel size.
      </definition>
    </definitions>
    Refer to [Treemap chart settings](#treemap-chart-settings) to find all configuration options for your treemap chart.
  </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 and reuse it later.
    - If you accessed Lens from the Visualize library, select **Save**. A menu opens and lets you add the visualization to a dashboard and to the Visualize library.
  </step>
</stepper>


## Treemap chart settings

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

### Group by settings

The **Group by** dimension defines how rectangles are grouped. You can add up to 2 levels of grouping to create hierarchical visualizations.
<definitions>
  <definition term="Data">
    The **Group by** dimension supports the following functions:
    - **Top values**: Create rectangles for the most common values in a field.
      - **Field**: Select the field to group by. You can add up to 4 fields to create multi-term groups. When multiple fields are selected, each group 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**.
      - **Collapse by**: Aggregate values into a single number using `Sum`, `Average`, `Min`, or `Max`.
      <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 into time-based buckets.
      - **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.
      - **Collapse by**: Aggregate values into a single number using `Sum`, `Average`, `Min`, or `Max`.
    - **Intervals**: Create numeric ranges for continuous data.
      - **Field**: Select the numeric field to create intervals from.
    - **Include empty rows**: Include intervals with no matching documents.
    - **Collapse by**: Aggregate values into a single number using `Sum`, `Average`, `Min`, or `Max`.
    - **Filters**: Define custom KQL filters to create specific groups.
      - **Collapse by**: Aggregate values into a single number using `Sum`, `Average`, `Min`, or `Max`.
  </definition>
  <definition term="Appearance">
    - **Name**: Customize the legend label.
    - **Color mapping**: Select a color palette or assign specific colors to categories. Refer to [Assign colors to terms](/docs/explore-analyze/visualize/lens#assign-colors-to-terms) for details. Color mapping is only available on the first **Group by** dimension. Nested levels inherit colors from their parent category.
  </definition>
</definitions>


### Metric settings

The **Metric** dimension defines the size of each rectangle.
<definitions>
  <definition term="Data">
    The value that determines rectangle size. When you drag a field onto the chart, Kibana suggests a function based on the field type. You can use aggregation functions like `Sum`, `Average`, `Count`, `Median`, and more, or create custom calculations with [formulas](/docs/explore-analyze/visualize/lens#lens-formulas).
    <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>
  <definition term="Appearance">
    - **Name**: Customize the metric label displayed in tooltips and legends.
    - **Value format**: Control how numeric values are displayed (number, percent, bytes, and more).
  </definition>
</definitions>


### General layout

When creating or editing a visualization, you can customize several appearance options from the `brush` **Style** or ![Legend icon](https://www.elastic.co/docs/explore-analyze/images/kibana-legend-icon.svg) **Legend** menus.

#### Style settings

<definitions>
  <definition term="Slice labels">
    Control how labels appear on rectangles:
    - **Show**: Display labels on all rectangles where space permits (default).
    - **Hide**: Do not display labels on rectangles.
  </definition>
  <definition term="Slice values">
    Control what values appear on rectangles:
    - **Percentage**: Display the percentage of total (default).
    - **Integer**: Display the raw numeric value.
    - **Hide**: Do not display values.
    When displaying percentages, you can also configure the **Decimal places** (default: 2).
  </definition>
</definitions>


#### Legend settings

<definitions>
  <definition term="Visibility">
    Specify whether to automatically show the legend or hide it:
    - **Auto**: Hide the legend (default).
    - **Show**: Always show the legend.
    - **Hide**: Never show the legend.
  </definition>
  <definition term="Width">
    Control the width of the legend panel: **Small**, **Medium**, **Large**, or **Extra large**.
  </definition>
  <definition term="Label truncation">
    Toggle whether to truncate long legend labels. When enabled, set the **Line limit** to control how many lines to display before truncating (1-5, default: 1).
  </definition>
  <definition term="Nested">
    When using multiple **Group by** dimensions, enable this option to show the legend in a hierarchical format.
  </definition>
</definitions>


## Treemap chart examples

The following examples show various configuration options for building impactful treemap charts.
<definitions>
  <definition term="Bytes per file extension">
    See which file extensions consume the most bandwidth, excluding blank values:
    - Example based on: Kibana Sample Data Logs
    - **Group by**: `extension.keyword`
      - Top 6 values
    - Advanced: include values matching the `.+` regular expression to exclude blank values
    - **Metric**: Sum of `bytes`
    - **Value display**: Percentage
  </definition>
</definitions>

![Treemap showing bytes per file extension](https://www.elastic.co/docs/explore-analyze/images/treemap-example-bytes-per-extension.png)
<dropdown title="Create this chart using the API" applies-to="Elastic Cloud Serverless: Preview, Elastic Stack: Preview since 9.4">
  This example creates a single-level treemap where each rectangle represents a file extension and its size reflects total bandwidth consumed.
  <tab-set>
    <tab-item title="Console">
      ```json

      {
        "type": "treemap", <1>
        "title": "Bytes per file extension",
        "filters": [],
        "query": { "expression": "" },
        "legend": { "size": "auto" },
        "metrics": [
          {
            "operation": "sum",
            "field": "bytes",
            "label": "Total bytes",
            "format": {
              "type": "number"
            },
            "filter": { "expression": "" }
          }
        ],
        "group_by": [
          {
            "operation": "terms", <2>
            "fields": ["extension.keyword"],
            "limit": 6,
            "includes": { "values": [".+"], "as_regex": true },
            "other_bucket": { "include_documents_without_field": false },
            "rank_by": { "type": "metric", "direction": "desc", "metric_index": 0 },
            "increase_accuracy": true
          }
        ],
        "data_source": {
          "type": "data_view_spec",
          "index_pattern": "kibana_sample_data_logs",
          "time_field": "timestamp"
        },
        "styling": { "values": { "mode": "percentage" } } <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": "treemap", 
        "title": "Bytes per file extension",
        "filters": [],
        "query": { "expression": "" },
        "legend": { "size": "auto" },
        "metrics": [
          {
            "operation": "sum",
            "field": "bytes",
            "label": "Total bytes",
            "format": {
              "type": "number"
            },
            "filter": { "expression": "" }
          }
        ],
        "group_by": [
          {
            "operation": "terms", 
            "fields": ["extension.keyword"],
            "limit": 6,
            "includes": { "values": [".+"], "as_regex": true },
            "other_bucket": { "include_documents_without_field": false },
            "rank_by": { "type": "metric", "direction": "desc", "metric_index": 0 },
            "increase_accuracy": true
          }
        ],
        "data_source": {
          "type": "data_view_spec",
          "index_pattern": "kibana_sample_data_logs",
          "time_field": "timestamp"
        },
        "styling": { "values": { "mode": "percentage" } } 
      }'
      ```
    </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="Flights by carrier and destination country">
    Show how flight volume is distributed across airlines and their destination countries, using two hierarchy levels:
    - Example based on: Kibana Sample Data Flights
    - **Group by** (Level 1): `Carrier` (Top 5 values)
    - **Group by** (Level 2): `DestCountry` (Top 5 values)
    - **Metric**: Count
    - **Value display**: Percentage
  </definition>
</definitions>

![Treemap showing flights by carrier and destination country](https://www.elastic.co/docs/explore-analyze/images/treemap-example-flights-carrier.png)
<dropdown title="Create this chart using the API" applies-to="Elastic Cloud Serverless: Preview, Elastic Stack: Preview since 9.4">
  This example creates a two-level treemap: the outer rectangles represent airlines and the inner rectangles show destination countries, revealing how each carrier's flight volume is distributed geographically.
  <tab-set>
    <tab-item title="Console">
      ```json

      {
        "type": "treemap",
        "title": "Flights by carrier and destination country",
        "filters": [],
        "query": { "expression": "" },
        "legend": { "size": "auto" },
        "metrics": [
          {
            "operation": "count",
            "label": "Flights",
            "format": { "type": "number" },
            "filter": { "expression": "" }
          }
        ],
        "group_by": [
          {
            "operation": "terms", <1>
            "fields": ["Carrier"],
            "limit": 5
          },
          {
            "operation": "terms", <2>
            "fields": ["DestCountry"],
            "limit": 5
          }
        ],
        "data_source": {
          "type": "data_view_spec",
          "index_pattern": "kibana_sample_data_flights",
          "time_field": "timestamp"
        },
        "styling": { "values": { "mode": "percentage" } }
      }
      ```
    </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": "treemap",
        "title": "Flights by carrier and destination country",
        "filters": [],
        "query": { "expression": "" },
        "legend": { "size": "auto" },
        "metrics": [
          {
            "operation": "count",
            "label": "Flights",
            "format": { "type": "number" },
            "filter": { "expression": "" }
          }
        ],
        "group_by": [
          {
            "operation": "terms", 
            "fields": ["Carrier"],
            "limit": 5
          },
          {
            "operation": "terms", 
            "fields": ["DestCountry"],
            "limit": 5
          }
        ],
        "data_source": {
          "type": "data_view_spec",
          "index_pattern": "kibana_sample_data_flights",
          "time_field": "timestamp"
        },
        "styling": { "values": { "mode": "percentage" } }
      }'
      ```
    </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="Response status per host">
    See which hosts handle the most traffic and how their response status breaks down:
    - Example based on: Kibana Sample Data Logs
    - **Group by** (Level 1): `host.keyword` (Top 3 values, with Other)
    - **Group by** (Level 2): Filters
      - "Success (2xx/3xx)": `response.keyword >= "200" AND response.keyword < "400"`
    - "Client errors (4xx)": `response.keyword >= "400" AND response.keyword < "500"`
    - "Server errors (5xx)": `response.keyword >= "500"`
    - **Metric**: Count
    - **Value display**: Percentage
    - **Color**: Gradient (`#ffc7db`), reversed
  </definition>
</definitions>

![Treemap showing response status per host](https://www.elastic.co/docs/explore-analyze/images/treemap-example-response-per-host.png)
<dropdown title="Create this chart using the API" applies-to="Elastic Cloud Serverless: Preview, Elastic Stack: Preview since 9.4">
  This example nests KQL-based response status categories inside host rectangles, combining `terms` and `filters` groupings to show both traffic volume and health per host.
  <tab-set>
    <tab-item title="Console">
      ```json

      {
        "type": "treemap",
        "title": "Response status per host",
        "filters": [],
        "query": { "expression": "" },
        "legend": { "size": "auto" },
        "metrics": [
          {
            "operation": "count",
            "label": "Count",
            "format": { "type": "number" },
            "filter": { "expression": "" }
          }
        ],
        "group_by": [
          {
            "operation": "terms", <1>
            "fields": ["host.keyword"],
            "limit": 3,
            "other_bucket": { "include_documents_without_field": false },
            "color": {
              "mode": "gradient",
              "palette": "default",
              "gradient": [{ "type": "color_code", "value": "#ffc7db" }],
              "sort": "desc"
            }
          },
          {
            "operation": "filters", <2>
            "filters": [
              {
                "filter": { "expression": "response.keyword >= \"200\" AND response.keyword < \"400\"" },
                "label": "Success (2xx/3xx)"
              },
              {
                "filter": { "expression": "response.keyword >= \"400\" AND response.keyword < \"500\"" },
                "label": "Client errors (4xx)"
              },
              {
                "filter": { "expression": "response.keyword >= \"500\"" },
                "label": "Server errors (5xx)"
              }
            ]
          }
        ],
        "data_source": {
          "type": "data_view_spec",
          "index_pattern": "kibana_sample_data_logs",
          "time_field": "timestamp"
        },
        "styling": { "values": { "mode": "percentage" } }
      }
      ```
    </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": "treemap",
        "title": "Response status per host",
        "filters": [],
        "query": { "expression": "" },
        "legend": { "size": "auto" },
        "metrics": [
          {
            "operation": "count",
            "label": "Count",
            "format": { "type": "number" },
            "filter": { "expression": "" }
          }
        ],
        "group_by": [
          {
            "operation": "terms", 
            "fields": ["host.keyword"],
            "limit": 3,
            "other_bucket": { "include_documents_without_field": false },
            "color": {
              "mode": "gradient",
              "palette": "default",
              "gradient": [{ "type": "color_code", "value": "#ffc7db" }],
              "sort": "desc"
            }
          },
          {
            "operation": "filters", 
            "filters": [
              {
                "filter": { "expression": "response.keyword >= \"200\" AND response.keyword < \"400\"" },
                "label": "Success (2xx/3xx)"
              },
              {
                "filter": { "expression": "response.keyword >= \"400\" AND response.keyword < \"500\"" },
                "label": "Client errors (4xx)"
              },
              {
                "filter": { "expression": "response.keyword >= \"500\"" },
                "label": "Server errors (5xx)"
              }
            ]
          }
        ],
        "data_source": {
          "type": "data_view_spec",
          "index_pattern": "kibana_sample_data_logs",
          "time_field": "timestamp"
        },
        "styling": { "values": { "mode": "percentage" } }
      }'
      ```
    </tab-item>
  </tab-set>
  For more information, refer to the [Visualizations API](https://www.elastic.co/docs/api/doc/kibana/group/endpoint-visualizations).
</dropdown>