Plotly for Elixir: Express API
Mix.install([
{:plotly_ex, "~> 0.1"},
{:kino, "~> 0.18"},
{:explorer, "~> 0.11"}
])
Section
The plotly_ex library offers an Express API that mirrors plotly.py‘s
high-level interface. Pass a list of maps (or an Explorer DataFrame) plus column
names and get an interactive chart in one call.
Scatter
Plotly.scatter/2 maps each row to a point. The x: and y: options name the
map keys to use for each axis. All data uses string keys — the library
accesses values via row["col_name"].
cities = [
%{"city" => "New York", "population" => 8_336_817, "area" => 783.8},
%{"city" => "Los Angeles", "population" => 3_979_576, "area" => 1_302.0},
%{"city" => "Chicago", "population" => 2_693_976, "area" => 606.1},
%{"city" => "Houston", "population" => 2_320_268, "area" => 1_777.0},
%{"city" => "Phoenix", "population" => 1_680_992, "area" => 1_340.0},
]
Plotly.scatter(cities,
x: "area",
y: "population",
title: "US Cities: Area vs Population"
)
|> Plotly.show()
Bar
Plotly.bar/2 draws one rectangular bar per row. Add color: to split rows
into groups — scatter and bar are the only Express functions that support
color grouping; each group becomes a separate trace, and plotly.js renders them
side by side by default.
monthly = [
%{"month" => "Jan", "sales" => 42},
%{"month" => "Feb", "sales" => 55},
%{"month" => "Mar", "sales" => 61},
%{"month" => "Apr", "sales" => 48},
%{"month" => "May", "sales" => 73}
]
Plotly.bar(monthly, x: "month", y: "sales", title: "Monthly Sales")
|> Plotly.show()
regional = [
%{"quarter" => "Q1", "sales" => 120, "region" => "North"},
%{"quarter" => "Q2", "sales" => 145, "region" => "North"},
%{"quarter" => "Q3", "sales" => 162, "region" => "North"},
%{"quarter" => "Q1", "sales" => 98, "region" => "South"},
%{"quarter" => "Q2", "sales" => 112, "region" => "South"},
%{"quarter" => "Q3", "sales" => 130, "region" => "South"}
]
Plotly.bar(regional, x: "quarter", y: "sales", color: "region",
title: "Sales by Region (grouped)")
|> Plotly.show()
Line
Plotly.line/2 is scatter with mode: "lines" forced. Ideal for time-series
data where you want connected points rather than individual markers.
temps = [
%{"month" => "Jan", "temp" => 2.3},
%{"month" => "Feb", "temp" => 3.1},
%{"month" => "Mar", "temp" => 7.5},
%{"month" => "Apr", "temp" => 12.8},
%{"month" => "May", "temp" => 17.2},
%{"month" => "Jun", "temp" => 20.9},
%{"month" => "Jul", "temp" => 22.4},
%{"month" => "Aug", "temp" => 21.8},
%{"month" => "Sep", "temp" => 17.6},
%{"month" => "Oct", "temp" => 12.1},
%{"month" => "Nov", "temp" => 6.7},
%{"month" => "Dec", "temp" => 3.2}
]
Plotly.line(temps, x: "month", y: "temp", title: "Average Monthly Temperature (°C)")
|> Plotly.show()
Histogram
Plotly.histogram/2 bins a single numeric column. Supply x: (required) and
plotly.js chooses sensible bin widths automatically.
heights = [
%{"height" => 163}, %{"height" => 170}, %{"height" => 175}, %{"height" => 168},
%{"height" => 172}, %{"height" => 165}, %{"height" => 178}, %{"height" => 171},
%{"height" => 169}, %{"height" => 174}, %{"height" => 167}, %{"height" => 176},
%{"height" => 173}, %{"height" => 164}, %{"height" => 179}, %{"height" => 170},
%{"height" => 166}, %{"height" => 177}, %{"height" => 171}, %{"height" => 173}
]
Plotly.histogram(heights, x: "height", title: "Height Distribution (cm)")
|> Plotly.show()
Box
Plotly.box/2 requires both x: (category) and y: (numeric values) —
passing only one raises KeyError. Each unique x value gets its own box
showing median, quartiles, and outliers.
scores = [
%{"group" => "A", "score" => 72}, %{"group" => "A", "score" => 85},
%{"group" => "A", "score" => 78}, %{"group" => "A", "score" => 91},
%{"group" => "A", "score" => 68}, %{"group" => "A", "score" => 88},
%{"group" => "B", "score" => 55}, %{"group" => "B", "score" => 62},
%{"group" => "B", "score" => 70}, %{"group" => "B", "score" => 58},
%{"group" => "B", "score" => 65}, %{"group" => "B", "score" => 73},
%{"group" => "C", "score" => 90}, %{"group" => "C", "score" => 95},
%{"group" => "C", "score" => 88}, %{"group" => "C", "score" => 92},
%{"group" => "C", "score" => 86}, %{"group" => "C", "score" => 97}
]
Plotly.box(scores, x: "group", y: "score", title: "Test Scores by Group")
|> Plotly.show()
Pie
Plotly.pie/2 requires values: (numeric, required) and accepts names:
(labels, optional). If names: is omitted, plotly.js numbers the slices.
budget = [
%{"category" => "Housing", "amount" => 1_500},
%{"category" => "Food", "amount" => 600},
%{"category" => "Transport", "amount" => 350},
%{"category" => "Entertainment", "amount" => 200},
%{"category" => "Savings", "amount" => 500},
%{"category" => "Other", "amount" => 250}
]
Plotly.pie(budget, values: "amount", names: "category", title: "Monthly Budget")
|> Plotly.show()
Explorer DataFrames
Every Express function accepts an Explorer.DataFrame in place of a list of
maps — the API is identical. The library detects the DataFrame struct and
extracts columns via Explorer.Series.to_list/1.
alias Explorer.DataFrame, as: DF
# Rebuild the cities data as a DataFrame
cities_df = DF.new(%{
"area" => [783.8, 1_302.0, 606.1, 1_777.0, 1_340.0],
"population" => [8_336_817, 3_979_576, 2_693_976, 2_320_268, 1_680_992],
"city" => ["New York", "Los Angeles", "Chicago", "Houston", "Phoenix"]
})
# Identical call — just swap the list for the DataFrame
Plotly.scatter(cities_df, x: "area", y: "population",
title: "US Cities: Area vs Population (DataFrame)")
|> Plotly.show()
monthly_df = DF.new(%{
"month" => ["Jan", "Feb", "Mar", "Apr", "May"],
"sales" => [42, 55, 61, 48, 73]
})
Plotly.bar(monthly_df, x: "month", y: "sales",
title: "Monthly Sales (DataFrame)")
|> Plotly.show()