# Visualize Operator

## Overview

{% hint style="info" %}
The `visualize` operator is in open beta starting with Panther version 1.110, and is available to all customers. Please take special note of the [Limitations](#limitations) listed below, and share any bug reports and feature requests with your Panther support team.
{% endhint %}

Use the `visualize` operator to generate a bar, line, pie chart, or table of your query results.

```kusto
| visualize <bar|line|pie|table> <annotation>=<expression>[, ...] 
```

You can use `visualize` with any results set that has two fields where at least one one field is numeric. It's particularly useful to use `visualize` with [`summarize`](https://docs.panther.com/pantherflow/operators/summarize) and aggregations like [`agg.count()`](https://docs.panther.com/functions/aggregation#agg.count). The `visualize` operator must be used last in a PantherFlow query, and does not filter or transform data.

{% hint style="info" %}
After you generate a visualization, you can add it to a [custom dashboard](https://docs.panther.com/search/visualization-and-dashboards/custom).
{% endhint %}

By default, `visualize` displays a vertical bar chart, but you can use `line`, `bar`, `pie`, or `table` to set the type. Further customize the visualization using the [supported annotations](#supported-annotations).

### Limitations

* For charts (`line`, `bar`, and `pie` visualizations), the wrong column may be selected when declaring a `series=` but not an `xcolumn=`, or vice versa (`xcolumn=` but not a `series`)
* To move a vertical bar chart horizontally (left/right), you must scroll vertically (up/down)
* A maximum of 999 data points can be visualized
* Data is displayed in sorted order. For timeseries data, you must sort the data by time if you want it to appear in time order in the graph
* In bar charts, columns are ordered alphabetically and cannot be rearranged

## Supported visualization types

* `bar` (default): Categorical data is represented using rectangular bars.
* `line`: Commonly used to show trends over time, data points are connected by straight lines.
  * To create a `line` chart, the field represented on the x-axis must have a date/time data type.
* `pie`: Displays data as slices of a circular chart, useful for showing proportions and parts of a whole.
  * Use this chart type for categorical data to visualize the relative size or percentage distribution across categories.
* `table`: Data is represented in a tabular format.
  * While this is similar to the results table already displayed in [Search](https://docs.panther.com/search/search-tool), using `table` may be useful if you'd like to add tabular data to a [custom dashboard](https://docs.panther.com/search/visualization-and-dashboards/custom).

## Supported annotations

Use annotations with `visualize` to customize the resulting visualization. Separate multiple annotations with a comma, for example:

```kusto
| visualize bar legend=left, orientation=horizontal, title="My Chart"
```

{% hint style="info" %}
In order to use any of the annotations below, your query must also explicitly set a visualization type (`bar`, `line`, or `pie`).
{% endhint %}

<table><thead><tr><th width="133.1796875">Annotation</th><th width="288.7109375">Description</th><th width="201.9119873046875">Supported visualization types</th><th width="176.8359375">Supported values</th><th width="143.1015625">Example</th></tr></thead><tbody><tr><td><code>title</code></td><td>The title of the chart. If not provided, the default is <code>&#x3C;name of x-axis field> vs &#x3C;name of y-axis field></code>. If value contains spaces, it must be enclosed in quotation marks.</td><td><code>bar</code>, <code>line</code>, <code>pie</code>, <code>table</code></td><td><code>&#x3C;String></code></td><td><code>title="My Chart"</code></td></tr><tr><td><code>orientation</code></td><td>The direction of the chart. If <code>xcolumn</code>, <code>ycolumn</code>, or <code>series</code> are set, they may take precedence over <code>orientation</code>.</td><td><code>bar</code></td><td><code>vertical</code> (default)<br><code>horizontal</code></td><td><code>orientation=horizontal</code></td></tr><tr><td><code>legend</code></td><td><p>The existence and position of a chart legend.<br><br>The default value is <code>hidden</code> for single-series data and <code>bottom</code> for multi-series data.</p><p>To hide the legend, use <code>hidden</code>.</p></td><td><code>bar</code>, <code>line</code>, <code>pie</code></td><td><code>hidden</code> (default for single-series data)<br><code>visible</code> (defaults to <code>bottom</code>)<br><code>top</code><br><code>bottom</code> (default for multi-series data)<br><code>left</code><br><code>right</code></td><td><code>legend=right</code></td></tr><tr><td><code>xcolumn</code></td><td>Name of field that should be represented on the x-axis. (This is not the label of the x-axis.)</td><td><code>bar</code>, <code>line</code></td><td><code>&#x3C;String></code></td><td><code>xcolumn=mean</code></td></tr><tr><td><code>ycolumn</code></td><td>Name of field that should be represented on the y-axis. (This is not the label of the y-axis.)</td><td><code>bar</code>, <code>line</code></td><td><code>&#x3C;String></code></td><td><code>ycolumn=detectionId</code></td></tr><tr><td><code>series</code></td><td><p>Name of field that should be used to group data.<br><br>A chart can be:</p><ul><li>Single-series: Represented by a single line for <code>line</code> charts and bars made up of a single color for <code>bar</code> charts</li><li>Multi-series: Represented by multiple lines, each with a different color, for <code>line</code> charts, and bars made up of multiple colors for <code>bar</code> charts</li></ul><p>If <code>series</code> is not provided, PantherFlow makes an assumption on which field should be treated as the <code>series</code> value.</p></td><td><code>bar</code>, <code>line</code></td><td><code>&#x3C;String></code></td><td><code>series=email</code></td></tr></tbody></table>

## Examples

{% hint style="info" %}
Example data

```kusto
let my_table = datatable [
  { "actionName": "SIGN_IN", "events": 12 },
  { "actionName": "CREATE_ALERT_DESTINATION", "events": 2 },
  { "actionName": "CREATE_USER", "events": 4 },
  { "actionName": "CREATE_RULE", "events": 10 }
];
```

{% endhint %}

### Default bar chart

```kusto
my_table
| visualize
```

<figure><img src="https://4011785613-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LgdiSWdyJcXPahGi9Rs-2910905616%2Fuploads%2Fgit-blob-91651dde32ef254c20c511ea121c8d72115728ad%2FScreenshot%202024-11-08%20at%2012.41.01%E2%80%AFPM.png?alt=media" alt="A table with the title &#x22;actionName vs events&#x22; is shown, with four vertical columns."><figcaption></figcaption></figure>

### Bar chart with `legend`, `orientation`, and `title` set

```kusto
my_table
| visualize bar legend=left, orientation=horizontal, title="My Chart"
```

<figure><img src="https://4011785613-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LgdiSWdyJcXPahGi9Rs-2910905616%2Fuploads%2Fgit-blob-bfc149d3f22f1483783ea68587349f25c177c4c9%2FScreenshot%202024-11-08%20at%2012.42.40%E2%80%AFPM.png?alt=media" alt="A table titled &#x22;My Chart&#x22; with four horizontal columns are shown."><figcaption></figcaption></figure>

### Bar chart with `agg.count()`

This example uses sample data that has more than two fields (like most real-world data sets). The query uses `summarize events = agg.count() by actionName` to generate a results set with two fields (`actionName` and `events`) before `visualize` is used. Learn more about aggregations on [PantherFlow Functions](https://docs.panther.com/functions#aggregations) and `summarize` on [Summarize Operator](https://docs.panther.com/pantherflow/operators/summarize).

This query has unique example data:

{% hint style="info" %}
Example data

```kusto
let panther_audit = datatable [
  { "actionName": "SIGN_IN", "id": "222ef2375b1bf394f687ea842065", "p_event_time": time.parse_timestamp("2024-11-14 00:00:00") },
  { "actionName": "CREATE_ALERT_DESTINATION", "id": "320a3b11b854c5ceebb2d08420d99d09", "p_event_time": time.parse_timestamp("2024-10-16 00:00:00") },
  { "actionName": "CREATE_ALERT_DESTINATION", "id": "86a6c88c5b39ede087d3e98420e022", "p_event_time": time.parse_timestamp("2024-11-04 00:00:00") },
  { "actionName": "CREATE_USER", "id": "5a0cbd047f5bf380c281d68420bec709", "p_event_time": time.parse_timestamp("2024-11-12 00:00:00") },
  { "actionName": "CREATE_USER", "id": "4b0d0f487a2ae459c3976f8420d1a810", "p_event_time": time.parse_timestamp("2024-11-11 00:00:00") },
  { "actionName": "CREATE_USER", "id": "7c1e1a59f6bcf4b6d5b83f8420baf911", "p_event_time": time.parse_timestamp("2024-10-27 00:00:00") },
  { "actionName": "CREATE_USER", "id": "9d2f2b60a7cdb58ff6a96f8420fa0b12", "p_event_time": time.parse_timestamp("2024-11-09 00:00:00") },
  { "actionName": "CREATE_RULE", "id": "1e3f3c7189eec6c1e8ca7f8420e3c213", "p_event_time": time.parse_timestamp("2024-11-13 00:00:00") },
  { "actionName": "CREATE_RULE", "id": "2f404d82aa1fe7d3f9d58f8420e5d314", "p_event_time": time.parse_timestamp("2024-10-31 00:00:00") },
  { "actionName": "CREATE_RULE", "id": "603f5e93bb20f8e509e79f8420e7e415", "p_event_time": time.parse_timestamp("2024-11-03 00:00:00") }
];
```

{% endhint %}

```kusto
panther_audit
| summarize events = agg.count() by actionName
| sort actionName desc
| limit 4
| visualize
```

<figure><img src="https://4011785613-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LgdiSWdyJcXPahGi9Rs-2910905616%2Fuploads%2Fgit-blob-380c4d2cba962d5b359c474ed60834546bd4d873%2FScreenshot%202024-11-08%20at%2012.46.42%E2%80%AFPM.png?alt=media" alt="A table titled &#x22;actionName vs events&#x22; is shown with four vertical columns."><figcaption></figcaption></figure>

### Line chart with `title` set

This query has unique example data:

{% hint style="info" %}
Example data

```kusto
let my_table = datatable [
  { "p_event_time": time.parse_timestamp("2024-08-14 00:00:00"), "events": 120 },
  { "p_event_time": time.parse_timestamp("2024-08-13 00:00:00"), "events": 20 },
  { "p_event_time": time.parse_timestamp("2024-08-12 00:00:00"), "events": 150 },
  { "p_event_time": time.parse_timestamp("2024-08-11 00:00:00"), "events": 200 },
  { "p_event_time": time.parse_timestamp("2024-08-10 00:00:00"), "events": 50 },
  { "p_event_time": time.parse_timestamp("2024-08-09 00:00:00"), "events": 80 },
  { "p_event_time": time.parse_timestamp("2024-08-08 00:00:00"), "events": 10 }
];
```

{% endhint %}

```kusto
my_table
| visualize line title="Last week's events"
```

<figure><img src="https://4011785613-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LgdiSWdyJcXPahGi9Rs-2910905616%2Fuploads%2Fgit-blob-98ae322d2a1f4a39d9ec348127e409813c698f13%2FScreenshot%202024-11-08%20at%2012.48.28%E2%80%AFPM.png?alt=media" alt="A line chart titled &#x22;Last week&#x27;s events&#x22; is shown, with seven data points."><figcaption></figcaption></figure>

### Line chart measuring action count by hour

The query below displays the [Panther Audit logs](https://docs.panther.com/data-onboarding/supported-logs/panther-audit-logs) action count per hour for the past two days, bucketing the data by hour. A separate chart line is added for each `actionName`.

{% hint style="info" %}
Unlike the other example queries on this page, which use a `datatable` to provide mock data, the query below pulls from live data in your `panther_logs` database.
{% endhint %}

```kusto
panther_logs.public.panther_audit
| where p_event_time >= time.ago(2d)
| summarize count = agg.count() by actionName, hour = time.trunc('hour', p_event_time)
| sort hour asc
| visualize line legend=bottom, title='Action count by hour'
```

<figure><img src="https://4011785613-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LgdiSWdyJcXPahGi9Rs-2910905616%2Fuploads%2Fgit-blob-56a7ccc721b579d17ceb74ae729a59afce5a52a9%2Fimage.png?alt=media" alt=""><figcaption></figcaption></figure>

### Line chart measuring the number of alerts by detectionId per day

The query below displays the number of alerts by `detectionId` per day for the past two weeks.

{% hint style="info" %}
Unlike the other example queries on this page, which use a `datatable` to provide mock data, the query below pulls from live data in your `panther_signals` database.
{% endhint %}

```kusto
panther_signals.public.signal_alerts
| where p_event_time >= time.ago(14d)
| summarize count = agg.count() by detectionId, hour = time.trunc('day', p_event_time)
| sort hour asc
| visualize line title="Alert count by detectionId per day"
```

<figure><img src="https://4011785613-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LgdiSWdyJcXPahGi9Rs-2910905616%2Fuploads%2Fgit-blob-f7cd5b52dca525bf2ac78af455381c218efcee71%2Fimage.png?alt=media" alt=""><figcaption></figcaption></figure>

### Bar chart measuring mean time to detection

The query below displays the mean time between when an event is ingested and when a detection is triggered, for the 15 slowest rules by `detectionId`.

{% hint style="info" %}
Unlike the other example queries on this page, which use a `datatable` to provide mock data, the query below pulls from live data in your `panther_signals` database.
{% endhint %}

```kusto
panther_signals.public.signal_alerts
| where p_event_time >= time.ago(7d) and ingestTimeToDetectionSeconds != null
| summarize mean = agg.avg(ingestTimeToDetectionSeconds) by detectionId
| sort mean desc
| limit 15
| visualize bar xcolumn=mean, ycolumn=detectionId, legend=right, orientation=horizontal, title='Mean Time to Detect'
```

<figure><img src="https://4011785613-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LgdiSWdyJcXPahGi9Rs-2910905616%2Fuploads%2Fgit-blob-e9dfdf149b2e999631c8b511ae8954a7acb4f5ad%2Fimage.png?alt=media" alt=""><figcaption></figcaption></figure>

### Bar chart using `series`

This query has unique example data:

{% hint style="info" %}
Example data:

```kusto
let my_table = datatable [  
  { "actionName": "SIGN_IN", "events": 12 , "user": "alice"},
  { "actionName": "SIGN_IN", "events": 7 , "user": "bob"},
  { "actionName": "SIGN_IN", "events": 4 , "user": "charlie"},
  { "actionName": "CREATE_ALERT_DESTINATION", "events": 2, "user": "alice"},
  { "actionName": "CREATE_ALERT_DESTINATION", "events": 3, "user": "chris"},
  { "actionName": "CREATE_ALERT_DESTINATION", "events": 5, "user": "emily"},
  { "actionName": "CREATE_USER", "events": 1, "user": "alice" },
  { "actionName": "CREATE_USER", "events": 4 , "user": "frankie"},
  { "actionName": "CREATE_USER", "events": 3 , "user": "ross"},
  { "actionName": "CREATE_RULE", "events": 12, "user": "betsy" },
  { "actionName": "CREATE_RULE", "events": 6, "user": "bob" },
  { "actionName": "CREATE_RULE", "events": 6, "user": "casey" }
];
```

{% endhint %}

```kusto
my_table
| visualize bar series=user
```

<figure><img src="https://4011785613-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LgdiSWdyJcXPahGi9Rs-2910905616%2Fuploads%2Fgit-blob-1ed621cdf285688cb874229b9450b5e6ecbcc835%2FScreenshot%202025-01-06%20at%205.41.49%E2%80%AFPM.png?alt=media" alt="Under an actionName vs events header is a bar chart. There are four vertical columns, and each column in separated into three colors."><figcaption></figcaption></figure>

### Bar chart displaying logins by city, country

{% hint style="info" %}
Unlike the other example queries on this page, which use a `datatable` to provide mock data, the query below pulls from live data in your `okta_systemlog` database.
{% endhint %}

```kusto
panther_logs.public.okta_systemlog
| where eventType == 'user.session.start' and p_event_time > time.ago(90d)
| extend country = client.geographicalContext.country, city = client.geographicalContext.city
| summarize events = agg.count() by country, city
| project country, events, city
| sort events desc
| limit 10
| visualize bar orientation=horizontal,title='Logins by city, country'
```

<figure><img src="https://4011785613-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LgdiSWdyJcXPahGi9Rs-2910905616%2Fuploads%2Fgit-blob-762c7b32956ce14d5c5729f256fd72f4ef2f54d3%2FScreenshot%202025-03-07%20at%2011.31.12%E2%80%AFAM.png?alt=media" alt="A bar char is shown, titled &#x22;Logins by city, country.&#x22; There are four bars, labeled Atlanta, Maplewood, Athens, and Thessaloniki."><figcaption></figcaption></figure>

### Pie chart visualization with proportional data

This example displays the distribution of different action types as proportional data:

{% hint style="info" %}
Example data

```kusto
let my_table = datatable [
  { "actionName": "SIGN_IN", "events": 12 },
  { "actionName": "CREATE_ALERT_DESTINATION", "events": 2 },
  { "actionName": "CREATE_USER", "events": 4 },
  { "actionName": "CREATE_RULE", "events": 10 }
];
```

{% endhint %}

```kusto
my_table
| visualize pie title="Action Distribution"
```

<figure><img src="https://4011785613-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LgdiSWdyJcXPahGi9Rs-2910905616%2Fuploads%2FT2D68pDu9dE4kZkxZZiY%2FScreenshot%202026-02-25%20at%2010.30.28%E2%80%AFAM.png?alt=media&#x26;token=6a5be008-039e-4f56-9bca-b3cb78220639" alt="" width="563"><figcaption></figcaption></figure>

### Pie chart with aggregated data

The query below displays the distribution of Panther audit actions by type for the past week:

```kusto
panther_logs.public.panther_audit
| where p_event_time >= time.ago(7d)
| summarize events = agg.count() by actionName
| sort events desc
| limit 8
| visualize pie title="Action Types Distribution (Last 7 Days)"
```

<figure><img src="https://4011785613-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LgdiSWdyJcXPahGi9Rs-2910905616%2Fuploads%2FVIfmbdIHmtbUG3VmO9Ro%2FScreenshot%202026-02-25%20at%209.37.05%E2%80%AFAM.png?alt=media&#x26;token=1b22ec71-2b04-47d2-b5d9-88b47e97daa8" alt="" width="563"><figcaption></figcaption></figure>

### Table visualization with `title` set

This query has unique example data:

{% hint style="info" %}
Example data:

```kusto
let my_table = datatable [  
  { "actionName": "SIGN_IN", "events": 12 , "user": "alice"},
  { "actionName": "SIGN_IN", "events": 7 , "user": "bob"},
  { "actionName": "SIGN_IN", "events": 4 , "user": "charlie"},
  { "actionName": "CREATE_ALERT_DESTINATION", "events": 2, "user": "alice"},
  { "actionName": "CREATE_ALERT_DESTINATION", "events": 3, "user": "chris"},
  { "actionName": "CREATE_ALERT_DESTINATION", "events": 5, "user": "emily"},
  { "actionName": "CREATE_USER", "events": 1, "user": "alice" },
  { "actionName": "CREATE_USER", "events": 4 , "user": "frankie"},
  { "actionName": "CREATE_USER", "events": 3 , "user": "ross"},
  { "actionName": "CREATE_RULE", "events": 12, "user": "betsy" },
  { "actionName": "CREATE_RULE", "events": 6, "user": "bob" },
  { "actionName": "CREATE_RULE", "events": 6, "user": "casey" }
];
```

{% endhint %}

```kusto
my_table
| visualize table title='Actions by user'
```

<figure><img src="https://4011785613-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LgdiSWdyJcXPahGi9Rs-2910905616%2Fuploads%2Fgit-blob-34f6abdf0e9d5786d3ba7901d84788cadb011189%2Fimage.png?alt=media" alt="Under an &#x22;Actions by user&#x22; title is a table with three columns, labeled actionName, events, and user."><figcaption></figcaption></figure>
