Repository: altair-viz/altair
Pull request #2774 (2022-12-28 11:12:25)

Update and simplify README
I updated the README.md. Furthermore, I really like READMEs which are concise, similar to https://github.com/pandas-dev/pandas, i.e. a README which summarizes what the library does, a fully contained example that can be copy-pasted, simple installation instructions, and a reference to the documentation. This is where users can then go to learn more. Afterwards, some additional content for developers. In my opinion, all the rest should be in the documentation so it's easier to find.

Reasoning for the changes is usually in the commit messages but let me know if anything is unclear!

Included content from #1122 in CONTRIBUTING.md

Is the Google Altair Group still something that should be actively recommended for asking questions or only StackOverflow? I think ideally there is one preferred place to ask questions (StackOverflow) and one place to report feature requests and bugs (GH issues). But as the Google Group already has quite some content, maybe we want to keep the reference to it and I could also add it in the [Getting Help](https://binste.github.io/altair-docs/getting_started/getting_help.html) page in the documentation?

mattijn: Thanks for the work here. I'm trying to understand the changes you made to the file `docbuild.yml` here: 

https://github.com/altair-viz/altair/pull/2774/files#diff-5f636d76e1060c18bf31565648228e016c5511b2cceed87d82af54c17d4c3f21

Can you explain a bit why you think that is necessary? Ah, maybe because you updated the requirements.txt as well. 

I think we still need `altair_saver` for the official docs, since `vl-convert` cannot create the png-thumbnail of isotype charts:

vl-convert:
<img width="192" alt="image" src="https://user-images.githubusercontent.com/5186265/210018548-71bfaa70-68d5-4f66-8c0b-9b601e3851a0.png">
altair_saver:
<img width="192" alt="image" src="https://user-images.githubusercontent.com/5186265/210018632-348f3136-0ea1-4322-bd1b-8e2e8dfd4687.png">

mattijn: There is also an Altair channel with >150 members in the Vega [slack group](https://bit.ly/join-vega-slack-2022). But it is not active. I think sticking to SO and GH is fine.
binste: I thought it's nice if we can switch to recommending vl-convert in `CONTRIBUTING.md` as it greatly simplifies the setup needed for building the docs. For example to get altair_saver working in a Debian (bullseye) Docker container running on an Apple M2 chip, I had to install the following additional dependencies on top of what is described in the `altair_saver` docs:
```
sudo apt-get install build-essential libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev
```
Consequently I also adapted it in `docbuild.yml` but I wasn't aware of the emoji limitation (turns out it's already documented at https://github.com/vega/vl-convert#emoji-support-in-png-export), thanks for noticing!

I reverted the change in `docbuild.yml` and `requirements.txt` and clarified in `RELEASING.md` and `CONTRIBUTING.md` that `vl-convert-python` is the easier way to quickly build the docs but for releases one needs to install `altair_saver` and **uninstall** `vl-convert-python` as the later is used by default.
mattijn: Yes, I agree. Everything outside building the docs should recommend using vl-convert. I think it’s possible to define/overrule an engine to be used to export the pngs. It would be a bit unpleasant if others have to delete packages for setting this.
mattijn: And with, _building the docs_ I mean, the official one within GitHub actions. For contributors it really is much easier to use vl-convert. Therefor I’m also not against including it in the `requirements.txt`. If that means a few more steps should be included to make the GitHub action workflow correctly work with altair_saver, then that’s fine by me.
mattijn: > I think it’s possible to define/overrule an engine to be used to export the pngs. It would be a bit unpleasant if others have to delete packages for setting this.

This PR is related to this: https://github.com/altair-viz/altair/pull/2784

binste: Thanks @mattijn! I agree, it's great if its easier for new contributors so I readded vl-convert-python to doc/requirements.txt and clarified in CONTRIBUTING.md when it needs to be replaced with altair_saver. In the github workflow, we can simply uninstall vl-convert-python.

With this, it's only a bit cumbersome when releasing a new version but at least it's well documented. I'm not sure how it currently works with access rights to pypi and this repo, but a more reliable way to publish new versions and update the documentation would probably be with github workflows, e.g. see the Pandas repo [wheels.yml](https://github.com/pandas-dev/pandas/blob/main/.github/workflows/wheels.yml) and [docbuild-and-upload.yml](https://github.com/pandas-dev/pandas/blob/main/.github/workflows/docbuild-and-upload.yml).
mattijn: I agree that streamlining the publication of releases to PyPi and Conda using Github Actions would be an improvement as it simplifies maintenance. Currently only Jake has the permissions to do so, perhaps creating a new issue to track this would be a good idea. It's likely that setting this up correctly will require some discussion to implement it properly.
binste: Sounds good, I'll create an issue with some first inputs for discussion. The GH actions might be a great way to share the credentials for pypi and conda between maintainers thereby reducing the single-person dependency risk on Jake.

Patch:
diff --git a/.github/workflows/docbuild.yml b/.github/workflows/docbuild.yml
index 914d2a11..788deac1 100644
--- a/.github/workflows/docbuild.yml
+++ b/.github/workflows/docbuild.yml
@@ -22,6 +22,7 @@ jobs:
         pip install "selenium<4.3.0"
         pip install altair_saver
         pip install -r doc/requirements.txt
+        pip uninstall vl-convert-python --yes
         pip install git+https://github.com/altair-viz/altair_viewer.git
     - name: Run docbuild
       run: |
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index cb89d42d..59de7e4f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -11,23 +11,18 @@ visualization.
 We are also seeking contributions of additional Jupyter notebook-based examples
 in our separate GitHub repository: https://github.com/altair-viz/altair_notebooks.
 
-The altair users mailing list can be found at
-https://groups.google.com/forum/#!forum/altair-viz. If you are working on
-Altair, you can talk to other developers in the `#altair` channel of the [Vega
-slack](https://bit.ly/join-vega-slack).
-
 ## How To Contribute Code to Altair
 
 ### Setting Up Your Environment
 
-Fork the Altair repository on GitHub and clone the fork to you local
+Fork the Altair repository on GitHub and then clone the fork to you local
 machine. For more details on forking see the [GitHub
 Documentation](https://help.github.com/en/articles/fork-a-repo).
 ```
 $ git clone https://github.com/YOUR-USERNAME/altair.git
 ```
 
-To keep your fork up to date with changes in the this repo,
+To keep your fork up to date with changes in this repo,
 you can [use the fetch upstream button on GitHub](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork).
 
 Now you can install the latest version of Altair locally using `pip`.
@@ -36,14 +31,11 @@ every time you open a new Python interpreter
 (instead of having to reinstall the package each time).
 ```
 $ cd altair/ 
-$ python -m pip install -e .
-```
-
-You can now install the development requirements using
-```
-$ python -m pip install -r requirements_dev.txt
+$ python -m pip install -e '.[dev]'
 ```
 
+'[dev]' indicates that pip should also install the development requirements
+which you can find in `requirements_dev.txt`
 
 ### Creating a Branch
 
@@ -55,14 +47,6 @@ $ git switch -c <branch-name>
 ```
 With this branch checked-out, make the desired changes to the package.
 
-Note that Altair code uses the [black](https://black.readthedocs.io/)
-code formatter and [flake8](https://flake8.pycqa.org/en/latest/) linter
-which you can apply to your modifications by running:
-```
-$ black --diff .  # View changes
-$ black .  # Apply changes
-$ flake8 .  --statistics  # View changes (fix manually)
-```
 
 ### Testing your Changes
 
@@ -74,6 +58,9 @@ which includes a number of tests to validate the correctness of your code:
 $ make test
 ```
 
+This also runs the [black](https://black.readthedocs.io/)
+code formatter and [flake8](https://flake8.pycqa.org/en/latest/) linter.
+
 Study the output of any failed tests and try to fix the issues
 before proceeding to the next section.
 
@@ -98,7 +85,18 @@ automatically shown in the PR.
 Hopefully your PR will be answered in a timely manner and your contribution will
 help others in the future.
 
-## Adding Examples
+## Documentation
+Altair documentation is written in [reStructuredText](http://docutils.sourceforge.net/rst.html)
+and compiled into html pages using [Sphinx](http://www.sphinx-doc.org/en/master/).
+Contributing to the documentation requires some extra dependencies and 
+we have some conventions and plugins that are used to help navigate the docs and 
+generate great Altair visualizations. 
+
+Note that the [Altair website](https://altair-viz.github.io/)
+is only updated when a new version is released so your contribution might not show
+up for a while.
+
+### Adding Examples
 
 We are always interested in new examples contributed from the community.  These
 could be everything from simple one-panel scatter and line plots, to more
@@ -154,7 +152,36 @@ Some additional notes:
   included then it should be referenced by URL, such as `source =
   data.movies.url`. This is to ensure that Altair's automated test suite does
   not depend on availability of external HTTP resources.
-  
-Note that examples shown on the [Altair website](https://altair-viz.github.io/)
-are only updated when a new version is released so your new example might not show
-up there for a while. 
+
+### Building the Documentation Locally
+In addition to the development dependencies mentioned further above,
+you will also need to install the dependencies for the documentation 
+listed in  `docs/requirements.txt`. Note that `geopandas` might require you to first
+install some other dependencies, see [their installation page](https://geopandas.org/en/stable/getting_started/install.html#installation)
+for details.
+
+```
+pip install -r doc/requirements.txt
+```
+
+If you want to build the documentation so it can be published on the [official Altair website](https://altair-viz.github.io), you need to
+additionally install [altair_saver](https://github.com/altair-viz/altair_saver/) and uninstall [vl-convert-python](https://github.com/vega/vl-convert/tree/main/vl-convert-python).
+These packages are used to generate PNG thumbnails for the example gallery. If both are installed, `vl-convert-python` is used by default.
+The reason for this is that `vl-convert-python` cannot create a thumbnail for the `isotype_emoji.py` example,
+which is fine for normal contributions but not when creating a new version of the official documentation.
+
+Once you have all the dependencies, you can build the documentation 
+using various commands defined in the Makefile. 
+From the `doc` folder, you can use `make help` to see all of the available commands
+which control the type of documentation you want to generate.
+
+Usually, you will want to run `make html` which will generate the documentation
+in a sub folder `_build/html`. You can then view the documentation by running:
+
+```
+cd _build/html
+python -m http.server
+```
+
+and then opening `http://localhost:8000` in your browser.
+
diff --git a/Makefile b/Makefile
index 92669bba..bacc76e3 100644
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@ install:
 	python setup.py install
 
 test :
-	black . --check
+	black --diff --color .
 	flake8 . --statistics
 	python -m pytest --pyargs --doctest-modules tests
 
diff --git a/README.md b/README.md
index 3ca11f1a..d4d70cfe 100644
--- a/README.md
+++ b/README.md
@@ -7,10 +7,6 @@
 [![code style black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
 [![JOSS Paper](https://joss.theoj.org/papers/10.21105/joss.01057/status.svg)](https://joss.theoj.org/papers/10.21105/joss.01057)
 [![PyPI - Downloads](https://img.shields.io/pypi/dm/altair)](https://pypi.org/project/altair)
-[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/altair-viz/altair_notebooks/master?urlpath=lab/tree/notebooks/Index.ipynb)
-[![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/altair-viz/altair_notebooks/blob/master/notebooks/Index.ipynb)
-
-[https://altair-viz.github.io](https://altair-viz.github.io)
 
 **Vega-Altair** is a declarative statistical visualization library for Python. With Vega-Altair, you can spend more time understanding your data and its meaning. Vega-Altair's
 API is simple, friendly and consistent and built on top of the powerful
@@ -19,10 +15,13 @@ simplicity produces beautiful and effective visualizations with a minimal amount
 Granger](https://github.com/ellisonbg) in close collaboration with the [UW
 Interactive Data Lab](https://idl.cs.washington.edu/).*
 
-## Vega-Altair Documentation
+## Documentation
+
+See [Vega-Altair's Documentation Site](https://altair-viz.github.io) as well as the [Tutorial Notebooks](https://github.com/altair-viz/altair_notebooks). You can
+run the notebooks directly in your browser by clicking on one of the following badges:
 
-See [Vega-Altair's Documentation Site](https://altair-viz.github.io),
-as well as Vega-Altair's [Tutorial Notebooks](https://github.com/altair-viz/altair_notebooks).
+[![Binder](https://beta.mybinder.org/badge.svg)](https://beta.mybinder.org/v2/gh/altair-viz/altair_notebooks/master)
+[![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/altair-viz/altair_notebooks/blob/master/notebooks/Index.ipynb)
 
 ## Example
 
@@ -76,160 +75,47 @@ points & bars
 
 ![Vega-Altair Visualization Gif](https://raw.githubusercontent.com/altair-viz/altair/master/images/cars_scatter_bar.gif)
 
-
-## Getting your Questions Answered
-
-If you have a question that is not addressed in the documentation, there are several ways to ask:
-
-- open a [Github Issue](https://github.com/altair-viz/altair/issues)
-- post a [StackOverflow Question](https://stackoverflow.com/questions/tagged/altair) (be sure to use the `altair` tag)
-- ask on the [Vega-Altair Google Group](https://groups.google.com/forum/#!forum/altair-viz)
-
-We'll do our best to get your question answered
-
-## A Python API for statistical visualizations
-
-Vega-Altair provides a Python API for building statistical visualizations in a declarative
-manner. By statistical visualization we mean:
-
-* The **data source** is a `DataFrame` that consists of columns of different data types (quantitative, ordinal, nominal and date/time).
-* The `DataFrame` is in a [tidy format](https://vita.had.co.nz/papers/tidy-data.pdf)
-  where the rows correspond to samples and the columns correspond to the observed variables.
-* The data is mapped to the **visual properties** (position, color, size, shape,
-  faceting, etc.) using the group-by data transformation.
-
-The Vega-Altair API contains no actual visualization rendering code but instead
-emits JSON data structures following the
-[Vega-Lite](https://github.com/vega/vega-lite) specification. The resulting
-Vega-Lite JSON data can be rendered in the following user-interfaces:
-
-* [Jupyter Notebook](https://github.com/jupyter/notebook) (by installing [ipyvega](https://github.com/vega/ipyvega)).
-* [JupyterLab](https://github.com/jupyterlab/jupyterlab) (no additional dependencies needed).
-* [nteract](https://github.com/nteract/nteract) (no additional dependencies needed).
-
 ## Features
-
-* Carefully-designed, declarative Python API based on
-  [traitlets](https://github.com/ipython/traitlets).
+* Carefully-designed, declarative Python API.
 * Auto-generated internal Python API that guarantees visualizations are type-checked and
   in full conformance with the [Vega-Lite](https://github.com/vega/vega-lite)
   specification.
-* Display visualizations in the live Jupyter Notebook, JupyterLab, nteract, on GitHub and
-  [nbviewer](https://nbviewer.jupyter.org/).
-* Export visualizations to PNG/SVG images, stand-alone HTML pages and the
+* Display visualizations in JupyterLab, Jupyter Notebook, Visual Studio Code, on GitHub and
+  [nbviewer](https://nbviewer.jupyter.org/), and many more.
+* Export visualizations to various formats such as PNG/SVG images, stand-alone HTML pages and the
 [Online Vega-Lite Editor](https://vega.github.io/editor/#/).
 * Serialize visualizations as JSON files.
-* Explore Vega-Altair with dozens of examples in the [Example Gallery](https://altair-viz.github.io/gallery/index.html)
 
 ## Installation
+Vega-Altair can be installed with:
+```bash
+pip install altair
+```
 
-To use Vega-Altair for visualization, you need to install two sets of tools
-
-1. The core Vega-Altair Package and its dependencies
-
-2. The renderer for the frontend you wish to use (i.e. `Jupyter Notebook`,
-   `JupyterLab`, or `nteract`)
-
-Vega-Altair can be installed with either ``pip`` or with ``conda``.
-For full installation instructions, please see
-https://altair-viz.github.io/getting_started/installation.html
-
-## Example and tutorial notebooks
-
-We maintain a separate Github repository of Jupyter Notebooks that contain an
-interactive tutorial and examples:
-
-https://github.com/altair-viz/altair_notebooks
-
-To launch a live notebook server with those notebook using [binder](https://mybinder.org/) or
-[Colab](https://colab.research.google.com), click on one of the following badges:
-
-[![Binder](https://beta.mybinder.org/badge.svg)](https://beta.mybinder.org/v2/gh/altair-viz/altair_notebooks/master)
-[![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/altair-viz/altair_notebooks/blob/master/notebooks/Index.ipynb)
-
-## Project philosophy
-
-Many excellent plotting libraries exist in Python, including the main ones:
-
-* [Matplotlib](https://matplotlib.org/)
-* [Bokeh](https://bokeh.pydata.org/en/latest/)
-* [Seaborn](https://seaborn.pydata.org/)
-* [Lightning](https://github.com/lightning-viz/lightning)
-* [Plotly](https://plot.ly/)
-* [Pandas built-in plotting](https://pandas.pydata.org/pandas-docs/stable/visualization.html)
-* [HoloViews](https://holoviews.org)
-* [VisPy](https://vispy.org/)
-* [pygg](https://www.github.com/sirrice/pygg)
-
-Each library does a particular set of things well.
-
-### User challenges
-
-However, such a proliferation of options creates great difficulty for users
-as they have to wade through all of these APIs to find which of them is the
-best for the task at hand. None of these libraries are optimized for
-high-level statistical visualization, so users have to assemble their own
-using a mishmash of APIs. For individuals just learning data science, this
-forces them to focus on learning APIs rather than exploring their data.
-
-Another challenge is current plotting APIs require the user to write code,
-even for incidental details of a visualization. This results in an unfortunate
-and unnecessary cognitive burden as the visualization type (histogram,
-scatterplot, etc.) can often be inferred using basic information such as the
-columns of interest and the data types of those columns.
-
-For example, if you are interested in the visualization of two numerical
-columns, a scatterplot is almost certainly a good starting point. If you add
-a categorical column to that, you probably want to encode that column using
-colors or facets. If inferring the visualization proves difficult at times, a
-simple user interface can construct a visualization without any coding.
-[Tableau](https://www.tableau.com/) and the [Interactive Data
-Lab's](https://idl.cs.washington.edu/)
-[Polestar](https://github.com/vega/polestar) and
-[Voyager](https://github.com/vega/voyager) are excellent examples of such UIs.
-
-### Design approach and solution
-
-We believe that these challenges can be addressed without the creation of yet
-another visualization library that has a programmatic API and built-in
-rendering. Vega-Altair's approach to building visualizations uses a layered design
-that leverages the full capabilities of existing visualization libraries:
-
-1. Create a constrained, simple Python API (Vega-Altair) that is purely declarative
-2. Use the API (Vega-Altair) to emit JSON output that follows the Vega-Lite spec
-3. Render that spec using existing visualization libraries
-
-This approach enables users to perform exploratory visualizations with a much
-simpler API initially, pick an appropriate renderer for their usage case, and
-then leverage the full capabilities of that renderer for more advanced plot
-customization.
-
-We realize that a declarative API will necessarily be limited compared to the
-full programmatic APIs of Matplotlib, Bokeh, etc. That is a deliberate design
-choice we feel is needed to simplify the user experience of exploratory
-visualization.
+If you are using the conda package manager, the equivalent is:
+```bash
+conda install altair -c conda-forge
+```
 
-## Development install
+For full installation instructions, please see [the documentation](https://altair-viz.github.io/getting_started/installation.html).
 
-Instructions on how to install Vega-Altair for development can be found in
-[the documentation](https://altair-viz.github.io/getting_started/installation.html).
+## Getting Help
+If you have a question that is not addressed in the documentation, 
+you can post it on [StackOverflow](https://stackoverflow.com/questions/tagged/altair) using the `altair` tag.
+For bugs and feature requests, please open a [Github Issue](https://github.com/altair-viz/altair/issues).
 
-## Testing
+## Development
+You can find the instructions on how to install the package for development in [the documentation](https://altair-viz.github.io/getting_started/installation.html).
 
-To run the test suite you must have [py.test](https://pytest.org/latest/) installed.
 To run the tests, use
-
 ```
-py.test --pyargs altair
+pytest --doctest-modules altair
 ```
-(you can omit the `--pyargs` flag if you are running the tests from a source checkout).
-
-## Feedback and Contribution
 
-See [`CONTRIBUTING.md`](https://github.com/altair-viz/altair/blob/master/CONTRIBUTING.md)
+For information on how to contribute your developments back to the Vega-Altair repository, see
+[`CONTRIBUTING.md`](https://github.com/altair-viz/altair/blob/master/CONTRIBUTING.md)
 
 ## Citing Vega-Altair
-
 [![JOSS Paper](https://joss.theoj.org/papers/10.21105/joss.01057/status.svg)](https://joss.theoj.org/papers/10.21105/joss.01057)
 
 If you use Vega-Altair in academic work, please consider citing https://joss.theoj.org/papers/10.21105/joss.01057 as
@@ -248,7 +134,7 @@ If you use Vega-Altair in academic work, please consider citing https://joss.the
     journal = {Journal of Open Source Software}
 }
 ```
-Please additionally consider citing the [vega-lite](https://vega.github.io/vega-lite/) project, which Vega-Altair is based on: https://dl.acm.org/doi/10.1109/TVCG.2016.2599030
+Please additionally consider citing the [Vega-Lite](https://vega.github.io/vega-lite/) project, which Vega-Altair is based on: https://dl.acm.org/doi/10.1109/TVCG.2016.2599030
 ```bib
 @article{Satyanarayan2017,
     author={Satyanarayan, Arvind and Moritz, Dominik and Wongsuphasawat, Kanit and Heer, Jeffrey},
@@ -261,7 +147,3 @@ Please additionally consider citing the [vega-lite](https://vega.github.io/vega-
     publisher={IEEE}
 } 
 ```
-
-## Whence Vega-Altair?
-
-The Vega project was named after the brightest star in the constellation Lyra; nearby Altair is the [brightest star](https://en.wikipedia.org/wiki/Altair) in the constellation Aquila, and along with Deneb and Vega forms the northern-hemisphere asterism known as the [Summer Triangle](https://en.wikipedia.org/wiki/Summer_Triangle).
diff --git a/RELEASING.md b/RELEASING.md
index 5c9d7cac..c4b7626a 100644
--- a/RELEASING.md
+++ b/RELEASING.md
@@ -1,8 +1,12 @@
-1. Make certain your branch is in sync with head
+1. Create a new virtual environment following the instructions in `CONTRIBUTING.md`. 
+   Make sure to also install all dependencies for the documentation including `altair_saver`
+   and uninstall `vl-convert-python` (this is not needed for normal contributions to the repo, see `CONTRIBUTING.md` for details).
+
+2. Make certain your branch is in sync with head
    
        $ git pull upstream master
    
-2. Do a clean doc build:
+3. Do a clean doc build:
 
        $ cd doc
        $ make clean-all
@@ -12,55 +16,55 @@
    Navigate to http://localhost:8000 and ensure it looks OK (particularly
    do a visual scan of the gallery thumbnails).
 
-3. Make sure changes.rst is up to date for the release: compare against PRs
+4. Make sure changes.rst is up to date for the release: compare against PRs
    merged since the last release & update top heading with release date.
 
-4. Update version to, e.g. 2.0.0
+5. Update version to, e.g. 5.0.0
 
    - in ``altair/__init__.py``
    - in ``doc/conf.py`` (two places)
 
-5. Double-check that all vega-lite/vega/vega-embed versions are up-to-date:
+6. Double-check that all vega-lite/vega/vega-embed versions are up-to-date:
 
    - URLs in ``doc/conf.py``
    - versions in ``altair/vegalite/v5/display.py``
 
-6. Commit change and push to master
+7. Commit change and push to master:
 
        git add . -u
-       git commit -m "MAINT: bump version to 2.0.0"
+       git commit -m "MAINT: bump version to 5.0.0"
        git push upstream master
 
-7. Tag the release:
+8. Tag the release:
 
-       git tag -a v2.0.0 -m "version 2.0.0 release"
+       git tag -a v5.0.0 -m "version 5.0.0 release"
        git push upstream v2.0.0
 
-8. Build source & wheel distributions
+9. Build source & wheel distributions:
 
        rm -r dist build  # clean old builds & distributions
        python setup.py sdist  # create a source distribution
        python setup.py bdist_wheel  # create a universal wheel
 
-9. publish to PyPI (Requires correct PyPI owner permissions)
+10. publish to PyPI (Requires correct PyPI owner permissions):
 
        twine upload dist/*
 
-10. build and publish docs (Requires write-access to altair-viz/altair-viz.github.io)
+11. build and publish docs (Requires write-access to altair-viz/altair-viz.github.io):
 
         cd doc
         make clean-all
         make html
         bash sync_website.sh
 
-11. update version to, e.g. 2.1.0dev
+12. update version to, e.g. 5.1.0dev:
 
     - in ``altair/__init__.py``
     - in ``doc/conf.py`` (two places)
 
-12. add a new changelog entry for the unreleased version:
+13. add a new changelog entry for the unreleased version:
 
-       Version 2.1.0 (unreleased)
+       Version 5.1.0 (unreleased)
        --------------------------
 
        Enhancements
@@ -70,15 +74,15 @@
        Backward-Incompatible Changes
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-13. Commit change and push to master
+14. Commit change and push to master
 
         git add . -u
-        git commit -m "MAINT: bump version to 2.1.0dev"
+        git commit -m "MAINT: bump version to 5.1.0dev"
         git push upstream master
 
-14. Double-check that a conda-forge pull request is generated from the updated
+15. Double-check that a conda-forge pull request is generated from the updated
     pip package by the conda-forge bot (may take up to ~an hour):
     https://github.com/conda-forge/altair-feedstock/pulls
 
-15. Copy changes.rst section into release notes within
+16. Copy changes.rst section into release notes within
     https://github.com/altair-viz/altair/releases/, and publish the release.
diff --git a/altair/utils/display.py b/altair/utils/display.py
index 92d7c783..bcf8232b 100644
--- a/altair/utils/display.py
+++ b/altair/utils/display.py
@@ -4,10 +4,9 @@ import textwrap
 from typing import Callable, Dict
 import uuid
 
-from jsonschema import validate
-
 from .plugin_registry import PluginRegistry
 from .mimebundle import spec_to_mimebundle
+from .schemapi import validate_jsonschema
 
 
 # ==============================================================================
@@ -126,7 +125,7 @@ class Displayable(object):
         # type: () -> None
         """Validate the spec against the schema."""
         schema_dict = json.loads(pkgutil.get_data(*self.schema_path).decode("utf-8"))
-        validate(self.spec, schema_dict)
+        validate_jsonschema(self.spec, schema_dict)
 
     def _repr_mimebundle_(self, include=None, exclude=None):
         """Return a MIME bundle for display in Jupyter frontends."""
diff --git a/altair/utils/schemapi.py b/altair/utils/schemapi.py
index 1cdc2778..2c86b1d2 100644
--- a/altair/utils/schemapi.py
+++ b/altair/utils/schemapi.py
@@ -8,12 +8,13 @@ import textwrap
 from typing import Any
 
 import jsonschema
+import jsonschema.exceptions
 import numpy as np
 import pandas as pd
 
 from altair import vegalite
 
-
+JSONSCHEMA_VALIDATOR = jsonschema.Draft7Validator
 # If DEBUG_MODE is True, then schema objects are converted to dict and
 # validated at creation time. This slows things down, particularly for
 # larger specs, but leads to much more useful tracebacks for the user.
@@ -43,6 +44,24 @@ def debug_mode(arg):
         DEBUG_MODE = original
 
 
+def validate_jsonschema(spec, schema, resolver=None):
+    # We don't use jsonschema.validate as this would validate the schema itself.
+    # Instead, we pass the schema directly to the validator class. This is done for
+    # two reasons: The schema comes from Vega-Lite and is not based on the user
+    # input, therefore there is no need to validate it in the first place. Furthermore,
+    # the "uri-reference" format checker fails for some of the references as URIs in
+    # "$ref" are not encoded,
+    # e.g. '#/definitions/ValueDefWithCondition<MarkPropFieldOrDatumDef,
+    # (Gradient|string|null)>' would be a valid $ref in a Vega-Lite schema but
+    # it is not a valid URI reference due to the characters such as '<'.
+    validator = JSONSCHEMA_VALIDATOR(
+        schema, format_checker=JSONSCHEMA_VALIDATOR.FORMAT_CHECKER, resolver=resolver
+    )
+    error = jsonschema.exceptions.best_match(validator.iter_errors(spec))
+    if error is not None:
+        raise error
+
+
 def _subclasses(cls):
     """Breadth-first sequence of all classes which inherit from cls."""
     seen = set()
@@ -158,7 +177,7 @@ class SchemaBase(object):
     _schema = None
     _rootschema = None
     _class_is_valid_at_instantiation = True
-    _validator = jsonschema.Draft7Validator
+    _validator = JSONSCHEMA_VALIDATOR
 
     def __init__(self, *args, **kwds):
         # Two valid options for initialization, which should be handled by
@@ -448,9 +467,7 @@ class SchemaBase(object):
         if schema is None:
             schema = cls._schema
         resolver = jsonschema.RefResolver.from_schema(cls._rootschema or cls._schema)
-        return jsonschema.validate(
-            instance, schema, cls=cls._validator, resolver=resolver
-        )
+        return validate_jsonschema(instance, schema, resolver=resolver)
 
     @classmethod
     def resolve_references(cls, schema=None):
@@ -469,7 +486,7 @@ class SchemaBase(object):
         value = _todict(value, validate=False, context={})
         props = cls.resolve_references(schema or cls._schema).get("properties", {})
         resolver = jsonschema.RefResolver.from_schema(cls._rootschema or cls._schema)
-        return jsonschema.validate(value, props.get(name, {}), resolver=resolver)
+        return validate_jsonschema(value, props.get(name, {}), resolver=resolver)
 
     def __dir__(self):
         return list(self._kwds.keys())
@@ -563,7 +580,7 @@ class _FromDict(object):
             for possible_schema in schemas:
                 resolver = jsonschema.RefResolver.from_schema(rootschema)
                 try:
-                    jsonschema.validate(dct, possible_schema, resolver=resolver)
+                    validate_jsonschema(dct, possible_schema, resolver=resolver)
                 except jsonschema.ValidationError:
                     continue
                 else:
diff --git a/altair/vegalite/v5/api.py b/altair/vegalite/v5/api.py
index f32ccd63..84a8018d 100644
--- a/altair/vegalite/v5/api.py
+++ b/altair/vegalite/v5/api.py
@@ -107,6 +107,8 @@ def _prepare_data(data, context=None):
 # ------------------------------------------------------------------------
 # Aliases & specializations
 Bin = core.BinParams
+Impute = core.ImputeParams
+Title = core.TitleParams
 
 
 @utils.use_signature(core.LookupData)
diff --git a/doc/getting_started/overview.rst b/doc/getting_started/overview.rst
index 65bab900..90f4ebb4 100644
--- a/doc/getting_started/overview.rst
+++ b/doc/getting_started/overview.rst
@@ -44,3 +44,4 @@ concise grammar.
    installation
    starting
    getting_help
+   project_philosophy
diff --git a/doc/getting_started/project_philosophy.rst b/doc/getting_started/project_philosophy.rst
new file mode 100644
index 00000000..721cd508
--- /dev/null
+++ b/doc/getting_started/project_philosophy.rst
@@ -0,0 +1,76 @@
+Project Philosophy
+==================
+
+Many excellent plotting libraries exist in Python, including:
+
+* `Matplotlib <https://matplotlib.org/>`_
+* `Bokeh <https://bokeh.pydata.org/en/latest/>`_
+* `Seaborn <https://seaborn.pydata.org/>`_
+* `Lightning <http://lightning-viz.org>`_
+* `Plotly <https://plot.ly/>`_
+* `Pandas built-in plotting <https://pandas.pydata.org/pandas-docs/stable/visualization.html>`_
+* `HoloViews <https://holoviews.org>`_
+* `VisPy <https://vispy.org/>`_
+* `pygg <https://www.github.com/sirrice/pygg>`_
+
+Each library does a particular set of things well.
+
+User Challenges
+---------------
+
+However, such a proliferation of options creates great difficulty for users
+as they have to wade through all of these APIs to find which of them is the
+best for the task at hand. None of these libraries are optimized for
+high-level statistical visualization, so users have to assemble their own
+using a mishmash of APIs. For individuals just learning to work with data, this
+forces them to focus on learning APIs rather than exploring their data.
+
+Another challenge is current plotting APIs require the user to write code,
+even for incidental details of a visualization. This results in an unfortunate
+and unnecessary cognitive burden as the visualization type (histogram,
+scatterplot, etc.) can often be inferred using basic information such as the
+columns of interest and the data types of those columns.
+
+For example, if you are interested in the visualization of two numerical
+columns, a scatterplot is almost certainly a good starting point. If you add
+a categorical column to that, you probably want to encode that column using
+colors or facets. If inferring the visualization proves difficult at times, a
+simple user interface can construct a visualization without any coding.
+`Tableau <https://www.tableau.com/>`_ and the `Interactive Data
+Lab's <https://idl.cs.washington.edu/>`_
+`Polestar <https://github.com/vega/polestar>`_ and
+`Voyager <https://github.com/vega/voyager>`_ are excellent examples of such UIs.
+
+Design Approach and Solution
+----------------------------
+
+We believe that these challenges can be addressed without the creation of yet
+another visualization library that has a programmatic API and built-in
+rendering. Vega-Altair's approach to building visualizations uses a layered design
+that leverages the full capabilities of existing visualization libraries:
+
+1. Create a constrained, simple Python API (Vega-Altair) that is purely declarative
+2. Use the API (Vega-Altair) to emit JSON output that follows the Vega-Lite spec
+3. Render that spec using existing visualization libraries
+
+This approach enables users to perform exploratory visualizations with a much
+simpler API initially, pick an appropriate renderer for their usage case, and
+then leverage the full capabilities of that renderer for more advanced plot
+customization.
+
+We realize that a declarative API will necessarily be limited compared to the
+full programmatic APIs of Matplotlib, Bokeh, etc. That is a deliberate design
+choice we feel is needed to simplify the user experience of exploratory
+visualization.
+
+You can find a more detailed comparison between Plotly and Altair in
+`this StackOverflow answer <https://stackoverflow.com/a/66040502>`.
+
+Whence Vega-Altair?
+-------------------
+
+The Vega project was named after the brightest star in the constellation Lyra;
+nearby Altair is the `brightest star <https://en.wikipedia.org/wiki/Altair>`_ 
+in the constellation Aquila, and along with Deneb and Vega forms 
+the northern-hemisphere asterism known as
+the `Summer Triangle <https://en.wikipedia.org/wiki/Summer_Triangle>`_.
\ No newline at end of file
diff --git a/doc/requirements.txt b/doc/requirements.txt
index efefc068..97310dcb 100644
--- a/doc/requirements.txt
+++ b/doc/requirements.txt
@@ -4,4 +4,5 @@ numpydoc
 pillow
 mistune<=0.8.4
 pydata-sphinx-theme
-geopandas
\ No newline at end of file
+geopandas
+vl-convert-python
\ No newline at end of file
diff --git a/tools/schemapi/jsonschema-draft04.json b/tools/schemapi/jsonschema-draft04.json
deleted file mode 100644
index bcbb8474..00000000
--- a/tools/schemapi/jsonschema-draft04.json
+++ /dev/null
@@ -1,149 +0,0 @@
-{
-    "id": "http://json-schema.org/draft-04/schema#",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "description": "Core schema meta-schema",
-    "definitions": {
-        "schemaArray": {
-            "type": "array",
-            "minItems": 1,
-            "items": { "$ref": "#" }
-        },
-        "positiveInteger": {
-            "type": "integer",
-            "minimum": 0
-        },
-        "positiveIntegerDefault0": {
-            "allOf": [ { "$ref": "#/definitions/positiveInteger" }, { "default": 0 } ]
-        },
-        "simpleTypes": {
-            "enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ]
-        },
-        "stringArray": {
-            "type": "array",
-            "items": { "type": "string" },
-            "minItems": 1,
-            "uniqueItems": true
-        }
-    },
-    "type": "object",
-    "properties": {
-        "id": {
-            "type": "string"
-        },
-        "$schema": {
-            "type": "string"
-        },
-        "title": {
-            "type": "string"
-        },
-        "description": {
-            "type": "string"
-        },
-        "default": {},
-        "multipleOf": {
-            "type": "number",
-            "minimum": 0,
-            "exclusiveMinimum": true
-        },
-        "maximum": {
-            "type": "number"
-        },
-        "exclusiveMaximum": {
-            "type": "boolean",
-            "default": false
-        },
-        "minimum": {
-            "type": "number"
-        },
-        "exclusiveMinimum": {
-            "type": "boolean",
-            "default": false
-        },
-        "maxLength": { "$ref": "#/definitions/positiveInteger" },
-        "minLength": { "$ref": "#/definitions/positiveIntegerDefault0" },
-        "pattern": {
-            "type": "string",
-            "format": "regex"
-        },
-        "additionalItems": {
-            "anyOf": [
-                { "type": "boolean" },
-                { "$ref": "#" }
-            ],
-            "default": {}
-        },
-        "items": {
-            "anyOf": [
-                { "$ref": "#" },
-                { "$ref": "#/definitions/schemaArray" }
-            ],
-            "default": {}
-        },
-        "maxItems": { "$ref": "#/definitions/positiveInteger" },
-        "minItems": { "$ref": "#/definitions/positiveIntegerDefault0" },
-        "uniqueItems": {
-            "type": "boolean",
-            "default": false
-        },
-        "maxProperties": { "$ref": "#/definitions/positiveInteger" },
-        "minProperties": { "$ref": "#/definitions/positiveIntegerDefault0" },
-        "required": { "$ref": "#/definitions/stringArray" },
-        "additionalProperties": {
-            "anyOf": [
-                { "type": "boolean" },
-                { "$ref": "#" }
-            ],
-            "default": {}
-        },
-        "definitions": {
-            "type": "object",
-            "additionalProperties": { "$ref": "#" },
-            "default": {}
-        },
-        "properties": {
-            "type": "object",
-            "additionalProperties": { "$ref": "#" },
-            "default": {}
-        },
-        "patternProperties": {
-            "type": "object",
-            "additionalProperties": { "$ref": "#" },
-            "default": {}
-        },
-        "dependencies": {
-            "type": "object",
-            "additionalProperties": {
-                "anyOf": [
-                    { "$ref": "#" },
-                    { "$ref": "#/definitions/stringArray" }
-                ]
-            }
-        },
-        "enum": {
-            "type": "array",
-            "minItems": 1,
-            "uniqueItems": true
-        },
-        "type": {
-            "anyOf": [
-                { "$ref": "#/definitions/simpleTypes" },
-                {
-                    "type": "array",
-                    "items": { "$ref": "#/definitions/simpleTypes" },
-                    "minItems": 1,
-                    "uniqueItems": true
-                }
-            ]
-        },
-        "format": { "type": "string" },
-        "allOf": { "$ref": "#/definitions/schemaArray" },
-        "anyOf": { "$ref": "#/definitions/schemaArray" },
-        "oneOf": { "$ref": "#/definitions/schemaArray" },
-        "not": { "$ref": "#" }
-    },
-    "dependencies": {
-        "exclusiveMaximum": [ "maximum" ],
-        "exclusiveMinimum": [ "minimum" ]
-    },
-    "default": {}
-}
diff --git a/tools/schemapi/schemapi.py b/tools/schemapi/schemapi.py
index a3f9cd3b..e652d2c3 100644
--- a/tools/schemapi/schemapi.py
+++ b/tools/schemapi/schemapi.py
@@ -6,12 +6,13 @@ import textwrap
 from typing import Any
 
 import jsonschema
+import jsonschema.exceptions
 import numpy as np
 import pandas as pd
 
 from altair import vegalite
 
-
+JSONSCHEMA_VALIDATOR = jsonschema.Draft7Validator
 # If DEBUG_MODE is True, then schema objects are converted to dict and
 # validated at creation time. This slows things down, particularly for
 # larger specs, but leads to much more useful tracebacks for the user.
@@ -41,6 +42,24 @@ def debug_mode(arg):
         DEBUG_MODE = original
 
 
+def validate_jsonschema(spec, schema, resolver=None):
+    # We don't use jsonschema.validate as this would validate the schema itself.
+    # Instead, we pass the schema directly to the validator class. This is done for
+    # two reasons: The schema comes from Vega-Lite and is not based on the user
+    # input, therefore there is no need to validate it in the first place. Furthermore,
+    # the "uri-reference" format checker fails for some of the references as URIs in
+    # "$ref" are not encoded,
+    # e.g. '#/definitions/ValueDefWithCondition<MarkPropFieldOrDatumDef,
+    # (Gradient|string|null)>' would be a valid $ref in a Vega-Lite schema but
+    # it is not a valid URI reference due to the characters such as '<'.
+    validator = JSONSCHEMA_VALIDATOR(
+        schema, format_checker=JSONSCHEMA_VALIDATOR.FORMAT_CHECKER, resolver=resolver
+    )
+    error = jsonschema.exceptions.best_match(validator.iter_errors(spec))
+    if error is not None:
+        raise error
+
+
 def _subclasses(cls):
     """Breadth-first sequence of all classes which inherit from cls."""
     seen = set()
@@ -156,7 +175,7 @@ class SchemaBase(object):
     _schema = None
     _rootschema = None
     _class_is_valid_at_instantiation = True
-    _validator = jsonschema.Draft7Validator
+    _validator = JSONSCHEMA_VALIDATOR
 
     def __init__(self, *args, **kwds):
         # Two valid options for initialization, which should be handled by
@@ -446,9 +465,7 @@ class SchemaBase(object):
         if schema is None:
             schema = cls._schema
         resolver = jsonschema.RefResolver.from_schema(cls._rootschema or cls._schema)
-        return jsonschema.validate(
-            instance, schema, cls=cls._validator, resolver=resolver
-        )
+        return validate_jsonschema(instance, schema, resolver=resolver)
 
     @classmethod
     def resolve_references(cls, schema=None):
@@ -467,7 +484,7 @@ class SchemaBase(object):
         value = _todict(value, validate=False, context={})
         props = cls.resolve_references(schema or cls._schema).get("properties", {})
         resolver = jsonschema.RefResolver.from_schema(cls._rootschema or cls._schema)
-        return jsonschema.validate(value, props.get(name, {}), resolver=resolver)
+        return validate_jsonschema(value, props.get(name, {}), resolver=resolver)
 
     def __dir__(self):
         return list(self._kwds.keys())
@@ -561,7 +578,7 @@ class _FromDict(object):
             for possible_schema in schemas:
                 resolver = jsonschema.RefResolver.from_schema(rootschema)
                 try:
-                    jsonschema.validate(dct, possible_schema, resolver=resolver)
+                    validate_jsonschema(dct, possible_schema, resolver=resolver)
                 except jsonschema.ValidationError:
                     continue
                 else:
diff --git a/tools/schemapi/utils.py b/tools/schemapi/utils.py
index 38875ab0..61261773 100644
--- a/tools/schemapi/utils.py
+++ b/tools/schemapi/utils.py
@@ -1,8 +1,6 @@
 """Utilities for working with schemas"""
 
-import json
 import keyword
-import pkgutil
 import re
 import textwrap
 import urllib
@@ -13,12 +11,6 @@ import jsonschema
 EXCLUDE_KEYS = ("definitions", "title", "description", "$schema", "id")
 
 
-def load_metaschema():
-    schema = pkgutil.get_data("schemapi", "jsonschema-draft04.json")
-    schema = schema.decode()
-    return json.loads(schema)
-
-
 def resolve_references(schema, root=None):
     """Resolve References within a JSON schema"""
     resolver = jsonschema.RefResolver.from_schema(root or schema)
@@ -144,7 +136,7 @@ class SchemaProperties(object):
 class SchemaInfo(object):
     """A wrapper for inspecting a JSON schema"""
 
-    def __init__(self, schema, rootschema=None, validate=False):
+    def __init__(self, schema, rootschema=None):
         if hasattr(schema, "_schema"):
             if hasattr(schema, "_rootschema"):
                 schema, rootschema = schema._schema, schema._rootschema
@@ -152,10 +144,6 @@ class SchemaInfo(object):
                 schema, rootschema = schema._schema, schema._schema
         elif not rootschema:
             rootschema = schema
-        if validate:
-            metaschema = load_metaschema()
-            jsonschema.validate(schema, metaschema)
-            jsonschema.validate(rootschema, metaschema)
         self.raw_schema = schema
         self.rootschema = rootschema
         self.schema = resolve_references(schema, rootschema)


Test patch:
diff --git a/tests/vegalite/v5/tests/test_alias.py b/tests/vegalite/v5/tests/test_alias.py
new file mode 100644
index 00000000..b9051f13
--- /dev/null
+++ b/tests/vegalite/v5/tests/test_alias.py
@@ -0,0 +1,21 @@
+import pytest
+
+import altair.vegalite.v5 as alt
+
+
+def test_aliases():
+    """Ensure that any aliases defined in `api.py` aren't colliding with names already defined in `core.py` or `channels.py`."""
+    for alias in ["Bin", "Impute", "Title"]:
+        # this test pass if the alias can resolve to its real name
+        try:
+            getattr(alt, alias)
+        except AttributeError as e:
+            assert False, f"cannot resolve '{alias}':, {e}"
+
+        # this test fails if the alias match a colliding name in core
+        with pytest.raises(AttributeError):
+            getattr(alt.core, alias)
+
+        # this test fails if the alias match a colliding name in channels
+        with pytest.raises(AttributeError):
+            getattr(alt.channels, alias)