Packages
Multi-surface application runtime for Elixir. One TEA module renders to terminal, browser (LiveView), SSH, and MCP (agents). 30+ widgets, flexbox + CSS grid, AI agent runtime, distributed swarm with CRDTs, time-travel debugging, session recording, sandboxed REPL, and agentic commerce.
Current section
Files
Jump to
Current section
Files
lib/raxol/terminal/graphics/chart_export.ex
defmodule Raxol.Terminal.Graphics.ChartExport do
@moduledoc """
Chart export and data processing functions extracted from DataVisualization.
Handles chart data export, ASCII generation, and format conversion.
"""
@doc """
Exports chart data in the specified format.
"""
def export_chart_data(chart_state, format) do
case format do
:ascii ->
# Export as ASCII representation
ascii_data = generate_ascii_chart(chart_state)
{:ok, ascii_data}
:json ->
# Export as JSON data
json_data =
chart_state.data_buffer
|> Jason.encode!()
{:ok, json_data}
:csv ->
# Export as CSV data
csv_data = generate_csv_chart(chart_state)
{:ok, csv_data}
_ ->
{:error, :unsupported_format}
end
end
@doc """
Generates ASCII representation of chart data.
"""
def generate_ascii_chart(chart_state) do
case chart_state.type do
:line ->
generate_line_chart_ascii(chart_state.data_buffer)
:bar ->
generate_bar_chart_ascii(chart_state.data_buffer)
:scatter ->
generate_scatter_chart_ascii(chart_state.data_buffer)
_ ->
"Chart data:\n" <> inspect(chart_state.data_buffer)
end
end
@doc """
Generates CSV representation of chart data.
"""
def generate_csv_chart(chart_state) do
headers = get_csv_headers(chart_state.type)
rows =
chart_state.data_buffer
|> Enum.map_join("\n", &format_data_point_as_csv(&1, chart_state.type))
headers <> "\n" <> rows
end
@doc """
Gets performance statistics for charts.
"""
def get_performance_stats do
%{
total_charts: get_total_charts(),
active_charts: get_active_charts(),
memory_usage: get_memory_usage(),
render_time: get_average_render_time()
}
end
# Private helper functions
defp generate_line_chart_ascii(data_points) do
case Enum.empty?(data_points) do
true ->
"No data available"
false ->
values = Enum.map(data_points, & &1.value)
max_val = Enum.max(values)
min_val = Enum.min(values)
range = max_val - min_val
data_points
|> Enum.with_index()
|> Enum.map_join("\n", fn {point, idx} ->
height =
case range > 0 do
true -> trunc(10 * (point.value - min_val) / range)
false -> 5
end
String.pad_leading("#{idx}", 3) <>
": " <> String.duplicate("*", height)
end)
end
end
defp generate_bar_chart_ascii(data_points) do
case Enum.empty?(data_points) do
true ->
"No data available"
false ->
max_val = data_points |> Enum.map(& &1.value) |> Enum.max()
data_points
|> Enum.with_index()
|> Enum.map_join("\n", fn {point, idx} ->
bar_length =
case max_val > 0 do
true -> trunc(20 * point.value / max_val)
false -> 1
end
label = Map.get(point, :label, "Item #{idx}")
String.pad_trailing(label, 10) <>
" |" <> String.duplicate("=", bar_length) <> " #{point.value}"
end)
end
end
defp generate_scatter_chart_ascii(data_points) do
case Enum.empty?(data_points) do
true ->
"No data available"
false ->
"Scatter Plot Data:\n" <>
(data_points
|> Enum.with_index()
|> Enum.map_join(", ", fn {point, idx} ->
x = Map.get(point, :x, idx)
y = Map.get(point, :y, point.value)
"(#{x}, #{y})"
end))
end
end
defp get_csv_headers(chart_type) do
case chart_type do
:line -> "index,value,timestamp"
:bar -> "label,value,timestamp"
:scatter -> "x,y,timestamp"
:heatmap -> "x,y,value,timestamp"
_ -> "value,timestamp"
end
end
defp format_data_point_as_csv(point, chart_type) do
case chart_type do
:line ->
"#{Map.get(point, :index, 0)},#{point.value},#{point.timestamp}"
:bar ->
label = Map.get(point, :label, "")
"\"#{label}\",#{point.value},#{point.timestamp}"
:scatter ->
x = Map.get(point, :x, 0)
y = Map.get(point, :y, point.value)
"#{x},#{y},#{point.timestamp}"
:heatmap ->
x = Map.get(point, :x, 0)
y = Map.get(point, :y, 0)
"#{x},#{y},#{point.value},#{point.timestamp}"
_ ->
"#{point.value},#{point.timestamp}"
end
end
defp get_total_charts, do: :ets.info(:chart_registry, :size) || 0
defp get_active_charts,
do: :ets.match(:chart_registry, {~c"_", %{active: true}}) |> length()
defp get_memory_usage, do: :erlang.memory(:total)
# Placeholder - would calculate from metrics
defp get_average_render_time, do: 5.2
end