Godot Version
4.7.2
Question
I made a custom LineGraph node that extends Container, and for some reason duplicating the graph inverts it’s display.
if I run this simple test code after duplicating my graph in the editor every even-numbered graph will be inverted
var example_data = [0, 1, 2, 2, 2, 1, 0, 1, 2, 3, 4, 4, 4, 4, 3, 3, 2, 2, 3, 3, 3, 0, 0, 1 ,1, 2, 2, 2, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 2, 2, 2, 2, 2, 2, 2, 1, 1, 0]
func _ready() -> void:
var data: Array = []
var i: int = 0
while(i < example_data.size()):
data.append([i, example_data[i]])
i+=1
var n: Node
for num in range(get_child_count()):
n = get_child(num)
if n is LineGraph:
n.initialize_graph(data)
However if I duplicate the graph in code every graph is inverted
var graph: LineGraph = get_child(0)
graph.initialize_graph(data)
var new_graph: LineGraph = graph.duplicate()
new_graph.position.x += graph.size.x + 45
add_child(new_graph)
new_graph = new_graph.duplicate()
new_graph.position.y += new_graph.size.y + 45
add_child(new_graph)
I doubt it will help, but here’s the whole class
class_name LineGraph
extends Container
@export var width: float = 10.0
@export var width_curve: Curve
@export var line_color: Color
@export_subgroup("Fill")
enum LineTextureMode {None, Tile, Stretch}
@export var gradient: Gradient
@export var texture: Texture
@export var texture_mode: LineTextureMode
@export_subgroup("Capping")
enum LineJointMode {Sharp, Bevel, Round}
enum LineCapMode {None, Box, Round}
@export var joint_mode: LineJointMode
@export var begin_cap_mode: LineCapMode
@export var end_cap_mode: LineCapMode
@export_subgroup("Border")
@export var sharp_limit: float = 2.0
@export var round_precision: int = 8
@export var antialiased: bool = false
@onready var DEFAULT_LINE_2D: Line2D
var line: Line2D
var data_numbers: Array
var data_normalized: Array
var largest_y: float = -999999999.9
var largest_x: float = -999999999.9
var smallest_x: float = -999999999.9
var smallest_y: float = -999999999.9
func _append_arrays(array_1: Array, array_2: Array, array_3: Array) -> Array:
var new_array: Array = []
for d in array_1:
new_array.append(d)
for d in array_2:
new_array.append(d)
for d in array_3:
new_array.append(d)
return new_array
func _quicksort_data(data_array) -> Array:
if data_array.size() < 1:
return []
var index: Array = data_array[0]
var less: Array
var more: Array
var i: int = 0
while(i < data_array.size()-1):
i+=1
if data_array[i][0] < index[0]:
less.append(data_array[i])
else:
more.append(data_array[i])
less = _quicksort_data(less)
more = _quicksort_data(more)
data_array = _append_arrays(less, [index], more)
return data_array
func initialize_graph(data: Array):
#print("initializing graph")
data_numbers = _quicksort_data(data)
largest_x = data[data.size()-1][0]
smallest_x = data[0][0] - 1.0
smallest_y = data[0][1] + 1.0
largest_y = data[0][1]-1.0
for d in data_numbers:
if d[0] < smallest_x:
smallest_x = d[0]
if d[1] < smallest_y:
smallest_y = d[1]
if d[1] > largest_y:
largest_y = d[1]
#print("largest values found")
normalize_all_data()
draw_graph()
func _insert_data(data: Array):
var dat: Array = []
var dat_normalized: Array = []
var i: int = 0
while(i < data_numbers.size()+1):
if data[0] > data_numbers[i][0]:
dat.append(data_numbers[i])
dat_normalized.append(data_normalized[i])
i+=1
else:
dat.append(data)
dat_normalized.append([dat[0] / largest_x, dat[1] / largest_y])
break
while (i < data_numbers.size()):
dat.append(data_numbers[i])
dat.append(data_normalized[i])
i+=1
func append(x: float, y: float) -> void:
data_numbers.append([x, y])
if y > largest_y:
largest_y = y
if x > largest_x:
largest_x = x
data_numbers.append([x, y])
else:
_insert_data([x, y])
draw_graph()
func _overide_fail(x: float, y: float) -> bool:
var failure: bool = true
for i in range(data_numbers.size()):
if data_numbers[i][0] == x:
data_numbers[i][1] = y
draw_graph()
failure = false
break
return failure
func overide_safe(x: float, y: float) -> void:
if _overide_fail(x, y):
append(x, y)
func overide(x: float, y: float) -> void:
if _overide_fail(x, y):
push_error("x value: {0} not found".format(str(x)))
func normalize_value(value: float, minimum: float, maximum: float) -> float:
if maximum == minimum:
return 1
maximum = maximum - minimum
value = value - minimum
return value / maximum
func normalize_all_data() -> void:
#print("normalizing: " + str(data_numbers.size()))
data_normalized = []
for d in data_numbers:
d[0] = normalize_value(d[0], smallest_x, largest_x)
d[1] = normalize_value(d[1], smallest_y, largest_y)
data_normalized.append(d)
for d in data_normalized:
print(d)
#print("normalized: " + str(data_normalized.size()))
func draw_graph() -> void:
line.clear_points()
var i: int = 0
for d in data_normalized:
d[0] = d[0] * size.x
d[1] = (size.y - (d[1] * size.y))
line.add_point(Vector2(d[0], d[1]), i)
i+=1
func _init() -> void:
DEFAULT_LINE_2D = Line2D.new()
DEFAULT_LINE_2D.set_default_color(line_color)
DEFAULT_LINE_2D.set_width(width)
DEFAULT_LINE_2D.width_curve = width_curve
line = DEFAULT_LINE_2D.duplicate()
add_child(line)
var _stop_process: bool = false
var _frames_alive: int = 0
func _process(_delta: float) -> void:
#stuttered init to win the data race
if _stop_process == false:
_frames_alive += 1
if _frames_alive > 3:
_frames_alive = 0
_stop_process = true
line.set_default_color(line_color)
line.set_width(width)
line.width_curve = width_curve
#Fill
line.gradient = gradient
line.texture = texture
line.texture_mode = int(texture_mode)
#Capping
line.joint_mode = int(joint_mode)
line.begin_cap_mode = int(begin_cap_mode)
line.end_cap_mode = int(end_cap_mode)
#Border
line.sharp_limit = sharp_limit
line.round_precision = round_precision
line.antialiased = antialiased
I have no concept to what might be causing this bug. The only reason I created my own Godot Line Graph is because I thought it would be easier than learning someone else's implementation

