Altair: Facet without column or row

Created on 21 May 2019  路  8Comments  路  Source: altair-viz/altair

With altair < 3.0, I was able to do this:

[1]
import altair.vegalite.v2 as alt
from vega_datasets import data

source = data.cars()

line = alt.Chart().mark_line().encode(x="Year", y="mean(Miles_per_Gallon)")

line.facet(data=source)

And then, on another jupyter cell, quickly iterate with facet plot with:

[2]
line.facet(data=source, column='Origin')

However, I get Javascript Error: Cannot read property 'length' of undefined when I specify a facet plot without column or row with altair 3.0.

Is there a way to specify a plot and a facet plot from line?

All 8 comments

This error is coming from javascript, so it's probably a difference in implementation between Vega-Lite v2 and Vega-Lite v3.

I'd suggest just putting the data in the line plot itself; for example:

line = alt.Chart(source).mark_line().encode(x="Year", y="mean(Miles_per_Gallon)")
line

and then in a later cell

line.facet(column='Origin')

This won't currently work if line is replaced by a layered chart, but that data handling will be fixed by #1521

Another note, in case it helps your current workflow: in place of the empty facet, you can always do:

line = alt.Chart().mark_line().encode(x="Year", y="mean(Miles_per_Gallon)")
line.properties(data=source)

Hi Jake,
In most of my figures, I use facet charts.
Unfortunately, I can't get your solutions to work with facet chart:

data specified with alt.Chart(data)

import altair as alt
from vega_datasets import data

source = data.cars()
base = alt.Chart(source).encode(x="Year")
line = base.mark_line().encode(y="mean(Miles_per_Gallon)")

band = base.mark_errorband(extent="ci").encode(
    y=alt.Y("Miles_per_Gallon", title="Miles/Gallon")
)

line.facet(column="Origin:N")  # works well
(line + band).facet(column="Origin:N")  # error: 'data' is a required property

data specified with chart.properties(data=data)

import altair as alt
from vega_datasets import data

source = data.cars()
base = alt.Chart().encode(x="Year")
line = base.mark_line().encode(y="mean(Miles_per_Gallon)")

band = base.mark_errorband(extent="ci").encode(
    y=alt.Y("Miles_per_Gallon", title="Miles/Gallon")
)

(line).properties(data=source)

Additional properties are not allowed ('Origin', 'Weight_in_lbs', 'Year', 'Acceleration', 'Miles_per_Gallon', 'Horsepower', 'Name', 'Cylinders', 'Displacement' were unexpected) [...]

As I mentioned, my approach will not work with layered charts (or with other compound charts, such as errorbars) until #1521 is in.

Until then, for the single chart you can use the properties approach I mentioned in my followup comment to avoid the javascript error, and continue passing data to the facet as you have been.

Oh sorry I didn't see your mention of #1521, thanks a lot. I'm going to be keeping an eye on that PR.

It's really close, I just need to update docs and changelog. I'll try to get to that tonight.

So #1521 is in. I also realized that I gave you bad advice regarding passing data to the properties method. I fixed that in #1525.

Let me know if you run into other issues; I'm going to try to get these fixes and others into a new release very soon.

Hi Jake, I can confirm that with the current master branch, both ways of declaring data (with alt.Chart(data) and chart.properties(data=data)) work correctly, even with layered charts. Thank you for the awesome support.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

pabloinsente picture pabloinsente  路  3Comments

morberg picture morberg  路  3Comments

bmcfee picture bmcfee  路  3Comments

SuperShinyEyes picture SuperShinyEyes  路  3Comments

mroswell picture mroswell  路  4Comments