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

Responsive sized charts #9

Closed
ddanieltan opened this issue Sep 30, 2024 · 3 comments
Closed

Responsive sized charts #9

ddanieltan opened this issue Sep 30, 2024 · 3 comments

Comments

@ddanieltan
Copy link
Contributor

ddanieltan commented Sep 30, 2024

Issue: The current altair chart does not resize responsively with the Div().

I found this discussion in Altair's issues that describe a fix by adding some CSS for the vega-embed class. vega/altair#2867

My suggestion to incorporate this fix:

  1. We add the additional CSS into altair_headers
  2. In altair2fasthtml(), we default to include .properties(width="container", height=240)

This allows the chart to resize responsively based on the width of it parent container, with a fixed height. I experimented with setting both width and height to "responsive" but I did not get the desired result.

Here's an example FastHTML app that reproduces this responsively sized chart

import altair as alt
from fasthtml.common import *
from vega_datasets import data

css = Style("""
.vega-embed {
  width: 100%;
  display: flex;
}
.vega-embed details,
.vega-embed details summary {
  position: relative;
}
""")

altair_headers = [
    Script(src="https://cdn.jsdelivr.net/npm/vega@5"),
    Script(src="https://cdn.jsdelivr.net/npm/vega-lite@5"),
    Script(src="https://cdn.jsdelivr.net/npm/vega-embed@6"),
]

hdrs = (
    picolink,
    css,
    altair_headers,
)

app, rt = fast_app(live=True, hdrs=hdrs, htmlkw={"data-theme": "light"})


def chart():
    source = data.seattle_weather()
    brush = alt.selection_interval(encodings=["x"])

    bars = (
        alt.Chart()
        .mark_bar()
        .encode(
            x="month(date):O",
            y="mean(precipitation):Q",
            opacity=alt.condition(brush, alt.OpacityValue(1), alt.OpacityValue(0.7)),
        )
        .add_params(brush)
    )

    line = (
        alt.Chart()
        .mark_rule(color="firebrick")
        .encode(y="mean(precipitation):Q", size=alt.SizeValue(3))
        .transform_filter(brush)
    )

    return alt.layer(bars, line, data=source)


def altair2html(chart):
    jsonstr = chart.properties(width="container", height=240).to_json()
    chart_id = f"uniq-{1}"
    settings = "{actions: false}"
    return Div(Script(f"vegaEmbed('#{chart_id}', {jsonstr}, {settings});"), id=chart_id)


@rt("/")
def get():
    return Title("Responsive Altair"), Container(
        altair2html(chart()),
    )


serve()

Happy to submit a PR if you like the idea

@koaning
Copy link
Owner

koaning commented Oct 1, 2024

Ah nice, this was on my mental to-do list for a bit so it is nice to see folks mentioning the same need.

I am wondering what the simplest solution might be for folks who know altair but not the vega ecosystem. I would for sure love a PR, but what do you link about adding an argument to the altair2html function. Something like:

def altair2html(chart, full_width=True, full_height=False):
   ...

This way the end user needs to know less but can still get the chart to render the way they like and we might be able to handle all that is needed internally.

@ddanieltan
Copy link
Contributor Author

folks who know altair but not the vega ecosystem

I think I belong in that category 😅

I like your suggestion but I do have an issue trying to implement responsive height. Thus far, I can only get responsive width to work. Here are some screenshots for illustration.

Basic chart without size params
image

Chart with width=container fills width of container
image

But chart with height=container behaves unexpectedly
image

@koaning
Copy link
Owner

koaning commented Oct 1, 2024

That's fine, lets drop the height. My thinking for the height was for consistently mostly, but it is fair to assume most people are interested in the width.

This was referenced Oct 3, 2024
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

No branches or pull requests

2 participants