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

Include helper function to test chart equality? #3590

Open
joelostblom opened this issue Sep 13, 2024 · 2 comments
Open

Include helper function to test chart equality? #3590

joelostblom opened this issue Sep 13, 2024 · 2 comments

Comments

@joelostblom
Copy link
Contributor

joelostblom commented Sep 13, 2024

What is your suggestion?

Would it be useful to have the equivalent of pandas assert_frame_equal for Altair charts? I was drafting a function for this to use when grading student submissions and thought maybe it would be beneficial to have more widely available.

Example usage:

chart1 = alt.Chart("data.csv").mark_point().encode(x="A:Q", y="B:Q")
chart2 = alt.Chart("data.csv").mark_point().encode(x="A:Q", y="C:Q")

assert_chart_equal(chart1, chart2)
AssertionError: Value mismatch at 'encoding.y.field': B != C

and

assert_chart_equal(chart1, chart2.mark_point(color="grey"))
AssertionError: Key mismatch: 'mark.color' was unexpected.
Function draft

This could be extended to e.g. optionally exclude keys from comparisons (such as the data/datasets which should probably be excluded by default).

import altair as alt


def assert_chart_equal(expected, actual):
    expected_dict = expected.to_dict()
    actual_dict = actual.to_dict()
    assert_dict_equal(expected_dict, actual_dict)


def assert_dict_equal(expected_dict, actual_dict, path=""):
    # Check all keys in dict1
    for key in expected_dict:
        if key not in actual_dict:
            raise AssertionError(
                f"Key mismatch: '{path + key}' was expected, but not found."
            )
        else:
            # If both values are dictionaries, recurse into them
            if isinstance(expected_dict[key], dict) and isinstance(
                actual_dict[key], dict
            ):
                assert_dict_equal(
                    expected_dict[key], actual_dict[key], path + key + "."
                )
            # Compare the values
            elif expected_dict[key] != actual_dict[key]:
                raise AssertionError(
                    f"Value mismatch at '{path + key}': {expected_dict[key]} != {actual_dict[key]}"
                )

    # Check for any extra keys in dict2
    for key in actual_dict:
        if key not in expected_dict:
            raise AssertionError(f"Key mismatch: '{path + key}' was unexpected.")

Have you considered any alternative solutions?

If we don't see a reason to include this in the main library, I can put it in altair ally, although it wouldn't be as visible or easy to access there.

There are already some packages that assert equality of dictionaries and json specs (e.g. deepdiff), but they don't have that easy to understand error messages and seem like unnecessary dependencies to take on.

@binste
Copy link
Contributor

binste commented Sep 16, 2024

This would be very handy! One issue will be the global counter for parameter names, see #3416 where this came up for Streamlit. See here how they solved it on their side.

@mattijn
Copy link
Contributor

mattijn commented Sep 26, 2024

Interesting suggestion! Where will these proposed functions be located? Within eg a new module like altair.testing?

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

No branches or pull requests

3 participants