Bar Widths in Interactive Altair Graphs

Viewed 527

How do I make the bars as wide as an entire day? Right now the bars are more like lines demarcating the start of the day. Do I switch from bar marks to rectangle marks? Do I toy with band scales? Or do I force binning without modifying the data?

Right now the bars are too thin. Because the graph is interactive I can't set the bar width; width is zoom-independent. Zoom too far out and the bars start overlapping. Zoom too far in and they look like lines again.

Days are on the x-axis. Labels shouldn't change. The graph is interactive and its width is fixed. Blank space between bars should reflect missing days and not be filled with bar.

import pandas as pd
import numpy as np
import altair as alt

c1 = np.random.randint(1,6, size=15)
c2 = pd.date_range(start="2021-01-01",end="2021-01-15")
df = pd.DataFrame({"day": c2, "value": c1})
df = df.drop([2, 5,6,7,13])
alt.Chart(df).mark_bar().encode(alt.X("day:T"), alt.Y("value")).interactive(bind_y=False).properties(width=800)

example of thin bars

And ideally, when the bar fills the entire day the day marker should be centered on the bar (rather than at the beginning).

1 Answers

You can do this by using a timeUnit with an ordinal encoding. That is, replace

alt.X("day:T")

with

alt.X("date(day):O")

The result looks like this: enter image description here

Depending on the axis labels you want, you can use the monthdate or yearmonthdate timeUnits instead.

If you want the axis to still be interactive, ordinal encodings are not an option. In this case, another option is to specify the bar widths using the X and X2 encodings, along with a calculate transform to define the limits. For example:

alt.Chart(df).transform_calculate(
    day = "toDate(datum.day)",
    start = "datum.day - 12 * 60 * 60 * 1000",  # -12 hours in milliseconds
    end = "datum.day + 12 * 60 * 60 * 1000",    # +12 hours in milliseconds
).mark_bar().encode(
    alt.X("start:T"),
    alt.X2("end:T"),
    alt.Y("value")
).interactive(bind_y=False).properties(width=800)

enter image description here

Related