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

Allow users to pass vega_options #10

Merged
merged 11 commits into from
Oct 7, 2024
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,18 @@ def generate_chart():

This will return a `Div` that contains your rendered altair chart.

### Custom Vega options

Under the hood, `altair2fasthtml` makes a call to the `vegaEmbed` javascript library. The `vegaEmbed` javascript library accepts [various options](https://github.com/vega/vega-embed?tab=readme-ov-file#options) that alter the rendered chart. You can optionally pass custom Vega options like so:

```python
# To render your chart as a svg instead of the default canvas element
altair2fasthtml(chart, vega_options={"renderer":"svg"})

# To render your chart with action links turned on (by default action links are disabled)
altair2fasthtml(chart, vega_options={"actions":True})
```

## Roadmap

This repository is originally meant to be simple helper, but if there are more advanced use-cases to consider I will gladly consider them. Please start a conversation by opening up an issue before starting a PR though.
35 changes: 28 additions & 7 deletions fh_altair/__init__.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,43 @@
import json
from uuid import uuid4
from fasthtml.common import Div, Script

from fasthtml.common import Div, Script

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")
Script(src="https://cdn.jsdelivr.net/npm/vega-embed@6"),
]


def altair2fasthml(chart):
"""This is the version with bad spelling"""
print("You have imported `altair2fasthml` which is a misspelled function. Sorry about that! It will be deprecated in favour of `altair2fasthtml` in a later release.")
print(
"You have imported `altair2fasthml` which is a misspelled function. Sorry about that! It will be deprecated in favour of `altair2fasthtml` in a later release."
)
return altair2fasthtml(chart)


def altair2fasthtml(chart):
def altair2fasthtml(chart, vega_options={"actions": False}):
koaning marked this conversation as resolved.
Show resolved Hide resolved
"""Convert an Altair chart to a FastHTML FT component

Parameters
----------
chart : altair.Chart
An Altair chart
vega_options : dict, optional
Options dictionary passed to the vegaEmbed function, by default {"actions": False}
which hides the Vega action menu.

Returns
-------
fastcore.xml.FT
A FastHTML FT component containing both the target div and embedding script

"""
jsonstr = chart.to_json()
chart_id = f'uniq-{uuid4()}'
settings = "{actions: false}"
return Div(Script(f"vegaEmbed('#{chart_id}', {jsonstr}, {settings});"), id=chart_id)
chart_id = f"uniq-{uuid4()}"
return Div(
Script(f"vegaEmbed('#{chart_id}', {jsonstr}, {json.dumps(vega_options)});"),
id=chart_id,
)
40 changes: 35 additions & 5 deletions tests/test_basics.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,38 @@
import pandas as pd
import altair as alt
import pandas as pd
import pytest
from fasthtml.common import to_xml

from fh_altair import altair2fasthtml

def test_no_err():
pltr = pd.DataFrame({'y': [1, 2, 3, 2], 'x': [3, 1, 2, 4]})
chart = alt.Chart(pltr).mark_line().encode(x='x', y='y').properties(width=400, height=200)
return altair2fasthtml(chart)

@pytest.fixture
def sample_chart():
pltr = pd.DataFrame({"y": [1, 2, 3, 2], "x": [3, 1, 2, 4]})
chart = (
alt.Chart(pltr)
.mark_line()
.encode(x="x", y="y")
.properties(width=400, height=200)
)
return chart


def test_no_err(sample_chart):
return altair2fasthtml(sample_chart)


@pytest.mark.parametrize(
"renderer,actions",
[("svg", True), ("svg", False), ("canvas", True), ("canvas", False)],
)
def test_vega_options(sample_chart, renderer, actions):
vega_embed_call = to_xml(
altair2fasthtml(
sample_chart, vega_options={"renderer": renderer, "actions": actions}
)
)
assert (
f'"renderer": "{renderer}", "actions": {str(actions).lower()}'
in vega_embed_call
)
Loading