Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Adds ThemeConfig (TypedDict) #3536

Open
wants to merge 163 commits into
base: main
Choose a base branch
from

Conversation

dangotbanned
Copy link
Member

@dangotbanned dangotbanned commented Aug 12, 2024

Resolves one item in #3519

Description

This PR aims to improve the UX when authoring a theme.
By utilising TypedDict(s) we can provide a very similar experience to that of writing in Vega Editor, with rich autocompletion and static validation feedback.

Main Additions

Interactions with public API

These classes are entirely isolated from the main alt.___ namespace, but can still be used anywhere a dict|Map annotation is present in existing code.
Currently:

  • The top-level object ThemeConfig is exported to altair.typing
  • All others are accessible via altair.typing.theme.

Using the classes themselves is entirely optional, as can be seen in test_theme.py.
Simply annotating ThemeConfig (and using a static type checker) allows the user to specify a theme using native python types.

Examples

Autocomplete w/ native python types

image

Type checking w/ mixed python|altair types

image

Options for imports

image

@register_theme doc

Default

image

With a registered theme

image

Early POC Demo

These screenshots were taken mid-development

Providing fully nested auto-complete

image

Type checking feedback

image

Tasks

Mostly avoiding use `list` unless properties of it are needed.
Also using `set` comprehensions
…tion`

Provides all existing functionality.
Adds `use_concrete`, for upcoming `TypedDict` changes
- Adapted to new `get_python_type_representation`
- Avoid nested listcomp
- Avoid repeated sorting
- Moved the generic parts to `_generate_sig_args`
Will be adding a docstring with more detail
Handled by `jsonschema_to_python_types`
Hopefully this will mean we can skip adding individual doc pages for each, just reuse the existing ones

vega#3536 (comment)
@dangotbanned dangotbanned enabled auto-merge (squash) September 16, 2024 17:22
@dangotbanned
Copy link
Member Author

This PR blows my mind! 🤯 Really appreciate all the work you put into it, this obviously required going very deep in the VL schema and the code generation and I think the outcome is super helpful for further advancing the UX of themes. Now I really want to write some new themes 😄

I only have some very minor comments. If you feel good with it, I'm ok if you merge it afterwards!

Thanks so much for the review @binste! (and helping me get unstuck midway through)

Hopefully this will make it easier to explore some of your points in #3519 (comment) once we've merged

I'll leave this open for a few hours in case you had any thoughts on #3536 (comment) - otherwise I'll follow this up with another PR as mentioned

@mattijn
Copy link
Contributor

mattijn commented Sep 16, 2024

Thanks for all the work. A concise PR description with an explanation of the what/why/how would really help future readers coming to this PR.
This description is also helpful for making the release notes better. Thanks again!

@dangotbanned
Copy link
Member Author

Thanks for all the work. A concise PR description with an explanation of the what/why/how would really help future readers coming to this PR. This description is also helpful for making the release notes better. Thanks again!

No worries, will work on that now thanks @mattijn

@dangotbanned dangotbanned marked this pull request as draft September 16, 2024 17:48
@dangotbanned dangotbanned marked this pull request as ready for review September 16, 2024 18:36
@dangotbanned
Copy link
Member Author

@mattijn just updated the description, hopefully you (and others) find it helpful 😄

@dangotbanned dangotbanned enabled auto-merge (squash) September 16, 2024 18:38
@mattijn
Copy link
Contributor

mattijn commented Sep 16, 2024

Thanks! Can you add also how this feature is being used? Do we want users to import the following?

import altair.vegalite.v5.schema._config as theme

And

from altair.vegalite.v5.schema._config import ThemeConfig

And then? I'd love to have a brief description that explains how a new user can start using this feature. It would be great if you could provide a simple example that highlights just one feature controlled by the ThemeConfig. Thanks again for all your hard work!

@dangotbanned dangotbanned marked this pull request as draft September 16, 2024 19:55
@joelostblom
Copy link
Contributor

Thanks for expanding on the PR description, that was helpful for me to appreciate just how much this PR improves the experience of defining custom themes, wow! In line with what Mattijn suggested, it would be great to update the custom theme section of the docs to use this approach and mention the autocompletion behavior.

The usage I described in the description was not actually possible:

>- The top-level object `ThemeConfig` is exported to `altair.typing`> - All others are accessible via `altair.typing.theme`.

This resolves the `ModuleNotFoundError` that would get raised when trying this
@dangotbanned
Copy link
Member Author

dangotbanned commented Sep 16, 2024

Thanks! Can you add also how this feature is being used? Do we want users to import the following?

import altair.vegalite.v5.schema._config as theme

Correction (1)

from altair.typing import theme

Usage

from altair.typing import ThemeConfig, theme

custom_theme = ThemeConfig(
    config=theme.ConfigKwds(
        axis=theme.AxisConfigKwds(grid=True, labelFont="system-ui"),
        circle=theme.MarkConfigKwds(fill="purple"),
    )
)
custom_theme

And

from altair.vegalite.v5.schema._config import ThemeConfig

Correction (2)

from altair.typing import ThemeConfig

And then? I'd love to have a brief description that explains how a new user can start using this feature. It would be great if you could provide a simple example that highlights just one feature controlled by the ThemeConfig. Thanks again for all your hard work!

Reading this made me spot a bug with the import behavior, just fixed in d4bd6db (#3536)

For reference, @register_theme has an example of the intended import path

https://github.com/dangotbanned/altair/blob/6e4af95becc8ff9be033535d45ce3db9b2c749a3/altair/vegalite/v5/theme.py#L94-L135

@dangotbanned
Copy link
Member Author

dangotbanned commented Sep 16, 2024

@joelostblom @mattijn thanks for your comments!

I'll be updating the description with more examples tomorrow, but hopefully you get a rough idea with d4bd6db (#3536)

it would be great to update the custom theme section of the docs to use this approach and mention the autocompletion behavior.

Absolutely agree, I added that to the list in #3519 (comment) an hour ago - I think it will make the remaining items much easier

@mattijn
Copy link
Contributor

mattijn commented Sep 16, 2024

Awesome! Looking forward to! Another question I have, why is this ThemeConfig not imported to the root level of Altair? It sounds like a top level object to me. Can you elaborate on this? With feature comes questions😀. Thanks!

@dangotbanned
Copy link
Member Author

dangotbanned commented Sep 16, 2024

Awesome! Looking forward to! Another question I have, why is this ThemeConfig not imported to the root level of Altair? It sounds like a top level object to me. Can you elaborate on this? With feature comes questions😀. Thanks!

For v6 I would agree, but right now I think this is much easier to find. (#2918)

I can't seem to find the thread, but I suggested to @binste having a small number of ...Kwds available in altair.typing - with the rest in altair.typing.theme.

With the current layout, I think this reinforces the relationship between ThemeConfig -> ...Kwds and that ThemeConfig is the entry point.

I'm not sure if all that made sense, if not apologies, I was supposed to call it a day already 😅

@dangotbanned dangotbanned marked this pull request as ready for review September 17, 2024 09:30
@dangotbanned dangotbanned enabled auto-merge (squash) September 17, 2024 09:30
@dangotbanned
Copy link
Member Author

dangotbanned commented Sep 18, 2024

@mattijn @joelostblom

FYI the conversation marked as unresolved is actually resolved.

I haven't updated the status of it yet, to block merging until you've both seen the updated description

Otherwise this should be ready to merge 👍

@joelostblom
Copy link
Contributor

I don't have much to comment on the changes to the import, so will refer to @mattijn for that.

On first look, the class based syntax looks maybe a bit verbose:

image

So I would probably opt for the combination with dicts myself:

image

But maybe I will change my mind when I try them; it's great that both exist and support autocompletion!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants