Time series with horizotal bar with vegalite

I am trying to create a time series in vegalite. I started with values at a given end date as points and a loess fit on that as line.

But I wanted to change from points to lines of x: start and end date at the given y: value and a fit on the center of start and end date.

I computed the “mid-date” as the point of time between start and end date. The start_date is first date, that shall be included.

defmodule PollGraphs do
  def create_graph(data_source, title, col, start_date) do
    Vl.new(width: 500, height: 300, title: title)
    |> Vl.data_from_values(DF.filter(data_source, mid_date > ^start_date),
      only: ["end_date", "start_date", "mid_date", col, "category"]
    )
    |> Vl.layers([
      Vl.new()
      |> Vl.mark(:bar, opacity: 0.5)
      |> Vl.encode_field(:x, "start_date", type: :temporal, title: "poll end date")
      |> Vl.encode_field(:x2, "end_date")
      |> Vl.encode_field(:y, col, type: :quantitative, title: "percentage", scale: [domain: [param: [35, 45]]])
      |> Vl.encode_field(:color, "category", type: :nominal),
      Vl.new()
      |> Vl.mark(:line, color: "firebrick", opacity: 0.5)
      |> Vl.transform(loess: col, on: "start_date", bandwidth: 0.5)
      |> Vl.encode_field(:x, "start_date", type: :temporal, title: "poll end date")
      |> Vl.encode_field(:y, col, type: :quantitative, title: "percentage")
    ])
    
  end

I have three problems.

  • how can I get round corners working?
  • the scale in y axis is twice the size as when I used, :point and can not change it.
  • I can’t get loess fit working on “mid_date”

Assuming you want rounded corners on the Vl.mark(:bar), try something like this:

Vl.mark(:bar, corner_radius_bottom_right: 3, corner_radius_top_right: 3)

If you have a minimal data set to share, that might help with understanding the other issues.

Edited to swap corners from vertical to horizontal.

The dataset for code testing:

test_df =DF.new(
  start_date: [~N[2023-09-25 00:00:01], ~N[2023-09-25 00:00:01], ~N[2023-09-25 00:00:01],~N[2023-10-04 00:00:01] ],
  end_date: [~N[2023-09-27 00:00:01], ~N[2023-09-28 00:00:01], ~N[2023-10-02 00:00:01],~N[2023-10-05 00:00:01] ],
  mid_date: [~N[2023-09-26 00:00:01], ~N[2023-09-26 12:00:01], ~N[2023-09-28 12:00:01],~N[2023-10-04 12:00:01] ],
  col: [36, 36, 36, 37])

@RemyXRenard setting the rounded corners removed the bar part completly.

The rounded corners appear to interact with the type of the y axis. If you remove the “quantitative” type it will display (but won’t look like what you want). I don’t have a solution for that. It may possibly be related to https://github.com/vega/vega-lite/issues/5800, but that’s just a guess.

However, the y scale and loess transform might be resolved using the following, depending on what you’re trying to do.

Assumptions:

  • The minimal data set is the result of the DF.filter
  • The category field is different for each data point (added “category” to test_df)

For the loess, I added another layer with the mid_date and opacity set to 0, so an invisible layer. This allows the use of mid_date in the mark(:line) layer.

For the scale, I removed the “param” from the scale domain.

I hope this helps.

test_df = DF.new(
  start_date: [~N[2023-09-25 00:00:01], ~N[2023-09-25 00:00:01], ~N[2023-09-25 00:00:01],~N[2023-10-04 00:00:01] ],
  end_date: [~N[2023-09-27 00:00:01], ~N[2023-09-28 00:00:01], ~N[2023-10-02 00:00:01],~N[2023-10-05 00:00:01] ],
  mid_date: [~N[2023-09-26 00:00:01], ~N[2023-09-26 12:00:01], ~N[2023-09-28 12:00:01],~N[2023-10-04 12:00:01] ],
  col: [36, 36, 36, 37],
  category: [1,2,3,4])

    Vl.new(width: 500, height: 300, title: "Test")
    |> Vl.data_from_values(test_df)
    |> Vl.layers([
      Vl.new()
      |> Vl.mark(:bar, opacity: 0.5)
      |> Vl.encode_field(:x, "start_date", type: :temporal, title: "poll end date")
      |> Vl.encode_field(:x2, "end_date")
      |> Vl.encode_field(:y, "col", type: :quantitative, title: "percentage", scale: [domain:  [35, 45]])
      |> Vl.encode_field(:color, "category", type: :nominal),
      Vl.new()
      |> Vl.mark(:bar, opacity: 0)
      |> Vl.encode_field(:x, "mid_date", type: :temporal)
      |> Vl.encode_field(:x2, "end_date")
      |> Vl.encode_field(:y, "col", type: :quantitative, title: "percentage", scale: [domain:  [35, 45]]),
      Vl.new()
      |> Vl.mark(:line, color: "firebrick", opacity: 0.5)
      |> Vl.transform(loess: "col", on: "mid_date", bandwidth: 0.5)
      |> Vl.encode_field(:x, "mid_date", type: :temporal, title: "poll end date")
      |> Vl.encode_field(:y, "col", type: :quantitative, title: "percentage")
    ])