From 897f3e99f46b6d752efd1858002533e6d71e827c Mon Sep 17 00:00:00 2001 From: HowToSD Date: Wed, 19 Feb 2025 12:59:11 -0800 Subject: [PATCH] Added Pandas Load HTML, CDA Float Create, CDA Int Create, CDA String Create, CDA Text Create, CDA Show Float, CDA Show Int nodes. --- __init__.py | 21 ++++++ docs/reference/cda_float_create.md | 17 +++++ docs/reference/cda_int_create.md | 17 +++++ docs/reference/cda_show_float.md | 17 +++++ docs/reference/cda_show_int.md | 17 +++++ docs/reference/cda_string_create.md | 17 +++++ docs/reference/cda_text_create.md | 17 +++++ docs/reference/node_reference.md | 7 ++ docs/reference/pandas_load_html.md | 27 ++++++++ examples/datasets/0.html | 8 +++ examples/datasets/1.html | 12 ++++ examples/datasets/2.html | 20 ++++++ examples/workflows/load_html.json | 1 + examples/workflows/variable_create.json | 1 + modules/cda/cda_float_create.py | 40 +++++++++++ modules/cda/cda_int_create.py | 41 +++++++++++ modules/cda/cda_show_float.py | 62 +++++++++++++++++ modules/cda/cda_show_int.py | 60 ++++++++++++++++ modules/cda/cda_string_create.py | 41 +++++++++++ modules/cda/cda_text_create.py | 41 +++++++++++ modules/pandas_wrapper/pandas_load_csv.py | 4 +- .../pandas_load_csv_with_encoding.py | 4 +- .../pandas_load_csv_with_index.py | 4 +- modules/pandas_wrapper/pandas_load_html.py | 68 +++++++++++++++++++ modules/pandas_wrapper/pandas_load_json.py | 4 +- pyproject.toml | 2 +- web/js/ShowText.js | 2 +- 27 files changed, 562 insertions(+), 10 deletions(-) create mode 100644 docs/reference/cda_float_create.md create mode 100644 docs/reference/cda_int_create.md create mode 100644 docs/reference/cda_show_float.md create mode 100644 docs/reference/cda_show_int.md create mode 100644 docs/reference/cda_string_create.md create mode 100644 docs/reference/cda_text_create.md create mode 100644 docs/reference/pandas_load_html.md create mode 100644 examples/datasets/0.html create mode 100644 examples/datasets/1.html create mode 100644 examples/datasets/2.html create mode 100644 examples/workflows/load_html.json create mode 100644 examples/workflows/variable_create.json create mode 100644 modules/cda/cda_float_create.py create mode 100644 modules/cda/cda_int_create.py create mode 100644 modules/cda/cda_show_float.py create mode 100644 modules/cda/cda_show_int.py create mode 100644 modules/cda/cda_string_create.py create mode 100644 modules/cda/cda_text_create.py create mode 100644 modules/pandas_wrapper/pandas_load_html.py diff --git a/__init__.py b/__init__.py index cbd36d8..89c827c 100644 --- a/__init__.py +++ b/__init__.py @@ -1,5 +1,11 @@ from typing import Dict, Type, TypeVar +from .modules.cda.cda_float_create import CDAFloatCreate +from .modules.cda.cda_int_create import CDAIntCreate from .modules.cda.cda_json_create import CDAJSONCreate +from .modules.cda.cda_show_float import CDAShowFloat +from .modules.cda.cda_show_int import CDAShowInt +from .modules.cda.cda_string_create import CDAStringCreate +from .modules.cda.cda_text_create import CDATextCreate from .modules.matplotlib.mpl_bar import MPLBar from .modules.matplotlib.mpl_line import MPLLine from .modules.matplotlib.mpl_scatter import MPLScatter @@ -33,6 +39,7 @@ from .modules.pandas_wrapper.pandas_join import PandasJoin from .modules.pandas_wrapper.pandas_load_csv import PandasLoadCSV from .modules.pandas_wrapper.pandas_load_csv_with_encoding import PandasLoadCSVWithEncoding from .modules.pandas_wrapper.pandas_load_csv_with_index import PandasLoadCSVWithIndex +from .modules.pandas_wrapper.pandas_load_html import PandasLoadHTML from .modules.pandas_wrapper.pandas_load_json import PandasLoadJSON from .modules.pandas_wrapper.pandas_loc_cell_str import PandasLocCellStr from .modules.pandas_wrapper.pandas_loc_row_series import PandasLocRowSeries @@ -68,7 +75,13 @@ from .modules.pandas_wrapper.pandas_vertical_split import PandasVerticalSplit T = TypeVar("T") NODE_CLASS_MAPPINGS: Dict[str, Type[T]] = { + "CDAFloatCreate": CDAFloatCreate, + "CDAIntCreate": CDAIntCreate, "CDAJSONCreate": CDAJSONCreate, + "CDAShowFloat": CDAShowFloat, + "CDAShowInt": CDAShowInt, + "CDAStringCreate": CDAStringCreate, + "CDATextCreate": CDATextCreate, "MPLBar": MPLBar, "MPLLine": MPLLine, "MPLScatter": MPLScatter, @@ -102,6 +115,7 @@ NODE_CLASS_MAPPINGS: Dict[str, Type[T]] = { "PandasLoadCSV": PandasLoadCSV, "PandasLoadCSVWithEncoding": PandasLoadCSVWithEncoding, "PandasLoadCSVWithIndex": PandasLoadCSVWithIndex, + "PandasLoadHTML": PandasLoadHTML, "PandasLoadJSON": PandasLoadJSON, "PandasLocCellStr": PandasLocCellStr, "PandasLocRowSeries": PandasLocRowSeries, @@ -140,7 +154,13 @@ NODE_CLASS_MAPPINGS (Dict[str, Type[T]]): """ NODE_DISPLAY_NAME_MAPPINGS: Dict[str, str] = { + "CDAFloatCreate": "CDA Float Create", + "CDAIntCreate": "CDA Int Create", "CDAJSONCreate": "CDA JSON Create", + "CDAShowFloat": "CDA Show Float", + "CDAShowInt": "CDA Show Int", + "CDAStringCreate": "CDA String Create", + "CDATextCreate": "CDA Text Create", "MPLBar": "MPL Bar Chart", "MPLLine": "MPL Line Plot", "MPLScatter": "MPL Scatter Plot", @@ -174,6 +194,7 @@ NODE_DISPLAY_NAME_MAPPINGS: Dict[str, str] = { "PandasLoadCSV": "Pandas Load CSV", "PandasLoadCSVWithEncoding": "Pandas Load CSV With Encoding", "PandasLoadCSVWithIndex": "Pandas Load CSV With Index", + "PandasLoadHTML": "Pandas Load HTML", "PandasLoadJSON": "Pandas Load JSON", "PandasLocCellStr": "Pandas Loc Cell Str", "PandasLocRowSeries": "Pandas Loc Row Series", diff --git a/docs/reference/cda_float_create.md b/docs/reference/cda_float_create.md new file mode 100644 index 0000000..432c990 --- /dev/null +++ b/docs/reference/cda_float_create.md @@ -0,0 +1,17 @@ +# CDA Float Create +Creates a Python float using a value entered in the text field. + +## Input +| Name | Data type | +|---|---| +| data | String | + +## Output +| Data type | +|---| +| Float | + +
+Category: IO + +ComfyUI Data Analysis Node Reference. © 2025 Hide Inada (HowToSD.com). All rights reserved. diff --git a/docs/reference/cda_int_create.md b/docs/reference/cda_int_create.md new file mode 100644 index 0000000..987cb8d --- /dev/null +++ b/docs/reference/cda_int_create.md @@ -0,0 +1,17 @@ +# CDA Int Create +Creates a Python int using a value entered in the text field. + +## Input +| Name | Data type | +|---|---| +| data | String | + +## Output +| Data type | +|---| +| Int | + +
+Category: IO + +ComfyUI Data Analysis Node Reference. © 2025 Hide Inada (HowToSD.com). All rights reserved. diff --git a/docs/reference/cda_show_float.md b/docs/reference/cda_show_float.md new file mode 100644 index 0000000..c7b06df --- /dev/null +++ b/docs/reference/cda_show_float.md @@ -0,0 +1,17 @@ +# C D A Show Float +Displays a floating-point number as text. + +## Input +| Name | Data type | +|---|---| +| float_scalar | Float | + +## Output +| Data type | +|---| +| String | + +
+Category: Display data + +ComfyUI Data Analysis Node Reference. © 2025 Hide Inada (HowToSD.com). All rights reserved. diff --git a/docs/reference/cda_show_int.md b/docs/reference/cda_show_int.md new file mode 100644 index 0000000..6f0d160 --- /dev/null +++ b/docs/reference/cda_show_int.md @@ -0,0 +1,17 @@ +# C D A Show Int +Displays a Pandas Int as text. + +## Input +| Name | Data type | +|---|---| +| int_scalar | Int | + +## Output +| Data type | +|---| +| String | + +
+Category: Display data + +ComfyUI Data Analysis Node Reference. © 2025 Hide Inada (HowToSD.com). All rights reserved. diff --git a/docs/reference/cda_string_create.md b/docs/reference/cda_string_create.md new file mode 100644 index 0000000..97bdec0 --- /dev/null +++ b/docs/reference/cda_string_create.md @@ -0,0 +1,17 @@ +# CDA String Create +Creates a Python String using a value entered in a single-line text field. + +## Input +| Name | Data type | +|---|---| +| data | String | + +## Output +| Data type | +|---| +| String | + +
+Category: IO + +ComfyUI Data Analysis Node Reference. © 2025 Hide Inada (HowToSD.com). All rights reserved. diff --git a/docs/reference/cda_text_create.md b/docs/reference/cda_text_create.md new file mode 100644 index 0000000..00b0ec1 --- /dev/null +++ b/docs/reference/cda_text_create.md @@ -0,0 +1,17 @@ +# CDA Text Create +Creates a Python String using a value entered in a multi-line text field. + +## Input +| Name | Data type | +|---|---| +| data | String | + +## Output +| Data type | +|---| +| String | + +
+Category: IO + +ComfyUI Data Analysis Node Reference. © 2025 Hide Inada (HowToSD.com). All rights reserved. diff --git a/docs/reference/node_reference.md b/docs/reference/node_reference.md index 2035082..acb64cf 100644 --- a/docs/reference/node_reference.md +++ b/docs/reference/node_reference.md @@ -45,6 +45,8 @@ ## Display data | Node | Description | | --- | --- | +| [C D A Show Float](cda_show_float.md) | Displays a floating-point number as text. | +| [C D A Show Int](cda_show_int.md) | Displays a Pandas Int as text. | | [Pandas Index To String](pandas_index_to_string.md) | Converts a pandas Index to a string representation. | | [Pandas Series To String](pandas_series_to_string.md) | Converts a pandas Series to a string representation. | | [Pandas Show Data Frame](pandas_show_dataframe.md) | Displays a Pandas DataFrame as text. | @@ -55,12 +57,17 @@ ## IO | Node | Description | | --- | --- | +| [CDA Float Create](cda_float_create.md) | Creates a Python float using a value entered in the text field. | +| [CDA Int Create](cda_int_create.md) | Creates a Python int using a value entered in the text field. | | [CDA JSON Create](cda_json_create.md) | Creates a serialized JSON object using values entered in the text field. | +| [CDA String Create](cda_string_create.md) | Creates a Python String using a value entered in a single-line text field. | +| [CDA Text Create](cda_text_create.md) | Creates a Python String using a value entered in a multi-line text field. | | [Pandas Create](pandas_create.md) | Creates a pandas DataFrame using values entered in the text field. | | [Pandas Create With Index](pandas_create_with_index.md) | Creates a pandas DataFrame using values entered in the text field. Input data is assumed to have an index. | | [Pandas Load CSV](pandas_load_csv.md) | Loads CSV files into a pandas DataFrame. | | [Pandas Load CSV With Encoding](pandas_load_csv_with_encoding.md) | Loads CSV files into a pandas DataFrame. | | [Pandas Load CSV With Index](pandas_load_csv_with_index.md) | Loads CSV files into a pandas DataFrame. | +| [Pandas Load HTML](pandas_load_html.md) | Scans HTML files for tables and returns the number of DataFrames, with each table represented as a separate DataFrame and the list of those DataFrames. | | [Pandas Load JSON](pandas_load_json.md) | Loads JSON files into a pandas DataFrame. | | [Pandas Save CSV](pandas_save_csv.md) | Saves a PandasDataFrame to a CSV file. | | [Pandas Save JSON](pandas_save_json.md) | Saves a PandasDataFrame to a JSON file. | diff --git a/docs/reference/pandas_load_html.md b/docs/reference/pandas_load_html.md new file mode 100644 index 0000000..eef16d1 --- /dev/null +++ b/docs/reference/pandas_load_html.md @@ -0,0 +1,27 @@ +# Pandas Load HTML +Scans HTML files for tables and returns the number of DataFrames, with each table represented as a separate DataFrame and the list of those DataFrames. + +## Input +| Name | Data type | +|---|---| +| file_path | String | + +## Output +| Data type | +|---| +| Int | +| DataFrame | +| DataFrame | +| DataFrame | +| DataFrame | +| DataFrame | +| DataFrame | +| DataFrame | +| DataFrame | +| DataFrame | +| DataFrame | + +
+Category: IO + +ComfyUI Data Analysis Node Reference. © 2025 Hide Inada (HowToSD.com). All rights reserved. diff --git a/examples/datasets/0.html b/examples/datasets/0.html new file mode 100644 index 0000000..bf0a5e4 --- /dev/null +++ b/examples/datasets/0.html @@ -0,0 +1,8 @@ + + + + +Empty HTML + + + diff --git a/examples/datasets/1.html b/examples/datasets/1.html new file mode 100644 index 0000000..57ba6e8 --- /dev/null +++ b/examples/datasets/1.html @@ -0,0 +1,12 @@ + + + + + + + + +
AB
110
220
+ + + diff --git a/examples/datasets/2.html b/examples/datasets/2.html new file mode 100644 index 0000000..605d4d8 --- /dev/null +++ b/examples/datasets/2.html @@ -0,0 +1,20 @@ + + + + +

First

+ + + + +
AB
110
220
+ +

Second

+ + + + +
XY
9.8798.76
8.7687.65
+ + + diff --git a/examples/workflows/load_html.json b/examples/workflows/load_html.json new file mode 100644 index 0000000..1abcbfb --- /dev/null +++ b/examples/workflows/load_html.json @@ -0,0 +1 @@ +{"last_node_id":27,"last_link_id":24,"nodes":[{"id":19,"type":"CDAShowInt","pos":[153.4486083984375,3679.399169921875],"size":[210,76],"flags":{},"order":6,"mode":0,"inputs":[{"name":"int_scalar","type":"INT","link":21,"widget":{"name":"int_scalar"}}],"outputs":[{"name":"STRING","type":"STRING","links":null,"shape":6}],"properties":{"Node name for S&R":"CDAShowInt"},"widgets_values":[0,"0"]},{"id":16,"type":"PandasLoadHTML","pos":[-404.91693115234375,3802.495849609375],"size":[401.24798583984375,274.3761901855469],"flags":{"collapsed":false},"order":0,"mode":0,"inputs":[],"outputs":[{"name":"Number of DataFrames","type":"INT","links":[21],"slot_index":0},{"name":"DataFrame1","type":"DATAFRAME","links":[20],"slot_index":1},{"name":"DataFrame2","type":"DATAFRAME","links":[19],"slot_index":2},{"name":"DataFrame3","type":"DATAFRAME","links":null},{"name":"DataFrame4","type":"DATAFRAME","links":null},{"name":"DataFrame5","type":"DATAFRAME","links":null},{"name":"DataFrame6","type":"DATAFRAME","links":null},{"name":"DataFrame7","type":"DATAFRAME","links":null},{"name":"DataFrame8","type":"DATAFRAME","links":null},{"name":"DataFrame9","type":"DATAFRAME","links":null},{"name":"DataFrame10","type":"DATAFRAME","links":null}],"properties":{"Node name for S&R":"PandasLoadHTML"},"widgets_values":["custom_nodes/data-analysis/examples/datasets/0.html"]},{"id":18,"type":"PandasShowDataFrame","pos":[150.1128692626953,3827.955322265625],"size":[210,114.44503784179688],"flags":{},"order":7,"mode":0,"inputs":[{"name":"dataframe","type":"DATAFRAME","link":20}],"outputs":[{"name":"STRING","type":"STRING","links":null,"shape":6}],"properties":{"Node name for S&R":"PandasShowDataFrame"},"widgets_values":["Empty DataFrame\nColumns: []\nIndex: []"]},{"id":17,"type":"PandasShowDataFrame","pos":[145.82835388183594,4022.322265625],"size":[218.20852661132812,124.71864318847656],"flags":{},"order":8,"mode":0,"inputs":[{"name":"dataframe","type":"DATAFRAME","link":19}],"outputs":[{"name":"STRING","type":"STRING","links":null,"shape":6}],"properties":{"Node name for S&R":"PandasShowDataFrame"},"widgets_values":["Empty DataFrame\nColumns: []\nIndex: []"]},{"id":25,"type":"Note","pos":[-403.0735778808594,3678.12890625],"size":[210,58],"flags":{},"order":1,"mode":0,"inputs":[],"outputs":[],"properties":{},"widgets_values":["0"],"color":"#432","bgcolor":"#653"},{"id":26,"type":"Note","pos":[-408.34283447265625,4308.71923828125],"size":[210,60],"flags":{},"order":2,"mode":0,"inputs":[],"outputs":[],"properties":{},"widgets_values":["1"],"color":"#432","bgcolor":"#653"},{"id":12,"type":"PandasShowDataFrame","pos":[140.2912139892578,4597.55126953125],"size":[252.4537811279297,124.71864318847656],"flags":{},"order":10,"mode":0,"inputs":[{"name":"dataframe","type":"DATAFRAME","link":10}],"outputs":[{"name":"STRING","type":"STRING","links":null,"shape":6}],"properties":{"Node name for S&R":"PandasShowDataFrame"},"widgets_values":[" 0 1\n0 A B\n1 1 10\n2 2 20"]},{"id":15,"type":"CDAShowInt","pos":[143.6732635498047,4448.93310546875],"size":[210,76],"flags":{},"order":9,"mode":0,"inputs":[{"name":"int_scalar","type":"INT","link":18,"widget":{"name":"int_scalar"}}],"outputs":[{"name":"STRING","type":"STRING","links":null,"shape":6}],"properties":{"Node name for S&R":"CDAShowInt"},"widgets_values":[0,"1"]},{"id":11,"type":"PandasLoadHTML","pos":[-411.18060302734375,4446.5068359375],"size":[401.24798583984375,274.3761901855469],"flags":{"collapsed":false},"order":3,"mode":0,"inputs":[],"outputs":[{"name":"Number of DataFrames","type":"INT","links":[18],"slot_index":0},{"name":"DataFrame1","type":"DATAFRAME","links":[10],"slot_index":1},{"name":"DataFrame2","type":"DATAFRAME","links":[11],"slot_index":2},{"name":"DataFrame3","type":"DATAFRAME","links":null},{"name":"DataFrame4","type":"DATAFRAME","links":null},{"name":"DataFrame5","type":"DATAFRAME","links":null},{"name":"DataFrame6","type":"DATAFRAME","links":null},{"name":"DataFrame7","type":"DATAFRAME","links":null},{"name":"DataFrame8","type":"DATAFRAME","links":null},{"name":"DataFrame9","type":"DATAFRAME","links":null},{"name":"DataFrame10","type":"DATAFRAME","links":null}],"properties":{"Node name for S&R":"PandasLoadHTML"},"widgets_values":["custom_nodes/data-analysis/examples/datasets/1.html"]},{"id":10,"type":"PandasShowDataFrame","pos":[144.56851196289062,4796.29638671875],"size":[241.6460418701172,98.23789978027344],"flags":{},"order":11,"mode":0,"inputs":[{"name":"dataframe","type":"DATAFRAME","link":11}],"outputs":[{"name":"STRING","type":"STRING","links":null,"shape":6}],"properties":{"Node name for S&R":"PandasShowDataFrame"},"widgets_values":["Empty DataFrame\nColumns: []\nIndex: []"]},{"id":27,"type":"Note","pos":[-410.1878662109375,5024.64599609375],"size":[210,60],"flags":{},"order":4,"mode":0,"inputs":[],"outputs":[],"properties":{},"widgets_values":["2"],"color":"#432","bgcolor":"#653"},{"id":23,"type":"CDAShowInt","pos":[136.4633331298828,5047.18310546875],"size":[210,76],"flags":{},"order":12,"mode":0,"inputs":[{"name":"int_scalar","type":"INT","link":24,"widget":{"name":"int_scalar"}}],"outputs":[{"name":"STRING","type":"STRING","links":null,"shape":6}],"properties":{"Node name for S&R":"CDAShowInt"},"widgets_values":[0,"2"]},{"id":20,"type":"PandasLoadHTML","pos":[-416.685791015625,5167.482421875],"size":[401.24798583984375,274.3761901855469],"flags":{"collapsed":false},"order":5,"mode":0,"inputs":[],"outputs":[{"name":"Number of DataFrames","type":"INT","links":[24],"slot_index":0},{"name":"DataFrame1","type":"DATAFRAME","links":[23],"slot_index":1},{"name":"DataFrame2","type":"DATAFRAME","links":[22],"slot_index":2},{"name":"DataFrame3","type":"DATAFRAME","links":null},{"name":"DataFrame4","type":"DATAFRAME","links":null},{"name":"DataFrame5","type":"DATAFRAME","links":null},{"name":"DataFrame6","type":"DATAFRAME","links":null},{"name":"DataFrame7","type":"DATAFRAME","links":null},{"name":"DataFrame8","type":"DATAFRAME","links":null},{"name":"DataFrame9","type":"DATAFRAME","links":null},{"name":"DataFrame10","type":"DATAFRAME","links":null}],"properties":{"Node name for S&R":"PandasLoadHTML"},"widgets_values":["custom_nodes/data-analysis/examples/datasets/2.html"]},{"id":22,"type":"PandasShowDataFrame","pos":[129.43141174316406,5204.55859375],"size":[224.93313598632812,111.91206359863281],"flags":{},"order":13,"mode":0,"inputs":[{"name":"dataframe","type":"DATAFRAME","link":23}],"outputs":[{"name":"STRING","type":"STRING","links":null,"shape":6}],"properties":{"Node name for S&R":"PandasShowDataFrame"},"widgets_values":[" 0 1\n0 A B\n1 1 10\n2 2 20"]},{"id":21,"type":"PandasShowDataFrame","pos":[132.9946746826172,5396.63427734375],"size":[216.35691833496094,113.26138305664062],"flags":{},"order":14,"mode":0,"inputs":[{"name":"dataframe","type":"DATAFRAME","link":22}],"outputs":[{"name":"STRING","type":"STRING","links":null,"shape":6}],"properties":{"Node name for S&R":"PandasShowDataFrame"},"widgets_values":[" 0 1\n0 X Y\n1 9.87 98.76\n2 8.76 87.65"]}],"links":[[10,11,1,12,0,"DATAFRAME"],[11,11,2,10,0,"DATAFRAME"],[18,11,0,15,0,"INT"],[19,16,2,17,0,"DATAFRAME"],[20,16,1,18,0,"DATAFRAME"],[21,16,0,19,0,"INT"],[22,20,2,21,0,"DATAFRAME"],[23,20,1,22,0,"DATAFRAME"],[24,20,0,23,0,"INT"]],"groups":[],"config":{},"extra":{"ds":{"scale":0.7283353282260016,"offset":[638.0053254787696,-4641.7708280414845]},"node_versions":{"data-analysis":"25c996f3ba2b40cf07d537c1dd65cbfbcc4cc121"},"ue_links":[]},"version":0.4} \ No newline at end of file diff --git a/examples/workflows/variable_create.json b/examples/workflows/variable_create.json new file mode 100644 index 0000000..11ba14b --- /dev/null +++ b/examples/workflows/variable_create.json @@ -0,0 +1 @@ +{"last_node_id":9,"last_link_id":4,"nodes":[{"id":6,"type":"CDAShowFloat","pos":[85.68311309814453,3906.311279296875],"size":[315,76],"flags":{},"order":5,"mode":0,"inputs":[{"name":"float_scalar","type":"FLOAT","link":2,"widget":{"name":"float_scalar"}}],"outputs":[{"name":"STRING","type":"STRING","links":null,"shape":6}],"properties":{"Node name for S&R":"CDAShowFloat"},"widgets_values":[0,"123.45"]},{"id":7,"type":"PandasShowText","pos":[87.57423400878906,4041.531494140625],"size":[315,76],"flags":{},"order":6,"mode":0,"inputs":[{"name":"text","type":"STRING","link":3,"widget":{"name":"text"}}],"outputs":[{"name":"STRING","type":"STRING","links":null,"shape":6}],"properties":{"Node name for S&R":"PandasShowText"},"widgets_values":["","apple"]},{"id":5,"type":"CDAShowInt","pos":[83.79193878173828,3764.472900390625],"size":[315,76],"flags":{},"order":4,"mode":0,"inputs":[{"name":"int_scalar","type":"INT","link":1,"widget":{"name":"int_scalar"}}],"outputs":[{"name":"STRING","type":"STRING","links":null,"shape":6}],"properties":{"Node name for S&R":"CDAShowInt"},"widgets_values":[0,"123"]},{"id":2,"type":"CDAFloatCreate","pos":[-392.78460693359375,3904.42041015625],"size":[315,58],"flags":{},"order":1,"mode":0,"inputs":[],"outputs":[{"name":"FLOAT","type":"FLOAT","links":[2],"slot_index":0}],"properties":{"Node name for S&R":"CDAFloatCreate"},"widgets_values":["123.45"]},{"id":3,"type":"CDAStringCreate","pos":[-393.7301025390625,4041.530517578125],"size":[315,58],"flags":{},"order":2,"mode":0,"inputs":[],"outputs":[{"name":"STRING","type":"STRING","links":[3],"slot_index":0}],"properties":{"Node name for S&R":"CDAStringCreate"},"widgets_values":["apple"]},{"id":1,"type":"CDAIntCreate","pos":[-393.7300720214844,3766.364501953125],"size":[315,58],"flags":{},"order":0,"mode":0,"inputs":[],"outputs":[{"name":"INT","type":"INT","links":[1],"slot_index":0}],"properties":{"Node name for S&R":"CDAIntCreate"},"widgets_values":["123"]},{"id":4,"type":"CDATextCreate","pos":[-393.73004150390625,4182.42138671875],"size":[316.78826904296875,126.24412536621094],"flags":{},"order":3,"mode":0,"inputs":[],"outputs":[{"name":"STRING","type":"STRING","links":[4],"slot_index":0}],"properties":{"Node name for S&R":"CDATextCreate"},"widgets_values":["banana\ncoconut"]},{"id":9,"type":"PandasShowText","pos":[87.57412719726562,4180.52783203125],"size":[315,76],"flags":{},"order":7,"mode":0,"inputs":[{"name":"text","type":"STRING","link":4,"widget":{"name":"text"}}],"outputs":[{"name":"STRING","type":"STRING","links":null,"shape":6}],"properties":{"Node name for S&R":"PandasShowText"},"widgets_values":["","banana\ncoconut"]}],"links":[[1,1,0,5,0,"INT"],[2,2,0,6,0,"FLOAT"],[3,3,0,7,0,"STRING"],[4,4,0,9,0,"STRING"]],"groups":[],"config":{},"extra":{"ds":{"scale":0.8812857471534622,"offset":[790.8771468343749,-3534.127789960823]},"node_versions":{"data-analysis":"c37db048eb1c8dbe3e84b9056337b7aa1cc6a026"},"ue_links":[]},"version":0.4} \ No newline at end of file diff --git a/modules/cda/cda_float_create.py b/modules/cda/cda_float_create.py new file mode 100644 index 0000000..0968090 --- /dev/null +++ b/modules/cda/cda_float_create.py @@ -0,0 +1,40 @@ +from typing import Any, Dict + + +class CDAFloatCreate: + """ + CDA Float Create: + Creates a Python float using a value entered in the text field. + + category: IO + """ + + @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": False}), + } + } + + RETURN_TYPES: tuple = ("FLOAT",) + FUNCTION: str = "create" + CATEGORY: str = "Data Analysis" + + def create(self, data: str) -> tuple: + """ + creating a Python float for the text entered in the text field. + + Args: + data (str): String value in the text field. + + Returns: + tuple: A tuple containing the float converted from the text. + """ + return (float(data),) diff --git a/modules/cda/cda_int_create.py b/modules/cda/cda_int_create.py new file mode 100644 index 0000000..e3e2fc1 --- /dev/null +++ b/modules/cda/cda_int_create.py @@ -0,0 +1,41 @@ +from typing import Any, Dict + + +class CDAIntCreate: + """ + CDA Int Create: + Creates a Python int using a value entered in the text field. + + category: IO + """ + + @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": False}), + } + } + + RETURN_TYPES: tuple = ("INT",) + FUNCTION: str = "create" + CATEGORY: str = "Data Analysis" + + def create(self, data: str) -> tuple: + """ + creating a Python int for the text entered in the text field. + + Args: + data (str): String value in the text field. + + Returns: + tuple: A tuple containing the int converted from the text. + """ + return (int(data),) + diff --git a/modules/cda/cda_show_float.py b/modules/cda/cda_show_float.py new file mode 100644 index 0000000..cb323b8 --- /dev/null +++ b/modules/cda/cda_show_float.py @@ -0,0 +1,62 @@ +""" +This code is based on +https://github.com/pythongosssss/ComfyUI-Custom-Scripts/blob/main/py/show_text.py + +See credit/credit.md for the full license. +""" +import sys + + +class CDAShowFloat: + """ + Displays a floating-point number as text. + + category: Display data + """ + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "float_scalar": ("FLOAT", {"default": 0.0, "min": sys.float_info.min, "max": sys.float_info.max}) + }, + "hidden": { + "unique_id": "UNIQUE_ID", + "extra_pnginfo": "EXTRA_PNGINFO", + }, + } + + INPUT_IS_LIST = True + RETURN_TYPES = ("STRING",) + FUNCTION = "notify" + OUTPUT_NODE = True + OUTPUT_IS_LIST = (True,) + + CATEGORY = "Data Analysis" + + def notify(self, float_scalar, unique_id=None, extra_pnginfo=None): + text = None + if unique_id is not None and extra_pnginfo is not None: + if not isinstance(extra_pnginfo, list): + print("Error: extra_pnginfo is not a list") + elif ( + not isinstance(extra_pnginfo[0], dict) + or "workflow" not in extra_pnginfo[0] + ): + print("Error: extra_pnginfo[0] is not a dict or missing 'workflow' key") + else: + float_val = float_scalar[0] + text = [str(float_val)] # wrap in list + workflow = extra_pnginfo[0]["workflow"] + node = next( + (x for x in workflow["nodes"] if str(x["id"]) == str(unique_id[0])), + None, + ) + if node: + node["widgets_values"] = text # [text] + else: + print("unique_id or extra_pnginfo is None.") + + # "ui" value is the one that is shown on the node UI. + # Note that "ui" return value needs to a list of strings. + return {"ui": {"text": text}, + "result": (text,)} diff --git a/modules/cda/cda_show_int.py b/modules/cda/cda_show_int.py new file mode 100644 index 0000000..520dba3 --- /dev/null +++ b/modules/cda/cda_show_int.py @@ -0,0 +1,60 @@ +""" +This code is based on +https://github.com/pythongosssss/ComfyUI-Custom-Scripts/blob/main/py/show_text.py + +See credit/credit.md for the full license. +""" + +class CDAShowInt: + """ + Displays a Pandas Int as text. + + category: Display data + """ + @classmethod + def INPUT_TYPES(s): + return { + "required": { + "int_scalar": ("INT", {"default": 0, "min": -1, "max": 2**31}) + }, + "hidden": { + "unique_id": "UNIQUE_ID", + "extra_pnginfo": "EXTRA_PNGINFO", + }, + } + + INPUT_IS_LIST = True + RETURN_TYPES = ("STRING",) + FUNCTION = "notify" + OUTPUT_NODE = True + OUTPUT_IS_LIST = (True,) + + CATEGORY = "Data Analysis" + + def notify(self, int_scalar, unique_id=None, extra_pnginfo=None): + text = None + if unique_id is not None and extra_pnginfo is not None: + if not isinstance(extra_pnginfo, list): + print("Error: extra_pnginfo is not a list") + elif ( + not isinstance(extra_pnginfo[0], dict) + or "workflow" not in extra_pnginfo[0] + ): + print("Error: extra_pnginfo[0] is not a dict or missing 'workflow' key") + else: + int_val = int_scalar[0] + text = [str(int_val)] # wrap in list + workflow = extra_pnginfo[0]["workflow"] + node = next( + (x for x in workflow["nodes"] if str(x["id"]) == str(unique_id[0])), + None, + ) + if node: + node["widgets_values"] = text # [text] + else: + print("unique_id or extra_pnginfo is None.") + + # "ui" value is the one that is shown on the node UI. + # Note that "ui" return value needs to a list of strings. + return {"ui": {"text": text}, + "result": (text,)} diff --git a/modules/cda/cda_string_create.py b/modules/cda/cda_string_create.py new file mode 100644 index 0000000..a69c129 --- /dev/null +++ b/modules/cda/cda_string_create.py @@ -0,0 +1,41 @@ +from typing import Any, Dict + + +class CDAStringCreate: + """ + CDA String Create: + Creates a Python String using a value entered in a single-line text field. + + category: IO + """ + + @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": False}), + } + } + + RETURN_TYPES: tuple = ("STRING",) + FUNCTION: str = "create" + CATEGORY: str = "Data Analysis" + + def create(self, data: str) -> tuple: + """ + creating a Python String for the text entered in the text field. + + Args: + data (str): String value in the text field. + + Returns: + tuple: A tuple containing the string converted from the text. + """ + return (data,) + diff --git a/modules/cda/cda_text_create.py b/modules/cda/cda_text_create.py new file mode 100644 index 0000000..997538b --- /dev/null +++ b/modules/cda/cda_text_create.py @@ -0,0 +1,41 @@ +from typing import Any, Dict + + +class CDATextCreate: + """ + CDA Text Create: + Creates a Python String using a value entered in a multi-line text field. + + category: IO + """ + + @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 Python String for the text entered in the text field. + + Args: + data (str): String value in the text field. + + Returns: + tuple: A tuple containing the string converted from the text. + """ + return (data,) + diff --git a/modules/pandas_wrapper/pandas_load_csv.py b/modules/pandas_wrapper/pandas_load_csv.py index b1522b2..82a122c 100644 --- a/modules/pandas_wrapper/pandas_load_csv.py +++ b/modules/pandas_wrapper/pandas_load_csv.py @@ -31,13 +31,13 @@ class PandasLoadCSV: def load_csv(self, file_path: str) -> tuple: """ - Loads a CSV file into a pandas DataFrame and converts it to a JSON string. + Loads a CSV file into a pandas DataFrame. Args: file_path (str): The path to the CSV file. Returns: - tuple: A tuple containing a JSON string representation of the DataFrame. + tuple: A tuple containing a DataFrame. """ # Read CSV file into DataFrame df = pd.read_csv(file_path) diff --git a/modules/pandas_wrapper/pandas_load_csv_with_encoding.py b/modules/pandas_wrapper/pandas_load_csv_with_encoding.py index 78c5f57..b577290 100644 --- a/modules/pandas_wrapper/pandas_load_csv_with_encoding.py +++ b/modules/pandas_wrapper/pandas_load_csv_with_encoding.py @@ -32,7 +32,7 @@ class PandasLoadCSVWithEncoding: def load_csv(self, file_path: str, encoding: str) -> tuple: """ - Loads a CSV file into a pandas DataFrame and converts it to a JSON string. Allows specifying the file encoding to support formats other than UTF-8. + Loads a CSV file into a pandas DataFrame. Allows specifying the file encoding to support formats other than UTF-8. Refer to the below documents for the list of encodings: https://docs.python.org/3/library/codecs.html#standard-encodings @@ -42,7 +42,7 @@ class PandasLoadCSVWithEncoding: encoding (str): Encoding of the file. Returns: - tuple: A tuple containing a JSON string representation of the DataFrame. + tuple: A tuple containing a DataFrame. """ # Read CSV file into DataFrame df = pd.read_csv(file_path, encoding=encoding) diff --git a/modules/pandas_wrapper/pandas_load_csv_with_index.py b/modules/pandas_wrapper/pandas_load_csv_with_index.py index ef0dd8f..8e2b10b 100644 --- a/modules/pandas_wrapper/pandas_load_csv_with_index.py +++ b/modules/pandas_wrapper/pandas_load_csv_with_index.py @@ -33,14 +33,14 @@ class PandasLoadCSVWithIndex: def load_csv(self, file_path: str, index_col: int=0) -> tuple: """ - Loads a CSV file into a pandas DataFrame and converts it to a JSON string. + Loads a CSV file into a pandas DataFrame. Input data is assume to have an index. Args: file_path (str): The path to the CSV file. Returns: - tuple: A tuple containing a JSON string representation of the DataFrame. + tuple: A tuple containing a DataFrame. """ # Read CSV file into DataFrame df = pd.read_csv(file_path, index_col=index_col) diff --git a/modules/pandas_wrapper/pandas_load_html.py b/modules/pandas_wrapper/pandas_load_html.py new file mode 100644 index 0000000..d24f45f --- /dev/null +++ b/modules/pandas_wrapper/pandas_load_html.py @@ -0,0 +1,68 @@ +from typing import Any, Dict +import pandas as pd + + +class PandasLoadHTML: + """ + Pandas Load HTML: + Scans HTML files for tables and returns the number of DataFrames, with each table represented as a separate DataFrame and the list of those DataFrames. + + category: IO + """ + + @classmethod + def INPUT_TYPES(cls) -> Dict[str, Any]: + """ + Defines the input types for the function. + + Returns: + Dict[str, Any]: A dictionary specifying required input types. + """ + return { + "required": { + "file_path": ("STRING", {"multiline": False}), + } + } + + # TODO: Reference doc generator script cannot parse programatically defined + # list yet, so we need to list return types for now. + RETURN_TYPES: tuple = ("INT", + "DATAFRAME", "DATAFRAME", "DATAFRAME","DATAFRAME", + "DATAFRAME", "DATAFRAME", "DATAFRAME", "DATAFRAME", + "DATAFRAME", "DATAFRAME") + RETURN_NAMES: tuple = ("Number of DataFrames", + "DataFrame1", "DataFrame2", "DataFrame3", "DataFrame4", + "DataFrame5", "DataFrame6", "DataFrame7", "DataFrame8", + "DataFrame9", "DataFrame10") + assert(len(RETURN_NAMES) == len(RETURN_TYPES)) + + FUNCTION: str = "f" + CATEGORY: str = "Data Analysis" + + def f(self, file_path: str) -> tuple: + """ + Loads an HTML file into a pandas DataFrame. + + Args: + file_path (str): The path to the HTML file. The path can be a URL. + + Returns: + tuple: A tuple containing a DataFrame. + """ + try: + dfs = pd.read_html(file_path, flavor="lxml") + except: + dfs = [] + num_dfs = 0 + + if dfs is None: + num_dfs = 0 + dfs = [] + else: + num_dfs = len(dfs) + + df_slot_count = len(PandasLoadHTML.RETURN_TYPES) - 1 + filler_count = df_slot_count - num_dfs + empty_dfs = [pd.DataFrame({})] * filler_count # If filler = 0, this will still return [] + dfs_out = dfs + empty_dfs + return tuple([num_dfs] + dfs_out) diff --git a/modules/pandas_wrapper/pandas_load_json.py b/modules/pandas_wrapper/pandas_load_json.py index 37b53c0..a1f9c78 100644 --- a/modules/pandas_wrapper/pandas_load_json.py +++ b/modules/pandas_wrapper/pandas_load_json.py @@ -31,13 +31,13 @@ class PandasLoadJSON: def load_json(self, file_path: str) -> tuple: """ - Loads a JSON file into a pandas DataFrame and converts it to a JSON string. + Loads a JSON file into a pandas DataFrame. Args: file_path (str): The path to the JSON file. Returns: - tuple: A tuple containing a JSON string representation of the DataFrame. + tuple: A tuple containing a DataFrame. """ # Read JSON file into DataFrame df = pd.read_json(file_path) diff --git a/pyproject.toml b/pyproject.toml index 2f3dd8f..bf3d364 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.1.6" +version = "1.1.7" license = {file = "LICENSE"} [project.urls] diff --git a/web/js/ShowText.js b/web/js/ShowText.js index bd23863..1fa1df7 100644 --- a/web/js/ShowText.js +++ b/web/js/ShowText.js @@ -12,7 +12,7 @@ import { ComfyWidgets } from "../../../scripts/widgets.js"; app.registerExtension({ name: "HowToSD.ShowText", async beforeRegisterNodeDef(nodeType, nodeData, app) { - if (nodeData.name === "PandasShowText") { // This needs to match NODE_CLASS_MAPPINGS in Python + if (["PandasShowText", "CDAShowInt", "CDAShowFloat"].includes(nodeData.name)) { // This needs to match NODE_CLASS_MAPPINGS in Python function populate(text) { if (this.widgets) { for (let i = 1; i < this.widgets.length; i++) {