Changing the width of a step in Altair line and area charts

Question:

I try to build a line chart that displays a value for each month of a full year. I also want to fill months that exceed a threshold. I have an issue with the appearance of the last values of both the line and the fill.

import altair as alt
from vega_datasets import data

source = data.stocks()
year_data = source[source.date.dt.year == 2007]

line = alt.Chart(year_data, width=600).mark_line(
    interpolate='step-after',
    color='red'
).encode(
    x='date',
    y='price'
).transform_filter(alt.datum.symbol == 'IBM')

fill = alt.Chart(year_data, width=600).mark_area(
    interpolate='step-after',
).encode(
    x='date',
    y='price',
).transform_filter(
    (alt.datum.symbol == 'IBM') &
    (alt.datum.price > 105)
)

fill + line

line chart for stock values

  1. How can I display December with the same width as the other months so it does not get chopped off visually?
  2. October also exceeds the threshold of 105 but doesn’t appear to be filled. What can I do to fill it like the other months?
Asked By: steffeng

||

Answers:

I think your issue with the extent of the step interpolation is similar to what is described in Drawing line plot for a histogram and I am not sure there is a good solution.

A workaround would be to perform temporal binning to convert your data to ordinal and use a bar mark instead of an area:

import altair as alt
from vega_datasets import data


source = data.stocks()
year_data = source[source.date.dt.year == 2007]

line = alt.Chart(year_data, width=600).mark_line(
    interpolate='step-after',
    color='red'
).encode(
    x='month(date)',
    y='price'
).transform_filter(
    alt.datum.symbol == 'IBM'
)

line.mark_bar().transform_filter(alt.datum.price > 105) + line

enter image description here

You can also make the x-axis ordinal to avoid Dec getting chopped off.

line = alt.Chart(year_data, width=600).mark_line(
    interpolate='step',
    color='red'
).encode(
    x='month(date):O',
    y='price'
).transform_filter(
    alt.datum.symbol == 'IBM'
)

line.mark_bar().transform_filter(alt.datum.price > 105) + line

enter image description here

Answered By: joelostblom
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.