When to use pie
Pie is the right choice for part-of-whole composition when the number of slices is small (typically ≤ 6) and proportional weight matters. Use the donut variant when you want to free the chart center for an inner label or a related KPI; use the rose variant for an alternative encoding where slice angle is fixed but radius reflects the value.
Use bar with chart.stack: percent instead when the categories are many, or when you want to compare composition across multiple groups. Use grid when the audience needs the actual percentages in tabular form.
Mapping
mapping.x— required. String field used as the slice name and the legend label.mapping.y— required. Numeric field that drives the slice angle.
mapping:
x: status
y: order_count
Slice colors come from the platform palette in query order. To control order, sort in the underlying Malloy query.
chart shortcuts
The chart block is typed and closed.
chart.variant—"pie"(default),"donut", or"rose". Donut adds an inner radius (free center); rose switches to a rose-area layout where slice angle is uniform and radius encodes the value.chart.inner_radius— number (pixels) or string (e.g."55%"). Use withvariant: donut; the larger the inner radius, the thinner the donut ring.chart.outer_radius— number or string.chart.slice_border_radius— pixels. Rounded corners on slices for a softer look.chart.show_value_labels— boolean. Turns slice labels on. Style them withchart.labelbelow.chart.cross_filter— boolean, defaulttrue.chart.height— pixel height of the viz container.
Pass-through fields (1:1 with the underlying chart):
chart.center— center of the pie. Array[x, y]of percent strings (e.g.["50%", "50%"]) or pixel numbers.chart.start_angle— degrees. Default90.chart.min_angle— degrees. Minimum angle for tiny slices to remain visible.chart.rose_type— when using a rose layout:"radius"or"area".
Slice labels
chart.label is an object that styles slice labels when chart.show_value_labels is on:
position—"inside","outside","top","bottom","left","right", plus the"insideLeft"/"insideRight"variants.rotate— degrees, between -90 and 90.color,font_size,font_weight.formatter— string template. Use{b}for the slice name,{c}for the value,{d}for the percentage.distance,align,vertical_align,clip.
chart:
show_value_labels: true
label:
position: outside
formatter: "{b}: {d}%"
Legend & tooltip
chart.legend controls the legend; chart.tooltip controls the hover tooltip. Both share the same shape as on bar — see that page for the full sub-block reference.
Pie-specific tip: for a donut variant with the legend on the right, set center: ["42%", "50%"] to nudge the donut left so the legend has more room.
format
format.yorformat[<value_field_name>]— pattern for slice tooltip values and inside-slice labels.formatat the root — fallback.
Cross-filter behavior
- Clicking a slice cross-filters the rest of the dashboard by the slice category (the
mapping.xfield). - The clicked field (the
mapping.xfield, e.g.status) must be declared as a parameter on a source signature in this viz's own model file, or the click is silently ignored. - Disable per viz with
chart.cross_filter: false.
See Cross-filtering for the full mechanism.
Worked examples
Donut with outside labels and bottom legend — note min_angle keeping tiny slices visible and center nudging the donut up to make room for the legend:
id: ec_revenue_share_by_category_pie
title: Revenue share by category
query: "models/ec_revenue_share.malloy::revenue_share_by_category"
type: pie
mapping:
x: category
y: revenue
chart:
variant: donut
height: 480
inner_radius: "52%"
outer_radius: "80%"
slice_border_radius: 4
min_angle: 4
show_value_labels: true
label:
position: outside
formatter: "{b}: {d}%"
center: ["50%", "48%"]
legend:
show: true
position: bottom
orient: horizontal
item_gap: 14
tooltip:
trigger: item
format:
revenue: "$#,##0a"
published: true
Solid pie with inside labels:
type: pie
mapping:
x: category
y: revenue
chart:
show_value_labels: true
label:
position: inside
color: "#fff"
font_weight: bold
legend:
show: false
format:
revenue: "$#,##0"
Rose layout (slice angle uniform, radius encodes value):
chart:
variant: rose
rose_type: area
start_angle: 0
show_value_labels: true
Design notes
- Keep it to about six slices — sort and limit in the Malloy query, or aggregate small slices into an "Other" bucket.
chart.min_anglekeeps near-zero slices visible; alternatively filter zeros out in the query.- On tight charts, place labels inside (
chart.label.position: "inside") or rotate them. - For a donut with content in the center, set
chart.label.position: "outside"so slice labels stay clear. - Colors follow query-result order from the platform palette — sort the query so the largest or most important slice takes the dominant color.