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

Various fixes to support updated Taxi Dashboard example #262

Merged
merged 16 commits into from
Mar 18, 2023

Conversation

jonmmease
Copy link
Collaborator

I'm working on a new version of the NYC Taxi Dashboard example. To improve the experience of zooming in on the pickup location view, I want to bind the bin extent to the axis scale. e.g.

pickup_chart = base.mark_rect().encode(
    x=alt.X(
        "pickup_x:Q",
        bin=alt.Bin(maxbins=width_bins, extent=scales),
        scale=alt.Scale(domain=x_domain),
    ),
    ...
)

This small change uncovered a whole slew of issues, mostly related to signals that have an initial state of undefined.

Here's a full example, based on the new DuckDB connection with an external DuckDB table:

import duckdb
import vegafusion as vf
import altair as alt

# Create DuckDB connection and set as the acive VegaFusion connection
conn = duckdb.connect()
vf.runtime.set_connection(conn)

# Read parquet file
rel = conn.read_parquet("./nyc_taxi.parquet")

# Clean data and build view named "taxi"
rel.query("tbl", """
    select * from tbl where tip_amount < 100
""").to_view("taxi")

# Build data URL referncing the taxi DuckDB table
source = "table://taxi"

# Initial domain values for the pickup heatmap
x_domain = [-8.243204e+06, -8.226511e+06]
y_domain = [4.968192e+06, 4.982886e+06]

width_bins = 180
height_bins = 180

width = 400
height = 400

# Build chart
base = alt.Chart(source, width=width, height=height).transform_calculate(
    pickup_hour="utchours(datum.tpep_pickup_datetime)",
    pickup_day="day(datum.tpep_pickup_datetime)",
    tip_perc="datum.tip_amount",
).transform_filter(
    "datum.tip_perc < 100"
)

scales = alt.selection_interval(
    name="pickup_scales",
    bind='scales',
    # fields=["pickup_x", "pickup_y"],
    on="[mousedown[event.altKey], window:mouseup] > window:mousemove![event.altKey]",
    translate="[mousedown[event.altKey], window:mouseup] > window:mousemove![event.altKey]",
    zoom="wheel![event.altKey]"
)

pickup_selection = alt.selection_interval(
    on="[mousedown[!event.altKey], window:mouseup] > window:mousemove![!event.altKey]",
    translate="[mousedown[!event.altKey], window:mouseup] > window:mousemove![!event.altKey]",
    zoom="wheel![!event.altKey]",
)

distance_selection = alt.selection_interval(encodings=["x"])
day_hour_selection = alt.selection_interval()

# Distance
distance_chart = base.mark_bar().encode(
    x=alt.X("trip_distance:Q", bin=alt.Bin(maxbins=20, extent=[0, 12])),
    y="count()"
).add_selection(
    distance_selection
).transform_filter(
    {"and": [
        pickup_selection,
        day_hour_selection
    ]}
)

# Pickup
pickup_chart = base.mark_rect().encode(
    x=alt.X(
        "pickup_x:Q",
        bin=alt.Bin(maxbins=width_bins, extent=scales),
        scale=alt.Scale(domain=x_domain),
        axis=alt.Axis(labels=False, ticks=False)
    ),
    y=alt.Y(
        "pickup_y:Q",
        bin=alt.Bin(maxbins=height_bins, extent=scales),
        scale=alt.Scale(domain=y_domain),
        axis=alt.Axis(labels=False, ticks=False),
    ),
    opacity=alt.Opacity("count():Q", scale=alt.Scale(type="log", range=[0.5, 1.0]), legend=None),
    # color=alt.value("steelblue")
    color=alt.Color("count():Q", scale=alt.Scale(type="log", scheme="purpleblue", reverse=False), legend=None)
).add_selection(
    scales
).add_selection(
    pickup_selection
).transform_filter(
    {"and": [
        scales,
        distance_selection,
        day_hour_selection
    ]}
)

# Tip percentage
tip_perc_chart = base.mark_rect().encode(
    x=alt.X(
        "pickup_day:O", 
        scale=alt.Scale(domain=[1, 2, 3, 4, 5, 6, 0]),
        axis=alt.Axis(labelExpr="datum.label==1 ? 'Mon': datum.label==0? 'Sun': ''")
    ),
    y=alt.Y("pickup_hour:O"),
    color=alt.Color(
        'mean(tip_perc):Q', 
        scale=alt.Scale(type="linear"),
        legend=alt.Legend(title="Tip Ratio")
    ),
    opacity=alt.condition(day_hour_selection, alt.value(1.0), alt.value(0.3))
).properties(
    width=120
).add_selection(
    day_hour_selection
).transform_filter(
    {"and": [
        pickup_selection,
        distance_selection
    ]}
)

layout = (
    distance_chart 
    | pickup_chart 
    | tip_perc_chart
).resolve_scale(
    color="independent"
)

widget = vf.jupyter.VegaFusionWidget(
    layout, 
    debounce_max_wait=400,
    debounce_wait=200,
)
widget
Screen.Recording.2023-03-18.at.11.48.12.AM.mov

The parquet file is available from https://vegafusion-datasets.s3.amazonaws.com/datashader/nyc_taxi.parquet

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

Successfully merging this pull request may close these issues.

1 participant