Add math operations and min/max for values and lists

This commit is contained in:
StableLlama
2025-05-08 00:13:39 +02:00
parent d31a8b4f3d
commit c29afc9e38
6 changed files with 750 additions and 7 deletions
+11 -2
View File
@@ -28,7 +28,7 @@ These nodes are very lightweight and require no additional dependencies.
- Modification: append, extend, insert, remove, pop, clear, set_item
- Access: get_item, slice, index, contains
- Information: length, count
- Operations: sort, reverse
- Operations: sort, reverse, min, max
- **SET**: Python set manipulation nodes (as a single variable)
- Conversion: convert to data list, to LIST
@@ -44,7 +44,7 @@ These nodes are very lightweight and require no additional dependencies.
- Modification: append, filter, extend, insert, remove, pop, clear, set_item
- Access: get_item, slice, index, contains
- Information: length, count
- Operations: sort, reverse, copy, zip
- Operations: sort, reverse, copy, zip, min, max
- **DICT**: Dictionary manipulation nodes
- Creation: create, from_items, from_lists, fromkeys, any_to_DICT
@@ -76,6 +76,15 @@ These nodes are very lightweight and require no additional dependencies.
- Conditional: if/else for branching logic based on conditions
- Selection: switch/case for selecting from multiple options based on an index
- **Math**: Mathematical operations
- Trigonometric: sin, cos, tan, asin, acos, atan, atan2
- Logarithmic/Exponential: log, log10, exp, sqrt
- Numerical: min, max
- Constants: pi, e
- Conversion: degrees/radians
- Rounding: floor, ceil
- Other: abs (absolute value)
## Understanding LIST vs. data list vs. SET
ComfyUI has different data types that serve different purposes:
+3 -1
View File
@@ -1,5 +1,5 @@
from . import (boolean_nodes, comparison_nodes, control_flow, data_list_nodes, dict_nodes,
float_nodes, int_nodes, list_nodes, set_nodes, string_nodes)
float_nodes, int_nodes, list_nodes, math_nodes, set_nodes, string_nodes)
NODE_CLASS_MAPPINGS = {}
NODE_CLASS_MAPPINGS.update(boolean_nodes.NODE_CLASS_MAPPINGS)
@@ -11,6 +11,7 @@ NODE_CLASS_MAPPINGS.update(float_nodes.NODE_CLASS_MAPPINGS)
NODE_CLASS_MAPPINGS.update(int_nodes.NODE_CLASS_MAPPINGS)
NODE_CLASS_MAPPINGS.update(list_nodes.NODE_CLASS_MAPPINGS)
NODE_CLASS_MAPPINGS.update(set_nodes.NODE_CLASS_MAPPINGS)
NODE_CLASS_MAPPINGS.update(math_nodes.NODE_CLASS_MAPPINGS)
NODE_CLASS_MAPPINGS.update(string_nodes.NODE_CLASS_MAPPINGS)
NODE_DISPLAY_NAME_MAPPINGS = {}
@@ -23,4 +24,5 @@ NODE_DISPLAY_NAME_MAPPINGS.update(float_nodes.NODE_DISPLAY_NAME_MAPPINGS)
NODE_DISPLAY_NAME_MAPPINGS.update(int_nodes.NODE_DISPLAY_NAME_MAPPINGS)
NODE_DISPLAY_NAME_MAPPINGS.update(list_nodes.NODE_DISPLAY_NAME_MAPPINGS)
NODE_DISPLAY_NAME_MAPPINGS.update(set_nodes.NODE_DISPLAY_NAME_MAPPINGS)
NODE_DISPLAY_NAME_MAPPINGS.update(math_nodes.NODE_DISPLAY_NAME_MAPPINGS)
NODE_DISPLAY_NAME_MAPPINGS.update(string_nodes.NODE_DISPLAY_NAME_MAPPINGS)
+2 -4
View File
@@ -21,7 +21,7 @@ class IfElse:
RETURN_TYPES = ("*",)
RETURN_NAMES = ("result",)
CATEGORY = "Basic/ ⎇ Flow Control"
CATEGORY = "Basic/Flow Control"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "execute"
@@ -40,7 +40,6 @@ class IfElse:
return needed
def execute(self, condition: bool, if_true: Any, if_false: Any) -> tuple[Any]:
"""Execute the if/else statement and return the appropriate value."""
return (if_true if condition else if_false,)
@@ -73,7 +72,7 @@ class SwitchCase:
RETURN_TYPES = ("*",)
RETURN_NAMES = ("result",)
CATEGORY = "Basic/ ⎇ Flow Control"
CATEGORY = "Basic/Flow Control"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "execute"
@@ -103,7 +102,6 @@ class SwitchCase:
def execute(self, selector: int, case_0: Any, case_1: Any,
case_2: Any = None, case_3: Any = None,
case_4: Any = None, default: Any = None) -> tuple[Any]:
"""Execute the switch/case statement and return the appropriate value."""
cases = [case_0, case_1, case_2, case_3, case_4]
if 0 <= selector < len(cases) and cases[selector] is not None:
@@ -721,6 +721,90 @@ class DataListToList:
return (kwargs.get('list', []).copy(),)
class DataListMin:
"""
Finds the minimum value in a list of numbers.
This node takes a list of numbers (either FLOAT or INT) and returns
the minimum value. Returns None if the list is empty or if it contains
non-numeric values.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"list": (["FLOAT", "INT"], {}),
}
}
RETURN_TYPES = ("*",)
RETURN_NAMES = ("min_value",)
CATEGORY = "Basic/data list"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "find_min"
INPUT_IS_LIST = True
@classmethod
def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool|str:
if input_types[0]["list"] not in ("FLOAT", "INT"):
return "list must contain FLOAT or INT types"
return True
def find_min(self, **kwargs: dict[str, list]) -> tuple[Any]:
values = kwargs.get('list', [])
if not values:
return (None,)
try:
# Return the same type as found in the minimum value
return (min(values),)
except (TypeError, ValueError):
# Handle case where list contains non-comparable elements
return (None,)
class DataListMax:
"""
Finds the maximum value in a list of numbers.
This node takes a list of numbers (either FLOAT or INT) and returns
the maximum value. Returns None if the list is empty or if it contains
non-numeric values.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"list": (["FLOAT", "INT"], {}),
}
}
RETURN_TYPES = ("*",)
RETURN_NAMES = ("max_value",)
CATEGORY = "Basic/data list"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "find_max"
INPUT_IS_LIST = True
@classmethod
def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool|str:
if input_types[0]["list"] not in ("FLOAT", "INT"):
return "list must contain FLOAT or INT types"
return True
def find_max(self, **kwargs: dict[str, list]) -> tuple[Any]:
values = kwargs.get('list', [])
if not values:
return (None,)
try:
# Return the same type as found in the maximum value
return (max(values),)
except (TypeError, ValueError):
# Handle case where list contains non-comparable elements
return (None,)
NODE_CLASS_MAPPINGS = {
"DataListAppend": DataListAppend,
"DataListExtend": DataListExtend,
@@ -742,6 +826,8 @@ NODE_CLASS_MAPPINGS = {
"DataListZip": DataListZip,
"DataListFilter": DataListFilter,
"DataListToList": DataListToList,
"DataListMin": DataListMin,
"DataListMax": DataListMax,
}
NODE_DISPLAY_NAME_MAPPINGS = {
@@ -765,4 +851,6 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"DataListZip": "zip",
"DataListFilter": "filter",
"DataListToList": "convert to LIST",
"DataListMin": "min",
"DataListMax": "max",
}
+68
View File
@@ -515,6 +515,70 @@ class AnyToList:
return ([input],)
class ListMin:
"""
Returns the minimum value in a LIST.
This node takes a LIST of comparable items and returns the minimum value.
Returns None if the LIST is empty or if items are not comparable.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"list": ("LIST", {}),
}
}
RETURN_TYPES = ("*",)
RETURN_NAMES = ("min_value",)
CATEGORY = "Basic/LIST"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "find_min"
def find_min(self, list: list[Any]) -> tuple[Any]:
if not list:
return (None,)
try:
return (min(list),)
except (TypeError, ValueError):
# Handle case where list contains non-comparable elements
return (None,)
class ListMax:
"""
Returns the maximum value in a LIST.
This node takes a LIST of comparable items and returns the maximum value.
Returns None if the LIST is empty or if items are not comparable.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"list": ("LIST", {}),
}
}
RETURN_TYPES = ("*",)
RETURN_NAMES = ("max_value",)
CATEGORY = "Basic/LIST"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "find_max"
def find_max(self, list: list[Any]) -> tuple[Any]:
if not list:
return (None,)
try:
return (max(list),)
except (TypeError, ValueError):
# Handle case where list contains non-comparable elements
return (None,)
NODE_CLASS_MAPPINGS = {
"ListAppend": ListAppend,
"ListExtend": ListExtend,
@@ -534,6 +598,8 @@ NODE_CLASS_MAPPINGS = {
"ListToDataList": ListToDataList,
"ListToSet": ListToSet,
"AnyToList": AnyToList,
"ListMin": ListMin,
"ListMax": ListMax,
}
NODE_DISPLAY_NAME_MAPPINGS = {
@@ -555,4 +621,6 @@ NODE_DISPLAY_NAME_MAPPINGS = {
"ListToDataList": "convert to data list",
"ListToSet": "convert to SET",
"AnyToList": "any to LIST",
"ListMin": "min",
"ListMax": "max",
}
+578
View File
@@ -0,0 +1,578 @@
import math
from inspect import cleandoc
from typing import Literal, Union
class MathSin:
"""
Calculates the sine of an angle in radians or degrees.
This node takes an angle value and unit type, and returns the sine of that angle.
The sine of an angle is the ratio of the length of the opposite side to the length
of the hypotenuse in a right-angled triangle.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"angle": ("FLOAT", {"default": 0.0}),
"unit": (["radians", "degrees"], {"default": "radians"}),
}
}
RETURN_TYPES = ("FLOAT",)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
def calculate(self, angle: float, unit: Literal["radians", "degrees"]) -> tuple[float]:
if unit == "degrees":
# Convert degrees to radians
angle = math.radians(angle)
return (math.sin(angle),)
class MathCos:
"""
Calculates the cosine of an angle in radians or degrees.
This node takes an angle value and unit type, and returns the cosine of that angle.
The cosine of an angle is the ratio of the length of the adjacent side to the length
of the hypotenuse in a right-angled triangle.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"angle": ("FLOAT", {"default": 0.0}),
"unit": (["radians", "degrees"], {"default": "radians"}),
}
}
RETURN_TYPES = ("FLOAT",)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
def calculate(self, angle: float, unit: Literal["radians", "degrees"]) -> tuple[float]:
if unit == "degrees":
# Convert degrees to radians
angle = math.radians(angle)
return (math.cos(angle),)
class MathTan:
"""
Calculates the tangent of an angle in radians or degrees.
This node takes an angle value and unit type, and returns the tangent of that angle.
The tangent of an angle is the ratio of the length of the opposite side to the length
of the adjacent side in a right-angled triangle.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"angle": ("FLOAT", {"default": 0.0}),
"unit": (["radians", "degrees"], {"default": "radians"}),
}
}
RETURN_TYPES = ("FLOAT",)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
def calculate(self, angle: float, unit: Literal["radians", "degrees"]) -> tuple[float]:
if unit == "degrees":
# Convert degrees to radians
angle = math.radians(angle)
# Handle specific angles that would result in division by zero
if abs(math.cos(angle)) < 1e-10:
raise ValueError("Tangent is undefined at this angle (division by zero)")
return (math.tan(angle),)
class MathAsin:
"""
Calculates the arc sine (inverse sine) of a value.
This node takes a value between -1 and 1, and returns the arc sine in radians or degrees.
The arc sine is the inverse operation of sine, returning the angle whose sine is the input value.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"value": ("FLOAT", {"default": 0.0, "min": -1.0, "max": 1.0}),
"unit": (["radians", "degrees"], {"default": "radians"}),
}
}
RETURN_TYPES = ("FLOAT",)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
def calculate(self, value: float, unit: Literal["radians", "degrees"]) -> tuple[float]:
result = math.asin(value)
if unit == "degrees":
result = math.degrees(result)
return (result,)
class MathAcos:
"""
Calculates the arc cosine (inverse cosine) of a value.
This node takes a value between -1 and 1, and returns the arc cosine in radians or degrees.
The arc cosine is the inverse operation of cosine, returning the angle whose cosine is the input value.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"value": ("FLOAT", {"default": 1.0, "min": -1.0, "max": 1.0}),
"unit": (["radians", "degrees"], {"default": "radians"}),
}
}
RETURN_TYPES = ("FLOAT",)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
def calculate(self, value: float, unit: Literal["radians", "degrees"]) -> tuple[float]:
result = math.acos(value)
if unit == "degrees":
result = math.degrees(result)
return (result,)
class MathAtan:
"""
Calculates the arc tangent (inverse tangent) of a value.
This node takes a value and returns the arc tangent in radians or degrees.
The arc tangent is the inverse operation of tangent, returning the angle whose tangent is the input value.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"value": ("FLOAT", {"default": 0.0}),
"unit": (["radians", "degrees"], {"default": "radians"}),
}
}
RETURN_TYPES = ("FLOAT",)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
def calculate(self, value: float, unit: Literal["radians", "degrees"]) -> tuple[float]:
result = math.atan(value)
if unit == "degrees":
result = math.degrees(result)
return (result,)
class MathAtan2:
"""
Calculates the arc tangent of y/x, considering the quadrant.
This node takes y and x coordinates and returns the arc tangent in radians or degrees.
Unlike atan(y/x), this function handles the case where x is zero and correctly determines
the quadrant of the resulting angle.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"y": ("FLOAT", {"default": 0.0}),
"x": ("FLOAT", {"default": 1.0}),
"unit": (["radians", "degrees"], {"default": "radians"}),
}
}
RETURN_TYPES = ("FLOAT",)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
def calculate(self, y: float, x: float, unit: Literal["radians", "degrees"]) -> tuple[float]:
result = math.atan2(y, x)
if unit == "degrees":
result = math.degrees(result)
return (result,)
class MathSqrt:
"""
Calculates the square root of a non-negative number.
This node takes a non-negative number and returns its square root.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"value": ("FLOAT", {"default": 0.0, "min": 0.0}),
}
}
RETURN_TYPES = ("FLOAT",)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
def calculate(self, value: float) -> tuple[float]:
return (math.sqrt(value),)
class MathExp:
"""
Calculates the exponential of a number (e^x).
This node takes a number and returns e (Euler's number) raised to the power of that number.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"value": ("FLOAT", {"default": 0.0}),
}
}
RETURN_TYPES = ("FLOAT",)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
def calculate(self, value: float) -> tuple[float]:
return (math.exp(value),)
class MathLog:
"""
Calculates the natural logarithm (base e) of a number.
This node takes a positive number and returns its natural logarithm.
If the specified base is not 'e', calculates the logarithm with the specified base.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"value": ("FLOAT", {"default": 1.0, "min": 0.0000001}),
},
"optional": {
"base": ("FLOAT", {"default": math.e, "min": 0.0000001}),
}
}
RETURN_TYPES = ("FLOAT",)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
def calculate(self, value: float, base: float = math.e) -> tuple[float]:
if base == math.e:
return (math.log(value),)
else:
return (math.log(value, base),)
class MathLog10:
"""
Calculates the base-10 logarithm of a number.
This node takes a positive number and returns its base-10 logarithm.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"value": ("FLOAT", {"default": 1.0, "min": 0.0000001}),
}
}
RETURN_TYPES = ("FLOAT",)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
def calculate(self, value: float) -> tuple[float]:
return (math.log10(value),)
class MathDegrees:
"""
Converts an angle from radians to degrees.
This node takes an angle in radians and returns the equivalent angle in degrees.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"radians": ("FLOAT", {"default": 0.0}),
}
}
RETURN_TYPES = ("FLOAT",)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
def calculate(self, radians: float) -> tuple[float]:
return (math.degrees(radians),)
class MathRadians:
"""
Converts an angle from degrees to radians.
This node takes an angle in degrees and returns the equivalent angle in radians.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"degrees": ("FLOAT", {"default": 0.0}),
}
}
RETURN_TYPES = ("FLOAT",)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
def calculate(self, degrees: float) -> tuple[float]:
return (math.radians(degrees),)
class MathFloor:
"""
Returns the floor of a number.
This node takes a number and returns the largest integer less than or equal to the input value.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"value": ("FLOAT", {"default": 0.0}),
}
}
RETURN_TYPES = ("INT",)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
def calculate(self, value: float) -> tuple[int]:
return (math.floor(value),)
class MathCeil:
"""
Returns the ceiling of a number.
This node takes a number and returns the smallest integer greater than or equal to the input value.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"value": ("FLOAT", {"default": 0.0}),
}
}
RETURN_TYPES = ("INT",)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
def calculate(self, value: float) -> tuple[int]:
return (math.ceil(value),)
class MathAbs:
"""
Returns the absolute value of a number.
This node takes a number and returns its absolute value (magnitude without sign).
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"value": (["FLOAT", "INT"], {}),
}
}
RETURN_TYPES = ("*",)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
@classmethod
def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool|str:
if input_types["value"] not in ("FLOAT", "INT"):
return "value must be a FLOAT or INT type"
return True
def calculate(self, value: Union[float, int]) -> tuple[Union[float, int]]:
return (abs(value),)
class MathPi:
"""
Returns the mathematical constant π (pi).
This node returns the value of π, which is approximately 3.14159.
"""
@classmethod
def INPUT_TYPES(cls):
return {"required": {}}
RETURN_TYPES = ("FLOAT",)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
def calculate(self) -> tuple[float]:
return (math.pi,)
class MathE:
"""
Returns the mathematical constant e.
This node returns the value of e (Euler's number), which is approximately 2.71828.
"""
@classmethod
def INPUT_TYPES(cls):
return {"required": {}}
RETURN_TYPES = ("FLOAT",)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
def calculate(self) -> tuple[float]:
return (math.e,)
class MathMin:
"""
Returns the minimum value among the inputs.
This node takes two or more values and returns the minimum value among them.
The function works with both FLOAT and INT types.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"value1": (["FLOAT", "INT"], {"default": 0}),
"value2": (["FLOAT", "INT"], {"default": 0}),
}
}
RETURN_TYPES = ("*",)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
@classmethod
def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool|str:
for key, value in input_types.items():
if key.startswith("value") and value not in ("FLOAT", "INT"):
return f"{key} must be a FLOAT or INT type"
return True
def calculate(self, value1: Union[float, int], value2: Union[float, int]) -> tuple[Union[float, int]]:
return (min(value1, value2),)
class MathMax:
"""
Returns the maximum value among the inputs.
This node takes two or more values and returns the maximum value among them.
The function works with both FLOAT and INT types.
"""
@classmethod
def INPUT_TYPES(cls):
return {
"required": {
"value1": (["FLOAT", "INT"], {"default": 0}),
"value2": (["FLOAT", "INT"], {"default": 0}),
}
}
RETURN_TYPES = ("*",)
CATEGORY = "Basic/maths"
DESCRIPTION = cleandoc(__doc__ or "")
FUNCTION = "calculate"
@classmethod
def VALIDATE_INPUTS(cls, input_types: dict[str, str]) -> bool|str:
for key, value in input_types.items():
if key.startswith("value") and value not in ("FLOAT", "INT"):
return f"{key} must be a FLOAT or INT type"
return True
def calculate(self, value1: Union[float, int], value2: Union[float, int]) -> tuple[Union[float, int]]:
return (max(value1, value2),)
NODE_CLASS_MAPPINGS = {
"MathSin": MathSin,
"MathCos": MathCos,
"MathTan": MathTan,
"MathAsin": MathAsin,
"MathAcos": MathAcos,
"MathAtan": MathAtan,
"MathAtan2": MathAtan2,
"MathSqrt": MathSqrt,
"MathExp": MathExp,
"MathLog": MathLog,
"MathLog10": MathLog10,
"MathDegrees": MathDegrees,
"MathRadians": MathRadians,
"MathFloor": MathFloor,
"MathCeil": MathCeil,
"MathAbs": MathAbs,
"MathPi": MathPi,
"MathE": MathE,
"MathMin": MathMin,
"MathMax": MathMax,
}
NODE_DISPLAY_NAME_MAPPINGS = {
"MathSin": "sin",
"MathCos": "cos",
"MathTan": "tan",
"MathAsin": "asin",
"MathAcos": "acos",
"MathAtan": "atan",
"MathAtan2": "atan2",
"MathSqrt": "sqrt",
"MathExp": "exp",
"MathLog": "log",
"MathLog10": "log10",
"MathDegrees": "degrees",
"MathRadians": "radians",
"MathFloor": "floor",
"MathCeil": "ceil",
"MathAbs": "abs",
"MathPi": "pi",
"MathE": "e",
"MathMin": "min",
"MathMax": "max",
}