-
Notifications
You must be signed in to change notification settings - Fork 21
Add learn-shiny article on custom components. #29
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
Conversation
gshotwell
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is great overall, a couple of writing style things, but overall I think it looks good.
| ); | ||
| ``` | ||
|
|
||
| This class has two methods that we need to implement: `find()` and `renderValue()`. The `find()` method is used to find the element that we want to render the table in. The `renderValue()` method is used to render the table in the element. After making that class we need to register it with Shiny so it can find and send data to instances of our output. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| This class has two methods that we need to implement: `find()` and `renderValue()`. The `find()` method is used to find the element that we want to render the table in. The `renderValue()` method is used to render the table in the element. After making that class we need to register it with Shiny so it can find and send data to instances of our output. | |
| This class has two methods that we need to implement: `find()` and `renderValue()`. The `find()` method is used to identify the element that will contain the rendered table. The `renderValue()` method is used to render the table in the element. After making that class we need to register it with Shiny so it can find and send data to instances of our output. |
|
|
||
| ### The `find()` method | ||
|
|
||
| Now that we have the scaffolding setup, we can fill it in. Starting with the `find` method, this function is passed a `scope` object, which is a `JQuery` selection and should return the element you wish to render your output into. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might have a bit too much passive voice, maybe something like :
"Now that we have the scaffolding setup we can start by filling in the find method. This function takes a scope object, which is a JQuery selection that should rereturn the element which will contain the output". I'm not sure if "contains the output" is the same as "render into".
| Shiny.outputBindings.register(...); | ||
| ``` | ||
|
|
||
| Note that we're using the class `".shiny-tabulator-output"` here to mark the element that we want to render the table in. This is the same class that we will use in our `output_tabulator()` function in our app's server code. You can use any valid css selector here, but it's common to use a descriptive class name like this. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| Note that we're using the class `".shiny-tabulator-output"` here to mark the element that we want to render the table in. This is the same class that we will use in our `output_tabulator()` function in our app's server code. You can use any valid css selector here, but it's common to use a descriptive class name like this. | |
| Note that we're using the class `".shiny-tabulator-output"` here to mark the element that we want to render the table in. This is the same class that we will use in our `output_tabulator()` function in our app's server code. You can use any valid css selector here, but it's common to use a class name which describes the output. |
| ) | ||
| ``` | ||
|
|
||
| We use the `HTMLDependency` function to bind up the assets needed for tabulator that we made in the previous step and making sure that they're included in our app anytime the `output_tabulator()` function is called (but not more than once.) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can include this in the callout
|
|
||
| `_meta` is a dictionary of metadata about the function that is being decorated. We don't use it in our example. | ||
|
|
||
| `_fn` is the function that is being decorated. Aka the function that goes below the `@render_tabulator()` in your app's server code. In this case we are expecting that that function returns either a pandas dataframe or `None`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| `_fn` is the function that is being decorated. Aka the function that goes below the `@render_tabulator()` in your app's server code. In this case we are expecting that that function returns either a pandas dataframe or `None`. | |
| `_fn` is the decorated function which appears below the `@render_tabulator()` decorator in your app's server code. In this case we are expecting the function to return either a pandas dataframe or `None`. |
| ... | ||
| ``` | ||
|
|
||
| `resolve_value_fn()` is a helper provided in `shiny.render.transformer` for resolving the value of a function that may or may not be async. This allows us to write our code in a way that is agnostic to how the user has written their render function. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| `resolve_value_fn()` is a helper provided in `shiny.render.transformer` for resolving the value of a function that may or may not be async. This allows us to write our code in a way that is agnostic to how the user has written their render function. | |
| `resolve_value_fn()` is a helper provided in `shiny.render.transformer` for resolving the value of a function that may or may not be async. This ensures that the function will work whether or not the end user has defined their render function asynchronously. |
|
|
||
| `resolve_value_fn()` is a helper provided in `shiny.render.transformer` for resolving the value of a function that may or may not be async. This allows us to write our code in a way that is agnostic to how the user has written their render function. | ||
|
|
||
| Next, we check to make sure that the value returned by the function is a dataframe. If it's not, we throw an error. This is not required, but it's good practice to do so. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| Next, we check to make sure that the value returned by the function is a dataframe. If it's not, we throw an error. This is not required, but it's good practice to do so. | |
| Next, we check to make sure that the value returned by the function is a dataframe. If it's not, we throw an error. This is not strictly required, but is a best practice. |
| 1. A javascript script that renders the element on the client side using the Tabulator library | ||
| 2. An `output_tabulator()` function for placing the element in your app's UI | ||
| 3. A `render_tabulator()` decorator for passing table data to the javascript code rendering the element on the server side | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be nice here to have a mermaid diagram of how all the components work together and what they do.
|
I ended up bringing this article over in #46 to simplify things. Still using comments from review there though. |
This is a fairly straightforward copying of the readme for the repo https://github.com/nstrayer/pyshiny-output-binding-example.
Adds a new article in the "In Depth" section of "Learn Shiny" that covers building a one-off javascript component for an app. Future work will add more info on packaging these custom components into a proper python package.