Malloy Documentation
search

When Malloy runs a query, it returns two things. The results of the query and metadata about the results. The metadata are the schema for the results, including type information. Malloy also provides a mechanism to tag things in the source code and return tags with this meta data.

In Malloy, anything that can be named can be tagged. A tag starts with a #. Tags that start on a new line attach the tag the thing on the following line. For more details about how tagging works, see the Tags section.

Malloy's rendering library interprets these tags to change how results are rendered.

Tagging individual elements

In the query below, the measure percent_of_total is tagged as a percentage. Any time percent_of_total is used in a query, Malloy's rendering library will be displayed as a percentage.

document
source: flights is duckdb.table('../data/flights.parquet') extend {
  measure:
    flight_count is count()
    # percent
    percent_of_flights is flight_count / all(flight_count)
}
document
run: flights -> {
  group_by: carrier
  aggregate: 
    flight_count 
    percent_of_flights
}
QUERY RESULTS
[
  {
    "carrier": "WN",
    "flight_count": 88751,
    "percent_of_flights": 0.2573783375431738
  },
  {
    "carrier": "US",
    "flight_count": 37683,
    "percent_of_flights": 0.10928088577750582
  },
  {
    "carrier": "AA",
    "flight_count": 34577,
    "percent_of_flights": 0.10027347046489979
  },
  {
    "carrier": "NW",
    "flight_count": 33580,
    "percent_of_flights": 0.09738216554968143
  },
  {
    "carrier": "UA",
    "flight_count": 32757,
    "percent_of_flights": 0.09499546149228454
  },
  {
    "carrier": "DL",
    "flight_count": 32130,
    "percent_of_flights": 0.09317715840116929
  },
  {
    "carrier": "RU",
    "flight_count": 16074,
    "percent_of_flights": 0.046614679244954715
  },
  {
    "carrier": "MQ",
    "flight_count": 15869,
    "percent_of_flights": 0.046020178234302996
  },
  {
    "carrier": "EV",
    "flight_count": 15769,
    "percent_of_flights": 0.04573017774130216
  },
  {
    "carrier": "HP",
    "flight_count": 9750,
    "percent_of_flights": 0.028275048067581715
  },
  {
    "carrier": "AS",
    "flight_count": 8453,
    "percent_of_flights": 0.024513741673360845
  },
  {
    "carrier": "CO",
    "flight_count": 7139,
    "percent_of_flights": 0.020703135195329833
  },
  {
    "carrier": "B6",
    "flight_count": 4842,
    "percent_of_flights": 0.01404182387110058
  },
  {
    "carrier": "OH",
    "flight_count": 4420,
    "percent_of_flights": 0.012818021790637044
  },
  {
    "carrier": "TZ",
    "flight_count": 3033,
    "percent_of_flights": 0.00879571495271542
  }
]
WITH __stage0 AS (
  SELECT
    group_set,
    CASE WHEN group_set=1 THEN
      base."carrier"
      END as "carrier__1",
    CASE WHEN group_set=1 THEN
      COUNT(1)
      END as "flight_count__1",
    (CASE WHEN group_set=1 THEN
      COUNT(1)
      END)*1.0/MAX((CASE WHEN group_set=0 THEN
      COUNT(1)
      END)) OVER () as "percent_of_flights__1"
  FROM '../data/flights.parquet' as base
  CROSS JOIN (SELECT UNNEST(GENERATE_SERIES(0,1,1)) as group_set  ) as group_set
  GROUP BY 1,2
)
SELECT
  "carrier__1" as "carrier",
  MAX(CASE WHEN group_set=1 THEN "flight_count__1" END) as "flight_count",
  MAX(CASE WHEN group_set=1 THEN "percent_of_flights__1" END) as "percent_of_flights"
