Added Pandas To Datetime and Pandas Strftime nodes.

This commit is contained in:
HowToSD
2025-02-22 17:15:14 -08:00
parent fbb7d63cbc
commit 15511db6fd
11 changed files with 280 additions and 1 deletions
+6
View File
@@ -87,6 +87,7 @@ from .modules.pandas_wrapper.pandas_sin import PandasSin
from .modules.pandas_wrapper.pandas_skew import PandasSkew
from .modules.pandas_wrapper.pandas_sort import PandasSort
from .modules.pandas_wrapper.pandas_std import PandasStd
from .modules.pandas_wrapper.pandas_strftime import PandasStrftime
from .modules.pandas_wrapper.pandas_sub import PandasSub
from .modules.pandas_wrapper.pandas_sub_scalar_float import PandasSubScalarFloat
from .modules.pandas_wrapper.pandas_sub_scalar_int import PandasSubScalarInt
@@ -94,6 +95,7 @@ from .modules.pandas_wrapper.pandas_sub_series import PandasSubSeries
from .modules.pandas_wrapper.pandas_sum import PandasSum
from .modules.pandas_wrapper.pandas_summary import PandasSummary
from .modules.pandas_wrapper.pandas_tan import PandasTan
from .modules.pandas_wrapper.pandas_to_datetime import PandasToDatetime
from .modules.pandas_wrapper.pandas_to_string import PandasToString
from .modules.pandas_wrapper.pandas_transpose import PandasTranspose
from .modules.pandas_wrapper.pandas_var import PandasVar
@@ -196,6 +198,7 @@ NODE_CLASS_MAPPINGS: Dict[str, Type[T]] = {
"PandasSkew": PandasSkew,
"PandasSort": PandasSort,
"PandasStd": PandasStd,
"PandasStrftime": PandasStrftime,
"PandasSub": PandasSub,
"PandasSubScalarFloat": PandasSubScalarFloat,
"PandasSubScalarInt": PandasSubScalarInt,
@@ -203,6 +206,7 @@ NODE_CLASS_MAPPINGS: Dict[str, Type[T]] = {
"PandasSum": PandasSum,
"PandasSummary": PandasSummary,
"PandasTan": PandasTan,
"PandasToDatetime": PandasToDatetime,
"PandasToString": PandasToString,
"PandasTranspose": PandasTranspose,
"PandasVar": PandasVar,
@@ -305,6 +309,7 @@ NODE_DISPLAY_NAME_MAPPINGS: Dict[str, str] = {
"PandasSkew": "Pandas Skew",
"PandasSort": "Pandas Sort",
"PandasStd": "Pandas Std",
"PandasStrftime": "Pandas Strftime",
"PandasSub": "Pandas Sub",
"PandasSubScalarFloat": "Pandas Sub Scalar Float",
"PandasSubScalarInt": "Pandas Sub Scalar Int",
@@ -312,6 +317,7 @@ NODE_DISPLAY_NAME_MAPPINGS: Dict[str, str] = {
"PandasSum": "Pandas Sum",
"PandasSummary": "Pandas Summary",
"PandasTan": "Pandas Tan",
"PandasToDatetime": "Pandas To Datetime",
"PandasToString": "Pandas To String",
"PandasTranspose": "Pandas Transpose",
"PandasVar": "Pandas Var",
+5
View File
@@ -65,6 +65,11 @@
| --- | --- |
| [Pandas Columns](pandas_columns.md) | Retrieves the column labels of a pandas DataFrame. |
| [Pandas Index](pandas_index.md) | Retrieves the row labels (index) of a pandas DataFrame. |
## Date and time processing
| Node | Description |
| --- | --- |
| [Pandas Strftime](pandas_strftime.md) | Converts one or more datetime columns in a DataFrame to string columns. |
| [Pandas To Datetime](pandas_to_datetime.md) | Converts one or more string columns in a DataFrame to datetime columns. |
## Display data
| Node | Description |
| --- | --- |
+21
View File
@@ -0,0 +1,21 @@
# Pandas Strftime
Converts one or more datetime columns in a DataFrame to string columns.
Refer to [https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior](Python document) for date/time format strings.
## Input
| Name | Data type |
|---|---|
| dataframe | DataFrame |
| column_names | String |
| date_format | String |
## Output
| Data type |
|---|
| DataFrame |
<HR>
Category: Date and time processing
ComfyUI Data Analysis Node Reference. © 2025 Hide Inada (HowToSD.com). All rights reserved.
+22
View File
@@ -0,0 +1,22 @@
# Pandas To Datetime
Converts one or more string columns in a DataFrame to datetime columns.
Note: When only the time portion is provided, the date defaults to 1900-01-01.
Refer to [https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior](the Python documentation) for valid date/time format strings.
## Input
| Name | Data type |
|---|---|
| dataframe | DataFrame |
| column_names | String |
| date_format | String |
## Output
| Data type |
|---|
| DataFrame |
<HR>
Category: Date and time processing
ComfyUI Data Analysis Node Reference. © 2025 Hide Inada (HowToSD.com). All rights reserved.
+55
View File
@@ -0,0 +1,55 @@
from typing import Any, Dict
import pandas as pd
import pandas.api.types as ptypes
class PandasStrftime:
"""
Converts one or more datetime columns in a DataFrame to string columns.
Refer to [https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior](Python document) for date/time format strings.
category: Date and time processing
"""
@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": {
"dataframe": ("DATAFRAME", {}),
"column_names": ("STRING", {"default": ""}),
"date_format": ("STRING", {"default": ""}),
}
}
RETURN_TYPES: tuple = ("DATAFRAME",)
FUNCTION: str = "f"
CATEGORY: str = "Data Analysis"
def f(self, dataframe: pd.DataFrame, column_names: str, date_format: str) -> tuple:
"""
Converts one or more datetime columns in a DataFrame to string columns.
Args:
dataframe (DataFrame): The DataFrame.
column_names (str): A comma-separated string of column names containing datetime values.
date_format (str): A date format string for strftime.
Returns:
tuple: A tuple containing the DataFrame with formatted date columns.
"""
date_columns = [col.strip() for col in column_names.split(",")]
df2 = dataframe.copy()
df2[date_columns] = df2[date_columns].apply(
# Keep the datetime column check in case the user specifies the non-date column
lambda col: col.dt.strftime(date_format) if ptypes.is_datetime64_any_dtype(col) else col
)
return (df2,)
@@ -0,0 +1,50 @@
from typing import Any, Dict
import pandas as pd
import pandas.api.types as ptypes
class PandasToDatetime:
"""
Converts one or more string columns in a DataFrame to datetime columns.
Note: When only the time portion is provided, the date defaults to 1900-01-01.
Refer to [https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior](the Python documentation) for valid date/time format strings.
category: Date and time processing
"""
@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": {
"dataframe": ("DATAFRAME", {}),
"column_names": ("STRING", {"default": ""}),
"date_format": ("STRING", {"default": ""}),
}
}
RETURN_TYPES: tuple = ("DATAFRAME",)
FUNCTION: str = "f"
CATEGORY: str = "Data Analysis"
def f(self, dataframe: pd.DataFrame, column_names: str, date_format: str) -> tuple:
"""
Converts one or more string columns to datetime columns.
Args:
dataframe (DataFrame): The DataFrame.
column_names (str): A comma-separated string of column names containing date time strings.
date_format (str): A date format.
Returns:
tuple: A tuple containing the DataFrame with selected columns.
"""
date_columns = [col.strip() for col in column_names.split(",")]
df2 = dataframe.apply(lambda col: pd.to_datetime(col, format=date_format) if col.name in date_columns else col)
return (df2,)
+1 -1
View File
@@ -1,7 +1,7 @@
[project]
name = "data-analysis"
description = "Data analysis custom modules for ComfyUI - Use Pandas & Matplotlib within ComfyUI"
version = "1.1.20"
version = "1.1.21"
license = {file = "LICENSE"}
[project.urls]
@@ -0,0 +1,57 @@
import os
import sys
import unittest
import pandas as pd
import pandas.api.types as ptypes
PROJECT_ROOT = os.path.realpath(os.path.join(__file__, "..", "..", ".."))
MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules")
sys.path.append(MODULE_ROOT)
print(MODULE_ROOT)
from pandas_wrapper.pandas_to_datetime import PandasToDatetime
class Test(unittest.TestCase):
def setUp(self):
"""Set up test data"""
self.node = PandasToDatetime()
self.pd_date = pd.DataFrame({
"A": ["2015-01-23", "2013-06-30"],
"B": ["2005-02-24", "2015-09-06"],
"C": [123.45, 987.65],
})
self.pd_date_time = pd.DataFrame({
"A": ["2015-01-23 00:12:34", "2013-06-30 12:50:59"],
"B": [123.45, 987.65],
})
self.pd_time = pd.DataFrame({
"A": ["00:12:34", "12:50:59"],
"B": [123.45, 987.65],
})
def test_date(self):
"""Test"""
df2 = self.node.f(self.pd_date, column_names="A,B", date_format="%Y-%m-%d")[0]
self.assertEqual(df2.at[0, "A"], pd.Timestamp("2015-01-23"))
self.assertEqual(df2.at[0, "C"], 123.45)
def test_date_time(self):
"""Test"""
df3 = self.node.f(self.pd_date_time, column_names="A", date_format="%Y-%m-%d %H:%M:%S")[0]
self.assertTrue(ptypes.is_datetime64_any_dtype(df3["A"]))
self.assertTrue(ptypes.is_float_dtype(df3["B"]))
self.assertEqual(df3.at[0, "A"], pd.Timestamp("2015-01-23 00:12:34"))
self.assertEqual(df3.at[0, "B"], 123.45)
def test_time(self):
"""Test"""
df3 = self.node.f(self.pd_time, column_names="A", date_format="%H:%M:%S")[0]
self.assertTrue(ptypes.is_datetime64_any_dtype(df3["A"]))
self.assertEqual(df3.at[0, "A"], pd.Timestamp("1900-01-01 00:12:34"))
self.assertEqual(df3.at[0, "B"], 123.45)
if __name__ == "__main__":
unittest.main()
@@ -0,0 +1,63 @@
import os
import sys
import unittest
import pandas as pd
import pandas.api.types as ptypes
PROJECT_ROOT = os.path.realpath(os.path.join(__file__, "..", "..", ".."))
MODULE_ROOT = os.path.join(PROJECT_ROOT, "modules")
sys.path.append(MODULE_ROOT)
print(MODULE_ROOT)
from pandas_wrapper.pandas_strftime import PandasStrftime
class Test(unittest.TestCase):
def setUp(self):
"""Set up test data"""
self.node = PandasStrftime()
self.pd_date = pd.DataFrame({
"A": [pd.Timestamp("2015-01-23"), pd.Timestamp("2013-06-30")],
"B": [pd.Timestamp("2005-02-24"), pd.Timestamp("2015-09-06")],
"C": [123.45, 987.65],
})
self.pd_date_time = pd.DataFrame({
"A": [pd.Timestamp("2015-01-23 00:12:34"), pd.Timestamp("2013-06-30 12:50:59")],
"B": [123.45, 987.65],
})
self.pd_time = pd.DataFrame({
"A": [pd.Timestamp("1900-01-01 00:12:34"), pd.Timestamp("1900-01-01 12:50:59")],
"B": [123.45, 987.65],
})
def test_date(self):
"""Test date formatting"""
df2 = self.node.f(self.pd_date, column_names="A,B", date_format="%Y-%m-%d")[0]
self.assertTrue(ptypes.is_string_dtype(df2["A"]))
self.assertTrue(ptypes.is_string_dtype(df2["B"]))
self.assertEqual(df2.at[0, "A"], "2015-01-23")
self.assertEqual(df2.at[1, "B"], "2015-09-06")
self.assertEqual(df2.at[0, "C"], 123.45) # Ensure non-date columns are unchanged
def test_date_time(self):
"""Test datetime formatting"""
df3 = self.node.f(self.pd_date_time, column_names="A", date_format="%Y-%m-%d %H:%M:%S")[0]
self.assertTrue(ptypes.is_string_dtype(df3["A"]))
self.assertTrue(ptypes.is_float_dtype(df3["B"]))
self.assertEqual(df3.at[0, "A"], "2015-01-23 00:12:34")
self.assertEqual(df3.at[1, "A"], "2013-06-30 12:50:59")
self.assertEqual(df3.at[0, "B"], 123.45)
def test_time(self):
"""Test time formatting"""
df4 = self.node.f(self.pd_time, column_names="A", date_format="%H:%M:%S")[0]
self.assertTrue(ptypes.is_string_dtype(df4["A"]))
self.assertEqual(df4.at[0, "A"], "00:12:34")
self.assertEqual(df4.at[1, "A"], "12:50:59")
self.assertEqual(df4.at[0, "B"], 123.45)
if __name__ == "__main__":
unittest.main()