Vega-Altair: Declarative Visualization in Python
altair-viz.github.io
altair-viz.github.io
If you need to learn a plotting library and you already work in Pandas, I recommend choosing Altair to learn. It's a natural extension to pd.DataFrame and the only magical incantation to learn is
alt.Chart(df).mark_<plot_type>.encode(x=df["col"], y=df["other_col"])
I find this significantly easier to work with than Matplotlib, where the same things can be done in several ways with subplots, plt.figure(), df.plot(), and maybe others?My only complaint with the library is that outputting to an image file feels weirdly complicated. I often resort to making HTML files and taking a screenshot if I don't want to take the time to look up all the steps equivalent to `.savefig("file.png")`.
(Disclaimer: I'm a Vega-Altair maintainer and the author of vl-convert)
Every data scientist endeavors to make an impact with their analysis, and ultimately that is typically tied to some kind of visualization. There needs to be a way to a) build the visualization you want and b) get it out there to people who would find it useful.
Just plotting in matplotlib means that you must either export as a PNG (ew) or provide the analysis itself to users/decision makers. PNGs are terrible because you completely lose interactivity. Providing the analysis means figuring out deployment of your python environment, which is possible but just causes another step between analysis and decision made on the analysis.
Altair and the vega-lite grammar of visualizations provides an interoperable and data centric way to build visualizations. It is extremely flexible when building visualizations and I find it very intuitive when it comes to complex plots. They can also be easily embedded into any webpage after being exported using the vega-lite spec, just include the vega-lite script in the html page. Can even be used with in dashboarding tools like Spotfire (I assume also with things like PowerBI although I haven't done it).
Imo no real reason to use matplotlib as a data scientist lest you seriously limit the future impact of your work
There are some drawbacks though that have been holding some of my colleagues back from switching from e.g. Seaborn to Altair:
- No zoom by selecting the x- or y-range. Almost all other libraries implement box-zoom, Altair does not have this. This is probably the biggest complaint I have heard so far.
- Annotating data inside the plot is difficult. I don't mean `mark_text`, I mean placing an annotation that you would do in Matplotlib via `ax.text(...)`.
- Along side that: No TeX support.
- It does become slow once there is a large number of points in the chart (and you don't want to aggregate).
- Missing mapping features. I know you can have maps in the background of your plot, but I'm talking OSM like mapping.
- Working with layered + faceted charts takes some time to get used to.
- It used to be that if you had a dataframe with 100 columns and you were only plotting two of them, still all 100 columns would be saved to html. I think this is addressed in VegaFusion?
Still, I want to just emphasize how much I love Altair. To understand relations in your data, it's amazing to just assign color to a column, shape to another column and so on. Really neat! With a background in mathematics, it was also helping me to think about the whole tidy approach to dataframes, so that was an added benefit!
Thanks for the feedback and for the kind words! All of these drawbacks are fair, just a couple of comments.
There is an experimental package called altair_tiles that makes is possible to add OSM-style maptile backgrounds to Altair charts. See https://github.com/altair-viz/altair_tiles. This is mostly for static charts at the moment, as it doesn't integrate well with pan/zoom yet.
As you mentioned, VegaFusion is able to remove unused columns in most cases. (And if it doesn't for a particular case, please open an issue!).
Maybe while you're here: Is there any desire to implement box-zoom (or x-range zoom) at any point in the future?
Sidenote: I like Altair and think it's a good development, despite rendering being performed client side.
This said, the claim here is tiring when it's used everywhere. Having spent significant time with Altair, I'd argue it might have tighter code but the documentation can be obscure. I haven't found it to make things easier from a developer perspective, but rather it does solve the use case that you are working in Python and need to have the client render a figure without callbacks (things like raw html dumps and similar).
(disclaimer: I'm a co-maintainer of Altair)
I'm using Plotly more lately, for 2 reasons - chart have very good interactivity by default and I'm also a Dash user - so it comes in naturally.
But I believe Altair is excellent for exploration - simple charts are very simple to create, and it's not complicated to create a complex exploration dashboard - with all charts linked between them - so you can select a subset of data on one chart, and it automatically updates the others. Highly recommend at least exploring it !
I'm also using it in a regular React app and it has quite decent APIs.
Plotly is definitely a great option as well, and it can do a bunch of things Vega-Altair is not designed for. One comment, just in case you weren't aware, is that there is a relatively new library that provides good integration between Altair and Dash: https://github.com/altair-viz/dash-vega-components. It even makes it possible to access Altair selection states in Dash callbacks so that you can have other dashboard components respond to selections.
Wasn't aware of that. Are there any plans to improve the interactivity - by that I mean scale on X / Y independently - 'plotly' like ? I know you can bind specifically to one axis, when generating the chart, however, what I usually want is to be able to just zoom in on a specific axis when looking at the chart - Plotly is really great as the behaviour is depending of what you select - a rectangle is just a rectangle (zoom on both axes), a vertical selection zooms on Y axis, and horizontal one on X axis.
We have been enjoying Perspective as a more declarative & high-performance flow. Altair/Vega is beautiful though so it was a bummer when we dropped it for a recent project.
However, when I used it a couples years back it struggled with large vizs, I think due to Vega(-lite)'s way of embedding the data in the viz artifact.
Also, interactive is nice but often I just need a quick static plot, and matplotlib is more convenient for this, you can easily see the png in any environment etc.
These days I'm eager to see an Observable Plot [1] wrapper for Python ! See [2] for a comparison to vega-lite
[0] https://github.com/livebook-dev/vega_lite
MaxRowsError: The number of rows in your dataset is greater than the maximum allowed (5000).
but ever since the Vegafusion companion library came unto the scene, I'm back using Altair.Overall, it's my preferred Python viz library although I do wish there was a better way for the Python library to better use introspection. After all, rather than
alt.Chart(df).mark_line.encode(x="abc:Q")
to provide the information that abc is a quantitative variable, I'd much rather the library be able to introspect the df object, column abc to derive the data type and make the inference the column is quantitative.That said, I'm already used to the extra syntax so still feel confident in using this library daily.
If you are reading the data directly from a URL instead of via a dataframe, the URL is passed on to Vega-Lite and Python never sees the data, so no introspection can be made on the Altair side of things.
(disclaimer: I'm a co-maintainer of Altair)
It’s amazing though. High quality and downloadable graphs. We use it for single cell rna seq plotting and it’s pretty performant with large data sets (5000+ points on an xy scatter graph)
[1] https://link.springer.com/book/10.1007/0-387-28695-0
[2] https://stackoverflow.com/questions/4892368/implementations-...
# Vega-Altair
alt.Chart(source).mark_line().encode(
x='x',
y='f(x)'
)
# Pyplot
plt.plot(source)
plt.xlabel('x')
plt.ylabel('f(x)')
[1]: https://matplotlib.org/stable/tutorials/pyplot.htmlTake a faceted plot like this scatter matrix [1] and try to plot it in matplotlib. You would need to set up the grid using subplots, then define the combinations you want and finally write logic to fill each subplot. The vega/altair code is much more declarative. You just tell it what needs to be in the rows/columns and vega/altair takes care of the rest.
[1]: https://altair-viz.github.io/gallery/scatter_matrix.html
*** SAS SCATTER MATRIX EXAMPLE ***
proc sgscatter data=sashelp.cars;
matrix Horsepower Acceleration Miles_per_Gallon / group=Origin;
*** ALTAIR SCATTER MARIX EXAMPLE ***
import altair as alt
from vega_datasets import data
source = data.cars()
alt.Chart(source).mark_circle().encode(
alt.X(alt.repeat("column"), type='quantitative'),
alt.Y(alt.repeat("row"), type='quantitative'),
color='Origin:N'
).properties(
width=150,
height=150
).repeat(
row=['Horsepower', 'Acceleration', 'Miles_per_Gallon'],
column=['Miles_per_Gallon', 'Acceleration', 'Horsepower']
).interactive()[1]: http://pandas.pydata.org/pandas-docs/stable/reference/api/pa...
(disclaimer: I'm a co-maintainer of Altair)
According to Wikipedia this is a style of programming where you describe _what_ you want rather than _how_ it should be done. What I see in my example is declarative per this definition: "I want a chart with <source>, with this X label and that Y label".
The fact that you can read it as if it were a description of the outcome is a happy accident (a purely aesthetic one at that) that would not necessarily happen with another example.
DeckGL
https://panel.holoviz.org/reference/panes/DeckGL.html
ipysigma
https://github.com/medialab/ipysigma