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: Support datetime.(date|datetime) as a SchemaBase parameter #3653

Merged
merged 18 commits into from
Oct 25, 2024

Conversation

dangotbanned
Copy link
Member

@dangotbanned dangotbanned commented Oct 22, 2024

Closes #3651

Example

This is now a working solution for #3643.

No user conversions, or dependency on pandas/polars required:

Code block

from datetime import date

import altair as alt
from vega_datasets import data

source = data.sp500.url

# Create a brush (interval) selection with initial range
brush = alt.selection_interval(
    encodings=["x"], value={"x": (date(2005, 1, 1), date(2009, 1, 1))}
)

base = (
    alt.Chart(source, width=600, height=200).mark_area().encode(x="date:T", y="price:Q")
)
upper = base.encode(alt.X("date:T").scale(domain=brush))
lower = base.properties(height=60).add_params(brush)
chart = upper & lower
chart

Screenshot

image

Schema output

{'config': {'view': {'continuousWidth': 300, 'continuousHeight': 300}},
 'vconcat': [{'mark': {'type': 'area'},
   'encoding': {'x': {'field': 'date',
     'scale': {'domain': {'param': 'param_9'}},
     'type': 'temporal'},
    'y': {'field': 'price', 'type': 'quantitative'}},
   'height': 200,
   'width': 600},
  {'mark': {'type': 'area'},
   'encoding': {'x': {'field': 'date', 'type': 'temporal'},
    'y': {'field': 'price', 'type': 'quantitative'}},
   'height': 60,
   'name': 'view_3',
   'width': 600}],
 'data': {'url': 'https://cdn.jsdelivr.net/npm/[email protected]/data/sp500.csv'},
 'params': [{'name': 'param_9',
   'select': {'type': 'interval', 'encodings': ['x']},
   'value': {'x': [{'year': 2005, 'month': 1, 'date': 1},
     {'year': 2009, 'month': 1, 'date': 1}]},
   'views': ['view_3']}],
 '$schema': 'https://vega.github.io/schema/vega-lite/v5.20.1.json'}

Typing Examples

Utilizing #3656, and making some progress towards resolving #3643 - these functions now have much more useful annotations.

This wasn't straightforward to piece together, but the types (and their docs) are informed by these sources:

alt.selection_interval

2024-10-24.15-37-04.mp4

alt.selection_point

2024-10-24.15-46-02.mp4

Tasks

  • Handle conversion from datetime.(date|datetime) -> core.DateTime
  • Update generated annotations
  • Update api.py annotations

