*added*- radar chart- better charts implementation- chart and chart2D classes to identify each chart- function_names_index as parameter to determine what's the index of the function names (both rows or columns)

This commit is contained in:
Nicolò Santilio 2020-05-26 23:52:45 +02:00
parent 9a199ff1c7
commit 009488b43b
27 changed files with 1002 additions and 87 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
*.import
*.png

View File

@ -1,4 +1,4 @@
[![version](https://img.shields.io/badge/plugin%20version-0.1.5-blue)](https://github.com/fenix-hub/godot-engine.easy-charts)
[![version](https://img.shields.io/badge/plugin%20version-0.2.1-blue)](https://github.com/fenix-hub/godot-engine.easy-charts)
[![updates](https://img.shields.io/badge/plugin%20updates-on%20discord-purple)](https://discord.gg/JNrcucg)
[![paypal](https://img.shields.io/badge/donations-PayPal-cyan)](https://paypal.me/NSantilio?locale.x=it_IT)
@ -9,7 +9,7 @@ Check my **[Discord](https://discord.gg/KnJGY9S)** to stay updated on this repos
A library of Charts plotted in Control, 2D and 3D nodes to visualize general purpose datasets.
Author: *"Nicolo (fenix) Santilio"*
Version: *0.1.5*
Version: *0.2.1*
Wiki: *[wip]*
Godot Version: *3.2stable*
@ -153,3 +153,4 @@ I don't assume any responsibility for possible corruptions of your project. It i

View File

@ -1,5 +1,5 @@
tool
extends Control
extends Chart
"""
[BarChart] - General purpose node for Bar Charts
@ -93,7 +93,7 @@ export (float,0,10,0.5) var column_gap : float = 2
export (float,0.1,10.0) var x_decim : float = 5.0
export (float,0.1,10.0) var y_decim : float = 5.0
export (int,"Dot,Triangle,Square") var point_shape : int = 0
export (point_shapes) var point_shape : int = 0
export (PoolColorArray) var function_colors = [Color("#1e1e1e")]
export (Color) var v_lines_color : Color = Color("#cacaca")
@ -104,7 +104,7 @@ export (Color) var box_color : Color = Color("#1e1e1e")
export (Font) var font : Font
export (Font) var bold_font : Font
export (Color) var font_color : Color = Color("#1e1e1e")
export (String,"Default","Clean","Gradient","Minimal","Invert") var template : String = "Default" setget apply_template
export (templates_names) var template : int = Chart.templates_names.Default setget apply_template
export (bool) var invert_chart : bool = false
var templates : Dictionary = {}
@ -169,7 +169,7 @@ func plot():
emit_signal("chart_plotted")
func clear_points():
if Points.get_children():
if Points.get_children().size():
for function in Points.get_children():
function.queue_free()
for legend in Legend.get_children():
@ -189,6 +189,7 @@ func point_pressed(point : Point):
func _enter_tree():
templates = Utilities._load_templates()
_ready()
func read_datas(source : String, delimiter : String):
var file : File = File.new()
@ -481,14 +482,15 @@ func create_legend():
function_legend.create_legend(f_name,function_colors[function],bold_font,font_color)
legend.append(function_legend)
func apply_template(template_name : String):
func apply_template(template_name : int):
template = template_name
templates = Utilities._load_templates()
if template_name!=null and template_name!="":
var custom_template = templates[template.to_lower()]
function_colors = custom_template.function_colors
if template_name!=null:
var custom_template = templates.get(templates.keys()[template_name])
function_colors = custom_template.function_colors as PoolColorArray
v_lines_color = Color(custom_template.v_lines_color)
h_lines_color = Color(custom_template.h_lines_color)
box_color = Color(custom_template.outline_color)
font_color = Color(custom_template.font_color)
property_list_changed_notify()

View File

@ -12,6 +12,7 @@ rect_min_size = Vector2( 70, 50 )
mouse_filter = 2
script = ExtResource( 2 )
__meta__ = {
"The file you want to use as a source for your chart. It must be a *.CSV file, or a plain *.TXT file formatted in the right way.": "",
"_edit_use_anchors_": false,
"_editor_description_": "[BarChart] - General purpose node for Bar Charts

View File

@ -1,5 +1,5 @@
tool
extends Node2D
extends Chart2D
"""
[BarChart2D] - General purpose node for Bar Charts
@ -16,13 +16,13 @@ values of more than one measured variable.
/ source : Wikipedia /
"""
onready var OutlinesTween : Tween = $OutlinesTween
onready var FunctionsTween : Tween = $FunctionsTween
onready var Functions : Node2D = $Functions
onready var GridTween : Tween = $GridTween
onready var PointData = $PointData/PointData
onready var Outlines : Line2D = $Outlines
onready var Grid : Node2D = $Grid
var OutlinesTween : Tween
var FunctionsTween
var Functions : Node2D
var GridTween : Tween
var PointData : PointData
var Outlines : Line2D
var Grid : Node2D
var point_node : PackedScene = preload("../Utilities/Point/Point.tscn")
var FunctionLegend : PackedScene = preload("../Utilities/Legend/FunctionLegend.tscn")
@ -96,7 +96,7 @@ export (float,0,10,0.5) var column_gap : float = 2
export (float,0.1,10.0) var x_decim : float = 5.0
export (float,0.1,10.0) var y_decim : float = 5.0
export (int,"Dot,Triangle,Square") var point_shape : int = 0
export (point_shapes) var point_shape : int = 0
export (PoolColorArray) var function_colors = [Color("#1e1e1e")]
export (Color) var v_lines_color : Color = Color("#cacaca")
export (Color) var h_lines_color : Color = Color("#cacaca")
@ -106,7 +106,7 @@ export (Color) var box_color : Color = Color("#1e1e1e")
export (Font) var font : Font
export (Font) var bold_font : Font
export (Color) var font_color : Color = Color("#1e1e1e")
export (String,"Default","Clean","Gradient","Minimal","Invert") var template : String = "Default" setget apply_template
export (templates_names) var template : int = Chart.templates_names.Default setget apply_template
export (float,0.1,1) var drawing_duration : float = 0.5
export (bool) var invert_chart : bool = false
@ -119,7 +119,15 @@ func _point_plotted():
pass
func _ready():
pass
_get_children()
func _get_children():
OutlinesTween = $OutlinesTween
Functions = $Functions
GridTween = $GridTween
PointData = $PointData/PointData
Outlines = $Outlines
Grid = $Grid
func _set_size(size : Vector2):
SIZE = size
@ -536,12 +544,12 @@ func create_legend():
function_legend.create_legend(f_name,function_colors[function],bold_font,font_color)
legend.append(function_legend)
func apply_template(template_name : String):
func apply_template(template_name : int):
template = template_name
templates = Utilities._load_templates()
if template_name!=null and template_name!="":
var custom_template = templates[template.to_lower()]
function_colors = custom_template.function_colors
if template_name!=null:
var custom_template = templates.get(templates.keys()[template_name])
function_colors = custom_template.function_colors as PoolColorArray
v_lines_color = Color(custom_template.v_lines_color)
h_lines_color = Color(custom_template.h_lines_color)
box_color = Color(custom_template.outline_color)
@ -549,6 +557,10 @@ func apply_template(template_name : String):
property_list_changed_notify()
if Engine.editor_hint:
_get_children()
Outlines.set_default_color(box_color)
Grid.get_node("VLine").set_default_color(v_lines_color)
Grid.get_node("HLine").set_default_color(h_lines_color)
func _enter_tree():
_ready()

View File

@ -1,5 +1,5 @@
tool
extends Control
extends Chart
"""
[Linechart] - General purpose node for Line Charts
@ -93,7 +93,7 @@ export(bool) var show_x_values_as_labels : bool = true
export (float,0.1,10.0) var x_decim : float = 5.0
export (float,0.1,10.0) var y_decim : float = 5.0
export (int,"Dot,Triangle,Square") var point_shape : int = 0
export (point_shapes) var point_shape : int = 0
export (PoolColorArray) var function_colors = [Color("#1e1e1e")]
export (Color) var v_lines_color : Color = Color("#cacaca")
export (Color) var h_lines_color : Color = Color("#cacaca")
@ -103,7 +103,7 @@ export (Color) var box_color : Color = Color("#1e1e1e")
export (Font) var font : Font
export (Font) var bold_font : Font
export (Color) var font_color : Color = Color("#1e1e1e")
export (String,"Default","Clean","Gradient","Minimal","Invert") var template : String = "Default" setget apply_template
export (templates_names) var template : int = Chart.templates_names.Default setget apply_template
export (bool) var invert_chart : bool = false
@ -114,7 +114,7 @@ signal point_pressed(point)
func _ready():
apply_template(template)
pass
func _plot(source_ : String, delimiter_ : String, are_values_columns_ : bool, x_values_index_ : int, invert_chart_ : bool = false):
randomize()
@ -502,14 +502,17 @@ func count_functions():
else:
functions = datas.size()-1
func apply_template(template_name : String):
func apply_template(template_name : int):
template = template_name
templates = Utilities._load_templates()
if template_name!=null and template_name!="":
var custom_template = templates[template.to_lower()]
function_colors = custom_template.function_colors
if template_name!=null:
var custom_template = templates.get(templates.keys()[template_name])
function_colors = custom_template.function_colors as PoolColorArray
v_lines_color = Color(custom_template.v_lines_color)
h_lines_color = Color(custom_template.h_lines_color)
box_color = Color(custom_template.outline_color)
font_color = Color(custom_template.font_color)
property_list_changed_notify()
func _enter_tree():
_ready()

View File

@ -1,5 +1,5 @@
tool
extends Node2D
extends Chart2D
"""
[Linechart2D] - General purpose node for Line Charts
@ -16,13 +16,13 @@ In these cases they are known as run charts.
"""
onready var OutlinesTween : Tween = $OutlinesTween
onready var FunctionsTween : Tween = $FunctionsTween
onready var Functions : Node2D = $Functions
onready var GridTween : Tween = $GridTween
onready var PointData = $PointData/PointData
onready var Outlines : Line2D = $Outlines
onready var Grid : Node2D = $Grid
var OutlinesTween : Tween
var FunctionsTween : Tween
var Functions : Node2D
var GridTween : Tween
var PointData : PointData
var Outlines : Line2D
var Grid : Node2D
var point_node : PackedScene = preload("../Utilities/Point/Point.tscn")
var FunctionLegend : PackedScene = preload("../Utilities/Legend/FunctionLegend.tscn")
@ -96,7 +96,7 @@ export(bool) var show_x_values_as_labels : bool = true
export (float,0.1,10.0) var x_decim : float = 5.0
export (float,0.1,10.0) var y_decim : float = 5.0
export (int,"Dot,Triangle,Square") var point_shape : int = 0
export (point_shapes) var point_shape : int = 0
export (PoolColorArray) var function_colors = [Color("#1e1e1e")]
export (Color) var v_lines_color : Color = Color("#cacaca")
export (Color) var h_lines_color : Color = Color("#cacaca")
@ -106,7 +106,7 @@ export (Color) var box_color : Color = Color("#1e1e1e")
export (Font) var font : Font
export (Font) var bold_font : Font
export (Color) var font_color : Color = Color("#1e1e1e")
export (String,"Default","Clean","Gradient","Minimal","Invert") var template : String = "Default" setget apply_template
export (templates_names) var template : int = Chart.templates_names.Default setget apply_template
export (float,0.1,1) var drawing_duration : float = 0.5
export (bool) var invert_chart : bool = false
@ -119,12 +119,21 @@ func _point_plotted():
pass
func _ready():
pass
_get_children()
func _get_children():
OutlinesTween = $OutlinesTween
Functions = $Functions
GridTween = $GridTween
PointData = $PointData/PointData
Outlines = $Outlines
Grid = $Grid
func _set_size(size : Vector2):
SIZE = size
build_chart()
if Engine.editor_hint:
_get_children()
Outlines.set_point_position(0,Vector2(origin.x,0))
Outlines.set_point_position(1,Vector2(SIZE.x,0))
Outlines.set_point_position(2,Vector2(SIZE.x,origin.y))
@ -533,12 +542,12 @@ func create_legend():
function_legend.create_legend(f_name,function_colors[function],bold_font,font_color)
legend.append(function_legend)
func apply_template(template_name : String):
func apply_template(template_name : int):
template = template_name
templates = Utilities._load_templates()
if template_name!=null and template_name!="":
var custom_template = templates[template.to_lower()]
function_colors = custom_template.function_colors
if template_name!=null:
var custom_template = templates.get(templates.keys()[template_name])
function_colors = custom_template.function_colors as PoolColorArray
v_lines_color = Color(custom_template.v_lines_color)
h_lines_color = Color(custom_template.h_lines_color)
box_color = Color(custom_template.outline_color)
@ -546,6 +555,10 @@ func apply_template(template_name : String):
property_list_changed_notify()
if Engine.editor_hint:
_get_children()
Outlines.set_default_color(box_color)
Grid.get_node("VLine").set_default_color(v_lines_color)
Grid.get_node("HLine").set_default_color(h_lines_color)
func _enter_tree():
_ready()

View File

@ -0,0 +1,377 @@
tool
extends Chart
"""
[RadarChart] - General purpose node for Radar Charts
A radar chart is a graphical method of displaying multivariate data in the form
of a two-dimensional chart of three or more quantitative variables represented on axes
starting from the same point. The relative position and angle of the axes is typically
uninformative, but various heuristics, such as algorithms that plot data as the maximal
total area, can be applied to sort the variables (axes) into relative positions that reveal
distinct correlations, trade-offs, and a multitude of other comparative measures.
/ source : Wikipedia /
"""
onready var PointData = $PointData/PointData
onready var Points = $Points
onready var Legend = $Legend
var point_node : PackedScene = preload("../Utilities/Point/Point.tscn")
var FunctionLegend : PackedScene = preload("../Utilities/Legend/FunctionLegend.tscn")
var font_size : float = 16
var const_height : float = font_size/2*font_size/20
var const_width : float = font_size/2
var OFFSET : Vector2 = Vector2(0,0)
#-------------------------------------------------------------------------#
var origin : Vector2
# actual distance between x and y values
var x_pass : float
var y_pass : float
# vertical distance between y consecutive points used for intervals
var v_dist : float
var h_dist : float
# quantization, representing the interval in which values will be displayed
# define values on x an y axis
var x_chors : Array
var y_chors : Array
# actual coordinates of points (in pixel)
var x_coordinates : Array
var y_coordinates : Array
# datas contained in file
var datas : Array
# amount of functions to represent
var functions : int = 0
# database values
var x_datas : Array
var y_datas : Array
# labels displayed on chart
var x_label : String
var x_labels : Array
var y_labels : Array
var x_margin_min : int = 0
var y_margin_min : int = 0
# actual values of point, from the database
var point_values : Array
# actual position of points in pixel
var point_positions : Array
var legend : Array setget set_legend,get_legend
# ---------------------
var SIZE : Vector2 = Vector2()
export (String, FILE, "*.txt, *.csv") var source : String = "" setget set_source
export (String) var delimiter : String = ";"
#export (bool) var origin_at_zero : bool = true
export (bool) var are_values_columns : bool = false
export (int,-1,100) var labels_index : int = 0
export (int,-1,100) var function_names_index : int = 0
#export(bool) var show_x_values_as_labels : bool = true
#export (float,1,20,0.5) var column_width : float = 10
#export (float,0,10,0.5) var column_gap : float = 2
export (bool) var use_height_as_radius : bool = false
export (float) var radius : float = 150.0
#export (float,0.1,10.0) var x_decim : float = 5.0
#export (float,0.1,10.0) var y_decim : float = 5.0
export (float,0.1,100) var full_scale : float = 1.0
export (point_shapes) var point_shape : int = 0
export (PoolColorArray) var function_colors = [Color("#1e1e1e")]
export (Color) var outline_color : Color = Color("#1e1e1e")
export (Color) var grid_color : Color = Color("#1e1e1e")
export (Font) var font : Font
export (Font) var bold_font : Font
export (Color) var font_color : Color = Color("#1e1e1e")
export (templates_names) var template : int = Chart.templates_names.Default setget apply_template
#export (bool) var invert_chart : bool = false
export (float,0,360) var rotation : float = 0
var templates : Dictionary = {}
signal chart_plotted(chart)
signal point_pressed(point)
func _ready():
pass
func _plot(source_ : String, delimiter_ : String, are_values_columns_ : bool, x_values_index_ : int, invert_chart_ : bool = false):
randomize()
load_font()
PointData.hide()
datas = read_datas(source_,delimiter_)
structure_datas(datas,are_values_columns_,x_values_index_)
build_chart()
count_functions()
calculate_pass()
calculate_coordinates()
calculate_colors()
create_legend()
emit_signal("chart_plotted")
func plot():
randomize()
load_font()
PointData.hide()
if source == "" or source == null:
Utilities._print_message("Can't plot a chart without a Source file. Please, choose it in editor, or use the custom function _plot().",1)
return
datas = read_datas(source,delimiter)
structure_datas(datas,are_values_columns,labels_index)
build_chart()
count_functions()
calculate_pass()
calculate_coordinates()
calculate_colors()
create_legend()
emit_signal("chart_plotted")
func calculate_colors():
if function_colors.empty() or function_colors.size() < functions:
for function in functions:
function_colors.append(Color("#1e1e1e"))
func load_font():
if font != null:
font_size = font.get_height()
var theme : Theme = Theme.new()
theme.set_default_font(font)
PointData.set_theme(theme)
else:
var lbl = Label.new()
font = lbl.get_font("")
lbl.free()
if bold_font != null:
PointData.Data.set("custom_fonts/font",bold_font)
func read_datas(source : String, delimiter : String):
var file : File = File.new()
file.open(source,File.READ)
var content : Array
while not file.eof_reached():
var line : PoolStringArray = file.get_csv_line(delimiter)
content.append(line)
file.close()
for data in content:
if data.size() < 2 or data.empty():
content.erase(data)
return content
func structure_datas(database : Array, are_values_columns : bool, labels_index : int):
# @x_values_index can be either a column or a row relative to x values
# @y_values can be either a column or a row relative to y values
self.labels_index = labels_index
self.are_values_columns = are_values_columns
match are_values_columns:
true:
for row in database.size():
if row == labels_index:
x_labels = database[row] as PoolStringArray
else:
if database[row].empty() or database[row].size() < 2:
continue
x_datas.append(PoolRealArray(database[row] as Array))
for column in database[row].size():
if column == function_names_index:
y_labels.append(database[row][column])
false:
for row in database.size():
if row == function_names_index:
y_labels = database[row] as PoolStringArray
var x_temp_datas : PoolRealArray = []
for column in database[row].size():
if column == labels_index:
x_labels.append(database[row][column] as String)
else:
x_temp_datas.append(database[row][column] as float)
x_datas.append(x_temp_datas)
if labels_index == -1 :
for data in x_datas[0].size():
x_labels.append("Element %s" % data)
if function_names_index == -1 :
for data in x_datas.size():
y_labels.append("Function %s" % data)
func build_chart():
SIZE = get_size()
origin = OFFSET + SIZE/2
var radar_polygon : Array
func calculate_pass() :
var ordered_max : Array
for data in x_datas :
var ordered_data : Array = (data as Array)
ordered_data.sort()
ordered_max.append(ordered_data.pop_back())
ordered_max.sort()
var max_value : float = ordered_max.pop_back()
var dist = full_scale * pow(10.0,str(max_value).length()-2)
var multi = 0
var value = dist * multi
x_chors.append(value as String)
while value < max_value:
multi+=1
value = dist * multi
x_chors.append(value as String)
func calculate_coordinates():
for chor in x_chors.size():
var inner_polyline : PoolVector2Array
var scalar_factor : float = (x_chors[chor] as float/x_chors.back() as float)
for function in functions:
var angle : float = ((2 * PI * function) / functions) - PI /2 + deg2rad(rotation)
var x_coordinate : float = (radius if not use_height_as_radius else SIZE.y/2) * scalar_factor * cos(angle) + origin.x
var y_coordinate : float = (radius if not use_height_as_radius else SIZE.y/2) * scalar_factor * sin(angle) + origin.y
inner_polyline.append(Vector2(x_coordinate, y_coordinate))
inner_polyline.append(inner_polyline[0])
radar_polygon.append(inner_polyline)
for datas in x_datas:
var function_positions : PoolVector2Array
var function_values : Array
for data in datas.size():
var scalar_factor : float = datas[data] /( x_chors.back() as float)
var angle : float = ((2 * PI * data) / datas.size()) - PI/2 + deg2rad(rotation)
var x_coordinate : float = (radius if not use_height_as_radius else SIZE.y/2) * scalar_factor * cos(angle) + origin.x
var y_coordinate : float = (radius if not use_height_as_radius else SIZE.y/2) * scalar_factor * sin(angle) + origin.y
function_positions.append(Vector2(x_coordinate,y_coordinate))
function_values.append([x_labels[data], datas[data]])
function_positions.append(function_positions[0])
point_positions.append(function_positions)
point_values.append(function_values)
func redraw():
build_chart()
calculate_pass()
calculate_coordinates()
update()
func _draw():
if Engine.editor_hint:
return
clear_points()
draw_grid()
for function in point_positions.size():
var function_color : Color = function_colors[function]
draw_polygon(point_positions[function], [Color(function_color.r, function_color.g, function_color.b, 0.2)],[],null,null,true)
draw_polyline(point_positions[function], function_color, 2,true)
for _function in point_values.size():
var PointContainer : Control = Control.new()
Points.add_child(PointContainer)
for function_point in point_values[_function].size():
var point : Point = point_node.instance()
point.connect("_point_pressed",self,"point_pressed")
point.connect("_mouse_entered",self,"show_data")
point.connect("_mouse_exited",self,"hide_data")
point.create_point(point_shape, function_colors[_function],
Color.white, point_positions[_function][function_point],
point.format_value(point_values[_function][function_point], false, false),
y_labels[_function])
# str("Function %s"%_function))
PointContainer.add_child(point)
func draw_grid():
for polyline in radar_polygon:
draw_polyline(polyline, grid_color, 1, true)
var text : String = x_chors[radar_polygon.find(polyline)] as String
draw_string(font, polyline[0] - Vector2(font.get_string_size(text).x/2,-5), text, font_color)
if not radar_polygon.empty():
draw_polyline(radar_polygon[radar_polygon.size()-1], outline_color, 1, true)
for label in x_labels.size():
var point_array : PoolVector2Array = radar_polygon[radar_polygon.size()-1]
draw_line(origin, point_array[label], grid_color, 1, true)
draw_string(font, point_array[label] - (Vector2(font.get_string_size(x_labels[label]).x/2,0) if point_array[label].x < origin.x else - Vector2(5,0)), x_labels[label], font_color)
func create_legend():
legend.clear()
for function in functions:
var function_legend = FunctionLegend.instance()
var f_name : String = x_labels[function]
var legend_font : Font
if font != null:
legend_font = font
if bold_font != null:
legend_font = bold_font
function_legend.create_legend(f_name,function_colors[function],bold_font,font_color)
legend.append(function_legend)
func show_data(point):
PointData.update_datas(point)
PointData.show()
func hide_data():
PointData.hide()
func clear_points():
if Points.get_children():
for function in Points.get_children():
function.queue_free()
for legend in Legend.get_children():
legend.queue_free()
func set_legend(l : Array):
legend = l
func get_legend():
return legend
func count_functions():
self.functions = x_labels.size()
func apply_template(template_name : int):
template = template_name
templates = Utilities._load_templates()
if template_name!=null:
var custom_template = templates.get(templates.keys()[template_name])
function_colors = custom_template.function_colors as PoolColorArray
outline_color = Color(custom_template.outline_color)
grid_color = Color(custom_template.v_lines_color)
font_color = Color(custom_template.font_color)
property_list_changed_notify()
func _enter_tree():
_ready()
func set_source(source_file : String):
source = source_file

View File

@ -0,0 +1,59 @@
[gd_scene load_steps=4 format=2]
[ext_resource path="res://addons/easy_charts/Utilities/Point/PointData.tscn" type="PackedScene" id=1]
[ext_resource path="res://addons/easy_charts/RadarChart/RadarChart.gd" type="Script" id=2]
[sub_resource type="Theme" id=1]
[node name="RadarChart" type="Control"]
anchor_right = 1.0
anchor_bottom = 1.0
rect_min_size = Vector2( 70, 50 )
mouse_filter = 2
script = ExtResource( 2 )
__meta__ = {
"_edit_use_anchors_": false,
"_editor_description_": "[RadarChart] - General purpose node for Radar Charts
A radar chart is a graphical method of displaying multivariate data in the form
of a two-dimensional chart of three or more quantitative variables represented on axes
starting from the same point. The relative position and angle of the axes is typically
uninformative, but various heuristics, such as algorithms that plot data as the maximal
total area, can be applied to sort the variables (axes) into relative positions that reveal
distinct correlations, trade-offs, and a multitude of other comparative measures."
}
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 )
grid_color = Color( 0.792157, 0.792157, 0.792157, 1 )
[node name="Background" type="ColorRect" parent="."]
visible = false
show_behind_parent = true
anchor_right = 1.0
anchor_bottom = 1.0
color = Color( 0.882353, 0.882353, 0.882353, 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Points" type="Control" parent="."]
margin_right = 40.0
margin_bottom = 40.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Legend" type="HBoxContainer" parent="."]
visible = false
margin_right = 1024.0
margin_bottom = 64.0
alignment = 1
__meta__ = {
"_edit_use_anchors_": false
}
[node name="PointData" parent="." instance=ExtResource( 1 )]
[node name="PointData" parent="PointData" index="0"]
visible = false
theme = SubResource( 1 )
[editable path="PointData"]

View File

@ -1,5 +1,5 @@
tool
extends Control
extends Chart
"""
[ScatterChart] - General purpose node for Scatter Charts
@ -91,7 +91,7 @@ export(bool) var show_x_values_as_labels : bool = true
export (float,0.1,10.0) var x_decim : float = 5.0
export (float,0.1,10.0) var y_decim : float = 5.0
export (int,"Dot,Triangle,Square") var point_shape : int = 0
export (point_shapes) var point_shape : int = 0
export (PoolColorArray) var function_colors = [Color("#1e1e1e")]
export (Color) var v_lines_color : Color = Color("#cacaca")
export (Color) var h_lines_color : Color = Color("#cacaca")
@ -101,7 +101,7 @@ export (Color) var box_color : Color = Color("#1e1e1e")
export (Font) var font : Font
export (Font) var bold_font : Font
export (Color) var font_color : Color = Color("#1e1e1e")
export (String,"Default","Clean","Gradient","Minimal","Invert") var template : String = "Default" setget apply_template
export (templates_names) var template : int = templates_names.Default setget apply_template
export (bool) var invert_chart : bool = false
@ -112,7 +112,7 @@ signal point_pressed(point)
func _ready():
apply_template(template)
pass
func _plot(source_ : String, delimiter_ : String, are_values_columns_ : bool, x_values_index_ : int, invert_chart_ : bool = false):
randomize()
@ -495,14 +495,18 @@ func count_functions():
else:
functions = datas.size()-1
func apply_template(template_name : String):
func apply_template(template_name : int):
template = template_name
templates = Utilities._load_templates()
if template_name!=null and template_name!="":
var custom_template = templates[template.to_lower()]
function_colors = custom_template.function_colors
if template_name!=null:
var custom_template = templates.get(templates.keys()[template_name])
function_colors = custom_template.function_colors as PoolColorArray
v_lines_color = Color(custom_template.v_lines_color)
h_lines_color = Color(custom_template.h_lines_color)
box_color = Color(custom_template.outline_color)
font_color = Color(custom_template.font_color)
property_list_changed_notify()
func _enter_tree():
templates = Utilities._load_templates()
_ready()

View File

@ -1,5 +1,5 @@
tool
extends Node2D
extends Chart2D
"""
[ScatterChart2D] - General purpose node for Scatter Charts
@ -13,13 +13,13 @@ the horizontal axis and the value of the other variable determining the position
/ source : Wikipedia /
"""
onready var OutlinesTween : Tween = $OutlinesTween
onready var PointTween : Tween = $PointTween
onready var Functions : Node2D = $Functions
onready var GridTween : Tween = $GridTween
onready var PointData = $PointData/PointData
onready var Outlines : Line2D = $Outlines
onready var Grid : Node2D = $Grid
var OutlinesTween : Tween
var PointTween : Tween
var Functions : Node2D
var GridTween : Tween
var PointData : PointData
var Outlines : Line2D
var Grid : Node2D
var point_node : PackedScene = preload("../Utilities/Point/Point.tscn")
var FunctionLegend : PackedScene = preload("../Utilities/Legend/FunctionLegend.tscn")
@ -93,8 +93,8 @@ export(bool) var show_x_values_as_labels : bool = true
export (float,0.1,10.0) var x_decim : float = 5.0
export (float,0.1,10.0) var y_decim : float = 5.0
export (int,"Dot,Triangle,Square") var point_shape : int = 0
export (PoolColorArray) var function_colors = [Color("#1e1e1e")]
export (point_shapes) var point_shape : int = 0
export (PoolColorArray) var function_colors = [Color("#1e1e1e")] as PoolColorArray
export (Color) var v_lines_color : Color = Color("#cacaca")
export (Color) var h_lines_color : Color = Color("#cacaca")
@ -103,7 +103,7 @@ export (Color) var box_color : Color = Color("#1e1e1e")
export (Font) var font : Font
export (Font) var bold_font : Font
export (Color) var font_color : Color = Color("#1e1e1e")
export (String,"Default","Clean","Gradient","Minimal","Invert") var template : String = "Default" setget apply_template
export (templates_names) var template : int = templates_names.Default setget apply_template
export (float,0.1,1) var drawing_duration : float = 0.5
export (bool) var invert_chart : bool = false
@ -116,12 +116,22 @@ func _point_plotted():
pass
func _ready():
pass
_get_children()
func _get_children():
OutlinesTween = $OutlinesTween
PointTween = $PointTween
Functions = $Functions
GridTween = $GridTween
PointData = $PointData/PointData
Outlines = $Outlines
Grid = $Grid
func _set_size(size : Vector2):
SIZE = size
build_chart()
if Engine.editor_hint:
_get_children()
Outlines.set_point_position(0,Vector2(origin.x,0))
Outlines.set_point_position(1,Vector2(SIZE.x,0))
Outlines.set_point_position(2,Vector2(SIZE.x,origin.y))
@ -197,7 +207,7 @@ func plot():
func calculate_colors():
if function_colors.empty() or function_colors.size() < functions:
for function in functions:
function_colors.append(Color("#1e1e1e"))
function_colors.append(Color("#1e1e1e") as Color)
func draw_chart():
draw_outlines()
@ -513,12 +523,12 @@ func create_legend():
function_legend.create_legend(f_name,function_colors[function],bold_font,font_color)
legend.append(function_legend)
func apply_template(template_name : String):
func apply_template(template_name : int):
template = template_name
templates = Utilities._load_templates()
if template_name!=null and template_name!="":
var custom_template = templates[template.to_lower()]
function_colors = custom_template.function_colors
if template_name!=null:
var custom_template = templates.get(templates.keys()[template_name])
function_colors = custom_template.function_colors as PoolColorArray
v_lines_color = Color(custom_template.v_lines_color)
h_lines_color = Color(custom_template.h_lines_color)
box_color = Color(custom_template.outline_color)
@ -526,6 +536,11 @@ func apply_template(template_name : String):
property_list_changed_notify()
if Engine.editor_hint:
_get_children()
Outlines.set_default_color(box_color)
Grid.get_node("VLine").set_default_color(v_lines_color)
Grid.get_node("HLine").set_default_color(h_lines_color)
func _enter_tree():
_ready()

View File

@ -1,10 +1,308 @@
tool
extends Spatial
onready var Point = $Chart/Point
"""
[ScatterChart] - General purpose node for Scatter Charts
A scatter plot (also called a scatterplot, scatter graph, scatter chart, scattergram, or scatter diagram)
is a type of plot or mathematical diagram using Cartesian coordinates to display values for typically two variables
for a set of data. If the points are coded (color/shape/size), one additional variable can be displayed.
The data are displayed as a collection of points, each having the value of one variable determining the position on
the horizontal axis and the value of the other variable determining the position on the vertical axis.
/ source : Wikipedia /
"""
onready var PlaceholderPoint = $Chart/Point
onready var Space = $ImmediateGeometry
onready var PointData = $PointData/PointData
var point_node : PackedScene = preload("../Utilities/Point/Point.tscn")
var FunctionLegend : PackedScene = preload("../Utilities/Legend/FunctionLegend.tscn")
var font_size : float = 16
var const_height : float = font_size/2*font_size/20
var const_width : float = font_size/2
var OFFSET : Vector2 = Vector2(0,0)
#-------------------------------------------------------------------------#
var origin : Vector2
# actual distance between x and y values
var x_pass : float
var y_pass : float
# vertical distance between y consecutive points used for intervals
var v_dist : float
var h_dist : float
# quantization, representing the interval in which values will be displayed
# define values on x an y axis
var x_chors : Array
var y_chors : Array
# actual coordinates of points (in pixel)
var x_coordinates : Array
var y_coordinates : Array
# datas contained in file
var datas : Array
# amount of functions to represent
var functions : int = 0
var x_label : String
var z_label : String
# database values
var x_datas : Array
var z_datas : Array
var y_datas : Array
# labels displayed on chart
var x_labels : Array
var y_labels : Array
var x_margin_min : int = 0
var y_margin_min : int = 0
# actual values of point, from the database
var point_values : Array
# actual position of points in pixel
var point_positions : Array
var legend : Array setget set_legend,get_legend
# ---------------------
export (Vector2) var SIZE : Vector2 = Vector2() setget _set_size
export (String, FILE, "*.txt, *.csv") var source : String = ""
export (String) var delimiter : String = ";"
export (bool) var origin_at_zero : bool = true
export (bool) var are_values_columns : bool = false
export (int,0,100) var x_values_index : int = 0
export (int,0,100) var z_values_index : int = 0
export(bool) var show_x_values_as_labels : bool = true
#export (float,1,20,0.5) var column_width : float = 10
#export (float,0,10,0.5) var column_gap : float = 2
export (float,0.1,10.0) var x_decim : float = 5.0
export (float,0.1,10.0) var y_decim : float = 5.0
export (int,"Dot,Triangle,Square") var point_shape : int = 0
export (PoolColorArray) var function_colors = [Color("#1e1e1e")]
export (Color) var v_lines_color : Color = Color("#cacaca")
export (Color) var h_lines_color : Color = Color("#cacaca")
export (bool) var boxed : bool = true
export (Color) var box_color : Color = Color("#1e1e1e")
export (Font) var font : Font
export (Font) var bold_font : Font
export (Color) var font_color : Color = Color("#1e1e1e")
export (String,"Default","Clean","Gradient","Minimal","Invert") var template : String = "Default" setget apply_template
export (float,0.1,1) var drawing_duration : float = 0.5
export (bool) var invert_chart : bool = false
var templates : Dictionary = {}
signal chart_plotted(chart)
signal point_pressed(point)
func _point_plotted():
pass
func _ready():
# var p : MeshInstance = Point.duplicate()
# p.transform.origin = Vector3(1,0,1)
# add_child(p)
pass
func _set_size(size : Vector2):
SIZE = size
# build_chart()
func clear():
pass
func load_font():
if font != null:
font_size = font.get_height()
var theme : Theme = Theme.new()
theme.set_default_font(font)
PointData.set_theme(theme)
else:
var lbl = Label.new()
font = lbl.get_font("")
lbl.free()
if bold_font != null:
PointData.Data.set("custom_fonts/font",bold_font)
func _plot(source_ : String, delimiter_ : String, are_values_columns_ : bool, x_values_index_ : int):
randomize()
clear()
load_font()
PointData.hide()
datas = read_datas(source_,delimiter_)
# count_functions()
structure_datas(datas,are_values_columns_,x_values_index_)
# build_chart()
# calculate_pass()
# calculate_coordinates()
# calculate_colors()
# draw_chart()
#
# create_legend()
emit_signal("chart_plotted", self)
func plot():
randomize()
clear()
load_font()
PointData.hide()
if source == "" or source == null:
Utilities._print_message("Can't plot a chart without a Source file. Please, choose it in editor, or use the custom function _plot().",1)
return
datas = read_datas(source,delimiter)
# count_functions()
structure_datas(datas,are_values_columns,x_values_index)
# build_chart()
# calculate_pass()
# calculate_coordinates()
# calculate_colors()
# draw_chart()
# create_legend()
emit_signal("chart_plotted", self)
func read_datas(source : String, delimiter : String):
var file : File = File.new()
file.open(source,File.READ)
var content : Array
while not file.eof_reached():
var line : PoolStringArray = file.get_csv_line(delimiter)
content.append(line)
file.close()
for data in content:
if data.size() < 2:
content.erase(data)
return content
func structure_datas(database : Array, are_values_columns : bool, x_values_index : int):
# @x_values_index can be either a column or a row relative to x values
# @y_values can be either a column or a row relative to y values
self.are_values_columns = are_values_columns
match are_values_columns:
true:
for row in database.size():
var t_vals : Array
for column in database[row].size():
if column == x_values_index:
var x_data = database[row][column]
if x_data.is_valid_float() or x_data.is_valid_integer():
x_datas.append(x_data as float)
else:
x_datas.append(x_data.replace(",",".") as float)
elif column == z_values_index:
var z_data = database[row][column]
if z_data.is_valid_float() or z_data.is_valid_integer():
z_datas.append(z_data as float)
else:
z_datas.append(z_data.replace(",",".") as float)
else:
if row != 0:
var y_data = database[row][column]
if y_data.is_valid_float() or y_data.is_valid_integer():
t_vals.append(y_data as float)
else:
t_vals.append(y_data.replace(",",".") as float)
else:
y_labels.append(str(database[row][column]))
if not t_vals.empty():
y_datas.append(t_vals)
x_label = str(x_datas.pop_front())
z_label = str(z_datas.pop_front())
false:
for row in database.size():
if row == x_values_index:
x_datas = (database[row])
x_label = x_datas.pop_front() as String
else:
var values = database[row] as Array
y_labels.append(values.pop_front() as String)
y_datas.append(values)
for data in y_datas:
for value in data.size():
data[value] = data[value] as float
# draw y labels
var to_order : Array
var to_order_min : Array
for cluster in y_datas.size():
# define x_chors and y_chors
var ordered_cluster = y_datas[cluster] as Array
ordered_cluster.sort()
ordered_cluster = PoolIntArray(ordered_cluster)
var margin_max = ordered_cluster[ordered_cluster.size()-1]
var margin_min = ordered_cluster[0]
to_order.append(margin_max)
to_order_min.append(margin_min)
to_order.sort()
to_order_min.sort()
var margin = to_order.pop_back()
if not origin_at_zero:
y_margin_min = to_order_min.pop_front()
v_dist = y_decim * pow(10.0,str(margin).length()-2)
var multi = 0
var p = (v_dist*multi) + ((y_margin_min) if not origin_at_zero else 0)
y_chors.append(p as String)
while p < margin:
multi+=1
p = (v_dist*multi) + ((y_margin_min) if not origin_at_zero else 0)
y_chors.append(p as String)
# draw x_labels
if not show_x_values_as_labels:
to_order.clear()
to_order = x_datas as PoolIntArray
to_order.sort()
margin = to_order.pop_back()
if not origin_at_zero:
x_margin_min = to_order.pop_front()
h_dist = x_decim * pow(10.0,str(margin).length()-2)
multi = 0
p = (h_dist*multi) + ((x_margin_min) if not origin_at_zero else 0)
x_labels.append(p as String)
while p < margin:
multi+=1
p = (h_dist*multi) + ((x_margin_min) if not origin_at_zero else 0)
x_labels.append(p as String)
func set_legend(l : Array):
legend = l
func get_legend():
return legend
func apply_template(template_name : String):
template = template_name
templates = Utilities._load_templates()
if template_name!=null and template_name!="":
var custom_template = templates[template.to_lower()]
function_colors = custom_template.function_colors
v_lines_color = Color(custom_template.v_lines_color)
h_lines_color = Color(custom_template.h_lines_color)
box_color = Color(custom_template.outline_color)
font_color = Color(custom_template.font_color)
property_list_changed_notify()
func _enter_tree():
_ready()

View File

@ -1,11 +1,10 @@
[gd_scene load_steps=7 format=2]
[ext_resource path="res://addons/easy_charts/ScatterChart3D/ScatterChart3D.gd" type="Script" id=1]
[ext_resource path="res://d4hj068-433f5832-3c04-42db-9c2e-173a26a6970a.png" type="Texture" id=2]
[ext_resource path="res://addons/easy_charts/Utilities/Point/PointData.tscn" type="PackedScene" id=2]
[sub_resource type="SpatialMaterial" id=1]
flags_unshaded = true
albedo_texture = ExtResource( 2 )
[sub_resource type="PlaneMesh" id=2]
material = SubResource( 1 )
@ -18,6 +17,7 @@ albedo_color = Color( 0, 1, 0.156863, 1 )
[node name="ScatterChart3D" type="Spatial"]
script = ExtResource( 1 )
function_colors = [ "#1e1e1e", "#1e1e1e", "#1e1e1e", "#1e1e1e" ]
[node name="MeshInstance" type="MeshInstance" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0 )
@ -39,3 +39,7 @@ near = 0.01
[node name="OmniLight" type="OmniLight" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 9, 0 )
[node name="PointData" parent="." instance=ExtResource( 2 )]
[editable path="PointData"]

View File

@ -0,0 +1,40 @@
tool
extends Container
var LineChart = preload("LineChart/LineChart.tscn")
export (String,"None","LineChart","BoxChart") var chart_type : String setget set_type,get_type
var chart : Control setget set_chart,get_chart
var templates : Dictionary
# Called when the node enters the scene tree for the first time.
func _ready():
set_chart(get_child(0))
var template_file : File = File.new()
template_file.open("res://addons/easy_charts/templates.json",File.READ)
templates = JSON.parse(template_file.get_as_text()).get_result()
template_file.close()
func set_type(type : String):
chart_type = type
var new_node
if get_children().size():
for child in get_children():
child.queue_free()
if Engine.editor_hint:
match type:
"LineChart":
new_node = LineChart.instance()
add_child(new_node)
new_node.set_owner(owner)
"None":
set_chart(null)
func get_type():
return chart_type
func set_chart(ch : Control):
chart = ch
func get_chart():
return chart

View File

@ -0,0 +1,40 @@
tool
extends Node2D
var LineChart = preload("LineChart2D/LineChart2D.tscn")
var ColumnChart = preload("BarChart2D/BarChart2D.tscn")
export (String,"None","LineChart2D","BarChart2D") var chart_type : String setget set_type,get_type
var chart : Node2D setget set_chart,get_chart
# Called when the node enters the scene tree for the first time.
func _ready():
set_chart(get_child(0))
func set_type(type : String):
chart_type = type
var new_node
if get_children().size():
for child in get_children():
child.queue_free()
if Engine.editor_hint:
match type:
"LineChart2D":
new_node = LineChart.instance()
add_child(new_node)
new_node.set_owner(owner)
"ColumnChart2D":
new_node = ColumnChart.instance()
add_child(new_node)
new_node.set_owner(owner)
"None":
set_chart(null)
func get_type():
return chart_type
func set_chart(ch : Node2D):
chart = ch
func get_chart():
return chart

View File

@ -11,7 +11,7 @@ var function : String setget set_function, get_function
var mouse_entered : bool = false
enum SHAPES {
DOT, TRIANGLE, SQUARE
DOT, TRIANGLE, SQUARE, CROSS
}
var shape : int = 0 setget set_shape, get_shape
@ -44,6 +44,10 @@ func draw_point(size : float, color : Color):
draw_colored_polygon([
OFFSET-Vector2(1,1)*size/2, OFFSET-Vector2(-1,1)*size/2, OFFSET+Vector2(1,1)*size/2, OFFSET-Vector2(1,-1)*size/2
], color,[],null,null,false)
SHAPES.CROSS:
size+=2
draw_line(OFFSET-Vector2(size,0), OFFSET+Vector2(size,0), color, size-5, true)
draw_line(OFFSET-Vector2(0,size), OFFSET+Vector2(0,size), color, size-5, true)
func create_point(shape : int, color : Color, color_outline : Color, position : Vector2, value : Array, function : String):
self.shape = shape

View File

@ -1,4 +1,5 @@
extends PanelContainer
class_name PointData
var value : String = ""
var position : Vector2 = Vector2()

View File

@ -0,0 +1,5 @@
extends Control
class_name Chart
enum point_shapes { Dot, Triangle, Square, Cross }
enum templates_names { Default, Clean, Gradient, Minimal, Invert }

View File

@ -0,0 +1,9 @@
extends Node2D
class_name Chart2D
enum point_shapes { Dot, Triangle, Square, Cross }
enum templates_names { Default, Clean, Gradient, Minimal, Invert }
# Called when the node enters the scene tree for the first time.
func _ready():
pass # Replace with function body.

View File

@ -0,0 +1,23 @@
tool
extends Node
var plugin_name : String = "Easy Charts"
var templates : Dictionary = {}
func _ready():
templates = _load_templates()
_print_message("Templates loaded")
func _print_message(message : String, type : int = 0):
match type:
0:
print("[%s] => %s" % [plugin_name, message])
1:
printerr("ERROR: [%s] => %s" % [plugin_name, message])
func _load_templates() -> Dictionary:
var template_file : File = File.new()
template_file.open("res://addons/easy_charts/templates.json",File.READ)
var templates = JSON.parse(template_file.get_as_text()).get_result()
template_file.close()
return templates

View File

@ -0,0 +1,4 @@
Eating;Drinking;Running;Sleeping;Coding
30;50;40;100;95
90;34;100;50;23
1 Eating Drinking Running Sleeping Coding
2 30 50 40 100 95
3 90 34 100 50 23

View File

@ -3,5 +3,5 @@
name="EasyCharts"
description=""
author="Nicolò \"fenix\" Santilio"
version="1.0"
version="0.2.1"
script="plugin.gd"

View File

@ -2,12 +2,11 @@ tool
extends EditorPlugin
func _enter_tree():
add_autoload_singleton("Utilities","res://addons/easy_charts/Utilities/utilities.gd")
# Containers are not really that useful
# add_custom_type("ChartContainer", "Container", load("Utilities/ChartContainer.gd"), load("Utilities/icons/linechart.svg"))
# add_custom_type("ChartContainer2D", "Node2D", load("Utilities/ChartContainer2D.gd"), load("Utilities/icons/linechart2d.svg"))
add_autoload_singleton("Utilities","res://addons/easy_charts/Utilities/Scripts/utilities.gd")
add_custom_type("Chart","Control", load("res://addons/easy_charts/Utilities/Scripts/Chart.gd"), preload("Utilities/icons/linechart.svg"))
add_custom_type("Chart2D","Node2D", preload("Utilities/Scripts/Chart2D.gd"), preload("Utilities/icons/linechart2d.svg"))
func _exit_tree():
# remove_custom_type("ChartContainer")
# remove_custom_type("ChartContainer2D")
remove_custom_type("Chart")
remove_custom_type("Chart2D")
remove_autoload_singleton("Utilities")