DEV Community

Parth Patil
Parth Patil

Posted on

Using ECharts in Elixir Livebook

I have been using a lot of Elixir Livebook lately and I am having a lot of fun with data exploration and analysis using Livebook. Livebook has great support for drawing charts using the excellent Vega-Lite library. Even though Vega-Lite is great and is sufficient for many usecases I wanted to try using Apache ECharts inside Livebook. We use ECharts at work and are happy with it.

I looked around and could not find any prior work/library that allowed me to use ECharts in Livebook so I decided to create a hex package for Livebook that used ECharts to draw charts. Its called lb_echarts check it out if you are interested.

After some research I found that Kino.JS could be used to integrate custom JS into Livebook.

To use Kino.JS I had to use Kino.JS in my module and then define the init JS function within the asset macro. This looks as follows. Note in the following code I have only shown how do define the asset section, later I will show how to write rest of the code.

defmodule LbEcharts do
  @moduledoc """
  Library to use Echarts in LiveBook
  """

  use Kino.JS

  asset "main.js" do
    """
    export async function init(ctx, chart_data) {
      await ctx.importJS("https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js");

      ctx.root.innerHTML = `
        <div id="echart_window" style="width: 800px;height:500px;"></div>`

        var myChart = echarts.init(document.getElementById('echart_window'));

        // Specify the configuration items and data for the chart
        var options = JSON.parse(chart_data);

        // Display the chart using the configuration items and data just specified.
        myChart.setOption(options);
    }
    """
  end
end
Enter fullscreen mode Exit fullscreen mode

The entire contents of the asset section are enclosed in triple quotes. Whatever you write inside these triple quotes are considered as JS code. In the above code you will note that I have used async and await in the JS code. This is because I am loading a JS file and I want to wait for the JS file to be loaded before executing rest of the code.

The init function in JS gets the context in ctx variable and second argument is what was passed to the Kino.JS.new() function. One can define the HTML markup for the output Livebook cell in the ctx.root.innerHTML attribute. Note how the markup is enclosed in the backticks.

Now lets look at how we implement a bar chart.

defmodule LbEcharts do
  @moduledoc """
  Library to use Echarts in LiveBook
  """

  use Kino.JS

  def new(chart_data) do
    Kino.JS.new(__MODULE__, chart_data)
  end

  def bar(opts) do
    options =
      %{
        "title" => %{"text" => opts.title},
        "tooltip" => %{},
        "legend" => %{"data" => opts.legend},
        "xAxis" => %{"data" => opts.x},
        "yAxis" => %{},
        "series" => [
          %{
            "name" => "sales",
            "type" => "bar",
            "data" => opts.y
          }
        ]
      }
      |> Jason.encode!()

    LbEcharts.new(options)
  end

  asset "main.js" do
    """
    export async function init(ctx, chart_data) {
      await ctx.importJS("https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js");

      ctx.root.innerHTML = `
        <div id="echart_window" style="width: 800px;height:500px;"></div>`

        var myChart = echarts.init(document.getElementById('echart_window'));

        // Specify the configuration items and data for the chart
        var options = JSON.parse(chart_data);

        // Display the chart using the configuration items and data just specified.
        myChart.setOption(options);
    }
    """
  end
end
Enter fullscreen mode Exit fullscreen mode

Following is how you would use the library to draw a bar chart

LbEcharts.bar(%{
  title: "Bar Chart",
  legend: ["sales"],
  x: ["shirt", "cardign", "chiffon shirt", "pants", "heels", 
  "socks"],
  y: [5, 20, 36, 10, 10, 20]
})
Enter fullscreen mode Exit fullscreen mode

To learn more check out lb_echarts

Top comments (0)