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

Support Vizzu data filter #51

Open
simzer opened this issue Mar 7, 2022 · 12 comments
Open

Support Vizzu data filter #51

simzer opened this issue Mar 7, 2022 · 12 comments

Comments

@simzer
Copy link
Member

simzer commented Mar 7, 2022

Data filter can be specified for Vizzu on the JS API as a JS function:

chart.animate({ data: { filter: record => expression ) }});

where data series can be referenced through the record object, e.g.:

record => { return record["foo"] == "blabla" || record["baz"] > 5; } 

It would be good to have two possibilities to define this filter on the ipyvizzu API

  • Simple solution, supplying the JS expression in a string:

    Python:

    filter = JSExpression("string-of-JS-code")

    where ipyvizzu should generate the following JS code:
    JS:

    filter: record => { return (string-of-JS-code); }

    e.g.:

    Python:

    filter = JSExpression("record['foo'] == 'blabla' || record['baz'] > 5")

    =>
    JS:

    filter: record => { return record['foo'] == 'blabla' || record['baz'] > 5; }
  • Through Python wrapper object with overloaded operators building the js code under the hood.
    Python:

    filter = Series("foo") == "blabla" || Series("baz" > 5)

    where ipyvizzu should generate the following:
    JS:

    filter: record => { return record["foo"] == "blabla" || record["baz"] > 5; }

    Operators, which should be supported:
    ==, !=, <, <=, >=, >, ||, &&

@simzer
Copy link
Member Author

simzer commented Mar 7, 2022

@nyirog Could you please check this proposal? Thanks!

@veghdev veghdev added the enhancement New feature or request label Mar 8, 2022
@veghdev veghdev added this to the 0.5.0 milestone Mar 8, 2022
@nyirog
Copy link
Collaborator

nyirog commented Mar 8, 2022

The JS expression as string would be easy to implement. But it would be good to detect syntax error. If the vizzu chart would have an on_failure callback hook then we could report the syntax error back to the user. Or we could evaluate the filter function on python side for syntax check (e.g.: js2py).

Filter("record['foo'] == 'blabla' || record['baz'] > 5")

The operator overload looks nice, but how do you describe parentheses?

Filter(Record("foo") == "blabla" | Record("baz") > 5)

How about some dot snake:

Filter(Record("foo").eq("blabla").or(Record("baz").gt(5)))

@simzer
Copy link
Member Author

simzer commented Mar 8, 2022

The JS interpreter would fail on syntax error before vizzu can even receive the faulty filter function. The error will be printed on the js console log. If it is not enough, we could check the syntax on the Python side.

About the operator overload solution:
I don't think we should describe parentheses if each operator generates the string this way:
A && B => "(A && B)"
This way the parenthesis nesting in the generated string will follow the execution order of the pyton code, so it will be the same as in the python code:

(A && B) && C => "((A && B) && C)"
A && (B && C) => "(A && (B && C))"

@nyirog
Copy link
Collaborator

nyirog commented Mar 9, 2022

Of course the user defined parentheses would more practical if we would support negation. But we might be good with python side parentheses if the overloaded operators would accept scalar values (int, str, ...) and Record instances.

For example in Record.__eq_(self, other) other could be scalar or Record and the Record.__eq__ would return with a Record instance so the expression could be chained.

Should we support comparition between record fields?

Record("foo") < `Record("bar")

Should we support basic arithmetics?

Record("foo") < Record("bar") + 5

@simzer
Copy link
Member Author

simzer commented Mar 9, 2022

The far most frequent use case is comparing dimension values to strings, so the most important operators to support would be ==, !=, &&, ||.
Comparison of record fields with each other is nice to have, and if it's not too complicated, it would be good to support basic arithmetic as well.

@veghdev veghdev modified the milestones: 0.5.0, 0.6.0 Mar 12, 2022
@veghdev veghdev self-assigned this Mar 14, 2022
@veghdev veghdev closed this as completed Mar 16, 2022
@simzer
Copy link
Member Author

simzer commented Mar 16, 2022

@veghdev did you want to close this issue? Should we create a new issue for the filter using the operator overload method?

@veghdev veghdev reopened this Mar 17, 2022
@veghdev veghdev removed this from the 0.6.0 milestone Mar 17, 2022
@veghdev
Copy link
Member

veghdev commented Mar 17, 2022

Raw Js string filter implemented and will be released in 0.6.0.

@simzer I reopened this (operator overload method implementation), but removed 0.6.0 milestone.

@veghdev veghdev removed their assignment Apr 23, 2022
@simzer
Copy link
Member Author

simzer commented Feb 21, 2023

An alternative method for supporting python filter functions would be to use pyodide. The basic idea would be something like this:

Python code:

filter = "record["foo"] == "blabla" | record["baz"] > 5"

Generated JS code:

      <script src="https://cdn.jsdelivr.net/pyodide/v0.22.1/full/pyodide.js"></script>
let pyodide = await loadPyodide();
...
let filter = (record) => { return pyodide.runPython(`
  f = lambda record: record["foo"] == "blabla" || record["baz"] > 5
  f(record)
`)); };

@simzer
Copy link
Member Author

simzer commented Mar 2, 2023

or micropython
https://micropython.org/

@simzer
Copy link
Member Author

simzer commented Apr 19, 2023

or transcript, rapidscript, pyjs

@simzer
Copy link
Member Author

simzer commented Jun 10, 2023

There is a solution in sqlalchemy similar to the operator overloading proposal above:
https://docs.sqlalchemy.org/en/20/core/operators.html#comparison-operators

Drawbacks: logical and/or/not cannot be overloaded in Python, bitwise operators can be used instead, but they have a higher precedence then comparison operators, which is confusing. e.g. parenthesis needed in this expr: (Year==2023)&(Month=='Jun')

@simzer
Copy link
Member Author

simzer commented Jun 10, 2023

Regardless, I have made a draft implementation for the operator overloading solution:
https://90b6028f-b426-4390-ab84-febd297bdf96.pyscriptapps.com/8df0cb69-f132-4e34-aa71-245c9c7f34ba/latest/

(see link to the source in the bottom right corner)

@schaumb schaumb removed the enhancement New feature or request label Jul 3, 2023
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

4 participants