-
Notifications
You must be signed in to change notification settings - Fork 81
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
docs: Dataframe docs update #693
base: dev
Are you sure you want to change the base?
Changes from all commits
c8704d2
014cc21
fe0dfbc
7c8e06a
b2ab8f8
bb103a1
7fcdb00
3860958
1856440
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,97 +2,254 @@ | |
title: "Dataframe" | ||
--- | ||
|
||
**writer framework places the dataframe at the core of the application**. This is a great way for modeling a complex and massive data system. | ||
it offers components as `dataframe` to manipulate dataframes. These components allow you to visualize and interact with dataframes. | ||
## DataFrames | ||
|
||
| compatibility | dataframe | | ||
|--------------------|---------------------------------------| | ||
| `pandas.DataFrame` | x | | ||
| `polar.DataFrame` | x | | ||
| `list of records` | x (with `EditableDataframe`) | | ||
If your application needs to present data as a table, it should use a **DataFrame**. DataFrames provide a simple way to present data in a grid format, require only a couple of lines of code to set up, and provide an interface that users expect from modern data applications. | ||
|
||
## Use a dataframe | ||
![DataFrame showing a table of popular ice cream flavors](/framework/images/dataframe.png) | ||
|
||
**a dataframe is simply added to the state**. A component like `dataframe` will be able to display it. | ||
DataFrames built-in features that users expect, such as headers that can be clicked to change the sort order and resizable columns... | ||
|
||
```python | ||
import pandas | ||
import writer as wf | ||
![DataFrame with arrows pointing to the re-sort and resizing features](/framework/images/dataframe_resort_resize.png) | ||
|
||
wf.init_state({ | ||
'mydf': pandas.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]}) | ||
}) | ||
``` | ||
...and with the simple change of a parameter, you can enable features such as the Search field, which lets the user find the data they’re looking for (or filter out unwanted data), and the Download button, which downloads the data currently being displayed as a .csv file: | ||
|
||
![DataFrame with arrows pointing to the Search field and Download button](/framework/images/dataframe_search_download.png) | ||
|
||
You can find the full list of DataFrame properties and fields on the [_DataFrame_ component page](/components/dataframe). | ||
|
||
### “DataFrame” has multiple meanings | ||
|
||
**Writer Framework has two objects with the name _DataFrame_:** | ||
|
||
1. **UI DataFrame:** In Writer Framework's UI, "DataFrame" refers to a **_user interface component_** that displays data in rows and columns in a way similar to a spreadsheet or SQL table. | ||
2. **Code Dataframe:** In code that you write for a Writer Framework application, `DataFrame` refers to a **_data structure_** that stores data in rows and columns in a way similar to a spreadsheet or SQL table. | ||
|
||
To present a data table in Writer Framework, you create a `DataFrame` data structure in your code and then bind it to a UI Dataframe. | ||
|
||
|
||
## Displaying a static DataFrame | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we please briefly discuss the options in the DataFrame component (e.g. sorting, downloading, searching) and link to the component documentation. |
||
|
||
A static DataFrame is one whose content does not change. The user can change its sort order, but the data within the DataFrame remains constant. | ||
|
||
<Steps> | ||
<Step title="Create a DataFrame data structure"> | ||
Writer Framework supports both [pandas](https://pandas.pydata.org/) and [Polars](https://pola.rs/) `DataFrame` data structures. Create a `DataFrame`, assign its value to a variable, then assign make that variable a value in the `state` dictionary: | ||
|
||
## Prepare a dataframe for editing | ||
<CodeGroup> | ||
```python pandas | ||
import writer as wf | ||
import pandas as pd | ||
|
||
**writer provides `EditableDataframe` as a helper to facilitate manipulation**. it makes it easier to write event handlers such as adding a line, | ||
deleting it or modifying a value, etc... | ||
data = [ | ||
{"rank": 1, "flavor": "Vanilla", "favorite": 0.11}, | ||
{"rank": 2, "flavor": "Chocolate", "favorite": 0.1}, | ||
{"rank": 3, "flavor": "Cookies and cream", "favorite": 0.07}, | ||
{"rank": 4, "flavor": "Strawberry", "favorite": 0.06}, | ||
{"rank": 5, "flavor": "Chocolate chip", "favorite": 0.02}, | ||
] | ||
df = pd.DataFrame(data) | ||
|
||
wf.init_state({ | ||
"mydf": df | ||
}) | ||
``` | ||
|
||
```python Polars | ||
import writer as wf | ||
import polars as pl | ||
|
||
data = [ | ||
{"rank": 1, "flavor": "Vanilla", "favorite": 0.11}, | ||
{"rank": 2, "flavor": "Chocolate", "favorite": 0.1}, | ||
{"rank": 3, "flavor": "Cookies and cream", "favorite": 0.07}, | ||
{"rank": 4, "flavor": "Strawberry", "favorite": 0.06}, | ||
{"rank": 5, "flavor": "Chocolate chip", "favorite": 0.02}, | ||
] | ||
df = pl.DataFrame(data) | ||
|
||
wf.init_state({ | ||
"mydf": df | ||
}) | ||
``` | ||
</CodeGroup> | ||
|
||
The call to `wf.init_state()` adds the `DataFrame` to the application's `state` variable as the value of the `mydf` key. | ||
</Step> | ||
<Step title="Add a DataFrame component to the UI and bind it to the DataFrame data structure"> | ||
Add a DataFrame UI component to the user interface, then set its **Data** property to `@{`_dataframe_key_`}`, where _dataframe_key_ is the `state` variable key whose value refers to the `DataFrame` data structure. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The underscores at the front and end of |
||
|
||
In the case of this example, `mydf` is the `state` variable key referring to the `DataFrame`, so set the **Data** property to `@{mydf}`. | ||
|
||
![DataFrame for static table example with properties panel open](/framework/images/dataframe_static_table_1.png) | ||
</Step> | ||
</Steps> | ||
|
||
|
||
## Displaying an editable DataFrame | ||
|
||
A editable DataFrame is one whose content can change. Like static DataFrames, editable DataFrames use the **DataFrame** UI component. Unlike static tables, the DataFrame UI component is bound to an instance of `EditableDataFrame`, a class provided by the Writer library. Changes to a `EditableDataFrame` object will be immediately reflected in the DataFrame UI component that it is bound to. | ||
|
||
<Steps> | ||
<Step title="Create an EditableDataFrame data structure"> | ||
An `EditableDataFrame` object can be instantiated from any of the following: | ||
|
||
1. A pandas `DataFrame` | ||
2. A Polars `DataFrame` | ||
3. A list of dictionaries | ||
|
||
<CodeGroup> | ||
```python pandas | ||
import writer as wf | ||
import pandas as pd | ||
|
||
data = [ | ||
{"rank": 1, "flavor": "Vanilla", "favorite": 0.11}, | ||
{"rank": 2, "flavor": "Chocolate", "favorite": 0.1}, | ||
{"rank": 3, "flavor": "Cookies and cream", "favorite": 0.07}, | ||
{"rank": 4, "flavor": "Strawberry", "favorite": 0.06}, | ||
{"rank": 5, "flavor": "Chocolate chip", "favorite": 0.02}, | ||
] | ||
df = pd.DataFrame(data) | ||
|
||
wf.init_state({ | ||
"mydf": wf.EditableDataFrame(df) | ||
}) | ||
``` | ||
|
||
```python Polars | ||
import writer as wf | ||
import polars as pl | ||
|
||
data = [ | ||
{"rank": 1, "flavor": "Vanilla", "favorite": 0.11}, | ||
{"rank": 2, "flavor": "Chocolate", "favorite": 0.1}, | ||
{"rank": 3, "flavor": "Cookies and cream", "favorite": 0.07}, | ||
{"rank": 4, "flavor": "Strawberry", "favorite": 0.06}, | ||
{"rank": 5, "flavor": "Chocolate chip", "favorite": 0.02}, | ||
] | ||
df = pl.DataFrame(data) | ||
|
||
wf.init_state({ | ||
"mydf": wf.EditableDataFrame(df) | ||
}) | ||
``` | ||
|
||
```python List of dictionaries | ||
import writer as wf | ||
|
||
data = [ | ||
{"rank": 1, "flavor": "Vanilla", "favorite": 0.11}, | ||
{"rank": 2, "flavor": "Chocolate", "favorite": 0.1}, | ||
{"rank": 3, "flavor": "Cookies and cream", "favorite": 0.07}, | ||
{"rank": 4, "flavor": "Strawberry", "favorite": 0.06}, | ||
{"rank": 5, "flavor": "Chocolate chip", "favorite": 0.02}, | ||
] | ||
|
||
wf.init_state({ | ||
"mydf": wf.EditableDataFrame(data) | ||
}) | ||
``` | ||
</CodeGroup> | ||
|
||
The call to `wf.init_state()` adds the `DataFrame` to the application's `state` variable as the value of the `mydf` key. | ||
</Step> | ||
<Step title="Add a DataFrame component to the UI and bind it to the DataFrame data structure"> | ||
Add a **DataFrame** component to the user interface, then set its **Data** property to `@{`_dataframe_key_`}`, where _dataframe_key_ is the `state` variable key whose value refers to the `DataFrame` data structure. | ||
|
||
In the case of this example, `mydf` is the `state` variable key referring to the `DataFrame`, so set the **Data** property to `@{mydf}`. | ||
|
||
![DataFrame for dynamic table example with properties panel open](/framework/images/dataframe_dynamic_table_1.png) | ||
</Step> | ||
</Steps> | ||
|
||
## Updating an editable DataFrame | ||
|
||
Editable DataFrames are updated by updating the `EditableDataFrame` object they are bound to, which is done using `EditableDataFrame`'s methods. | ||
|
||
### `record_add`: Add a new row | ||
|
||
`record_add()` adds a new row to an `EditableDataFrame`. It takes a dictionary with the following structure... | ||
|
||
```python | ||
import pandas | ||
import writer as wf | ||
{"record": new_row} | ||
``` | ||
|
||
df = pandas.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]}) | ||
...where `new_row` is a dictionary containing the data for the row to be added. | ||
|
||
wf.init_state({ | ||
'mydf': wf.EditableDataframe(df) | ||
}) | ||
In the code example above, you would add a new row to the DataFrame with the following code: | ||
|
||
```python | ||
state["mydf"].record_add({"record": {"rank": 6, "flavor": "Birthday cake", "favorite": 0.01}}) | ||
``` | ||
|
||
### Handle events from a dataframe editor | ||
### `record`: Read the contents of a row | ||
|
||
`record()` returns a row in an `EditableDataFrame`. It takes an integer specifying the index of the row. | ||
|
||
**The dataframe component emits events when an action is performed**. You must subscribe to events to integrate changes to the state of the application. | ||
In the code example above, you would retrieve the record at row 1 with the following code: | ||
|
||
```python | ||
import pandas | ||
import writer as wf | ||
record = state["mydf"].record(1) | ||
``` | ||
|
||
df = pandas.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]}) | ||
wf.init_state({ | ||
'mydf': wf.EditableDataframe(df) | ||
}) | ||
### `record_update`: Change an existing row | ||
|
||
# Subscribe this event handler to the `wf-dataframe-add` event | ||
def on_record_add(state, payload): | ||
payload['record']['sales'] = 0 # default value inside the dataframe | ||
state['mydf'].record_add(payload) | ||
`record_update()` replaces an existing row in an `EditableDataFrame` with a new one. It takes a dictionary with the following structure... | ||
|
||
```python | ||
{ | ||
"record_index": index, | ||
"record": row_to_update | ||
} | ||
``` | ||
|
||
# Subscribe this event handler to the `wf-dataframe-update` event | ||
def on_record_change(state, payload): | ||
state['mydf'].record_update(payload) | ||
...where `index` is an integer specifying which row should be updated and `row_to_update` is a dictionary containing the updated row data. | ||
|
||
In the code example above, you would update the row at index 0 with the following code: | ||
|
||
# Subscribe this event handler to the `wf-dataframe-action` event | ||
def on_record_action(state, payload): | ||
""" | ||
This event corresponds to a quick action in the drop-down menu to the left of the dataframe. | ||
""" | ||
record_index = payload['record_index'] | ||
if payload['action'] == 'remove': | ||
state['mydf'].record_remove(payload) | ||
if payload['action'] == 'open': | ||
state['record'] = state['df'].record(record_index) # dict representation of record | ||
```python | ||
state["mydf"].record_update({ | ||
"record_index": 0, | ||
"record": {"rank": 6, "flavor": "Bubble gum", "favorite": 0.08} | ||
}) | ||
``` | ||
|
||
### Datastructures supported by `EditableDataframe` | ||
### `record_remove`: Delete an existing row | ||
|
||
`EditableDataframe` can be used with a panda dataframe, a polar dataframe and list of records. | ||
`record_remove()` removes an existing row from an `EditableDataFrame`. It takes a dictionary with the following structure... | ||
|
||
```python | ||
import pandas | ||
import polars | ||
{"record_index": index} | ||
``` | ||
|
||
import writer as wf | ||
...where `index` is an integer specifying which row should be deleted. | ||
|
||
panda_df = pandas.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]}) | ||
polars_df = polars.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]}) | ||
list_of_records = [{'a': 1, 'b': 4}, {'a': 2, 'b': 5}, {'a': 3, 'b': 6}] | ||
In the code example above, you would delete the row at index 2 with the following code: | ||
|
||
wf.init_state({ | ||
'mypandas': wf.EditableDataframe(panda_df), | ||
'mypolars': wf.EditableDataframe(polars_df), | ||
'mylistofrecords': wf.EditableDataframe(list_of_records) | ||
}) | ||
```python | ||
state["mydf"].record_remove({"record_index": 2}) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems like this is missing a conclusion or something to wrap this up and tell the user where to go next |
||
``` | ||
|
||
|
||
## Enabling additional features | ||
|
||
The DataFrame component has these “always-on” features: | ||
|
||
1. **Sorting:** Clicking a column header sorts the entire DataFrame based on that column's values. The first click sorts that DataFrame in ascending order, a second click changes it to descending order, and a third click restores the DataFrame to its original sort order. | ||
2. **Column resizing:** Click and drag the dividing line on the right edge of a column header to adjust its width. | ||
|
||
DataFrames have other features that you need to activate, which are listed below. | ||
|
||
### Search field | ||
|
||
To enable the Search field, select the DataFrame, open the Component settings panel, and set **Enable search** to **yes**. | ||
|
||
![Enabling the Search field in a DataFrame](/framework/images/dataframe_enable_search.png) | ||
|
||
### Download button | ||
|
||
To enable the Download button, select the DataFrame, open the Component settings panel, and set **Enable download** to **yes**. | ||
|
||
![Enabling the Download button in a DataFrame](/framework/images/dataframe_enable_download.png) | ||
|
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.
Can we add an intro sentence here to help people understand what they're trying to accomplish with dataframes?