update scatter_chart_base

This commit is contained in:
fenix-hub 2022-01-10 00:01:10 +01:00
parent a5ce0a5cd6
commit ef76c04470
5 changed files with 102 additions and 62 deletions

View File

@ -26,11 +26,11 @@ In these cases they are known as run charts."
}
Chart_Properties/are_values_columns = false
Chart_Properties/labels_index = 0
Chart_Properties/show_x_values_as_labels = false
Chart_Display/autoscale_x = true
Chart_Display/x_decim = 1.0
Chart_Display/autoscale_y = true
Chart_Display/y_decim = 1.0
Chart_Display/show_points = true
Chart_Style/points_shape = [ 0 ]
Chart_Style/function_colors = PoolColorArray( 0.117647, 0.117647, 0.117647, 1, 0.117647, 0.117647, 0.117647, 1, 0.117647, 0.117647, 0.117647, 1, 0.117647, 0.117647, 0.117647, 1 )
Chart_Style/function_line_width = 2
@ -46,7 +46,6 @@ Chart_Style/template = 0
Chart_Modifiers/treshold = Vector2( 0, 0 )
Chart_Modifiers/only_disp_values = Vector2( 0, 0 )
Chart_Modifiers/invert_chart = false
Chart_Display/show_points = true
[node name="Background" type="ColorRect" parent="."]
visible = false
@ -86,10 +85,10 @@ __meta__ = {
[node name="CanvasLayer" type="CanvasLayer" parent="."]
[node name="DataTooltip" parent="CanvasLayer" instance=ExtResource( 1 )]
margin_left = -50.9019
margin_top = -37.7724
margin_right = -51.0379
margin_bottom = -36.9724
margin_left = -124.653
margin_top = -56.7206
margin_right = -124.789
margin_bottom = -55.9206
[node name="PointData" parent="CanvasLayer/DataTooltip" index="0"]
margin_left = -189.809

View File

@ -317,6 +317,9 @@ func _set(property, value):
func _init():
build_property_list()
func _ready():
load_font()
# .......................... Shared Functions and virtuals ........................
# Structure and Display a new plot if a dataset source is given
@ -324,7 +327,6 @@ func _init():
func plot(_dataset: Array = read_data(source, delimiter)) -> void:
clean_variables()
clean_points()
load_font()
data_tooltip.hide()
if _dataset.empty():
@ -418,8 +420,10 @@ func display_plot():
calculate_coordinates()
func redraw_plot():
data_tooltip.hide()
clean_points()
display_plot()
update()
# ................................. Helper Functions .................................

View File

@ -5,6 +5,8 @@ class_name ScatterChartBase
# of points in a two-variable space. It handles basic data structure and grid
# layout and leaves to child classes the more specific behaviour.
var x_values := []
var y_values := []
#Stored in the form of [[min_func1, min_func2, min_func3, ...], [max_func1, max_func2, ...]]
var x_domain := [[], []]
var y_domain := [[], []]
@ -272,14 +274,11 @@ func _get(property):
"Chart_Display/max_y_range":
return y_range[1]
func plot_function(x:Array, y:Array, param_dic := {}):
func plot_function(id: String, x:Array, y:Array, param_dic := {}):
# Add a function to the chart. If no identifier (label) is given a generic one
# is generated.
# param_dic is a dictionary with specific parameters to this curve
data_tooltip.hide()
var id := ""
if x.empty() or y.empty():
ECUtilities._print_message("Can't plot a chart with an empty Array.",1)
return
@ -287,16 +286,6 @@ func plot_function(x:Array, y:Array, param_dic := {}):
ECUtilities._print_message("Can't plot a chart with x and y having different number of elements.",1)
return
for param in param_dic.keys():
match param:
"label":
id = param_dic[param]
"color":
if function_colors.size() < functions + 1: #There is going to be a new function
function_colors.append(param_dic[param])
else:
function_colors[functions] = param_dic[param]
id = generate_identifier() if id.empty() else id
if y_labels.has(id):
@ -308,15 +297,33 @@ func plot_function(x:Array, y:Array, param_dic := {}):
x_domain[0].append(null)
x_domain[1].append(null)
x_datas.append(x)
y_datas.append(y)
y_labels.append(id)
x_values.append_array(x)
y_values = y
populate_x_datas()
populate_y_datas()
calculate_range(id)
plot()
calculate_tics()
redraw_plot()
update()
func update_functions(new_x, new_y : Array, param_dic : = {}) :
x_values.append(new_x)
for function in y_labels.size():
_update_function(y_labels[function], new_y[function])
calculate_tics()
redraw_plot()
update()
func update_function(id:String, x:Array, y:Array, param_dic := {}):
func update_function(id: String, new_x, new_y, param_dic := {}) -> void:
x_values.append(new_x)
_update_function(id, new_y, param_dic)
calculate_tics()
redraw_plot()
update()
func _update_function(id: String, new_y, param_dic := {}):
var function = y_labels.find(id)
if function == -1: #Not found
@ -330,22 +337,20 @@ func update_function(id:String, x:Array, y:Array, param_dic := {}):
"color":
function_colors[function] = param_dic[param]
x_datas[function] = x
y_datas[function] = y
for y_data_i in range(0, y_datas.size()):
if y_data_i == function: y_datas[y_data_i].append(new_y)
else: y_datas[y_data_i].append(y_datas[y_data_i][y_datas[y_data_i].size()-1])
calculate_range(id)
plot()
update()
func delete_function(id:String):
func delete_function(id: String):
var function = y_labels.find(id)
if function == -1: #Not found
ECUtilities._print_message("The identifier %s does not exist." % id,1)
return
y_labels.remove(function)
# y_labels.remove(function)
x_datas.remove(function)
y_datas.remove(function)
y_domain[0].remove(function)
@ -354,14 +359,25 @@ func delete_function(id:String):
x_domain[1].remove(function)
function_colors.remove(function)
plot()
calculate_tics()
redraw_plot()
update()
func generate_identifier():
#TODO: Check if the identifier generated already exist (given by the user)
return "f%d" % (y_labels.size() + 1)
func populate_x_datas():
x_labels = x_values
x_datas.append(x_values)
func populate_y_datas():
y_labels.append(y_values.duplicate(true).pop_front() as String)
for val in y_values.size():
y_values[val] = y_values[val] as float
y_datas.append(y_values)
func structure_data(database : Array):
# @labels_index can be either a column or a row relative to x values
@ -371,8 +387,6 @@ func structure_data(database : Array):
#This function is called from the "old" methods such as plot_from_array and
#for the moment it doesn't clean this variables on clean_variable.
var x_values := []
var y_values := []
x_domain = [[], []]
y_domain = [[], []]
@ -380,22 +394,11 @@ func structure_data(database : Array):
if database_size.has(labels_index):
x_values = database[labels_index]
x_label = x_values.pop_front() as String
x_labels = x_values
database_size.erase(labels_index) #Remove x row from the iterator
for row in database_size:
y_values = database[row] as Array
y_labels.append(y_values.pop_front() as String)
for val in y_values.size():
y_values[val] = y_values[val] as float
y_datas.append(y_values)
for x_value in x_values:
if str(x_value).is_valid_float():
x_datas.append(x_values if not x_values.empty() else range(y_values.size()))
else:
x_datas.append(x_labels)
for size in database_size:
populate_x_datas()
y_values = database[size]
populate_y_datas()
for function in y_labels:
y_domain[0].append(null)
@ -449,13 +452,13 @@ func calculate_tics():
calculate_interval_tics(y_margin_min, y_margin_max, v_dist, y_chors)
for i in y_chors.size():
y_chors[i] = String(y_chors[i]) #Can't cast directly on calculate_interval_tics because it mess up with the sorting
x_chors = x_labels
x_chors = x_labels.duplicate(true)
func build_chart():
var longest_y_tic = 0
for y_tic in y_chors:
var length = font.get_string_size(y_tic).x
var length = font.get_string_size(str(y_tic)).x
if length > longest_y_tic:
longest_y_tic = length
@ -489,7 +492,7 @@ func calculate_coordinates():
for function in y_labels.size():
for val in x_datas[function].size():
var value_x = (int(x_datas[function][val]) - x_margin_min) * x_pass / h_dist if h_dist else \
x_chors.find(String(x_datas[function][val])) * x_pass
val * x_pass
var value_y = (y_datas[function][val] - y_margin_min) * y_pass / v_dist if v_dist else 0
point_values[function].append([x_datas[function][val], y_datas[function][val]])
@ -500,13 +503,13 @@ func draw_grid():
# ascisse
for p in x_chors.size():
var point : Vector2 = origin + Vector2(p * x_pass, 0)
var size_text : Vector2 = font.get_string_size(x_chors[p])
var size_text : Vector2 = font.get_string_size(str(x_chors[p]))
# v grid
draw_line(point, point - Vector2(0, SIZE.y - OFFSET.y), v_lines_color, grid_lines_width, true)
# ascisse
draw_line(point + Vector2(0, tic_length), point, v_lines_color, grid_lines_width, true)
draw_string(font, point + Vector2(-size_text.x / 2, size_text.y + tic_length),
x_chors[p], font_color)
str(x_chors[p]), font_color)
# ordinate
for p in y_chors.size():
@ -578,3 +581,11 @@ func calculate_interval_tics(v_from:float, v_to:float, dist:float, chords:Array,
p = (dist * multi) + v_from
missing_tics = p < v_to if dist > 0 else p > v_to
chords.append(p)
func _to_string() -> String:
return \
"X DATA: %s\n" % str(x_datas) + \
"Y DATA: %s\n" % str(y_datas) + \
"X LABELS: %s\n" % str(x_labels) + \
"Y LABELS: %s\n" % str(y_labels)

View File

@ -9,8 +9,9 @@ var datamatrix : Matrix = null
var dataset : Array = []
func _init(datamatrix : Matrix, headers : PoolStringArray = [], labels : PoolStringArray = [] , table_name : String = "") -> void:
if labels.empty() : for label in range(datamatrix.get_size().x) : labels.append(label as String)
if headers.empty() : for header in range(datamatrix.get_size().y) : headers.append(MatrixGenerator.get_letter_index(header))
if labels.empty() : for label in range(datamatrix.get_size().x) : labels.append(label as String)
if datamatrix.empty(): datamatrix.resize(labels.size(), headers.size())
build_dataframe(datamatrix, headers, labels, table_name)
func build_dataframe(datamatrix : Matrix, headers : PoolStringArray = [], labels : PoolStringArray = [] , table_name : String = "") -> void:
@ -32,12 +33,18 @@ func build_dataset_from_matrix(datamatrix : Matrix, headers : PoolStringArray, l
func insert_column(column : Array, header : String = "", index : int = dataset[0].size()) -> void:
assert(column.size() == datamatrix.rows(), "error: the column size must match the dataset column size")
headers.insert(index, header if header != "" else MatrixGenerator.get_letter_index(index))
datamatrix.insert_column(column, index-1)
if datamatrix.get_column(index-2 if index > 2 else 0).count(null) == datamatrix.rows():
datamatrix.update_column(column, index-2)
else:
datamatrix.insert_column(column, index-1)
dataset = build_dataset_from_matrix(datamatrix, headers, labels)
func insert_row(row : Array, label : String = "", index : int = dataset.size()) -> PoolStringArray:
labels.insert(index-1, label if label != "" else (index-1) as String)
datamatrix.insert_row(row, index-1)
if datamatrix.get_row(index-2 if index > 2 else 0).count(null) == datamatrix.columns():
datamatrix.update_row(row, index-2 if index > 2 else 0)
else:
datamatrix.insert_row(row, index-1)
dataset = build_dataset_from_matrix(datamatrix, headers, labels)
return PoolStringArray([label] + row)

View File

@ -12,12 +12,28 @@ func insert_row(row : Array, index : int = values.size()) -> void:
assert(row.size() == columns(), "the row size must match matrix row size")
values.insert(index, row)
func update_row(row : Array, index : int) -> void:
assert(rows() > index, "the row size must match matrix row size")
values[index] = row
func insert_column(column : Array, index : int = values[0].size()) -> void:
if columns() != 0:
assert(column.size() == rows(), "the column size must match matrix column size")
for row_idx in column.size():
values[row_idx].insert(index, column[row_idx])
func update_column(column : Array, index : int) -> void:
assert(columns() > index, "the column size must match matrix column size")
for row_idx in column.size():
values[row_idx][index] = column[row_idx]
func resize(rows: int, columns: int) -> void:
for row in range(rows):
var value_row := []
for column in range(columns):
value_row.append(null)
values.append(value_row)
func to_array() -> Array:
return values.duplicate(true)
@ -37,7 +53,7 @@ func get_column(column : int) -> Array:
column_array.append(row[column])
return column_array
func get_columns(from : int, to : int) -> Array:
func get_columns(from : int = 0, to : int = columns()-1) -> Array:
var values : Array = []
for column in range(from, to):
values.append(get_column(column))
@ -48,10 +64,13 @@ func get_row(row : int) -> Array:
assert(row < rows(), "index of the row requested (%s) exceedes matrix rows (%s)"%[row, rows()])
return values[row]
func get_rows(from : int, to : int) -> Array:
func get_rows(from : int = 0, to : int = rows()-1) -> Array:
return values.slice(from, to)
# return MatrixGenerator.from_array(values)
func empty() -> bool:
return rows() == 0 and columns() == 0
func _to_string() -> String:
var last_string_len : int
for row in values: