A simple Elixir charting library that generates easy to customize charts for Phoenix and LiveView.
- Easily generate pie charts, column charts, bar charts, progress counters, and line charts
- Generates responsive and accessible SVGs as LiveView components
- Provides advanced styling like gradients and rounded corners
- Smooth animations for updating live data to the UI
We've worked hard to ensure Uncharted Phoenix is both screen reader and keyboard accessible. Learn more about our approach here: Accessibility Documentation
Add this to your mix.exs deps:
{:uncharted_phoenix, "~> 0.2.0"}
To render any of the built-in UnchartedPhoenix chart components, pass an Uncharted.chart
to the render/2
function:
my_chart = %Uncharted.BaseChart{...}
# Inside of a LiveView or LiveComponent .leex template:
<%= UnchartedPhoenix.render(@socket, @my_chart) %>
By defining an implementation of the Uncharted.Component
protocol for all of Uncharted's built-in chart types, UnchartedPhoenix.render/2
knows how to render the appropriate kind of chart based on the dataset of the Uncharted.BaseChart
struct you pass in. For example, if you pass a chart with a %Uncharted.BarChart.Dataset{}
to UnchartedPhoenix.render/2
, UnchartedPhoenix will render the UnchartedPhoenix.LiveBarComponent
for you and handle other setup the component needs to attach event handlers, such as giving the component an ID.
If you wish to render more than one of the same type of chart in the same view, you can override the default ID by defining a value for the %Uncharted.BaseChart{}
struct's :component_id
field.
By default, if you do not set the :component_id
field on the BaseChart
, UnchartedPhoenix will give the LiveComponent it renders an id equal to the stringified version of the dataset module defined on the BaseChart, i.e. if you pass a BaseChart
with an Uncharted.BarChart.Dataset
to UnchartedPhoenix.render/2
, the id of the LiveBarComponent that gets rendered will be "Uncharted.BarChart.Dataset"
. If you define a component_id
on your BaseChart
struct, the component_id will be appended to the default id like this: "Uncharted.BarChart.Dataset__#{my_custom_component_id}"
.
column_chart = %BaseChart{
title: "Cheese Coney Consumption by Neighborhood",
colors: colors,
width: 700,
height: 400,
dataset: %ColumnChart.Dataset{
axes: %BaseAxes{
magnitude_axis: %MagnitudeAxis{
max: 10_000,
min: 0
}
},
data: Cincy.get()
}
}
defp bar_chart do
memory_data = MemoryChart.get()
data = MemoryChart.convert_to_datum(memory_data)
%BaseChart{
title: "Live Beam Memory Stats",
width: 600,
height: 400,
colors: %{
blue: "#36D1DC",
rosy_gradient: %Gradient{
start_color: "#642B73",
stop_color: "#C6426E"
}
},
dataset: %BarChart.Dataset{
axes: %BaseAxes{
magnitude_axis: %MagnitudeAxis{
max: MemoryChart.chart_max(memory_data),
min: 0
}
},
data: data
}
}
end
pie_chart = %BaseChart{
title: "Best kind of pie",
colors: %{
rose_gradient: %Gradient{
start_color: "#642B73",
stop_color: "#C6426E"
},
blue_gradient: %Gradient{
start_color: "#36D1DC",
stop_color: "#5B86E5"
},
red_gradient: %Gradient{
start_color: "#FF9486",
stop_color: "#FF1379"
}
},
dataset: %PieChart.Dataset{
data: [
%BaseDatum{
name: "Pecan",
fill_color: :red_gradient,
values: [20.0]
},
%BaseDatum{
name: "Blueberry",
fill_color: :blue_gradient,
values: [28.0]
},
%BaseDatum{
name: "Pumpkin",
fill_color: :rose_gradient,
values: [35.0]
},
%BaseDatum{
name: "Chocolate",
fill_color: :blue_gradient,
values: [17.0]
}
]
}
}
line_chart = %BaseChart{
title: "Live Line Chart",
colors: colors,
width: 700,
height: 400,
dataset: %ColumnChart.Dataset{
axes: %XYAxes{
x: %MagnitudeAxis{
max: 700,
min: 0
},
y: %MagnitudeAxis{
max: 2500,
min: 0
}
},
data: [
%BaseDatum{
name: "Point 1",
fill_color: :blue_gradient,
values: [70, 500]
},
%BaseDatum{
name: "Point 2",
fill_color: :blue_gradient,
values: [150, 1000]
},
%BaseDatum{
name: "Point 3",
fill_color: :blue_gradient,
values: [350, 1600]
},
%BaseDatum{
name: "Point 4",
fill_color: :blue_gradient,
values: [450, 1500]
},
%BaseDatum{
name: "Point 5",
fill_color: :blue_gradient,
values: [550, 2000]
}
]
}
}
defp progress_chart(from: %BaseChart{} = chart) do
memory = Memory.get()
%BaseChart{
chart
| title: "Process Memory / Total",
colors: %{
rose_gradient: %Gradient{
start_color: "#642B73",
stop_color: "#C6426E"
},
blue_gradient: %Gradient{
start_color: "#36D1DC",
stop_color: "#5B86E5"
},
red_gradient: %Gradient{
start_color: "#FF9486",
stop_color: "#FF1379"
},
gray: "#e2e2e2"
},
dataset: %ProgressChart.Dataset{
background_stroke_color: :gray,
label: "Proc Memory",
secondary_label: "(% Of Total)",
to_value: memory.total,
current_value: memory.process,
percentage_text_fill_color: :blue_gradient,
percentage_fill_color: :rose_gradient,
label_fill_color: :rose_gradient,
doughnut_width: 5,
progress_shape: :round
}
}
end
Base chart configuration allows you to define set solid colors and gradients for any chart you will use within the application.
colors = %{
blue: "#6bdee4"
}
colors = %{
rose_gradient: %Gradient{
start_color: "#642B73",
stop_color: "#C6426E"
}
}
You can configure the color and width of grid lines, as well as whether or not to display them. Set line_color
to a string or the atom key of a set base color or gradient (see above). Set line_width
to an integer to change the width of grid lines. Set display_lines
to false
to hide grid lines along that axis. Set show_gridlines
on XYAxes
or BaseAxes
to false
to hide all grid lines.
%MagnitudeAxis{
line_color: "#efefef"
line_width: 2,
display_lines: true
}