FROM __stage0
WHERE group_set NOT IN (0)
GROUP BY 1
ORDER BY 2 desc NULLS LAST
document
run: duckdb.table('../data/flights.parquet') ->  {
  group_by: carrier
  aggregate: flight_count is count()
}
QUERY RESULTS
[
  {
    "carrier": "WN",
    "flight_count": 88751
  },
  {
    "carrier": "US",
    "flight_count": 37683
  },
  {
    "carrier": "AA",
    "flight_count": 34577
  },
  {
    "carrier": "NW",
    "flight_count": 33580
  },
  {
    "carrier": "UA",
    "flight_count": 32757
  },
  {
    "carrier": "DL",
    "flight_count": 32130
  },
  {
    "carrier": "RU",
    "flight_count": 16074
  },
  {
    "carrier": "MQ",
    "flight_count": 15869
  },
  {
    "carrier": "EV",
    "flight_count": 15769
  },
  {
    "carrier": "HP",
    "flight_count": 9750
  },
  {
    "carrier": "AS",
    "flight_count": 8453
  },
  {
    "carrier": "CO",
    "flight_count": 7139
  },
  {
    "carrier": "B6",
    "flight_count": 4842
  },
  {
    "carrier": "OH",
    "flight_count": 4420
  },
  {
    "carrier": "TZ",
    "flight_count": 3033
  }
]
SELECT 
   base."carrier" as "carrier",
   COUNT(1) as "flight_count"
FROM '../data/flights.parquet' as base
GROUP BY 1
ORDER BY 2 desc NULLS LAST

Simply adding # bar_chart before the query tags it and tells the rendering library to show the result as a bar chart. See the docs on the Bar Chart tag for more information.

document
# bar_chart
run: duckdb.table('../data/flights.parquet') ->  {
  group_by: carrier
  aggregate: flight_count is count()
}
QUERY RESULTS
[
  {
    "carrier": "WN",
    "flight_count": 88751
  },
  {
    "carrier": "US",
    "flight_count": 37683
  },
  {
    "carrier": "AA",
    "flight_count": 34577
  },
  {
    "carrier": "NW",
    "flight_count": 33580
  },
  {
    "carrier": "UA",
    "flight_count": 32757
  },
  {
    "carrier": "DL",
    "flight_count": 32130
  },
  {
    "carrier": "RU",
    "flight_count": 16074
  },
  {
    "carrier": "MQ",
    "flight_count": 15869
  },
  {
    "carrier": "EV",
    "flight_count": 15769
  },
  {
    "carrier": "HP",
    "flight_count": 9750
  },
  {
    "carrier": "AS",
    "flight_count": 8453
  },
  {
    "carrier": "CO",
    "flight_count": 7139
  },
  {
    "carrier": "B6",
    "flight_count": 4842
  },
  {
    "carrier": "OH",
    "flight_count": 4420
  },
  {
    "carrier": "TZ",
    "flight_count": 3033
  }
]
SELECT 
   base."carrier" as "carrier",
   COUNT(1) as "flight_count"
FROM '../data/flights.parquet' as base
GROUP BY 1
ORDER BY 2 desc NULLS LAST

Malloy's rendering library uses Vega-Lite for charting. The rendering library is a separate layer from Malloy's data access layer.

Tag Quick Reference

Charts

Tag Description Key Properties
# bar_chart Bar chart .stack, .size, .x, .y, .series, .title, .subtitle
# line_chart Line chart .zero_baseline, .size, .interpolate, .x, .y, .series, .title, .subtitle
# scatter_chart Scatter plot Uses field order: x, y, color, size, shape
# shape_map Choropleth map (US states) Uses field order: state, value
# segment_map Segment map (US) Uses field order: lat1, lon1, lat2, lon2, color
# big_value Prominent metric cards .size, .sparkline, .comparison_field, .down_is_good

Layout & Structure

Tag Description Key Properties
# dashboard Dashboard layout .table.max_height, # break on nested views
# table Table (default) .size=fill, # column { width, height, word_break }
# pivot Pivot nested query into columns .dimensions
# transpose Swap rows and columns .limit
# list Comma-separated list First non-hidden field
# list_detail List with detail values First two non-hidden fields
# flatten Flatten nested record into parent columns On nest: without group_by

Field Formatting

Tag Description Example
# number Number format # number="$#,##0", # number=1m, # number=auto
# percent Percentage # percent
# currency Currency format # currency, # currency=usd2m, # currency=eur
# duration Duration format # duration=seconds, # duration.terse
# link Hyperlink # link { url_template="https://...$$" field=id }
# image Render as image # image { height=40px alt.field=name }
# data_volume Storage size format # data_volume=bytes, # data_volume=mb

Utilities

Tag Description
# hidden Hide field from rendering
# label Override display name, e.g. # label="Total Sales"
# description Tooltip description (used in # big_value)
# tooltip Include nested view in parent chart tooltip
# break Layout break in dashboards