Fude (筆, "brush") draws charts in a Phoenix app.
Fude.bar(sales, x: :region, y: :revenue)
Fude.line(visits, x: :day, y: :count, color: :source)
Fude.histogram(orders, x: :total, bins: 30)
Fude.number(totals, value: :mrr, format: :compact, label: "MRR")Each function takes the data and the chart's channels and options, and
gives a Fude.Chart, which <.chart> draws (Fude.Components):
<.chart id="revenue" chart={Fude.bar(@sales, x: :region, y: :revenue)} />The data is a list of maps or a map of :columns and :rows (as a
query result has them). A channel is a field, or a field with what to
do with it ({:sum, :revenue}, {:month, :created_at}, see
Fude.Channel).
Every function also takes the keys of the chart:
:title,:subtitle- above the chart.:caption,:source- below it, as a graphics desk sets them.:description- what a screen reader says of the chart; Fude writes one when it is not given.:height- the height of the plot in pixels.:data- the name of the chart's data in its spec,"data"when not given (seeFude.Spec).
A chart is plain data: Fude.Spec.dump/1 gives a map to save, and
Fude.Spec.load/1 takes it back.
Layers
Charts drawn one over the other share their axes:
Fude.layers(visits, [
Fude.area(x: :day, y: :count),
Fude.line(x: :day, y: :count),
Fude.rule(y: 1000, label: "Goal")
])
Summary
Functions
Writes a note on the chart, at a place of its data (see
Fude.Annotation)
Areas: as lines, filled down to zero; stacked when they have a color.
Bars: a category on x and a number on y; horizontal: true turns them.
Points at x and y, sized by size.
A map with a circle at each region, sized by size.
A map of regions colored by color: each region an ISO code ("PRT", "PT"), a number code or a name; map is "world" (the default) or "us-states".
A donut: a pie with a hole (inner, the hole's share of the radius).
Small multiples: the chart drawn once for each value of a field, side by side, on the same scales, so that the panels compare at a glance.
A funnel: the stages on x with their y, each with its share of the first.
One number on an arc from min to max (0 and 100 when not given), with a target.
A heatmap: a cell for each x and y, colored by color.
A histogram: the numbers of x counted in bins (bins, about how many).
A chart of layers drawn one over the other, on the same axes: the first at the back. Each layer is a chart of one kind, made without data; the layers read the same data.
Lines: a time or a number on x, a number on y, a line for each color.
One number, large, with a label.
A pie: a slice for each color, as large as its value.
One number on a bar towards a goal.
Gives the chart its data, under its data's name. A chart loaded from a
spec gets its data again this way, or from <.chart data={...}>.
Gives the chart a dataset of a name, for a layer that reads it.
The data of an Ecto query or schema, grouped and aggregated in the
database when the chart draws (see Fude.Query)
A rule across the chart at x or at y, with a label.
Points at x and y, colored by color and sized by size.
A small line with no axes, for a table or a card.
Text at x and y.
Sets the chart's title, and with :subtitle, its subtitle.
One number with its change from compare.
Fude's version.
A waterfall: how each change of y (a step on x) moves a running total; total adds a bar of the end, start names the first bar as a total.
Functions
@spec annotate(Fude.Chart.t(), Fude.Annotation.type(), keyword()) :: Fude.Chart.t()
Writes a note on the chart, at a place of its data (see
Fude.Annotation):
chart
|> Fude.annotate(:label, x: "North", y: 136_000, text: "Best quarter on record")
|> Fude.annotate(:band, x: {~D[2026-03-01], ~D[2026-05-01]}, text: "Launch")
|> Fude.annotate(:line, y: 4000, text: "Goal")
@spec area(keyword() | term()) :: Fude.Chart.t()
@spec area(term(), keyword()) :: Fude.Chart.t()
Areas: as lines, filled down to zero; stacked when they have a color.
Fude.area(data, ...)
Fude.area(...) # a layer, for Fude.layers/2
@spec bar(keyword() | term()) :: Fude.Chart.t()
@spec bar(term(), keyword()) :: Fude.Chart.t()
Bars: a category on x and a number on y; horizontal: true turns them.
Fude.bar(data, ...)
Fude.bar(...) # a layer, for Fude.layers/2
@spec bubble(keyword() | term()) :: Fude.Chart.t()
@spec bubble(term(), keyword()) :: Fude.Chart.t()
Points at x and y, sized by size.
Fude.bubble(data, ...)
Fude.bubble(...) # a layer, for Fude.layers/2
@spec bubble_map(keyword() | term()) :: Fude.Chart.t()
@spec bubble_map(term(), keyword()) :: Fude.Chart.t()
A map with a circle at each region, sized by size.
Fude.bubble_map(data, ...)
Fude.bubble_map(...) # a layer, for Fude.layers/2
@spec choropleth(keyword() | term()) :: Fude.Chart.t()
@spec choropleth(term(), keyword()) :: Fude.Chart.t()
A map of regions colored by color: each region an ISO code ("PRT", "PT"), a number code or a name; map is "world" (the default) or "us-states".
Fude.choropleth(data, ...)
Fude.choropleth(...) # a layer, for Fude.layers/2
@spec donut(keyword() | term()) :: Fude.Chart.t()
@spec donut(term(), keyword()) :: Fude.Chart.t()
A donut: a pie with a hole (inner, the hole's share of the radius).
Fude.donut(data, ...)
Fude.donut(...) # a layer, for Fude.layers/2
@spec facet(Fude.Chart.t(), atom() | String.t(), keyword()) :: Fude.Chart.t()
Small multiples: the chart drawn once for each value of a field, side by side, on the same scales, so that the panels compare at a glance.
Fude.line(sales, x: :month, y: :revenue)
|> Fude.facet(:region, columns: 3)columns is how many panels make a row; as many as fit when not given.
@spec funnel(keyword() | term()) :: Fude.Chart.t()
@spec funnel(term(), keyword()) :: Fude.Chart.t()
A funnel: the stages on x with their y, each with its share of the first.
Fude.funnel(data, ...)
Fude.funnel(...) # a layer, for Fude.layers/2
@spec gauge(keyword() | term()) :: Fude.Chart.t()
@spec gauge(term(), keyword()) :: Fude.Chart.t()
One number on an arc from min to max (0 and 100 when not given), with a target.
Fude.gauge(data, ...)
Fude.gauge(...) # a layer, for Fude.layers/2
@spec heatmap(keyword() | term()) :: Fude.Chart.t()
@spec heatmap(term(), keyword()) :: Fude.Chart.t()
A heatmap: a cell for each x and y, colored by color.
Fude.heatmap(data, ...)
Fude.heatmap(...) # a layer, for Fude.layers/2
@spec histogram(keyword() | term()) :: Fude.Chart.t()
@spec histogram(term(), keyword()) :: Fude.Chart.t()
A histogram: the numbers of x counted in bins (bins, about how many).
Fude.histogram(data, ...)
Fude.histogram(...) # a layer, for Fude.layers/2
@spec layers(term(), [Fude.Chart.t()], keyword()) :: Fude.Chart.t()
A chart of layers drawn one over the other, on the same axes: the first at the back. Each layer is a chart of one kind, made without data; the layers read the same data.
@spec line(keyword() | term()) :: Fude.Chart.t()
@spec line(term(), keyword()) :: Fude.Chart.t()
Lines: a time or a number on x, a number on y, a line for each color.
Fude.line(data, ...)
Fude.line(...) # a layer, for Fude.layers/2
@spec number(keyword() | term()) :: Fude.Chart.t()
@spec number(term(), keyword()) :: Fude.Chart.t()
One number, large, with a label.
Fude.number(data, ...)
Fude.number(...) # a layer, for Fude.layers/2
@spec pie(keyword() | term()) :: Fude.Chart.t()
@spec pie(term(), keyword()) :: Fude.Chart.t()
A pie: a slice for each color, as large as its value.
Fude.pie(data, ...)
Fude.pie(...) # a layer, for Fude.layers/2
@spec progress(keyword() | term()) :: Fude.Chart.t()
@spec progress(term(), keyword()) :: Fude.Chart.t()
One number on a bar towards a goal.
Fude.progress(data, ...)
Fude.progress(...) # a layer, for Fude.layers/2
@spec put_data(Fude.Chart.t(), term()) :: Fude.Chart.t()
Gives the chart its data, under its data's name. A chart loaded from a
spec gets its data again this way, or from <.chart data={...}>.
@spec put_data(Fude.Chart.t(), String.t(), term()) :: Fude.Chart.t()
Gives the chart a dataset of a name, for a layer that reads it.
@spec query(Ecto.Queryable.t(), module(), keyword()) :: Fude.Query.t()
The data of an Ecto query or schema, grouped and aggregated in the
database when the chart draws (see Fude.Query):
Order |> Fude.query(Repo) |> Fude.bar(x: :status, y: {:count, :id})
@spec rule(keyword() | term()) :: Fude.Chart.t()
@spec rule(term(), keyword()) :: Fude.Chart.t()
A rule across the chart at x or at y, with a label.
Fude.rule(data, ...)
Fude.rule(...) # a layer, for Fude.layers/2
@spec scatter(keyword() | term()) :: Fude.Chart.t()
@spec scatter(term(), keyword()) :: Fude.Chart.t()
Points at x and y, colored by color and sized by size.
Fude.scatter(data, ...)
Fude.scatter(...) # a layer, for Fude.layers/2
@spec sparkline(keyword() | term()) :: Fude.Chart.t()
@spec sparkline(term(), keyword()) :: Fude.Chart.t()
A small line with no axes, for a table or a card.
Fude.sparkline(data, ...)
Fude.sparkline(...) # a layer, for Fude.layers/2
@spec text(keyword() | term()) :: Fude.Chart.t()
@spec text(term(), keyword()) :: Fude.Chart.t()
Text at x and y.
Fude.text(data, ...)
Fude.text(...) # a layer, for Fude.layers/2
@spec title(Fude.Chart.t(), String.t(), keyword()) :: Fude.Chart.t()
Sets the chart's title, and with :subtitle, its subtitle.
@spec trend(keyword() | term()) :: Fude.Chart.t()
@spec trend(term(), keyword()) :: Fude.Chart.t()
One number with its change from compare.
Fude.trend(data, ...)
Fude.trend(...) # a layer, for Fude.layers/2
@spec version() :: String.t()
Fude's version.
@spec waterfall(keyword() | term()) :: Fude.Chart.t()
@spec waterfall(term(), keyword()) :: Fude.Chart.t()
A waterfall: how each change of y (a step on x) moves a running total; total adds a bar of the end, start names the first bar as a total.
Fude.waterfall(data, ...)
Fude.waterfall(...) # a layer, for Fude.layers/2