The [vega-lite docs](https://vega.github.io/vega-lite/docs/datetime.html) don't mention the `utc` property - but this restricts us to `utc` or `None`
Annotation support will be complete once `mypy` starts complaining that these comments are unused
Adds two tests with "fake" utc timezones
- Tentative
- Copied from `core.SelectionParameter`
dangotbanned added a commit that referenced this pull request Oct 23, 2024
The doc stated that `None` would appear after builtins, but any builtin with a length greater than 4 appeared after.

The issue is not new, but became more apparent to me while writing #3653 (comment)
This was incomplete as it didn't include `None`, but was serving the same purpose as the generated alias
Need to fix this, but adding this first to demonstrate the issue.
Currently the way I've typed it prevents using different types for each encoding.

The goal is for each encoding to restrict types independently.
E.g. here `x` is **only** `date`, `y` is **only** `float`
@dangotbanned dangotbanned marked this pull request as ready for review October 24, 2024 14:56
@dangotbanned
Copy link
Member Author

dangotbanned commented Oct 24, 2024

@dsmedia I'm hoping this PR will make it easier to resolve #3643 for you 😅

Not sure how much of the typing-oriented parts will come across well.
However, the issue you raised identified a few pain points to me:

  • Using dates within parameters was not trivial
  • altair had no understanding of https://docs.python.org/3/library/datetime.html
  • Knowing what you can provide as initial values for selection_point, selection_interval was very difficult to find

Once this is merged I definitely want to look at how we can demonstrate this better throughout the docs.

Thank you for introducing me to this rabbit hole

@mattijn
Copy link
Contributor

mattijn commented Oct 25, 2024

Thanks! I tested this with datetime like:

import datetime

dt_values = [datetime.date(2005, 1, 1), datetime.date(2009, 1, 1)] 

in this example:

import altair as alt
from vega_datasets import data
import datetime

dt_values = [datetime.date(2005, 1, 1), datetime.date(2009, 1, 1)]

source = data.sp500.url

brush = alt.selection_interval(
    encodings=["x"], 
    value={"x": dt_values},
    mark=alt.BrushConfig(fill="#fdbb84", fillOpacity=0.5, stroke="#e34a33", strokeWidth=2),
)

base = alt.Chart(source).mark_area().encode(
    x="date:T", 
    y="price:Q",
).properties(width=600)

upper = base.encode(
    x=alt.X("date:T").scale(domain=brush)
).properties(height=200)

lower = base.encode(
).add_params(brush).properties(height=60)

upper & lower

And that works good:

image

I also tried:

import polars as pl
import pandas as pd

pd_values = [pd.Timestamp('2005-01-01'), pd.Timestamp('2009-01-01')]
pl_values = [pl.date(2005, 1, 1), pl.date(2005, 1, 1)]

But that didn't work. when using pd_values I got an empty chart for the upper and when using pl_values it gave me a SchemaValidationError:

Error 1: '2005.dt.datetime([1, 1, 0, 0, 0, 0, String(raise)]).strict_cast(Date).alias("date")' is an invalid value for `0`. Valid values are of type 'boolean', 'number', 'string', or 'object'.

I know that these might be out of scope of this PR, but just trying anyways.

Btw, using the alt.BrushConfig() for mark within alt.selection_interval() (as is used here in the docs too: https://altair-viz.github.io/user_guide/interactions.html#parameter-composition) gives me an Pylance Error stating:

Argument of type "BrushConfig" cannot be assigned to parameter "mark" of type "Optional[Mark]" in function "selection_interval"
  Type "BrushConfig" is not assignable to type "Optional[Mark]"
    "BrushConfig" is not assignable to "Mark"
    "BrushConfig" is not assignable to "UndefinedType"

@dangotbanned
Copy link
Member Author

Thanks! I tested this with datetime like:

import datetime

dt_values = [datetime.date(2005, 1, 1), datetime.date(2009, 1, 1)] 

in this example:
...
And that works good
...

Thanks for trying these out @mattijn

I also tried:

import polars as pl
import pandas as pd

pd_values = [pd.Timestamp('2005-01-01'), pd.Timestamp('2009-01-01')]
pl_values = [pl.date(2005, 1, 1), pl.date(2005, 1, 1)]

But that didn't work. when using pd_values I got an empty chart for the upper and when using pl_values it gave me a SchemaValidationError:

Error 1: '2005.dt.datetime([1, 1, 0, 0, 0, 0, String(raise)]).strict_cast(Date).alias("date")' is an invalid value for `0`. Valid values are of type 'boolean', 'number', 'string', or 'object'.

I know that these might be out of scope of this PR, but just trying anyways.

Keeping things simple for now by only supporting stdlib, so yeah those would be out of scope (for now).
Definitely something I thought about while working on this though!

It seems nw.to_py_scalar() would be the right tool (docs, code)

We can always widen the support in a follow up PR?

@dangotbanned
Copy link
Member Author

Btw, using the alt.BrushConfig() for mark within alt.selection_interval() (as is used here in the docs too: altair-viz.github.io/user_guide/interactions.html#parameter-composition) gives me an Pylance Error stating:

Argument of type "BrushConfig" cannot be assigned to parameter "mark" of type "Optional[Mark]" in function "selection_interval"
  Type "BrushConfig" is not assignable to type "Optional[Mark]"
    "BrushConfig" is not assignable to "Mark"
    "BrushConfig" is not assignable to "UndefinedType"

Yeah I encountered that as well while working on #3544.
I'm not sure if I changed anything there or ignored it since we don't type check .rst - but I did find it odd

@mattijn
Copy link
Contributor

mattijn commented Oct 25, 2024

Widen the support in a follow up PR sounds good.

Out of curiosity: is the BrushConfig themable?

@dangotbanned
Copy link
Member Author

Widen the support in a follow up PR sounds good.

Out of curiosity: is the BrushConfig themable?

Do you mean can this be set within a theme?

If so, then I would say yes if there is a BrushConfigKwds in v5.schema._config.
I'll have look later today

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.

Support datetime.(date|datetime) as a SchemaBase parameter
2 participants