diff --git a/__init__.py b/__init__.py
index 66c65de..42d3ecb 100644
--- a/__init__.py
+++ b/__init__.py
@@ -51,6 +51,7 @@ from .modules.pandas_wrapper.pandas_load_csv_with_index import PandasLoadCSVWith
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_multiindex_dataframe import PandasLocRowMultiIndexDataFrame
from .modules.pandas_wrapper.pandas_loc_row_series import PandasLocRowSeries
from .modules.pandas_wrapper.pandas_log import PandasLog
from .modules.pandas_wrapper.pandas_max import PandasMax
@@ -154,6 +155,7 @@ NODE_CLASS_MAPPINGS: Dict[str, Type[T]] = {
"PandasLoadHTML": PandasLoadHTML,
"PandasLoadJSON": PandasLoadJSON,
"PandasLocCellStr": PandasLocCellStr,
+ "PandasLocRowMultiIndexDataFrame": PandasLocRowMultiIndexDataFrame,
"PandasLocRowSeries": PandasLocRowSeries,
"PandasLog": PandasLog,
"PandasMax": PandasMax,
@@ -257,6 +259,7 @@ NODE_DISPLAY_NAME_MAPPINGS: Dict[str, str] = {
"PandasLoadHTML": "Pandas Load HTML",
"PandasLoadJSON": "Pandas Load JSON",
"PandasLocCellStr": "Pandas Loc Cell Str",
+ "PandasLocRowMultiIndexDataFrame": "Pandas Loc Row Multi Index DataFrame",
"PandasLocRowSeries": "Pandas Loc Row Series",
"PandasLog": "Pandas Log",
"PandasMax": "Pandas Max",
diff --git a/docs/images/multiindex.png b/docs/images/multiindex.png
new file mode 100644
index 0000000..a0cd3fc
Binary files /dev/null and b/docs/images/multiindex.png differ
diff --git a/docs/reference/node_reference.md b/docs/reference/node_reference.md
index f09f1bc..b0de593 100644
--- a/docs/reference/node_reference.md
+++ b/docs/reference/node_reference.md
@@ -49,6 +49,7 @@
| [Pandas Iloc Row Series](pandas_iloc_row_series.md) | Selects a row from a pandas DataFrame and returning it as a Series. |
| [Pandas Iloc Rows Data Frame](pandas_iloc_rows_dataframe.md) | Selects rows from a pandas DataFrame and returning it as a DataFrame. |
| [Pandas Loc Cell Str](pandas_loc_cell_str.md) | Selects a cell from a pandas DataFrame and output as a string. |
+| [Pandas Loc Row Multi Index Data Frame](pandas_loc_row_multiindex_dataframe.md) | Selects a row from a pandas DataFrame with MultiIndex and output as a DataFrame. |
| [Pandas Loc Row Series](pandas_loc_row_series.md) | Selects a row from a pandas DataFrame and output as a Series. |
| [Pandas Select Columns](pandas_select_columns.md) | Selects specific columns from a pandas DataFrame. |
| [Pandas Select Rows](pandas_select_rows.md) | Selects specific rows from a pandas DataFrame based on a condition. |
diff --git a/docs/reference/pandas_loc_row_multiindex_dataframe.md b/docs/reference/pandas_loc_row_multiindex_dataframe.md
new file mode 100644
index 0000000..c25fe49
--- /dev/null
+++ b/docs/reference/pandas_loc_row_multiindex_dataframe.md
@@ -0,0 +1,26 @@
+# Pandas Loc Row Multi Index Data Frame
+Selects a row from a pandas DataFrame with MultiIndex and output as a DataFrame.
+
+Specify comma-separated MultiIndex labels (row index) and the data type for the MultiIndex to select a row.
+
+Below screenshots illustrate these options:
+
+
+The top DataFrame has an integer-type MultiIndex, while the bottom DataFrame has a string-type MultiIndex. In both cases, two index values are specified to select a single row while the correct MultiIndex data type is also selected. Note that mixed data types for MultiIndex are not currently supported.
+
+## Input
+| Name | Data type |
+|---|---|
+| dataframe | DataFrame |
+| row_index | String |
+| row_index_type | |
+
+## Output
+| Data type |
+|---|
+| DataFrame |
+
+
+Category: Data subset selection
+
+ComfyUI Data Analysis Node Reference. © 2025 Hide Inada (HowToSD.com). All rights reserved.
diff --git a/examples/workflows/multiindex.json b/examples/workflows/multiindex.json
new file mode 100644
index 0000000..1b6522c
--- /dev/null
+++ b/examples/workflows/multiindex.json
@@ -0,0 +1 @@
+{"last_node_id":80,"last_link_id":85,"nodes":[{"id":78,"type":"PandasShowDataFrame","pos":[-219.4473419189453,4061.099365234375],"size":[285.6177673339844,97.01778411865234],"flags":{},"order":10,"mode":0,"inputs":[{"name":"dataframe","type":"DATAFRAME","link":83}],"outputs":[{"name":"STRING","type":"STRING","links":null,"shape":6}],"properties":{"Node name for S&R":"PandasShowDataFrame"},"widgets_values":[" A B\nIndex C \nW Dog donut 40"]},{"id":77,"type":"PandasLocRowMultiIndexDataFrame","pos":[-220.60975646972656,3891.671142578125],"size":[302.3999938964844,86.90418243408203],"flags":{},"order":7,"mode":0,"inputs":[{"name":"dataframe","type":"DATAFRAME","link":85}],"outputs":[{"name":"DATAFRAME","type":"DATAFRAME","links":[83],"slot_index":0}],"properties":{"Node name for S&R":"PandasLocRowMultiIndexDataFrame"},"widgets_values":["W,Dog","string"]},{"id":73,"type":"PandasShowDataFrame","pos":[-232.98275756835938,3642.0107421875],"size":[285.6177673339844,97.01778411865234],"flags":{},"order":11,"mode":0,"inputs":[{"name":"dataframe","type":"DATAFRAME","link":81}],"outputs":[{"name":"STRING","type":"STRING","links":null,"shape":6}],"properties":{"Node name for S&R":"PandasShowDataFrame"},"widgets_values":[" A C\n B \n1 20 banana Cat"]},{"id":72,"type":"PandasLocRowMultiIndexDataFrame","pos":[-235.06532287597656,3491.6162109375],"size":[302.3999938964844,86.90418243408203],"flags":{},"order":9,"mode":0,"inputs":[{"name":"dataframe","type":"DATAFRAME","link":80}],"outputs":[{"name":"DATAFRAME","type":"DATAFRAME","links":[81],"slot_index":0}],"properties":{"Node name for S&R":"PandasLocRowMultiIndexDataFrame"},"widgets_values":["1,20","int"]},{"id":76,"type":"PandasShowDataFrame","pos":[-487.3261413574219,4040.76318359375],"size":[210,149.5841064453125],"flags":{},"order":6,"mode":0,"inputs":[{"name":"dataframe","type":"DATAFRAME","link":84}],"outputs":[{"name":"STRING","type":"STRING","links":null,"shape":6}],"properties":{"Node name for S&R":"PandasShowDataFrame"},"widgets_values":[" A B\nIndex C \nX Dog apple 10\nY Cat banana 20\nZ Rabbit coconut 30\nW Dog donut 40"]},{"id":67,"type":"PandasSetIndex","pos":[-1046.9400634765625,3486.258544921875],"size":[315,106],"flags":{},"order":5,"mode":0,"inputs":[{"name":"dataframe","type":"DATAFRAME","link":76}],"outputs":[{"name":"DATAFRAME","type":"DATAFRAME","links":[72,80],"slot_index":0}],"properties":{"Node name for S&R":"PandasSetIndex"},"widgets_values":["B",true,true]},{"id":74,"type":"PandasCreateWithIndex","pos":[-1307.4989013671875,3888.37060546875],"size":[210,157.9644317626953],"flags":{},"order":0,"mode":0,"inputs":[],"outputs":[{"name":"DATAFRAME","type":"DATAFRAME","links":[82],"slot_index":0}],"properties":{"Node name for S&R":"PandasCreateWithIndex"},"widgets_values":["Index, A,B,C\nX,apple,10,Dog\nY,banana,20,Cat\nZ,coconut,30,Rabbit\nW,donut,40,Dog",0]},{"id":75,"type":"PandasSetIndex","pos":[-1060.0457763671875,3890.282958984375],"size":[315,106],"flags":{},"order":4,"mode":0,"inputs":[{"name":"dataframe","type":"DATAFRAME","link":82}],"outputs":[{"name":"DATAFRAME","type":"DATAFRAME","links":[84,85],"slot_index":0}],"properties":{"Node name for S&R":"PandasSetIndex"},"widgets_values":["C",true,true]},{"id":80,"type":"MarkdownNote","pos":[-698.1348876953125,3896.85693359375],"size":[320,60],"flags":{},"order":1,"mode":0,"inputs":[],"outputs":[],"properties":{},"widgets_values":["### Connected to DataFrame with String MultiIndex"],"color":"#432","bgcolor":"#653"},{"id":79,"type":"MarkdownNote","pos":[-693.662353515625,3498.498291015625],"size":[313.4215393066406,58],"flags":{},"order":2,"mode":0,"inputs":[],"outputs":[],"properties":{},"widgets_values":["### Connected to DataFrame with Integer MultiIndex"],"color":"#432","bgcolor":"#653"},{"id":71,"type":"PandasShowDataFrame","pos":[-497.32952880859375,3643.9404296875],"size":[210,149.5841064453125],"flags":{},"order":8,"mode":0,"inputs":[{"name":"dataframe","type":"DATAFRAME","link":72}],"outputs":[{"name":"STRING","type":"STRING","links":null,"shape":6}],"properties":{"Node name for S&R":"PandasShowDataFrame"},"widgets_values":[" A C\n B \n0 10 apple Dog\n1 20 banana Cat\n2 30 coconut Dog\n3 40 donut Dog"]},{"id":63,"type":"PandasCreate","pos":[-1296.004638671875,3489.03857421875],"size":[210,132.85110473632812],"flags":{},"order":3,"mode":0,"inputs":[],"outputs":[{"name":"DATAFRAME","type":"DATAFRAME","links":[76],"slot_index":0}],"properties":{"Node name for S&R":"PandasCreate"},"widgets_values":["A,B,C\napple,10,Dog\nbanana,20,Cat\ncoconut,30,Dog\ndonut,40,Dog"]}],"links":[[72,67,0,71,0,"DATAFRAME"],[76,63,0,67,0,"DATAFRAME"],[80,67,0,72,0,"DATAFRAME"],[81,72,0,73,0,"DATAFRAME"],[82,74,0,75,0,"DATAFRAME"],[83,77,0,78,0,"DATAFRAME"],[84,75,0,76,0,"DATAFRAME"],[85,75,0,77,0,"DATAFRAME"]],"groups":[],"config":{},"extra":{"ds":{"scale":0.8936655747208404,"offset":[1278.415275533177,-3326.2076217917866]},"node_versions":{"data-analysis":"554d9dda206203af7225966e218bb0ff8357bf76"},"ue_links":[]},"version":0.4}
\ No newline at end of file
diff --git a/modules/pandas_wrapper/pandas_loc_row_multiindex_dataframe.py b/modules/pandas_wrapper/pandas_loc_row_multiindex_dataframe.py
new file mode 100644
index 0000000..9e17fae
--- /dev/null
+++ b/modules/pandas_wrapper/pandas_loc_row_multiindex_dataframe.py
@@ -0,0 +1,66 @@
+from typing import Any, Dict
+import pandas as pd
+
+class PandasLocRowMultiIndexDataFrame:
+ """
+ Selects a row from a pandas DataFrame with MultiIndex and output as a DataFrame.
+
+ Specify comma-separated MultiIndex labels (row index) and the data type for the MultiIndex to select a row.
+
+ Below screenshots illustrate these options:
+ 
+
+ The top DataFrame has an integer-type MultiIndex, while the bottom DataFrame has a string-type MultiIndex. In both cases, two index values are specified to select a single row while the correct MultiIndex data type is also selected. Note that mixed data types for MultiIndex are not currently supported.
+
+ category: Data subset selection
+ """
+
+ @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", {}),
+ "row_index": ("STRING", {"default": ""}),
+ "row_index_type":(("string", "int"),)
+ }
+ }
+
+ RETURN_TYPES: tuple = ("DATAFRAME",)
+ FUNCTION: str = "f"
+ CATEGORY: str = "Data Analysis"
+
+ def f(self, dataframe: pd.DataFrame,
+ row_index: str,
+ row_index_type: str) -> tuple:
+ """
+ Selects a specific row using a comma-separated MultiIndex labels (row index) from a pandas DataFrame, and returns the DataFrame.
+
+ Args:
+ dataframe (DataFrame): The DataFrame.
+ row_index (str): A comma-separated MultiIndex label for the row.
+ row_index_type (str): The data type of the row index.
+
+ Returns:
+ tuple: A tuple containing the Pandas DataFrame.
+ """
+ # We need to pass a tuple of MultiIndex.
+ # e.g. if the first index is A, second is B, we need to pass:
+ # ("A", "B")
+ ind_list = [ind.strip() for ind in row_index.split(",")]
+
+ # This will throw an exception if the MultiIndex is not an int.
+ if row_index_type == "int":
+ ind_list = [int(ind) for ind in ind_list]
+
+ ind_tuple = tuple(ind_list)
+
+ # We need to wrap it to get the DataFrame. Otherwise, we will get a Series.
+ ind_tuple_list = [ind_tuple]
+ value = dataframe.loc[ind_tuple_list]
+ return (value,)
diff --git a/pyproject.toml b/pyproject.toml
index 8ca92e3..1614496 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.15"
+version = "1.1.16"
license = {file = "LICENSE"}
[project.urls]