📈 CSV Curve¶
Documentation¶
- Class name:
CSV Curve [Dream]
- Category:
✨ Dream/🎥 animation/📈 curves
- Output node:
False
The CSV Curve node is designed to interpret and apply animation curves based on data extracted from CSV files. It allows for the dynamic generation of animation parameters through the parsing of CSV file content, supporting interpolation and customization of the CSV parsing process.
Input types¶
Required¶
frame_counter
- A counter tracking the current frame of the animation, essential for timing and synchronization of the animation curve with the overall animation sequence.
- Comfy dtype:
FRAME_COUNTER
- Python dtype:
FrameCounter
csvfile
- Specifies the path to the CSV file to be used for generating the animation curve, enabling the node to dynamically interpret and apply the data contained within.
- Comfy dtype:
STRING
- Python dtype:
str
first_column_type
- Determines whether the first column of the CSV file represents seconds or frames, affecting how the data is interpreted in the context of animation timing.
- Comfy dtype:
COMBO[STRING]
- Python dtype:
List[str]
interpolate
- Controls whether interpolation is applied between data points in the CSV file, allowing for smoother transitions in the generated animation curve.
- Comfy dtype:
COMBO[STRING]
- Python dtype:
List[str]
csv_dialect
- Specifies the dialect of the CSV file, enabling the node to accurately parse files with different formatting conventions.
- Comfy dtype:
COMBO[STRING]
- Python dtype:
List[str]
Output types¶
FLOAT
- Comfy dtype:
FLOAT
- The floating-point value generated by the CSV Curve node, representing a point on the animation curve.
- Python dtype:
float
- Comfy dtype:
INT
- Comfy dtype:
INT
- An integer representation of the generated animation curve point, providing an alternative precision level.
- Python dtype:
int
- Comfy dtype:
Usage tips¶
- Infra type:
CPU
- Common nodes: unknown
Source code¶
class DreamCSVCurve:
NODE_NAME = "CSV Curve"
@classmethod
def INPUT_TYPES(cls):
return {
"required": SharedTypes.frame_counter | {
"csvfile": ("STRING", {"default": "", "multiline": False}),
"first_column_type": (["seconds", "frames"],),
"interpolate": (["true", "false"],),
"csv_dialect": (csv.list_dialects(),)
},
}
CATEGORY = NodeCategories.ANIMATION_CURVES
RETURN_TYPES = ("FLOAT", "INT")
RETURN_NAMES = ("FLOAT", "INT")
FUNCTION = "result"
@classmethod
def IS_CHANGED(cls, *values):
return hashed_as_strings(*values)
def _row_yield(self, file, csv_dialect):
prev_row = None
for row in csv.reader(file, dialect=csv_dialect):
if len(row) == 2 and _is_as_float(row[0]) and _is_as_float(row[1]):
row = list(map(float, row))
yield (prev_row, row)
prev_row = row
if prev_row is not None:
yield (prev_row, None)
def result(self, csvfile, frame_counter: FrameCounter, first_column_type, interpolate, csv_dialect):
interpolate = interpolate == "true"
def _first_col_to_frame(v: float):
if first_column_type == "frames":
return round(v)
else:
return round(v * frame_counter.frames_per_second)
with open(csvfile) as f:
for (prev, current) in self._row_yield(f, csv_dialect):
if prev is None and frame_counter.current_frame < _first_col_to_frame(current[0]):
# before first row
return (current[1], int(round(current[1])))
if current is None:
# after last row
return (prev[1], int(round(prev[1])))
if prev is not None and current is not None:
frame1 = _first_col_to_frame(prev[0])
value1 = prev[1]
frame2 = _first_col_to_frame(current[0])
value2 = current[1]
if frame1 <= frame_counter.current_frame and interpolate and frame2 > frame_counter.current_frame:
offset = (frame_counter.current_frame - frame1) / float(frame2 - frame1)
v = value1 * (1.0 - offset) + value2 * offset
return (v, int(round(v)))
elif frame1 <= frame_counter.current_frame and frame2 > frame_counter.current_frame:
return (value1, int(round(value1)))
return (0.0, 0)