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

Feature : custom user functions for the plot plugin interpreter. #335

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

tcoppex
Copy link

@tcoppex tcoppex commented Apr 29, 2022

Hey everyone,

So I'm interested into adding custom functions - like smoothstep - to the plot plugin using the import function of the underlying mathjs library.

Here is a proof of concept implementation which allow the user to provide an imported attribute to the plot function accepting a dictionnary of functions.

For example :

plot( { 
  expression: 'mix(0, 1, x)',
  imported: {
    mix: (a: number, b: number, x: number) => {
      return a + (b - a) * x
    })

The idea is to define the functions in a general dictionnary once and pass it to a plot wrapper for the whole app, as each plot will instanciate mathjs before evaluation to import its custom functions (a bit of a caveat I suppose).

Here's a simplified clojurescript version of what I'm using for example :

(def custom-mathjs-functions {:smoothstep #(.smoothstep THREE/MathUtils %3 %1 %2)})

(defn plot-expr
  [expr]
  (plot (clj->js {:expression expr
                  :boundsX [0 1] 
                  :boundsY [0 1]
                  :graph true
                  :imported custom-mathjs-functions})

So it might become cumbersome for larger functions dictionnaries.

@changeset-bot
Copy link

changeset-bot bot commented Apr 29, 2022

⚠️ No Changeset found

Latest commit: 89d4eb9

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel
Copy link

vercel bot commented Apr 29, 2022

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Updated
leva ✅ Ready (Inspect) Visit Preview May 7, 2022 at 4:56PM (UTC)

@codesandbox-ci
Copy link

codesandbox-ci bot commented Apr 29, 2022

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit 89d4eb9:

Sandbox Source
pmndrs/leva Configuration
pmndrs/leva Configuration
leva-scroll Configuration
pmndrs/leva Configuration
leva-ui Configuration
leva-theme Configuration
leva-transient Configuration
leva-plugin-plot Configuration
pmndrs/leva Configuration
leva-plugin-spring Configuration
leva-custom-plugin Configuration

Comment on lines +7 to +9
if (imported !== undefined) {
math.import(imported, {})
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it problematic to import multiple times? In that case, could we check if the expressions has already been imported?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it is, at first I tried to create one global instance and to call import inside the getSymbols function but it fails because of dupplication.

@gsimone
Copy link
Member

gsimone commented Apr 30, 2022

This is very cool! I don't see the clunkyness as a big problem 🤔

What would happen if the user tried to import the same expression twice? If it fails silently, we can just leave that to the user - assuming they'd read docs

@tcoppex
Copy link
Author

tcoppex commented May 7, 2022

Hi @gsimone and thanks for you review.

Yes as mentionned above multiple imports on the same symbols fails (the plot also fails to render properly). I guess if we want to avoid recreating an instance we can check symbols on a map / set but it seems overkill.

Also we might want to discuss the proper keyword to use for this, imported is a bit broad but does the job also.

Cheers.

@gsimone
Copy link
Member

gsimone commented May 9, 2022

@tcoppex

Maybe we could think of an alternate api where we extend the plot fn?
eg.

// imagine using it in a setup file

plot.extend({ mix: ... }) 
// calling this again would not fail as we can in an object wether we already extend 

@tcoppex
Copy link
Author

tcoppex commented May 14, 2022

Good idea that might be worth a try. Looking into it I'm not sure how to go about it though, do you have an idea for the actual implementation ?

It seems the advantage of the current implementation is to be able to extend plots individually, for example by giving previous functions / symbols to the next plot (à la graphtoy).

So maybe we can go with both ideas : a default extend initialization and a per-plot assignement.

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.

2 participants