diff --git a/__init__.py b/__init__.py index 4c891f4..8cbf839 100644 --- a/__init__.py +++ b/__init__.py @@ -1,4 +1,5 @@ from typing import Dict, Type, TypeVar +from .modules.cda.cda_json_create import CDAJSONCreate from .modules.matplotlib.mpl_bar import MPLBar from .modules.matplotlib.mpl_line import MPLLine from .modules.matplotlib.mpl_scatter import MPLScatter @@ -7,6 +8,7 @@ from .modules.pandas_wrapper.pandas_create import PandasCreate from .modules.pandas_wrapper.pandas_create_with_index import PandasCreateWithIndex from .modules.pandas_wrapper.pandas_head import PandasHead from .modules.pandas_wrapper.pandas_iloc_row_series import PandasIlocRowSeries +from .modules.pandas_wrapper.pandas_iloc_rows_dataframe import PandasIlocRowsDataFrame from .modules.pandas_wrapper.pandas_index import PandasIndex from .modules.pandas_wrapper.pandas_join import PandasJoin from .modules.pandas_wrapper.pandas_load_csv import PandasLoadCSV @@ -27,6 +29,7 @@ from .modules.pandas_wrapper.pandas_to_string import PandasToString T = TypeVar("T") NODE_CLASS_MAPPINGS: Dict[str, Type[T]] = { + "CDAJSONCreate": CDAJSONCreate, "MPLBar": MPLBar, "MPLLine": MPLLine, "MPLScatter": MPLScatter, @@ -35,6 +38,7 @@ NODE_CLASS_MAPPINGS: Dict[str, Type[T]] = { "PandasCreateWithIndex": PandasCreateWithIndex, "PandasHead": PandasHead, "PandasIlocRowSeries": PandasIlocRowSeries, + "PandasIlocRowsDataFrame": PandasIlocRowsDataFrame, "PandasIndex": PandasIndex, "PandasJoin": PandasJoin, "PandasLoadCSV": PandasLoadCSV, @@ -58,6 +62,7 @@ NODE_CLASS_MAPPINGS (Dict[str, Type[T]]): """ NODE_DISPLAY_NAME_MAPPINGS: Dict[str, str] = { + "CDAJSONCreate": "CDA JSON Create", "MPLBar": "MPL Bar Chart", "MPLLine": "MPL Line Plot", "MPLScatter": "MPL Scatter Plot", @@ -66,6 +71,7 @@ NODE_DISPLAY_NAME_MAPPINGS: Dict[str, str] = { "PandasCreateWithIndex": "Pandas Create With Index", "PandasHead": "Pandas Head", "PandasIlocRowSeries": "Pandas Iloc Row Series", + "PandasIlocRowsDataFrame": "Pandas Iloc Rows DataFrame", "PandasIndex": "Pandas Index", "PandasJoin": "Pandas Join", "PandasLoadCSV": "Pandas Load CSV", diff --git a/docs/images/iloc_rows_dataframe.png b/docs/images/iloc_rows_dataframe.png new file mode 100644 index 0000000..894bca5 Binary files /dev/null and b/docs/images/iloc_rows_dataframe.png differ diff --git a/docs/ug.md b/docs/ug.md index 65494c4..2902f4f 100644 --- a/docs/ug.md +++ b/docs/ug.md @@ -11,6 +11,8 @@ To connect the DataFrame JSON string output from one Pandas node to another, mov ### How to add a node You can right-click, select **Add Node**, go to **Data Analysis**, and look for the following nodes: +### List of nodes +**Data loading, creation, saving** | Node Name | Functionality | |-------------------------|-------------------------------------| | **Pandas Load CSV** | Load a CSV file | @@ -19,21 +21,43 @@ You can right-click, select **Add Node**, go to **Data Analysis**, and look for | **Pandas Save CSV** | Save a DataFrame to a CSV file | | **Pandas Create** | Create a DataFrame from CSV text field | | **Pandas Create With Index** | Create a DataFrame from CSV text field containing index | +| **CDA JSON Create** | Create JSON from a string entered in a text field | + +**Selecting subset of data** +| Node Name | Functionality | +|-------------------------|-------------------------------------| | **Pandas Columns** | Extract column labels | | **Pandas Index** | Extract row labels (index) | | **Pandas Select Columns** | Select specific columns from a DataFrame | | **Pandas Select Rows** | Filter rows based on conditions | | **Pandas Iloc Row Series** | Select a row by row integer position | +| **Pandas Iloc Rows DataFrame** | Select rows by the list of row integer positions | | **Pandas Loc Row Series** | Select a row by row label (index) | | **Pandas Loc Cell Str** | Select a cell by row label (index) and column label (index) | -| **Pandas Join** | Join two DataFrames | | **Pandas Head** | Extract the first few rows | + +**Manipulating data** +| Node Name | Functionality | +|-------------------------|-------------------------------------| +| **Pandas Join** | Join two DataFrames | +| **Pandas Sort** | Sort DataFrame by a column | + +**Displaying data** +| Node Name | Functionality | +|-------------------------|-------------------------------------| | **Pandas Show DataFrame** | Display DataFrame contents | | **Pandas Show Text** | Display Text | | **Pandas Summary** | Extract DataFrame statistics | -| **Pandas Sort** | Sort DataFrame by a column | + +**Converting to displayable string** +| Node Name | Functionality | +|-------------------------|-------------------------------------| | **Pandas Series To String** | Convert Series to a displayable string | | **Pandas To String** | Convert DataFrame to a displayable string | + +**Plot, chart** +| Node Name | Functionality | +|-------------------------|-------------------------------------| | **MPL Bar Chart** | Generate a bar chart | | **MPL Line Plot** | Generate a line plot | | **MPL Scatter Plot** | Generate a scatter plot | @@ -52,12 +76,14 @@ CSV file path is relative to the ComfyUI installation directory unless you speci ## Saving data Use **Pandas Save CSV** node to save the DataFrame to a CSV file. -## Creating DataFrame on the UI -Use **Pandas Create** or **Pandas Create with Index** nodes. These nodes display the multiline text area where you can enter the data in CSV format. +## Creating data on the UI +To construct a DataFrame on the UI, use **Pandas Create** or **Pandas Create with Index** nodes. These nodes display the multiline text area where you can enter the data in CSV format. If the data contains an index column, use **Pandas Create with Index** and specify the index column. ![Pandas Columns and Pandas Index](images/columns_index.png) +Use **CDA JSON Create** to create JSON from a string entered in a text field. For example, if you want to create a list for a node that requires the list of integers for input, this node is ideal. + ## Extracting column and row labels Use **Pandas Columns** and **Pandas Index** nodes. As these nodes output JSON-serialized Index object, to display the value, use **Pandas Show Text** node as shown below: @@ -70,7 +96,13 @@ Use **Pandas Select Rows** to select rows by a filter condition. ![Pandas select subset](images/subset.jpg) -You can use **Pandas Loc Row Series** to select a row by row label (index), or you can use **Pandas Iloc Row Series** to select a row by row integer position. Both nodes returns a JSON-serialized Series object. +You can use **Pandas Loc Row Series** to select a row by row label (index). +You can use **Pandas Iloc Row Series** to select a row by row integer position. +These nodes returns a JSON-serialized Series object. + +You can use **Pandas Iloc Rows DataFrame** to select rows by the list of row integer positions. This node returns a JSON-serialized DataFrame object. +You need to pass the list of integers to this node. This can be done by using the **CDA JSON Create** node. +![Pandas Iloc Rows DataFrame](images/iloc_rows_dataframe.png) For **Pandas Loc Row Series**, data type of the labels needs to be specified as shown below: ![Pandas Loc Row Series](images/loc_row_series.png) diff --git a/modules/cda/cda_json_create.py b/modules/cda/cda_json_create.py new file mode 100644 index 0000000..f0fb9bb --- /dev/null +++ b/modules/cda/cda_json_create.py @@ -0,0 +1,45 @@ +from typing import Any, Dict +import json + +class CDAJSONCreate: + """ + CDAJSONCreate: + A class for creating a serialized JSON object using values entered in the text field. + """ + + @classmethod + def INPUT_TYPES(cls) -> Dict[str, Any]: + """ + Defines the input types for the `create` function. + + Returns: + Dict[str, Any]: A dictionary specifying required input types. + """ + return { + "required": { + "data": ("STRING", {"multiline": True}), + } + } + + RETURN_TYPES: tuple = ("STRING",) + FUNCTION: str = "create" + CATEGORY: str = "Data Analysis" + + def create(self, data: str) -> tuple: + """ + creating a serialized JSON object using values entered in the text field. + + Args: + data (str): String value in the text field. + + Returns: + tuple: A tuple containing a JSON string representation of the DataFrame. + """ + # Convert to JSON + json_obj = json.loads(data) + + # Serialize to a string + result_jsons = json.dumps(json_obj) + + return (result_jsons,) + diff --git a/modules/pandas_wrapper/pandas_create.py b/modules/pandas_wrapper/pandas_create.py index f7184f2..9299c84 100644 --- a/modules/pandas_wrapper/pandas_create.py +++ b/modules/pandas_wrapper/pandas_create.py @@ -5,7 +5,7 @@ import pandas as pd class PandasCreate: """ - PandasLoadCSV: + PandasCreate: A class for creating a pandas DataFrame using values entered in the text field. """ @@ -32,7 +32,7 @@ class PandasCreate: Create a pandas DataFrame using values entered in the text field and converts it to a JSON string. Args: - file_path (str): The path to the CSV file. + data (str): String value in the text field. Returns: tuple: A tuple containing a JSON string representation of the DataFrame. diff --git a/modules/pandas_wrapper/pandas_create_with_index.py b/modules/pandas_wrapper/pandas_create_with_index.py index a14b2c2..777503f 100644 --- a/modules/pandas_wrapper/pandas_create_with_index.py +++ b/modules/pandas_wrapper/pandas_create_with_index.py @@ -5,7 +5,7 @@ import pandas as pd class PandasCreateWithIndex: """ - PandasLoadCSV: + PandasCreateWithIndex: A class for creating a pandas DataFrame using values entered in the text field. Input data is assume to have an index. """ @@ -35,7 +35,8 @@ class PandasCreateWithIndex: Input data is assume to have an index. Args: - file_path (str): The path to the CSV file. + data (str): String value in the text field. + index_col (int): Position of the index column. Returns: tuple: A tuple containing a JSON string representation of the DataFrame. diff --git a/modules/pandas_wrapper/pandas_iloc_rows_dataframe.py b/modules/pandas_wrapper/pandas_iloc_rows_dataframe.py new file mode 100644 index 0000000..2836c86 --- /dev/null +++ b/modules/pandas_wrapper/pandas_iloc_rows_dataframe.py @@ -0,0 +1,52 @@ +from typing import Any, Dict +from io import StringIO +import json +import pandas as pd +from .utils import series_to_jsons + +class PandasIlocRowsDataFrame: + """ + PandasIlocRowsDataFrame: + A class for selecting rows from a pandas DataFrame and returning it as a DataFrame. + Rows are specified by the list of integer positions. + """ + + @classmethod + def INPUT_TYPES(cls) -> Dict[str, Any]: + """ + Defines the input types for the `select_rows` function. + + Returns: + Dict[str, Any]: A dictionary specifying required input types. + """ + return { + "required": { + "dataframe_json": ("STRING", {"multiline": True}), + "row_int_pos_list_json": ("STRING", {"multiline": False}) + } + } + + RETURN_TYPES: tuple = ("STRING",) + FUNCTION: str = "select_rows" + CATEGORY: str = "Data Analysis" + + def select_rows(self, dataframe_json: str, + row_int_pos_list_json: str) -> tuple: + """ + Select rows from a pandas DataFrame and returning it as a DataFrame. + Rows are specified by the list of integer positions and returned as + the JSON serialized DataFrame object. + + Args: + dataframe_json (str): A JSON string representation of the DataFrame. + row_int_pos_list_json (str): A list containing row integer positions. + + Returns: + tuple: A tuple containing the value of the row in string. The string is + a JSON string containing the serialized Pandas Series object. + """ + # Deserialize JSON string to DataFrame + df = pd.read_json(StringIO(dataframe_json)) + row_int_pos_list = json.loads(row_int_pos_list_json) + df2 = df.iloc[row_int_pos_list] + return (df2.to_json(),) diff --git a/pyproject.toml b/pyproject.toml index 04aa882..fda45be 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "data-analysis" description = "Data analysis custom modules for ComfyUI - Use Pandas & Matplotlib within ComfyUI" -version = "1.0.13" +version = "1.0.14" license = {file = "LICENSE"} [project.urls]