Docs / Build Workflow

Visualization — pie

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 with variant: 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 with chart.label below.
  • chart.cross_filter — boolean, default true.
  • 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. Default 90.
  • 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.y or format[<value_field_name>] — pattern for slice tooltip values and inside-slice labels.
  • format at the root — fallback.

Cross-filter behavior

  • Clicking a slice cross-filters the rest of the dashboard by the slice label.
  • The clicked field (the slice-label field, e.g. status) must be declared as a parameter in at least one model used by the dashboard, 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:

id: ec_orders_by_status_pie
title: Orders by Status
query: "models/ec_revenue.malloy::by_status"
type: pie
mapping:
  label: status
  value: order_count
chart:
  variant: donut
  inner_radius: "55%"
  outer_radius: "78%"
  show_value_labels: true
  label:
    position: outside
    formatter: "{b}: {d}%"
  legend:
    show: true
    position: bottom
format:
  order_count: "#,##0"
published: true

Solid pie with inside labels:

type: pie
mapping:
  label: category
  value: 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

Common pitfalls

  • Too many slices. A pie with more than ~6 slices becomes hard to read. Sort + limit in the Malloy query, or aggregate small slices into an "Other" bucket.
  • Slices with zero or near-zero values disappear. Use chart.min_angle to enforce a minimum visible angle, or filter zeros out in the query.
  • Labels overlap on a tight chart. Move them inside (chart.label.position: "inside") or rotate.
  • Donut inner content collides with labels. When you put a KPI in the donut center via dashboard layout, set chart.label.position: "outside" so the slice labels do not collide.
  • Slice colors are not what you expected. Colors are assigned in query-result order from the platform palette. Sort the query so the largest or most important slice gets the dominant color.
  • Cross-filter clicks have no effect. The slice-label field must be declared as a parameter in at least one model used by the dashboard.