Visualize Operator

Overview

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 listed below, and share any bug reports and feature requests with your Panther support team.

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

| visualize <bar|line> <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 and aggregations like agg.count(). The visualize operator must be used last in a PantherFlow query, and does not filter or transform data.

By default, visualize displays a vertical bar chart, but you can use line or bar to set the type. Further customize the chart using the supported annotations.

Limitations

  • 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 graphed 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

  • Timeseries data renders incorrectly when used as an axis (xcolumn or ycolumn) value in a bar chart. Use a line chart with timeseries data instead.

Supported chart types

  • bar (default)

  • line

    • In order to create a line chart, the field represented on the x-axis must have a date/time data type.

Supported annotations

Use annotations with visualize to customize the resulting chart. Separate multiple annotations with a comma.

In order to use any of the annotations below, your query must also explicitly set a chart type (bar or line).

Annotation
Description
Supported values
Example

title

The title of the chart. If not provided, the default is <name of x-axis field> vs <name of y-axis field>. If value contains spaces, it must be enclosed in quotation marks.

<String>

title="My Chart"

orientation

The direction of the chart. Applicable only to bar charts.

vertical (default) horizontal

orientation=horizontal

legend

The existence and placement of a chart legend.

hidden (default) visible (defaults to top) top bottom left right

legend=right

xcolumn

Name of field that should be represented on the x-axis. (This is not the label of the x-axis.) If a timeseries field, must be used with a line chart.

<String>

xcolumn=mean

ycolumn

Name of field that should be represented on the y-axis. (This is not the label of the y-axis.) If a timeseries field, must be used with a line chart.

<String>

ycolumn=detectionId

series

Name of field that should be used to group data.

<String>

series=email

Examples

Example data

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 }
];

Default bar chart

my_table
| visualize

Bar chart with legend, orientation, and title set

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

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 and summarize on Summarize Operator.

This query has unique example data:

Example data

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") }
];
panther_audit
| summarize events = agg.count() by actionName
| sort actionName desc
| limit 4
| visualize

Line chart with title set

This query has unique example data:

Example data

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 }
];
my_table
| visualize line title="Last week's events"

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.

Unlike the other example queries (which use a datatable to provide mock data), the query below pulls from live data in your panther_signals database.

panther_signals.public.signal_alerts
| where p_event_time >= time.ago(7d)
| 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'

Bar chart using series

This query has unique example data:

Example data:

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" }
];
my_table
| visualize bar series=user

Last updated