Merge pull request #35 from fenix-hub/dev

Dev
This commit is contained in:
Nicolò Santilio 2020-12-31 17:51:09 +01:00 committed by GitHub
commit a3e79b3643
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 769 additions and 2384 deletions

11
.gitignore vendored
View File

@ -1,15 +1,20 @@
.import/
export.cfg
export_presets.cfg
# Imported translations (automatically generated from CSV files)
*.translation
# Plugin specific ignores
.github/
file-editor/
scn/
default_env.tres
icon.png
icon.png.import
project.godot
# Mono-specific ignores
.mono/
data_*/
mono_crash.*.json
# System/tool-specific ignores
.directory
*~

View File

@ -1,18 +1,17 @@
*Want to stay updated or having an issue?*
<p align="right">
<a href="https://discord.gg/KnJGY9S">
<img src="https://github.com/fenix-hub/ColoredBadges/blob/master/svg/social/discord.svg" alt="react" style="vertical-align:top; margin:6px 4px">
<img src="https://github.com/fenix-hub/ColoredBadges/blob/master/svg/social/discord.svg" alt="react" style="vertical-align:top; margin:6px 4px">
</a>
</p>
<img src="addons/easy_charts/icon.png" align="left" width="64" height="64">
# Easy Charts
A library of Charts plotted in Control, 2D and 3D nodes to visualize general purpose datasets.
Author: *"Nicolo (fenix) Santilio"*
Version: *0.5.0*
Version: *0.5.3*
Wiki: *[wip](https://github.com/fenix-hub/godot-engine.easy-charts/wiki)*
Godot Version: *3.2stable*
## What is this?
*Easy Charts* is a collection of Control, 2D and 3D nodes to plot charts.
This plugin was born from the personal necessity to plot some charts and tables for my university degree project.
@ -21,53 +20,42 @@ Charts are really useful when it comes to visually represent values in a powerfu
If you need to plot a chart with some values in it and just take a screenshot, or use it in your Godot Engine's game or project, you've come to the right place.
![st](imgs/startup_company2.jpg)
[*Startup Company*](https://store.steampowered.com/app/606800/Startup_Company/)
![wa](imgs/workplace_analytics.png)
[*Microsoft Workplace Analytics*](https://www.microsoft.com/microsoft-365/partners/workplaceanalytics)
## How does it work?
There is a [WIKI](https://github.com/fenix-hub/godot-engine.easy-charts/wiki) with some tutorials, even if it is a work in progress.
I'll make some videos as soon as possible.
# Available Charts and when to use them
This library offers a set of charts for each main Godot Node:
- **Control Nodes:** "Control Charts" are fast Charts that can be plotted in a Control space, such as UIs or Control user interactable areas. They offer basic Control properties, such as Margins, size inheritance and control. No animations, no real time changes, just charts.
- **2D Nodes:** "2D Charts" are a set of Charts which can be Used in 2D spaces. They offer additional tools, such as animations and real time changes in editor. They can be used to implement more aesthetic charts in 2D contexts.
- **[wip] 3D Nodes:** "3D Charts" are a set of Charts which can be Used in both 2D and 3D spaces. They offer the possibility to plot 3D datasets, which are common in machine learning contexts or just data analysis. A Camera Control will also be available, which can be used to move around the chart.
*Available Charts*:
- **[wip] 3D Nodes:** "3D Charts" are a set of Charts which can be Used in both 2D and 3D spaces. They offer the possibility to plot 3D datasets, which are common in machine learning contexts or just data analysis. A Camera Control will also be available, which can be used to move around the chart.
### Available Charts
- LineChart [Control, 2D, wip 3D]
- BarChart [Control, 2D, wipr 3D]
- ColumnChart [Control, 2D, wipr 3D]
- ScatterChart [wip Control, wip 2D, 3D]
- Piechart [Control]
- RadarChart [Control]
*Work in progress*:
### WIP Charts
- Area Chart
- Donut Chart
- Radar Chart
- Bubble Chart
- Parliament Chart
### Some Examples
![example_LineChart_realtime](imgs/real_time_line.gif)
![example_Piechart](imgs/pie_chart_realtime.gif)
![exampleradar](imgs/radar.png)
![example01](imgs/scatter.gif)
![example02](imgs/example02.png)
![example03](imgs/example03.gif)
##### Some references for charts and plots
[Flourish](https://app.flourish.studio/projects)
[Chart.js](https://www.chartjs.org/samples/latest/)
[Google Charts](https://developers.google.com/chart)
# Disclaimer
This addon was built for a **personal use** intention. It was released as an open source plugin in the hope that it could be useful to the Godot Engine Community.
As a "work in progress" project, there is *no warranty* for any eventual issue and bug that may broke your project.
I don't assume any responsibility for possible corruptions of your project. It is always advisable to keep a copy of your project and check any changes you make in your Github repository.
-----------------
> This text file was created via [TextEditor Integration](https://github.com/fenix-hub/godot-engine.text-editor) inside Godot Engine's Editor.
> This text file was pushed via [GitHub Integration](https://github.com/fenix-hub/godot-engine.github-integretion) inside Godot Engine's Editor.

View File

@ -1,108 +0,0 @@
[gd_scene load_steps=4 format=2]
[ext_resource path="res://addons/easy_charts/LineChart2D/LineChart2D.gd" type="Script" id=1]
[ext_resource path="res://addons/easy_charts/Utilities/Point/PointData.gd" type="Script" id=3]
[sub_resource type="StyleBoxFlat" id=1]
content_margin_left = 8.0
content_margin_right = 8.0
content_margin_top = 5.0
content_margin_bottom = 5.0
bg_color = Color( 1, 1, 1, 0 )
border_width_left = 2
border_width_top = 2
border_width_right = 2
border_width_bottom = 2
border_color = Color( 1, 1, 1, 1 )
corner_radius_top_left = 5
corner_radius_top_right = 5
corner_radius_bottom_right = 5
corner_radius_bottom_left = 5
corner_detail = 20
[node name="LineChart2D" type="Node2D"]
script = ExtResource( 1 )
drawing_duration = 0.3
font_color = Color( 0.137255, 0.137255, 0.137255, 1 )
[node name="Grid" type="Node2D" parent="."]
[node name="VLine" type="Line2D" parent="Grid"]
points = PoolVector2Array( 0, 0, 0, 0 )
width = 1.0
default_color = Color( 0.792157, 0.792157, 0.792157, 1 )
[node name="HLine" type="Line2D" parent="Grid"]
points = PoolVector2Array( 0, 0, 0, 0 )
width = 1.0
default_color = Color( 0.792157, 0.792157, 0.792157, 1 )
[node name="Outlines" type="Line2D" parent="."]
points = PoolVector2Array( 0, 0, 2, 0, 2, 2, 0, 2, 0, 0 )
width = 2.0
default_color = Color( 0.117647, 0.117647, 0.117647, 1 )
[node name="Functions" type="Node2D" parent="."]
[node name="Function" type="Line2D" parent="Functions"]
points = PoolVector2Array( 0, 0, 0, 0 )
width = 2.0
default_color = Color( 0.117647, 0.117647, 0.117647, 1 )
[node name="FunctionsTween" type="Tween" parent="."]
[node name="OutlinesTween" type="Tween" parent="."]
[node name="GridTween" type="Tween" parent="."]
[node name="UI" type="CanvasLayer" parent="."]
[node name="PointData" type="PanelContainer" parent="UI"]
margin_right = 67.0
margin_bottom = 38.0
mouse_filter = 2
custom_styles/panel = SubResource( 1 )
script = ExtResource( 3 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="PointData" type="VBoxContainer" parent="UI/PointData"]
margin_left = 8.0
margin_top = 5.0
margin_right = 59.0
margin_bottom = 36.0
custom_constants/separation = 3
alignment = 1
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Function" type="Label" parent="UI/PointData/PointData"]
margin_right = 51.0
margin_bottom = 14.0
align = 1
valign = 1
[node name="Value" type="HBoxContainer" parent="UI/PointData/PointData"]
margin_top = 17.0
margin_right = 51.0
margin_bottom = 31.0
[node name="x" type="Label" parent="UI/PointData/PointData/Value"]
margin_right = 39.0
margin_bottom = 14.0
custom_colors/font_color = Color( 1, 1, 1, 1 )
text = "Value:"
valign = 1
[node name="y" type="Label" parent="UI/PointData/PointData/Value"]
margin_left = 43.0
margin_right = 51.0
margin_bottom = 14.0
custom_colors/font_color = Color( 1, 1, 1, 1 )
text = "0"
valign = 1

View File

@ -1,11 +1,11 @@
[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/BarChart/bar_chart.gd" type="Script" id=2]
[ext_resource path="res://addons/easy_charts/ColumnChart/column_chart.gd" type="Script" id=2]
[sub_resource type="Theme" id=1]
[node name="BarChart" type="Control"]
[node name="ColumnChart" type="Control"]
anchor_right = 1.0
anchor_bottom = 1.0
rect_min_size = Vector2( 70, 50 )
@ -82,10 +82,10 @@ __meta__ = {
[node name="PointData" parent="." instance=ExtResource( 1 )]
[node name="PointData" parent="PointData" index="0"]
margin_left = -32.6676
margin_top = -84.4238
margin_right = -32.8033
margin_bottom = -83.6237
margin_left = -593.381
margin_top = -80.9071
margin_right = -593.517
margin_bottom = -80.107
theme = SubResource( 1 )
[editable path="PointData"]

View File

@ -1,9 +1,9 @@
tool
extends Chart
class_name BarChart
class_name ColumnChart
"""
[BarChart] - General purpose node for Bar Charts
[ColumnChart] - General purpose node for Column Charts
A bar chart or bar graph is a chart or graph that presents categorical data with
rectangular bars with heights or lengths proportional to the values that they represent.
@ -25,7 +25,7 @@ func _get_property_list():
{
"hint": PROPERTY_HINT_NONE,
"usage": PROPERTY_USAGE_CATEGORY,
"name": "BarChart",
"name": "ColumnChart",
"type": TYPE_STRING
},
{
@ -160,14 +160,14 @@ func build_chart():
SIZE = get_size()
origin = Vector2(OFFSET.x,SIZE.y-OFFSET.y)
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
self.are_values_columns = are_values_columns
func structure_datas(database : Array):
# @labels_index can be either a column or a row relative to x values
are_values_columns = (invert_chart != are_values_columns)
if are_values_columns:
for row in database.size():
var t_vals: Array
for column in database[row].size():
if column == x_values_index:
if column == labels_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)
@ -187,7 +187,7 @@ func structure_datas(database : Array, are_values_columns : bool, x_values_index
x_label = str(x_datas.pop_front())
else:
for row in database.size():
if row == x_values_index:
if row == labels_index:
x_datas = (database[row])
x_label = x_datas.pop_front() as String
else:
@ -246,19 +246,16 @@ func structure_datas(database : Array, are_values_columns : bool, x_values_index
func calculate_pass():
if invert_chart:
x_chors = y_labels as PoolStringArray
if show_x_values_as_labels:
x_chors = x_datas as PoolStringArray
else:
if show_x_values_as_labels:
x_chors = x_datas as PoolStringArray
else:
x_chors = x_labels
x_chors = x_labels
# calculate distance in pixel between 2 consecutive values/datas
if not are_values_columns:
x_pass = (SIZE.x - OFFSET.x*2 - (column_width) * ( y_datas.size() if not invert_chart else y_datas[0].size()+1 ) - column_gap - column_width/2) / ((x_chors.size()-1) if x_chors.size()!=1 else 1)
x_pass = (SIZE.x - OFFSET.x*2 - (column_width) * ( y_datas.size()) - column_gap - column_width/2) / ((x_chors.size()-1) if x_chors.size()!=1 else 1)
else:
x_pass = (SIZE.x - OFFSET.x*2 - (column_width) * ( y_datas.size() if invert_chart else y_datas[0].size()+1 ) - column_gap - column_width/2) / (x_chors.size()-1)
x_pass = (SIZE.x - OFFSET.x*2 - (column_width) * ( y_datas[0].size()+1 ) - column_gap - column_width/2) / (x_chors.size()-1)
y_pass = (origin.y - ChartName.get_rect().size.y*2) / (y_chors.size() - 1)
func calculate_coordinates():
@ -266,25 +263,15 @@ func calculate_coordinates():
y_coordinates.clear()
point_values.clear()
point_positions.clear()
if invert_chart:
for column in y_datas[0].size():
var single_coordinates : Array
for row in y_datas:
if origin_at_zero:
single_coordinates.append((row[column]*y_pass)/v_dist)
else:
single_coordinates.append((row[column] - y_margin_min)*y_pass/v_dist)
y_coordinates.append(single_coordinates)
else:
for cluster in y_datas:
var single_coordinates : Array
for value in cluster.size():
if origin_at_zero:
single_coordinates.append((cluster[value]*y_pass)/v_dist)
else:
single_coordinates.append((cluster[value] - y_margin_min)*y_pass/v_dist)
y_coordinates.append(single_coordinates)
for cluster in y_datas:
var single_coordinates : Array
for value in cluster.size():
if origin_at_zero:
single_coordinates.append((cluster[value]*y_pass)/v_dist)
else:
single_coordinates.append((cluster[value] - y_margin_min)*y_pass/v_dist)
y_coordinates.append(single_coordinates)
if show_x_values_as_labels:
for x in x_datas.size():
@ -292,10 +279,7 @@ func calculate_coordinates():
else:
for x in x_datas.size():
if origin_at_zero:
if not invert_chart:
x_coordinates.append(x_pass*x)
else:
x_coordinates.append(x*x_pass/h_dist)
x_coordinates.append(x_pass*x)
else:
x_coordinates.append((x_datas[x] - x_margin_min)*x_pass/h_dist)
@ -303,24 +287,14 @@ func calculate_coordinates():
point_values.append([])
point_positions.append([])
if invert_chart:
for function in y_coordinates.size():
for function_value in y_coordinates[function].size():
if are_values_columns:
point_values[function].append([x_datas[function_value],y_datas[function_value][function]])
point_positions[function].append(Vector2(OFFSET.x/2 + column_width/2 + (column_width + column_gap)*function + x_coordinates[function_value]+origin.x,origin.y-y_coordinates[function][function_value]))
else:
point_positions[function].append(Vector2(OFFSET.x/2 + column_width/2 + (column_width + column_gap)*function + x_coordinates[function_value]+origin.x,origin.y-y_coordinates[function][function_value]))
point_values[function].append([x_datas[function_value],y_datas[function_value][function]])
else:
for cluster in y_coordinates.size():
for y in y_coordinates[cluster].size():
if are_values_columns:
point_positions[y].append(Vector2(OFFSET.x/2 + column_width/2 + (column_width + column_gap)*y + x_coordinates[cluster] + origin.x, origin.y-y_coordinates[cluster][y]))
point_values[y].append([x_datas[cluster],y_datas[cluster][y]])
else:
point_values[cluster].append([x_datas[y],y_datas[cluster][y]])
point_positions[cluster].append(Vector2(OFFSET.x/2 + column_width/2 + (column_width + column_gap)*cluster + x_coordinates[y]+origin.x,origin.y-y_coordinates[cluster][y]))
for cluster in y_coordinates.size():
for y in y_coordinates[cluster].size():
if are_values_columns:
point_positions[y].append(Vector2(OFFSET.x/2 + column_width/2 + (column_width + column_gap)*y + x_coordinates[cluster] + origin.x, origin.y-y_coordinates[cluster][y]))
point_values[y].append([x_datas[cluster],y_datas[cluster][y]])
else:
point_values[cluster].append([x_datas[y],y_datas[cluster][y]])
point_positions[cluster].append(Vector2(OFFSET.x/2 + column_width/2 + (column_width + column_gap)*cluster + x_coordinates[y]+origin.x,origin.y-y_coordinates[cluster][y]))
func _draw():
clear_points()
@ -342,10 +316,10 @@ func _draw():
point.connect("_mouse_entered",self,"show_data")
point.connect("_mouse_exited",self,"hide_data")
point.create_point(points_shape[_function], function_colors[function_point if invert_chart else _function],
point.create_point(points_shape[_function], function_colors[_function],
Color.white, point_positions[_function][function_point] + Vector2(0,7),
point.format_value(point_values[_function][function_point], false, false),
y_labels[function_point if invert_chart else _function] as String)
y_labels[_function] as String)
PointContainer.add_child(point)
point.rect_size.y = origin.y - point_positions[_function][function_point].y
draw_line( Vector2(point_positions[_function][function_point].x, origin.y),
@ -362,9 +336,9 @@ func draw_grid():
draw_line(point-Vector2(0,5),point,v_lines_color,1,true)
var calculated_gap : float
if not are_values_columns:
calculated_gap = ( y_datas.size() if not invert_chart else y_datas[0].size()+1 )
calculated_gap = ( y_datas.size() )
else:
calculated_gap = ( y_datas.size() if invert_chart else y_datas[0].size()+1 )
calculated_gap = ( y_datas[0].size()+1 )
draw_string(
font,
point + Vector2(-const_width/2*x_chors[p].length() + (column_width + column_gap) * functions, font_size),

View File

@ -1,9 +1,9 @@
tool
extends Chart2D
class_name BarChart2D
class_name ColumnChart2D
"""
[BarChart2D] - General purpose node for Bar Charts
[ColumnChart2D] - General purpose node for Bar Charts
A bar chart or bar graph is a chart or graph that presents categorical data with
rectangular bars with heights or lengths proportional to the values that they represent.
@ -17,105 +17,6 @@ values of more than one measured variable.
/ source : Wikipedia /
"""
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")
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
# database values
var x_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(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 (PointShapes) 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 (TemplatesNames) var template : int = Chart.TemplatesNames.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

View File

@ -1,8 +1,10 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://addons/easy_charts/BarChart2D/BarChart2D.gd" type="Script" id=1]
[ext_resource path="res://addons/easy_charts/ColumnChart2D/ColumnChart2D.gd" type="Script" id=1]
[ext_resource path="res://addons/easy_charts/Utilities/Point/PointData.tscn" type="PackedScene" id=2]
[node name="BarChart2D" type="Node2D"]
script = ExtResource( 1 )
__meta__ = {

View File

@ -154,14 +154,14 @@ func _get_property_list():
]
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
self.are_values_columns = are_values_columns
func structure_datas(database: Array):
# @labels_index can be either a column or a row relative to x values
are_values_columns = (invert_chart != are_values_columns)
if are_values_columns:
for row in database.size():
var t_vals: Array
for column in database[row].size():
if column == x_values_index:
if column == labels_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)
@ -181,7 +181,7 @@ func structure_datas(database: Array, are_values_columns: bool, x_values_index:
x_label = str(x_datas.pop_front())
else:
for row in database.size():
if row == x_values_index:
if row == labels_index:
x_datas = (database[row])
x_label = x_datas.pop_front() as String
else:
@ -244,13 +244,10 @@ func build_chart():
func calculate_pass():
if invert_chart:
x_chors = y_labels.duplicate(true) as PoolStringArray
if show_x_values_as_labels:
x_chors = x_datas.duplicate(true) as PoolStringArray
else:
if show_x_values_as_labels:
x_chors = x_datas.duplicate(true) as PoolStringArray
else:
x_chors = x_labels.duplicate(true)
x_chors = x_labels.duplicate(true)
# calculate distance in pixel between 2 consecutive values/datas
x_pass = (SIZE.x - OFFSET.x) / (x_chors.size()-1 if x_chors.size()>1 else x_chors.size() )
@ -262,25 +259,15 @@ func calculate_coordinates():
y_coordinates.clear()
point_values.clear()
point_positions.clear()
if invert_chart:
for column in y_datas[0].size():
var single_coordinates: Array
for row in y_datas:
if origin_at_zero:
single_coordinates.append((row[column] * y_pass) / v_dist)
else:
single_coordinates.append((row[column] - y_margin_min) * y_pass / v_dist)
y_coordinates.append(single_coordinates)
else:
for cluster in y_datas:
var single_coordinates: Array
for value in cluster.size():
if origin_at_zero:
single_coordinates.append((cluster[value] * y_pass) / v_dist)
else:
single_coordinates.append((cluster[value] - y_margin_min) * y_pass / v_dist)
y_coordinates.append(single_coordinates)
for cluster in y_datas:
var single_coordinates: Array
for value in cluster.size():
if origin_at_zero:
single_coordinates.append((cluster[value] * y_pass) / v_dist)
else:
single_coordinates.append((cluster[value] - y_margin_min) * y_pass / v_dist)
y_coordinates.append(single_coordinates)
if show_x_values_as_labels:
for x in x_datas.size():
@ -288,10 +275,7 @@ func calculate_coordinates():
else:
for x in x_datas.size():
if origin_at_zero:
if invert_chart:
x_coordinates.append(x_pass * x)
else:
x_coordinates.append(x_datas[x] * x_pass / h_dist)
x_coordinates.append(x_datas[x] * x_pass / h_dist)
else:
x_coordinates.append((x_datas[x] - x_margin_min) * x_pass / h_dist)
@ -299,33 +283,17 @@ func calculate_coordinates():
point_values.append([])
point_positions.append([])
if invert_chart:
for function in y_coordinates.size():
for function_value in y_coordinates[function].size():
if are_values_columns:
point_positions[function_value].append(Vector2(
x_coordinates[function] + origin.x,
origin.y - y_coordinates[function][function_value]))
point_values[function_value].append(
[x_datas[function_value], y_datas[function_value][function]])
else:
point_positions[function].append(Vector2(
x_coordinates[function_value] + origin.x,
origin.y - y_coordinates[function][function_value]))
point_values[function].append(
[x_datas[function_value], y_datas[function_value][function]])
else:
for cluster in y_coordinates.size():
for y in y_coordinates[cluster].size():
if are_values_columns:
point_values[y].append([x_datas[cluster], y_datas[cluster][y]])
point_positions[y].append(Vector2(
x_coordinates[cluster] + origin.x, origin.y - y_coordinates[cluster][y]))
else:
point_values[cluster].append([x_datas[y], y_datas[cluster][y]])
point_positions[cluster].append(Vector2(
x_coordinates[y] + origin.x,
origin.y - y_coordinates[cluster][y]))
for cluster in y_coordinates.size():
for y in y_coordinates[cluster].size():
if are_values_columns:
point_values[y].append([x_datas[cluster], y_datas[cluster][y]])
point_positions[y].append(Vector2(
x_coordinates[cluster] + origin.x, origin.y - y_coordinates[cluster][y]))
else:
point_values[cluster].append([x_datas[y], y_datas[cluster][y]])
point_positions[cluster].append(Vector2(
x_coordinates[y] + origin.x,
origin.y - y_coordinates[cluster][y]))
func _draw():
clear_points()
@ -346,14 +314,14 @@ func _draw():
point.connect("_point_pressed", self, "point_pressed")
point.connect("_mouse_entered", self, "show_data")
point.connect("_mouse_exited", self, "hide_data")
point.create_point(points_shape[_function],function_colors[function_point if invert_chart else _function],Color.white,point_positions[_function][function_point],point.format_value(point_values[_function][function_point], false, false),y_labels[function_point if invert_chart else _function] as String)
point.create_point(points_shape[_function],function_colors[_function],Color.white,point_positions[_function][function_point],point.format_value(point_values[_function][function_point], false, false),y_labels[_function] as String)
Points.add_child(point)
if function_point > 0:
draw_line(
point_positions[_function][function_point - 1],
point_positions[_function][function_point],
function_colors[function_point if invert_chart else _function],
function_colors[_function],
2,
false)
draw_treshold()

View File

@ -14,108 +14,6 @@ class_name LineChart2D
# In these cases they are known as run charts.
# Source: Wikipedia
signal chart_plotted(chart)
signal point_pressed(point)
const OFFSET: Vector2 = Vector2(0,0)
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(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 (PointShapes) 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 (TemplatesNames) var template: int = Chart.TemplatesNames.Default setget apply_template
export (float, 0.1, 1) var drawing_duration: float = 0.5
export (bool) var invert_chart: bool = false
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")
var font_size: float = 16
var const_height: float = font_size / 2 * font_size / 20
var const_width: float = font_size / 2
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
# database values
var x_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
var templates: Dictionary = {}
func _point_plotted():
pass
@ -124,16 +22,6 @@ func _ready():
_get_children()
func _get_children():
OutlinesTween = $OutlinesTween
FunctionsTween = $FunctionsTween
Functions = $Functions
GridTween = $GridTween
PointData = $PointData/PointData
Outlines = $Outlines
Grid = $Grid
func _set_size(size: Vector2):
SIZE = size
build_chart()
@ -566,94 +454,12 @@ func calculate_coordinates():
origin.y - y_coordinates[cluster][y]))
func redraw():
build_chart()
calculate_pass()
calculate_coordinates()
update()
func show_data(point):
PointData.update_datas(point)
PointData.show()
func hide_data():
PointData.hide()
func clear_points():
function_colors.clear()
if Functions.get_children():
for function in Functions.get_children():
function.queue_free()
func set_legend(l: Array):
legend = l
func get_legend():
return legend
func invert_chart():
invert_chart = !invert_chart
count_functions()
redraw()
create_legend()
func count_functions():
if are_values_columns:
if not invert_chart:
functions = datas[0].size() - 1
else:
functions = datas.size() - 1
else:
if invert_chart:
functions = datas[0].size() - 1
else:
functions = datas.size() - 1
func create_legend():
legend.clear()
for function in functions:
var function_legend = FunctionLegend.instance()
var f_name: String
if invert_chart:
f_name = x_datas[function] as String
else:
f_name = y_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 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
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()
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,108 +0,0 @@
[gd_scene load_steps=4 format=2]
[ext_resource path="res://addons/easy_charts/LineChart2D/LineChart2D.gd" type="Script" id=1]
[ext_resource path="res://addons/easy_charts/Utilities/Point/PointData.gd" type="Script" id=3]
[sub_resource type="StyleBoxFlat" id=1]
content_margin_left = 8.0
content_margin_right = 8.0
content_margin_top = 5.0
content_margin_bottom = 5.0
bg_color = Color( 1, 1, 1, 0 )
border_width_left = 2
border_width_top = 2
border_width_right = 2
border_width_bottom = 2
border_color = Color( 1, 1, 1, 1 )
corner_radius_top_left = 5
corner_radius_top_right = 5
corner_radius_bottom_right = 5
corner_radius_bottom_left = 5
corner_detail = 20
[node name="LineChart2D" type="Node2D"]
script = ExtResource( 1 )
drawing_duration = 0.3
font_color = Color( 0.137255, 0.137255, 0.137255, 1 )
[node name="Grid" type="Node2D" parent="."]
[node name="VLine" type="Line2D" parent="Grid"]
points = PoolVector2Array( 0, 0, 0, 0 )
width = 1.0
default_color = Color( 0.792157, 0.792157, 0.792157, 1 )
[node name="HLine" type="Line2D" parent="Grid"]
points = PoolVector2Array( 0, 0, 0, 0 )
width = 1.0
default_color = Color( 0.792157, 0.792157, 0.792157, 1 )
[node name="Outlines" type="Line2D" parent="."]
points = PoolVector2Array( 0, 0, 2, 0, 2, 2, 0, 2, 0, 0 )
width = 2.0
default_color = Color( 0.117647, 0.117647, 0.117647, 1 )
[node name="Functions" type="Node2D" parent="."]
[node name="Function" type="Line2D" parent="Functions"]
points = PoolVector2Array( 0, 0, 0, 0 )
width = 2.0
default_color = Color( 0.117647, 0.117647, 0.117647, 1 )
[node name="FunctionsTween" type="Tween" parent="."]
[node name="OutlinesTween" type="Tween" parent="."]
[node name="GridTween" type="Tween" parent="."]
[node name="UI" type="CanvasLayer" parent="."]
[node name="PointData" type="PanelContainer" parent="UI"]
margin_right = 67.0
margin_bottom = 38.0
mouse_filter = 2
custom_styles/panel = SubResource( 1 )
script = ExtResource( 3 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="PointData" type="VBoxContainer" parent="UI/PointData"]
margin_left = 8.0
margin_top = 5.0
margin_right = 59.0
margin_bottom = 36.0
custom_constants/separation = 3
alignment = 1
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Function" type="Label" parent="UI/PointData/PointData"]
margin_right = 51.0
margin_bottom = 14.0
align = 1
valign = 1
[node name="Value" type="HBoxContainer" parent="UI/PointData/PointData"]
margin_top = 17.0
margin_right = 51.0
margin_bottom = 31.0
[node name="x" type="Label" parent="UI/PointData/PointData/Value"]
margin_right = 39.0
margin_bottom = 14.0
custom_colors/font_color = Color( 1, 1, 1, 1 )
text = "Value:"
valign = 1
[node name="y" type="Label" parent="UI/PointData/PointData/Value"]
margin_left = 43.0
margin_right = 51.0
margin_bottom = 14.0
custom_colors/font_color = Color( 1, 1, 1, 1 )
text = "0"
valign = 1

View File

@ -108,15 +108,15 @@ func plot_placeholder() -> void:
]
plot_from_array(data)
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
func structure_datas(database: Array):
# @labels_index can be either a column or a row relative to x values
clean_variables()
self.are_values_columns = are_values_columns
are_values_columns = invert_chart != are_values_columns
if are_values_columns:
for row in database.size():
var t_vals: Array
for column in database[row].size():
if column == x_values_index:
if column == labels_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)
@ -136,7 +136,7 @@ func structure_datas(database: Array, are_values_columns: bool, x_values_index:
x_label = str(x_datas.pop_front())
else:
for row in database.size():
if row == x_values_index:
if row == labels_index:
x_datas = (database[row])
x_label = x_datas.pop_front() as String
else:

View File

@ -1,280 +0,0 @@
tool
extends Chart
class_name RadarChart
"""
[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 /
"""
func _get_property_list():
return [
# Chart Properties
{
"hint": PROPERTY_HINT_NONE,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Properties/are_values_columns",
"type": TYPE_BOOL
},
{
"hint": PROPERTY_HINT_RANGE,
"hint_string": "-1,100,1",
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Properties/labels_index",
"type": TYPE_INT
},
{
"hint": PROPERTY_HINT_RANGE,
"hint_string": "-1,100,1",
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Properties/function_names_index",
"type": TYPE_INT
},
{
"hint": PROPERTY_HINT_NONE,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Properties/use_height_as_radius",
"type": TYPE_BOOL
},
{
"hint": PROPERTY_HINT_RANGE,
"hint_string": "0,2000",
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Properties/radius",
"type": TYPE_REAL
},
# Chart Display
{
"hint": PROPERTY_HINT_RANGE,
"hint_string": "0.1,100",
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Display/full_scale",
"type": TYPE_REAL
},
# Chart Style
{
"hint": 24,
"hint_string": "%d/%d:%s"%[TYPE_INT, PROPERTY_HINT_ENUM,
PoolStringArray(PointShapes.keys()).join(",")],
"name": "Chart_Style/points_shape",
"type": TYPE_ARRAY,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE
},
{
"hint": PROPERTY_HINT_NONE,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/function_colors",
"type": TYPE_COLOR_ARRAY
},
{
"hint": PROPERTY_HINT_NONE,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/outline_color",
"type": TYPE_COLOR
},
{
"hint": PROPERTY_HINT_NONE,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/grid_color",
"type": TYPE_COLOR
},
{
"class_name": "Font",
"hint": PROPERTY_HINT_RESOURCE_TYPE,
"hint_string": "Font",
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/font",
"type": TYPE_OBJECT
},
{
"class_name": "Font",
"hint": PROPERTY_HINT_RESOURCE_TYPE,
"hint_string": "Font",
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/bold_font",
"type": TYPE_OBJECT
},
{
"hint": PROPERTY_HINT_NONE,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/font_color",
"type": TYPE_COLOR
},
{
"hint": PROPERTY_HINT_ENUM,
"hint_string": PoolStringArray(TemplatesNames.keys()).join(","),
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/template",
"type": TYPE_INT
},
{
"hint": PROPERTY_HINT_RANGE,
"hint_string": "0,360",
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Modifiers/rotation",
"type": TYPE_REAL
},
]
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 and radius<SIZE.y/2) else SIZE.y/2) * scalar_factor * cos(angle) + origin.x
var y_coordinate : float = (radius if (not use_height_as_radius and radius<SIZE.y/2) 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 and radius<SIZE.y/2) else SIZE.y/2) * scalar_factor * cos(angle) + origin.x
var y_coordinate : float = (radius if (not use_height_as_radius and radius<SIZE.y/2) 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 _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(points_shape[_function], 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)
if point_array[label].x != origin.x:
draw_string(font, point_array[label] - (Vector2(font.get_string_size(x_labels[label]).x+10,(5 if point_array[label].y <= origin.y else -10)) if point_array[label].x <= origin.x else - Vector2(10,(-5 if point_array[label].y <= origin.y else 10))), x_labels[label], font_color)
else:
draw_string(font, point_array[label] - (Vector2(font.get_string_size(x_labels[label]).x/2, 10) if point_array[label].y < origin.x else - Vector2(font.get_string_size(x_labels[label]).x/2, 5)), x_labels[label], font_color)
func create_legend():
pass
# 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 count_functions():
if x_labels.size():
functions = x_labels.size()

View File

@ -125,11 +125,10 @@ func _get_property_list():
},
]
func structure_datas(database : Array, are_values_columns : bool, labels_index : int):
func structure_datas(database : Array):
# @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
are_values_columns = invert_chart != are_values_columns
match are_values_columns:
true:
for row in database.size():

View File

@ -1,343 +0,0 @@
tool
extends Chart
class_name ScatterChart
"""
[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 /
"""
# ---------------------
func _get_property_list():
return [
# Chart Properties
{
"hint": PROPERTY_HINT_NONE,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Properties/are_values_columns",
"type": TYPE_BOOL
},
{
"hint": PROPERTY_HINT_RANGE,
"hint_string": "-1,100,1",
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Properties/labels_index",
"type": TYPE_INT
},
{
"hint": PROPERTY_HINT_NONE,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Properties/show_x_values_as_labels",
"type": TYPE_BOOL
},
# Chart Display
{
"hint": PROPERTY_HINT_RANGE,
"hint_string": "0.1,10",
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Display/x_decim",
"type": TYPE_REAL
},
{
"hint": PROPERTY_HINT_RANGE,
"hint_string": "0.1,10",
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Display/y_decim",
"type": TYPE_REAL
},
# Chart Style
{
"hint": 24,
"hint_string": "%d/%d:%s"%[TYPE_INT, PROPERTY_HINT_ENUM,
PoolStringArray(PointShapes.keys()).join(",")],
"name": "Chart_Style/points_shape",
"type": TYPE_ARRAY,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE
},
{
"hint": PROPERTY_HINT_NONE,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/function_colors",
"type": TYPE_COLOR_ARRAY
},
{
"hint": PROPERTY_HINT_NONE,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/box_color",
"type": TYPE_COLOR
},
{
"hint": PROPERTY_HINT_NONE,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/v_lines_color",
"type": TYPE_COLOR
},
{
"hint": PROPERTY_HINT_NONE,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/h_lines_color",
"type": TYPE_COLOR
},
{
"class_name": "Font",
"hint": PROPERTY_HINT_RESOURCE_TYPE,
"hint_string": "Font",
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/font",
"type": TYPE_OBJECT
},
{
"class_name": "Font",
"hint": PROPERTY_HINT_RESOURCE_TYPE,
"hint_string": "Font",
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/bold_font",
"type": TYPE_OBJECT
},
{
"hint": PROPERTY_HINT_NONE,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/font_color",
"type": TYPE_COLOR
},
{
"hint": PROPERTY_HINT_ENUM,
"hint_string": PoolStringArray(Utilities.templates.keys()).join(","),
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/template",
"type": TYPE_INT
},
# Chart Modifiers
{
"hint": PROPERTY_HINT_NONE,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Modifiers/invert_chart",
"type": TYPE_BOOL
},
]
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)
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())
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 build_chart():
SIZE = get_size()
origin = Vector2(OFFSET.x,SIZE.y-OFFSET.y)
func calculate_pass():
if invert_chart:
x_chors = y_labels as PoolStringArray
else:
if show_x_values_as_labels:
x_chors = x_datas as PoolStringArray
else:
x_chors = x_labels
# calculate distance in pixel between 2 consecutive values/datas
x_pass = (SIZE.x - OFFSET.x) / (x_chors.size()-1)
y_pass = origin.y / (y_chors.size()-1)
func calculate_coordinates():
x_coordinates.clear()
y_coordinates.clear()
point_values.clear()
point_positions.clear()
if invert_chart:
for column in y_datas[0].size():
var single_coordinates : Array
for row in y_datas:
if origin_at_zero:
single_coordinates.append((row[column]*y_pass)/v_dist)
else:
single_coordinates.append((row[column] - y_margin_min)*y_pass/v_dist)
y_coordinates.append(single_coordinates)
else:
for cluster in y_datas:
var single_coordinates : Array
for value in cluster.size():
if origin_at_zero:
single_coordinates.append((cluster[value]*y_pass)/v_dist)
else:
single_coordinates.append((cluster[value] - y_margin_min)*y_pass/v_dist)
y_coordinates.append(single_coordinates)
if show_x_values_as_labels:
for x in x_datas.size():
x_coordinates.append(x_pass*x)
else:
for x in x_datas.size():
if origin_at_zero:
if invert_chart:
x_coordinates.append(x_pass*x)
else:
x_coordinates.append(x_datas[x]*x_pass/h_dist)
else:
x_coordinates.append((x_datas[x] - x_margin_min)*x_pass/h_dist)
for f in functions:
point_values.append([])
point_positions.append([])
if invert_chart:
for function in y_coordinates.size():
for function_value in y_coordinates[function].size():
if are_values_columns:
point_positions[function_value].append(Vector2(x_coordinates[function]+origin.x, origin.y-y_coordinates[function][function_value]))
point_values[function_value].append([x_datas[function_value],y_datas[function_value][function]])
else:
point_positions[function].append(Vector2(x_coordinates[function_value]+origin.x,origin.y-y_coordinates[function][function_value]))
point_values[function].append([x_datas[function_value],y_datas[function_value][function]])
else:
for cluster in y_coordinates.size():
for y in y_coordinates[cluster].size():
if are_values_columns:
point_values[y].append([x_datas[cluster],y_datas[cluster][y]])
point_positions[y].append(Vector2(x_coordinates[cluster]+origin.x,origin.y-y_coordinates[cluster][y]))
else:
point_values[cluster].append([x_datas[y],y_datas[cluster][y]])
point_positions[cluster].append(Vector2(x_coordinates[y]+origin.x,origin.y-y_coordinates[cluster][y]))
func _draw():
clear_points()
draw_grid()
draw_chart_outlines()
var defined_colors : bool = false
if function_colors.size():
defined_colors = 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(points_shape[_function], function_colors[function_point if invert_chart else _function],
Color.white, point_positions[_function][function_point],
point.format_value(point_values[_function][function_point], false, false),
y_labels[function_point if invert_chart else _function] as String)
PointContainer.add_child(point)
func draw_grid():
# ascisse
for p in x_chors.size():
var point : Vector2 = origin+Vector2((p)*x_pass,0)
# v grid
draw_line(point,point-Vector2(0,SIZE.y-OFFSET.y),v_lines_color,0.2,true)
# ascisse
draw_line(point-Vector2(0,5),point,v_lines_color,1,true)
draw_string(font,point+Vector2(-const_width/2*x_chors[p].length(),font_size+const_height),x_chors[p],font_color)
# ordinate
for p in y_chors.size():
var point : Vector2 = origin-Vector2(0,(p)*y_pass)
# h grid
draw_line(point,point+Vector2(SIZE.x-OFFSET.x,0),h_lines_color,0.2,true)
# ordinate
draw_line(point,point+Vector2(5,0),h_lines_color,1,true)
draw_string(font,point-Vector2(y_chors[p].length()*const_width+font_size,-const_height),y_chors[p],font_color)
func draw_chart_outlines():
draw_line(origin,SIZE-Vector2(0,OFFSET.y),box_color,1,true)
draw_line(origin,Vector2(OFFSET.x,0),box_color,1,true)
draw_line(Vector2(OFFSET.x,0),Vector2(SIZE.x,0),box_color,1,true)
draw_line(Vector2(SIZE.x,0),SIZE-Vector2(0,OFFSET.y),box_color,1,true)

View File

@ -1,7 +1,7 @@
[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/ScatterChart/ScatterChart.gd" type="Script" id=2]
[ext_resource path="res://addons/easy_charts/ScatterChart/scatter_chart.gd" type="Script" id=2]
[sub_resource type="Theme" id=1]
@ -75,11 +75,10 @@ __meta__ = {
[node name="PointData" parent="." instance=ExtResource( 1 )]
[node name="PointData" parent="PointData" index="0"]
visible = false
margin_left = 58.5211
margin_top = -187.685
margin_right = 58.3851
margin_bottom = -186.885
margin_left = -311.73
margin_top = -167.672
margin_right = -311.866
margin_bottom = -166.872
theme = SubResource( 1 )
[editable path="PointData"]

View File

@ -0,0 +1,317 @@
tool
extends Chart
class_name ScatterChart
"""
[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 /
"""
# ---------------------
func _get_property_list():
return [
# Chart Properties
{
"hint": PROPERTY_HINT_NONE,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Properties/are_values_columns",
"type": TYPE_BOOL
},
{
"hint": PROPERTY_HINT_RANGE,
"hint_string": "-1,100,1",
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Properties/labels_index",
"type": TYPE_INT
},
{
"hint": PROPERTY_HINT_NONE,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Properties/show_x_values_as_labels",
"type": TYPE_BOOL
},
# Chart Display
{
"hint": PROPERTY_HINT_RANGE,
"hint_string": "0.1,10",
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Display/x_decim",
"type": TYPE_REAL
},
{
"hint": PROPERTY_HINT_RANGE,
"hint_string": "0.1,10",
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Display/y_decim",
"type": TYPE_REAL
},
# Chart Style
{
"hint": 24,
"hint_string": "%d/%d:%s"%[TYPE_INT, PROPERTY_HINT_ENUM,
PoolStringArray(PointShapes.keys()).join(",")],
"name": "Chart_Style/points_shape",
"type": TYPE_ARRAY,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE
},
{
"hint": PROPERTY_HINT_NONE,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/function_colors",
"type": TYPE_COLOR_ARRAY
},
{
"hint": PROPERTY_HINT_NONE,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/box_color",
"type": TYPE_COLOR
},
{
"hint": PROPERTY_HINT_NONE,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/v_lines_color",
"type": TYPE_COLOR
},
{
"hint": PROPERTY_HINT_NONE,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/h_lines_color",
"type": TYPE_COLOR
},
{
"class_name": "Font",
"hint": PROPERTY_HINT_RESOURCE_TYPE,
"hint_string": "Font",
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/font",
"type": TYPE_OBJECT
},
{
"class_name": "Font",
"hint": PROPERTY_HINT_RESOURCE_TYPE,
"hint_string": "Font",
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/bold_font",
"type": TYPE_OBJECT
},
{
"hint": PROPERTY_HINT_NONE,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/font_color",
"type": TYPE_COLOR
},
{
"hint": PROPERTY_HINT_ENUM,
"hint_string": PoolStringArray(Utilities.templates.keys()).join(","),
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Style/template",
"type": TYPE_INT
},
# Chart Modifiers
{
"hint": PROPERTY_HINT_NONE,
"usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
"name": "Chart_Modifiers/invert_chart",
"type": TYPE_BOOL
},
]
func structure_datas(database : Array):
# @labels_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
are_values_columns = invert_chart != 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 == labels_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)
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())
false:
for row in database.size():
if row == labels_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 build_chart():
SIZE = get_size()
origin = Vector2(OFFSET.x,SIZE.y-OFFSET.y)
func calculate_pass():
if show_x_values_as_labels:
x_chors = x_datas as PoolStringArray
else:
x_chors = x_labels
# calculate distance in pixel between 2 consecutive values/datas
x_pass = (SIZE.x - OFFSET.x) / (x_chors.size()-1)
y_pass = origin.y / (y_chors.size()-1)
func calculate_coordinates():
x_coordinates.clear()
y_coordinates.clear()
point_values.clear()
point_positions.clear()
for cluster in y_datas:
var single_coordinates : Array
for value in cluster.size():
if origin_at_zero:
single_coordinates.append((cluster[value]*y_pass)/v_dist)
else:
single_coordinates.append((cluster[value] - y_margin_min)*y_pass/v_dist)
y_coordinates.append(single_coordinates)
if show_x_values_as_labels:
for x in x_datas.size():
x_coordinates.append(x_pass*x)
else:
for x in x_datas.size():
if origin_at_zero:
x_coordinates.append(x_datas[x]*x_pass/h_dist)
else:
x_coordinates.append((x_datas[x] - x_margin_min)*x_pass/h_dist)
for f in functions:
point_values.append([])
point_positions.append([])
for cluster in y_coordinates.size():
for y in y_coordinates[cluster].size():
if are_values_columns:
point_values[y].append([x_datas[cluster],y_datas[cluster][y]])
point_positions[y].append(Vector2(x_coordinates[cluster]+origin.x,origin.y-y_coordinates[cluster][y]))
else:
point_values[cluster].append([x_datas[y],y_datas[cluster][y]])
point_positions[cluster].append(Vector2(x_coordinates[y]+origin.x,origin.y-y_coordinates[cluster][y]))
func _draw():
clear_points()
draw_grid()
draw_chart_outlines()
var defined_colors : bool = false
if function_colors.size():
defined_colors = 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(points_shape[_function], function_colors[_function],
Color.white, point_positions[_function][function_point],
point.format_value(point_values[_function][function_point], false, false),
y_labels[_function] as String)
PointContainer.add_child(point)
func draw_grid():
# ascisse
for p in x_chors.size():
var point : Vector2 = origin+Vector2((p)*x_pass,0)
# v grid
draw_line(point,point-Vector2(0,SIZE.y-OFFSET.y),v_lines_color,0.2,true)
# ascisse
draw_line(point-Vector2(0,5),point,v_lines_color,1,true)
draw_string(font,point+Vector2(-const_width/2*x_chors[p].length(),font_size+const_height),x_chors[p],font_color)
# ordinate
for p in y_chors.size():
var point : Vector2 = origin-Vector2(0,(p)*y_pass)
# h grid
draw_line(point,point+Vector2(SIZE.x-OFFSET.x,0),h_lines_color,0.2,true)
# ordinate
draw_line(point,point+Vector2(5,0),h_lines_color,1,true)
draw_string(font,point-Vector2(y_chors[p].length()*const_width+font_size,-const_height),y_chors[p],font_color)
func draw_chart_outlines():
draw_line(origin,SIZE-Vector2(0,OFFSET.y),box_color,1,true)
draw_line(origin,Vector2(OFFSET.x,0),box_color,1,true)
draw_line(Vector2(OFFSET.x,0),Vector2(SIZE.x,0),box_color,1,true)
draw_line(Vector2(SIZE.x,0),SIZE-Vector2(0,OFFSET.y),box_color,1,true)

View File

@ -14,105 +14,6 @@ the horizontal axis and the value of the other variable determining the position
/ source : Wikipedia /
"""
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")
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
# database values
var x_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(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 (Array, PointShapes) var points_shape : Array = 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")
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 (TemplatesNames) var template : int = TemplatesNames.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

View File

@ -2,9 +2,9 @@ tool
extends Node2D
var LineChart = preload("LineChart2D/LineChart2D.tscn")
var ColumnChart = preload("BarChart2D/BarChart2D.tscn")
var ColumnChart = preload("ColumnChart2D/ColumnChart2D.tscn")
export (String,"None","LineChart2D","BarChart2D") var chart_type : String setget set_type,get_type
export (String,"None","LineChart2D","ColumnChart2D") 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.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

View File

@ -1,34 +0,0 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/Line-Graph1.png-cf75f72c04876dd893d0cb31b406bc73.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/easy_charts/Utilities/Rect/Line-Graph1.png"
dest_files=[ "res://.import/Line-Graph1.png-cf75f72c04876dd893d0cb31b406bc73.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

View File

@ -1,638 +0,0 @@
extends Control
class_name Chart
# Classes
enum TYPES { Line, Bar, Scatter, Radar, Pie }
# Signals ..................................
signal chart_plotted(chart) # emit when a chart is plotted (static) or updated (dynamic)
signal point_pressed(point)
# Onready Vars ............................
onready var PointData = $PointData/PointData
onready var Points = $Points
onready var Legend = $Legend
onready var ChartName : Label = $ChartName
# Scenes and Reosurces ......................
var point_node : PackedScene = preload("../Point/Point.tscn")
var LegendElement : PackedScene = preload("../Legend/FunctionLegend.tscn")
# Enums .....................................
enum PointShapes { Dot, Triangle, Square, Cross }
# Shared Variables .........................
var SIZE : Vector2 = Vector2()
var OFFSET : Vector2 = Vector2(0,0)
var origin : Vector2
var font_size : float = 16
var const_height : float = font_size/2*font_size/20
var const_width : float = font_size/2
# 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
# 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
# data contained in file
var data : 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 templates : Dictionary = {}
# ................... Export Shared Variables ..................
export (String) var chart_name : String = "" setget set_chart_name
export (String, FILE, "*.txt, *.csv") var source : String = "" setget set_source
export (String) var delimiter : String = ";" setget set_delimiter
var origin_at_zero : bool = true setget set_origin_at_zero#, get_origin_at_zero
var are_values_columns : bool = false setget set_are_values_columns#, get_are_values_columns
var show_x_values_as_labels : bool = true setget set_show_x_values_as_labels#, get_show_x_values_as_labels
var labels_index : int = 0 setget set_labels_index#, get_labels_index
var function_names_index : int = 0 setget set_function_names_index#, get_function_names_index
# for radar
var use_height_as_radius : bool = false setget set_use_height_as_radius
var radius : float = 150.0 setget _set_radius,get_radius
# for columns
var column_width : float = 10 setget set_column_width
var column_gap : float = 2 setget set_column_gap
var full_scale : float = 1.0 setget set_full_scale
var x_decim : float = 5.0 setget set_x_decim
var y_decim : float = 5.0 setget set_y_decim
var points_shape : Array = [PointShapes.Dot] setget set_points_shape
var function_colors = [Color("#1e1e1e")] setget set_function_colors
var outline_color : Color = Color("#1e1e1e") setget set_outline_color
var box_color : Color = Color("#1e1e1e") setget set_box_color
var v_lines_color : Color = Color("#cacaca") setget set_v_lines_color
var h_lines_color : Color = Color("#cacaca") setget set_h_lines_color
var grid_color : Color = Color("#1e1e1e") setget set_grid_color
var font : Font setget set_font
var bold_font : Font setget set_bold_font
var font_color : Color = Color("#1e1e1e") setget set_font_color
var template : int = 0 setget set_template
# modifiers
var rotation : float = 0 setget set_rotation
var invert_chart : bool = false setget set_invert_chart
static func instance(chart_type : int):
var chart_t : String = Utilities.get_chart_type(chart_type)
var chart : String = "res://addons/easy_charts/%s/%s.tscn" % [chart_t, chart_t]
return load(chart).instance()
# .......................... Properties Manager ....................................
func _get(property):
match property:
"Chart_Properties/origin_at_zero":
return origin_at_zero
"Chart_Properties/are_values_columns":
return are_values_columns
"Chart_Properties/show_x_values_as_labels":
return show_x_values_as_labels
"Chart_Properties/labels_index":
return labels_index
"Chart_Properties/function_names_index":
return function_names_index
"Chart_Properties/use_height_as_radius":
return use_height_as_radius
"Chart_Properties/radius":
return radius
"Chart_Properties/column_width":
return column_width
"Chart_Properties/column_gap":
return column_gap
"Chart_Display/full_scale":
return full_scale
"Chart_Display/x_decim":
return x_decim
"Chart_Display/y_decim":
return y_decim
"Chart_Style/points_shape":
return points_shape
"Chart_Style/function_colors":
return function_colors
"Chart_Style/template":
return template
"Chart_Style/outline_color":
return outline_color
"Chart_Style/grid_color":
return grid_color
"Chart_Style/box_color":
return box_color
"Chart_Style/v_lines_color":
return v_lines_color
"Chart_Style/h_lines_color":
return h_lines_color
"Chart_Style/font":
return font
"Chart_Style/bold_font":
return bold_font
"Chart_Style/font_color":
return font_color
"Chart_Modifiers/rotation":
return rotation
"Chart_Modifiers/invert_chart":
return invert_chart
func _set(property, value):
match property:
"Chart_Properties/origin_at_zero":
origin_at_zero = value
return true
"Chart_Properties/are_values_columns":
are_values_columns = value
return true
"Chart_Properties/show_x_values_as_labels":
show_x_values_as_labels = value
return true
"Chart_Properties/labels_index":
labels_index = value
return true
"Chart_Properties/function_names_index":
function_names_index = value
return true
"Chart_Properties/use_height_as_radius":
use_height_as_radius = value
return true
"Chart_Properties/radius":
radius = value
return true
"Chart_Properties/column_width":
column_width = value
return true
"Chart_Properties/column_gap":
column_width = value
return true
"Chart_Display/full_scale":
full_scale = value
return true
"Chart_Display/x_decim":
x_decim = value
return true
"Chart_Display/y_decim":
y_decim = value
return true
"Chart_Style/points_shape":
points_shape = value
return true
"Chart_Style/function_colors":
function_colors = value
return true
"Chart_Style/template":
template = value
apply_template(template)
return true
"Chart_Style/outline_color":
outline_color = value
return true
"Chart_Style/grid_color":
grid_color = value
return true
"Chart_Style/box_color":
box_color = value
return true
"Chart_Style/v_lines_color":
v_lines_color = value
return true
"Chart_Style/h_lines_color":
h_lines_color = value
return true
"Chart_Style/font":
font = value
return true
"Chart_Style/bold_font":
bold_font = value
return true
"Chart_Style/font_color":
font_color = value
apply_template(template)
return true
"Chart_Modifiers/rotation":
rotation = value
return true
"Chart_Modifiers/invert_chart":
invert_chart = value
return true
func _ready():
templates = Utilities._load_templates()
# .......................... Shared Functions and virtuals ........................
func plot():
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
data = read_datas(source)
structure_datas(data.duplicate(true),are_values_columns,labels_index)
build_chart()
count_functions()
calculate_pass()
calculate_colors()
calculate_coordinates()
set_shapes()
create_legend()
emit_signal("chart_plotted",self)
func plot_from_csv(csv_file : String, _delimiter : String = delimiter):
load_font()
PointData.hide()
if csv_file == "" or csv_file == 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
data = read_datas(csv_file, _delimiter)
structure_datas(data.duplicate(true),are_values_columns,labels_index)
build_chart()
count_functions()
calculate_pass()
calculate_colors()
calculate_coordinates()
set_shapes()
create_legend()
emit_signal("chart_plotted",self)
func plot_from_array(array : Array) -> void:
load_font()
PointData.hide()
if array.empty():
Utilities._print_message("Can't plot a chart without an empty Array.",1)
return
data = array
structure_datas(data.duplicate(true),are_values_columns,labels_index)
build_chart()
count_functions()
calculate_pass()
calculate_colors()
calculate_coordinates()
set_shapes()
create_legend()
emit_signal("chart_plotted",self)
if not is_connected("item_rect_changed",self, "redraw"): connect("item_rect_changed", self, "redraw")
func plot_from_dataframe(dataframe : DataFrame) -> void:
load_font()
PointData.hide()
data = dataframe.get_dataset()
if data.empty():
Utilities._print_message("Can't plot a chart without an empty Array.",1)
return
structure_datas(data.duplicate(true),are_values_columns,labels_index)
build_chart()
count_functions()
calculate_pass()
calculate_colors()
calculate_coordinates()
set_shapes()
create_legend()
emit_signal("chart_plotted",self)
# Append new data (in array format) to the already plotted data.
# All data are stored.
func update_plot_data(array : Array) -> void:
if array.empty():
Utilities._print_message("Can't plot a chart without an empty Array.",1)
return
data.append(array)
structure_datas(data.duplicate(true),are_values_columns,labels_index)
redraw()
count_functions()
calculate_colors()
set_shapes()
create_legend()
emit_signal("chart_plotted",self)
update()
func plot_placeholder() -> void:
pass
func load_font():
if font != null:
font_size = font.get_height()
var theme : Theme = Theme.new()
theme.set_default_font(font)
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 calculate_colors():
if function_colors.size() <= functions:
for function in range(functions - function_colors.size() + 1): function_colors.append(Color(randf(),randf(), randf()))
func set_shapes():
if points_shape.empty() or points_shape.size() < functions:
for function in functions:
points_shape.append(PointShapes.Dot)
func read_datas(source : String, _delimiter : String = delimiter):
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 count_functions():
if are_values_columns:
if not invert_chart:
functions = data[0].size()-1
else:
functions = data.size()-1
else:
if invert_chart:
functions = x_datas.size()
else:
functions = y_datas.size()
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 redraw():
build_chart()
calculate_pass()
calculate_coordinates()
update()
func clean_variables():
x_datas.clear()
y_datas.clear()
x_label = ""
x_labels.clear()
y_labels.clear()
# .................. VIRTUAL FUNCTIONS .........................
func structure_datas(database : Array, are_values_columns : bool, labels_index : int):
pass
func build_chart():
pass
func calculate_pass():
pass
func calculate_coordinates():
pass
func function_colors():
pass
func create_legend():
legend.clear()
for function in functions:
var function_legend : LegendElement = LegendElement.instance()
var f_name : String = y_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)
# ........................... Shared Setters & Getters ..............................
func apply_template(template_name : int):
if Engine.editor_hint:
set_template(template_name)
property_list_changed_notify()
# !!! API v2
func set_chart_name(ch_name : String):
chart_name = ch_name
get_node("ChartName").set_text(chart_name)
# !!! API v2
func set_source(source_file : String):
source = source_file
# !!! API v2
func set_indexes(lb : int = 0, function_names : int = 0):
labels_index = lb
function_names_index = function_names
# !!! API v2
func set_radius(use_height : bool = false, f : float = 0):
use_height_as_radius = use_height
radius = f
# !!! API v2
func set_chart_colors(f_colors : PoolColorArray, o_color : Color, b_color : Color, g_color : Color, h_lines : Color, v_lines : Color):
function_colors = f_colors
outline_color = o_color
box_color = b_color
grid_color = g_color
h_lines_color = h_lines
v_lines_color = v_lines
# !!! API v2
func set_chart_fonts(normal_font : Font, bold_font : Font, f_color : Color = Color.white):
font = normal_font
self.bold_font = bold_font
font_color = f_color
# !!! API v2
func set_delimiter(d : String):
delimiter = d
# ! API
func set_origin_at_zero(b : bool):
origin_at_zero = b
# ! API
func set_are_values_columns(b : bool):
are_values_columns = b
# ! API
func set_show_x_values_as_labels(b : bool):
show_x_values_as_labels = b
func set_labels_index(i : int):
labels_index = i
func set_function_names_index(i : int):
function_names_index = i
func set_use_height_as_radius(b : bool):
use_height_as_radius = b
func _set_radius(r : float):
radius = r
func get_radius() -> float:
if use_height_as_radius: return get_size().y/2
else: return radius
# ! API
func set_column_width(f : float):
column_width = f
# ! API
func set_column_gap(f : float):
column_gap = f
# ! API
func set_full_scale(f : float):
full_scale = f
# ! API
func set_x_decim(f : float):
x_decim = f
# ! API
func set_y_decim(f : float):
y_decim = f
# ! API
func set_points_shape(a : Array):
points_shape = a
# ! API
func set_function_colors(a : Array):
function_colors = a
# ! API
func set_outline_color(c : Color):
outline_color = c
# ! API
func set_box_color(c : Color):
box_color = c
# ! API
func set_grid_color(c : Color):
grid_color = c
# ! API
func set_v_lines_color(c : Color):
v_lines_color = c
# ! API
func set_h_lines_color(c : Color):
h_lines_color = c
# ! API
func set_font(f : Font):
font = f
# ! API
func set_bold_font(f : Font):
bold_font = f
# ! API
func set_font_color(c : Color):
font_color = c
# ! API
func set_template(template_name : int):
template = template_name
templates = Utilities.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)
box_color = Color(custom_template.outline_color)
grid_color = Color(custom_template.v_lines_color)
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)
# ! API
func set_rotation(f : float):
rotation = f
# ! API
func set_invert_chart(b : bool):
invert_chart = b
func set_legend(l : Array):
legend = l
func get_legend() -> Array:
return legend
# ............................. Shared Signals ..............................
func point_pressed(point : Point):
emit_signal("point_pressed",point)
func show_data(point : Point):
PointData.update_datas(point)
PointData.show()
func hide_data():
PointData.hide()
func show_slice_data(slice : Slice):
PointData.update_slice_datas(slice)
PointData.show()

View File

@ -1,10 +0,0 @@
tool
extends Node2D
class_name Chart2D
enum PointShapes { Dot, Triangle, Square, Cross }
enum TemplatesNames { 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

@ -1,39 +0,0 @@
#extends Object
#class_name ChartObject
#
#"""
#[ChartObject] :: Class
#
#this class is used to store all the functions that Chart, Chart2D and Chart3D custom instances
#will share in-between.
#Chart classes will extend this class.
#"""
#
#enum PointShapes { Dot, Triangle, Square, Cross }
#enum TemplatesNames { Default, Clean, Gradient, Minimal, Invert }
#
#class Chart extends Control:
# var CHART_TYPE : String = "Chart"
# enum PointShapes { Dot, Triangle, Square, Cross }
# enum TemplatesNames { Default, Clean, Gradient, Minimal, Invert }
#
# export (PoolColorArray) var function_colors = [Color("#1e1e1e")]
# export (Array, PointShapes) var points_shape : Array = [PointShapes.Dot]
#
# var functions : int = 0
#
# func calculate_colors():
# if function_colors.empty() or function_colors.size() < functions:
# for function in functions:
# function_colors.append(Color("#1e1e1e"))
#
# func set_shapes():
# if points_shape.empty() or points_shape.size() < functions:
# for function in functions:
# points_shape.append(PointShapes.Dot)
#
#
#class Chart2D extends Node2D:
# var CHART_TYPE : String = "Chart2D"
# enum PointShapes { Dot, Triangle, Square, Cross }
# enum TemplatesNames { Default, Clean, Gradient, Minimal, Invert }

View File

@ -320,7 +320,7 @@ func plot():
data = read_datas(source)
structure_datas(slice_data(),are_values_columns,labels_index)
structure_datas(slice_data())
build_chart()
count_functions()
calculate_pass()
@ -339,7 +339,7 @@ func plot_from_csv(csv_file : String, _delimiter : String = delimiter):
return
data = read_datas(csv_file, _delimiter)
structure_datas(slice_data(),are_values_columns,labels_index)
structure_datas(slice_data())
build_chart()
count_functions()
calculate_pass()
@ -360,7 +360,7 @@ func plot_from_array(array : Array) -> void:
return
data = array.duplicate()
structure_datas(slice_data(), are_values_columns,labels_index)
structure_datas(slice_data())
build_chart()
count_functions()
calculate_pass()
@ -385,7 +385,7 @@ func plot_from_dataframe(dataframe : DataFrame) -> void:
Utilities._print_message("Can't plot a chart with an empty Array.",1)
return
structure_datas(slice_data(),are_values_columns,labels_index)
structure_datas(slice_data())
build_chart()
count_functions()
calculate_pass()
@ -405,7 +405,7 @@ func update_plot_data(array : Array) -> void:
return
data.append(array)
structure_datas(slice_data(),are_values_columns,labels_index)
structure_datas(slice_data())
redraw()
count_functions()
calculate_colors()
@ -463,16 +463,8 @@ func read_datas(source : String, _delimiter : String = delimiter):
return content
func count_functions():
if are_values_columns:
if not invert_chart:
functions = data[0].size()-1
else:
functions = data.size()-1
else:
if invert_chart:
functions = x_datas.size()
else:
functions = y_datas.size()
if are_values_columns: functions = data[0].size()-1
else: functions = y_datas.size()
func clear_points():
if $Points.get_children():
@ -497,7 +489,7 @@ func clean_variables():
y_labels.clear()
# .................. VIRTUAL FUNCTIONS .........................
func structure_datas(database : Array, are_values_columns : bool, labels_index : int):
func structure_datas(database : Array):
pass
func build_chart():
@ -520,7 +512,7 @@ func create_legend():
else:
function_legend = LegendElement.instance()
legend.append(function_legend)
var f_name : String = y_labels[function]
var f_name : String = y_labels[function] if not are_values_columns else str(x_datas[function])
var legend_font : Font
if font != null:
legend_font = font

View File

@ -5,6 +5,207 @@ class_name Chart2D
enum PointShapes { Dot, Triangle, Square, Cross }
enum TemplatesNames { Default, Clean, Gradient, Minimal, Invert }
signal chart_plotted(chart)
signal point_pressed(point)
const OFFSET: Vector2 = Vector2(0,0)
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(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 (PointShapes) 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 var template : int = 0 setget apply_template
export (float, 0.1, 1) var drawing_duration: float = 0.5
export (bool) var invert_chart: bool = false
var OutlinesTween: Tween
var FunctionsTween: Tween
var PointTween : Tween
var Functions: Node2D
var GridTween: Tween
var PointData: PointData
var Outlines: Line2D
var Grid: Node2D
var point_node: PackedScene = preload("../Point/Point.tscn")
var FunctionLegend: PackedScene = preload("../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 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
# database values
var x_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
var templates: Dictionary = {}
# Called when the node enters the scene tree for the first time.
func _ready():
pass # Replace with function body.
pass # Replace with function body.
func build_chart():
pass
func calculate_pass():
pass
func calculate_coordinates():
pass
func _set_size(v : Vector2):
SIZE = v
func _get_children():
OutlinesTween = $OutlinesTween
FunctionsTween = $FunctionsTween
Functions = $Functions
GridTween = $GridTween
PointData = $PointData/PointData
Outlines = $Outlines
Grid = $Grid
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
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()
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 redraw():
build_chart()
calculate_pass()
calculate_coordinates()
update()
func show_data(point):
PointData.update_datas(point)
PointData.show()
func hide_data():
PointData.hide()
func clear_points():
function_colors.clear()
if Functions.get_children():
for function in Functions.get_children():
function.queue_free()
func count_functions():
if are_values_columns:
if not invert_chart:
functions = datas[0].size() - 1
else:
functions = datas.size() - 1
else:
if invert_chart:
functions = datas[0].size() - 1
else:
functions = datas.size() - 1
func set_legend(l: Array):
legend = l
func get_legend():
return legend
func create_legend():
legend.clear()
for function in functions:
var function_legend = FunctionLegend.instance()
var f_name: String
if invert_chart:
f_name = x_datas[function] as String
else:
f_name = y_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)

View File

@ -1,39 +0,0 @@
#extends Object
#class_name ChartObject
#
#"""
#[ChartObject] :: Class
#
#this class is used to store all the functions that Chart, Chart2D and Chart3D custom instances
#will share in-between.
#Chart classes will extend this class.
#"""
#
#enum PointShapes { Dot, Triangle, Square, Cross }
#enum TemplatesNames { Default, Clean, Gradient, Minimal, Invert }
#
#class Chart extends Control:
# var CHART_TYPE : String = "Chart"
# enum PointShapes { Dot, Triangle, Square, Cross }
# enum TemplatesNames { Default, Clean, Gradient, Minimal, Invert }
#
# export (PoolColorArray) var function_colors = [Color("#1e1e1e")]
# export (Array, PointShapes) var points_shape : Array = [PointShapes.Dot]
#
# var functions : int = 0
#
# func calculate_colors():
# if function_colors.empty() or function_colors.size() < functions:
# for function in functions:
# function_colors.append(Color("#1e1e1e"))
#
# func set_shapes():
# if points_shape.empty() or points_shape.size() < functions:
# for function in functions:
# points_shape.append(PointShapes.Dot)
#
#
#class Chart2D extends Node2D:
# var CHART_TYPE : String = "Chart2D"
# enum PointShapes { Dot, Triangle, Square, Cross }
# enum TemplatesNames { Default, Clean, Gradient, Minimal, Invert }

View File

@ -5,7 +5,7 @@ var plugin_name : String = "Easy Charts"
var templates : Dictionary = {}
var chart_types : Dictionary = {
0:"LineChart",
1:"BarChart",
1:"ColumnChart",
2:"ScatterChart",
3:"RadarChart",
4:"PieChart"

View File

@ -1,10 +0,0 @@
Year;Column 1
2009;36200
2010;36600
2011;37500
2012;38700
2013;39600
2014;40500
2015;41200
2016;41803
2017;42600
1 Year Column 1
2 2009 36200
3 2010 36600
4 2011 37500
5 2012 38700
6 2013 39600
7 2014 40500
8 2015 41200
9 2016 41803
10 2017 42600

View File

@ -1,10 +0,0 @@
[remap]
importer="csv"
type="TextFile"
[deps]
source_file="res://addons/easy_charts/file.samples/2_columns.csv"
[params]

View File

@ -1,10 +0,0 @@
[remap]
importer="csv"
type="TextFile"
[deps]
source_file="res://addons/easy_charts/file.samples/datas.csv"
[params]

View File

@ -1,5 +0,0 @@
Year;2009;2010;2011;2012;2013;2014;2015;2016;2017
Column 1;36200;36600;37500;38700;39600;40500;41200;41803;42600
Column 2;27200;27800;28500;29400;30200;30900;31500;31931;32600
Column 3;26200;26600;27500;28700;29600;20500;21200;21803;22600
Column 4;17200;17800;18500;19400;10200;10900;11500;11931;12600
1 Year 2009 2010 2011 2012 2013 2014 2015 2016 2017
2 Column 1 36200 36600 37500 38700 39600 40500 41200 41803 42600
3 Column 2 27200 27800 28500 29400 30200 30900 31500 31931 32600
4 Column 3 26200 26600 27500 28700 29600 20500 21200 21803 22600
5 Column 4 17200 17800 18500 19400 10200 10900 11500 11931 12600

View File

@ -1,10 +0,0 @@
[remap]
importer="csv"
type="TextFile"
[deps]
source_file="res://addons/easy_charts/file.samples/datas2.csv"
[params]

View File

@ -1,10 +0,0 @@
[remap]
importer="csv"
type="TextFile"
[deps]
source_file="res://addons/easy_charts/file.samples/datas_on_columns.csv"
[params]

View File

@ -1,5 +0,0 @@
Year;2009;2010;2011;2012;2013;2014;2015;2016;2017
Column 1;36200;36600;37500;38700;39600;40500;41200;41803;42600
Column 2;27200;27800;28500;29400;30200;30900;31500;31931;32600
Column 3;26200;26600;27500;28700;29600;20500;21200;21803;22600
Column 4;17200;17800;18500;19400;10200;10900;11500;11931;12600
1 Year 2009 2010 2011 2012 2013 2014 2015 2016 2017
2 Column 1 36200 36600 37500 38700 39600 40500 41200 41803 42600
3 Column 2 27200 27800 28500 29400 30200 30900 31500 31931 32600
4 Column 3 26200 26600 27500 28700 29600 20500 21200 21803 22600
5 Column 4 17200 17800 18500 19400 10200 10900 11500 11931 12600

View File

@ -1,10 +0,0 @@
[remap]
importer="csv"
type="TextFile"
[deps]
source_file="res://addons/easy_charts/file.samples/datas_on_rows.csv"
[params]

View File

@ -1,3 +0,0 @@
Meccaniche;deve essere possibile rallentare/fermare il tempo;deve essere basato su una griglia;deve essere un gioco a tentativi;deve implementare della magia;non deve contenere istruzioni
Valori;22;13;20;20;15
Valori2;22;13;20;20;15
1 Meccaniche deve essere possibile rallentare/fermare il tempo deve essere basato su una griglia deve essere un gioco a tentativi deve implementare della magia non deve contenere istruzioni
2 Valori 22 13 20 20 15
3 Valori2 22 13 20 20 15

View File

@ -1,10 +0,0 @@
[remap]
importer="csv"
type="TextFile"
[deps]
source_file="res://addons/easy_charts/file.samples/gei_jam#2columns.csv"
[params]

View File

@ -1,6 +0,0 @@
Meccaniche;Voti
deve essere possibile rallentare/fermare il tempo;22
deve essere basato su una griglia;13
deve essere un gioco a tentativi;20
deve implementare della magia;20
non deve contenere istruzioni;15
1 Meccaniche Voti
2 deve essere possibile rallentare/fermare il tempo 22
3 deve essere basato su una griglia 13
4 deve essere un gioco a tentativi 20
5 deve implementare della magia 20
6 non deve contenere istruzioni 15

View File

@ -1,10 +0,0 @@
[remap]
importer="csv"
type="TextFile"
[deps]
source_file="res://addons/easy_charts/file.samples/godot_engine_italia_jam#2.csv"
[params]

View File

@ -0,0 +1,10 @@
[remap]
importer="csv"
type="TextFile"
[deps]
source_file="res://addons/easy_charts/file.samples/linechart (columns).csv"
[params]

View File

@ -0,0 +1,10 @@
[remap]
importer="csv"
type="TextFile"
[deps]
source_file="res://addons/easy_charts/file.samples/linechart (rows).csv"
[params]

View File

@ -1,101 +1,101 @@
x;y1;y2
50,05732879;116,61234;90,55501121
53,23295081;105,6457011;47,41275029
47,28686102;95,61795061;36,33108959
53,0250493;106,4552515;85,4302022
57,10271278;111,9088163;39,80610352
40,71992494;78,27201391;79,55208897
55,62752569;122,7859036;94,15837791
54,17819455;107,9817124;39,80351785
40,8610371;107,92736;61,0663229
54,06159551;110,0647495;93,00315399
64,35130431;134,5556319;114,2043276
49,29181834;88,18806126;64,89624292
44,63823505;102,8364528;108,1982178
58,62487836;126,0319541;78,40707574
55,78566879;95,81224088;75,02657209
50,76570445;94,73143882;39,96573437
48,45339259;92,86957776;88,41618517
49,40446173;70,21723661;9,81277488
48,34604978;97,87616091;40,53011113
43,62470151;103,7308337;97,10613219
50,8877046;117,1558657;62,2681611
52,25082012;103,3922334;79,14141328
50,35929987;87,68936817;19,3300683
46,42761861;90,1655428;67,73792419
55,67926036;93,17073084;69,49147048
61,72779383;142,8458546;106,1180608
58,99808851;102,3529041;27,35481559
43,6620999;77,36405233;17,70195243
55,42639088;121,0878726;78,66148172
58,79311097;111,8698686;49,07675763
50,71073988;106,5406487;97,82990882
45,57346035;104,7456111;56,17215075
45,7981314;83,9963622;75,1982308
46,46484131;82,94617575;77,48133444
57,9492853;144,9994608;129,0501755
48,3999722;72,83510082;30,43512862
54,2097076;114,7785416;82,568834
46,67548966;95,25014621;37,57465655
38,21698894;88,21423442;64,99724548
51,95614673;90,93548401;66,97933728
51,22522594;105,1106925;101,8854666
52,84741658;105,0503069;75,20289032
54,78984594;109,9873973;87,19755136
52,00296104;101,442706;89,43974496
51,43150193;88,40178257;36,97028064
47,40407943;89,44141735;55,03733792
51,6749185;96,54147702;31,86655852
40,74049925;83,85842913;79,11792988
49,82155418;112,9093356;96,08778142
57,57763531;115,7709369;72,19330159
51,49652924;127,9054098;118,4088806
53,10710725;112,6337002;90,52659295
42,93645994;102,8111834;102,8747235
44,14066275;78,88897631;41,74831356
46,60936983;98,64046333;54,0310935
47,41415307;95,89594769;58,48179462
47,99032677;106,3655192;102,3751924
50,68360992;106,9507457;44,26713578
50,57070899;83,19613908;61,62543009
57,14992785;115,5596634;40,40973555
50,45105658;97,6950217;64,24396512
46,76779029;99,20006513;60,43227484
50,49802495;99,43092076;87,93289581
51,52523583;84,24653091;17,72129508
40,72692657;102,1715902;67,44466363
54,96034411;111,5346596;82,57431549
48,86213774;101,4305303;58,56839256
52,76166432;108,021472;60,25980768
55,46249302;83,51709356;51,05460054
51,78186354;79,45870906;11,67684552
54,7256505;108,6386184;58,9129679
55,03288163;112,1224042;72,08952257
52,83806054;104,53718;101,6991195
45,86692682;91,39643691;29,52951009
49,67284006;110,1908352;88,51799514
53,18552185;119,0135337;113,8280119
41,69070011;62,78988486;53,09918475
53,36320564;118,5841731;108,2209675
44,27369117;74,58882658;69,31513541
49,92198979;76,93363417;52,01164438
44,91221355;82,33766098;44,42544743
37,92316535;68,0076039;17,08443855
50,10889447;103,6209931;49,51209863
44,20348231;84,19989748;57,99641517
57,11433271;102,0528226;84,93848989
41,90764861;109,1360517;50,22840309
51,88278094;89,01870776;69,13592682
44,31355843;81,19982464;76,88626621
44,25547817;72,64564157;53,3901634
48,93179315;107,7773458;40,84555265
39,36849865;59,39799005;68,0294914
53,33338181;99,04871654;92,71533473
61,63696872;129,3884947;76,75152598
46,40148646;102,9511032;92,54961674
43,81949012;75,15673812;44,337248
53,78046359;85,87008695;50,08962336
41,27977392;60,49700348;50,21722956
52,32206122;106,8462547;57,52419348
41,36660384;105,0465099;78,67990606
47,62423286;96,62455823;84,00032537
x;y1;y2
50,05732879;116,61234;90,55501121
53,23295081;105,6457011;47,41275029
47,28686102;95,61795061;36,33108959
53,0250493;106,4552515;85,4302022
57,10271278;111,9088163;39,80610352
40,71992494;78,27201391;79,55208897
55,62752569;122,7859036;94,15837791
54,17819455;107,9817124;39,80351785
40,8610371;107,92736;61,0663229
54,06159551;110,0647495;93,00315399
64,35130431;134,5556319;114,2043276
49,29181834;88,18806126;64,89624292
44,63823505;102,8364528;108,1982178
58,62487836;126,0319541;78,40707574
55,78566879;95,81224088;75,02657209
50,76570445;94,73143882;39,96573437
48,45339259;92,86957776;88,41618517
49,40446173;70,21723661;9,81277488
48,34604978;97,87616091;40,53011113
43,62470151;103,7308337;97,10613219
50,8877046;117,1558657;62,2681611
52,25082012;103,3922334;79,14141328
50,35929987;87,68936817;19,3300683
46,42761861;90,1655428;67,73792419
55,67926036;93,17073084;69,49147048
61,72779383;142,8458546;106,1180608
58,99808851;102,3529041;27,35481559
43,6620999;77,36405233;17,70195243
55,42639088;121,0878726;78,66148172
58,79311097;111,8698686;49,07675763
50,71073988;106,5406487;97,82990882
45,57346035;104,7456111;56,17215075
45,7981314;83,9963622;75,1982308
46,46484131;82,94617575;77,48133444
57,9492853;144,9994608;129,0501755
48,3999722;72,83510082;30,43512862
54,2097076;114,7785416;82,568834
46,67548966;95,25014621;37,57465655
38,21698894;88,21423442;64,99724548
51,95614673;90,93548401;66,97933728
51,22522594;105,1106925;101,8854666
52,84741658;105,0503069;75,20289032
54,78984594;109,9873973;87,19755136
52,00296104;101,442706;89,43974496
51,43150193;88,40178257;36,97028064
47,40407943;89,44141735;55,03733792
51,6749185;96,54147702;31,86655852
40,74049925;83,85842913;79,11792988
49,82155418;112,9093356;96,08778142
57,57763531;115,7709369;72,19330159
51,49652924;127,9054098;118,4088806
53,10710725;112,6337002;90,52659295
42,93645994;102,8111834;102,8747235
44,14066275;78,88897631;41,74831356
46,60936983;98,64046333;54,0310935
47,41415307;95,89594769;58,48179462
47,99032677;106,3655192;102,3751924
50,68360992;106,9507457;44,26713578
50,57070899;83,19613908;61,62543009
57,14992785;115,5596634;40,40973555
50,45105658;97,6950217;64,24396512
46,76779029;99,20006513;60,43227484
50,49802495;99,43092076;87,93289581
51,52523583;84,24653091;17,72129508
40,72692657;102,1715902;67,44466363
54,96034411;111,5346596;82,57431549
48,86213774;101,4305303;58,56839256
52,76166432;108,021472;60,25980768
55,46249302;83,51709356;51,05460054
51,78186354;79,45870906;11,67684552
54,7256505;108,6386184;58,9129679
55,03288163;112,1224042;72,08952257
52,83806054;104,53718;101,6991195
45,86692682;91,39643691;29,52951009
49,67284006;110,1908352;88,51799514
53,18552185;119,0135337;113,8280119
41,69070011;62,78988486;53,09918475
53,36320564;118,5841731;108,2209675
44,27369117;74,58882658;69,31513541
49,92198979;76,93363417;52,01164438
44,91221355;82,33766098;44,42544743
37,92316535;68,0076039;17,08443855
50,10889447;103,6209931;49,51209863
44,20348231;84,19989748;57,99641517
57,11433271;102,0528226;84,93848989
41,90764861;109,1360517;50,22840309
51,88278094;89,01870776;69,13592682
44,31355843;81,19982464;76,88626621
44,25547817;72,64564157;53,3901634
48,93179315;107,7773458;40,84555265
39,36849865;59,39799005;68,0294914
53,33338181;99,04871654;92,71533473
61,63696872;129,3884947;76,75152598
46,40148646;102,9511032;92,54961674
43,81949012;75,15673812;44,337248
53,78046359;85,87008695;50,08962336
41,27977392;60,49700348;50,21722956
52,32206122;106,8462547;57,52419348
41,36660384;105,0465099;78,67990606
47,62423286;96,62455823;84,00032537
1 x y1 y2
2 50,05732879 116,61234 90,55501121
3 53,23295081 105,6457011 47,41275029
4 47,28686102 95,61795061 36,33108959
5 53,0250493 106,4552515 85,4302022
6 57,10271278 111,9088163 39,80610352
7 40,71992494 78,27201391 79,55208897
8 55,62752569 122,7859036 94,15837791
9 54,17819455 107,9817124 39,80351785
10 40,8610371 107,92736 61,0663229
11 54,06159551 110,0647495 93,00315399
12 64,35130431 134,5556319 114,2043276
13 49,29181834 88,18806126 64,89624292
14 44,63823505 102,8364528 108,1982178
15 58,62487836 126,0319541 78,40707574
16 55,78566879 95,81224088 75,02657209
17 50,76570445 94,73143882 39,96573437
18 48,45339259 92,86957776 88,41618517
19 49,40446173 70,21723661 9,81277488
20 48,34604978 97,87616091 40,53011113
21 43,62470151 103,7308337 97,10613219
22 50,8877046 117,1558657 62,2681611
23 52,25082012 103,3922334 79,14141328
24 50,35929987 87,68936817 19,3300683
25 46,42761861 90,1655428 67,73792419
26 55,67926036 93,17073084 69,49147048
27 61,72779383 142,8458546 106,1180608
28 58,99808851 102,3529041 27,35481559
29 43,6620999 77,36405233 17,70195243
30 55,42639088 121,0878726 78,66148172
31 58,79311097 111,8698686 49,07675763
32 50,71073988 106,5406487 97,82990882
33 45,57346035 104,7456111 56,17215075
34 45,7981314 83,9963622 75,1982308
35 46,46484131 82,94617575 77,48133444
36 57,9492853 144,9994608 129,0501755
37 48,3999722 72,83510082 30,43512862
38 54,2097076 114,7785416 82,568834
39 46,67548966 95,25014621 37,57465655
40 38,21698894 88,21423442 64,99724548
41 51,95614673 90,93548401 66,97933728
42 51,22522594 105,1106925 101,8854666
43 52,84741658 105,0503069 75,20289032
44 54,78984594 109,9873973 87,19755136
45 52,00296104 101,442706 89,43974496
46 51,43150193 88,40178257 36,97028064
47 47,40407943 89,44141735 55,03733792
48 51,6749185 96,54147702 31,86655852
49 40,74049925 83,85842913 79,11792988
50 49,82155418 112,9093356 96,08778142
51 57,57763531 115,7709369 72,19330159
52 51,49652924 127,9054098 118,4088806
53 53,10710725 112,6337002 90,52659295
54 42,93645994 102,8111834 102,8747235
55 44,14066275 78,88897631 41,74831356
56 46,60936983 98,64046333 54,0310935
57 47,41415307 95,89594769 58,48179462
58 47,99032677 106,3655192 102,3751924
59 50,68360992 106,9507457 44,26713578
60 50,57070899 83,19613908 61,62543009
61 57,14992785 115,5596634 40,40973555
62 50,45105658 97,6950217 64,24396512
63 46,76779029 99,20006513 60,43227484
64 50,49802495 99,43092076 87,93289581
65 51,52523583 84,24653091 17,72129508
66 40,72692657 102,1715902 67,44466363
67 54,96034411 111,5346596 82,57431549
68 48,86213774 101,4305303 58,56839256
69 52,76166432 108,021472 60,25980768
70 55,46249302 83,51709356 51,05460054
71 51,78186354 79,45870906 11,67684552
72 54,7256505 108,6386184 58,9129679
73 55,03288163 112,1224042 72,08952257
74 52,83806054 104,53718 101,6991195
75 45,86692682 91,39643691 29,52951009
76 49,67284006 110,1908352 88,51799514
77 53,18552185 119,0135337 113,8280119
78 41,69070011 62,78988486 53,09918475
79 53,36320564 118,5841731 108,2209675
80 44,27369117 74,58882658 69,31513541
81 49,92198979 76,93363417 52,01164438
82 44,91221355 82,33766098 44,42544743
83 37,92316535 68,0076039 17,08443855
84 50,10889447 103,6209931 49,51209863
85 44,20348231 84,19989748 57,99641517
86 57,11433271 102,0528226 84,93848989
87 41,90764861 109,1360517 50,22840309
88 51,88278094 89,01870776 69,13592682
89 44,31355843 81,19982464 76,88626621
90 44,25547817 72,64564157 53,3901634
91 48,93179315 107,7773458 40,84555265
92 39,36849865 59,39799005 68,0294914
93 53,33338181 99,04871654 92,71533473
94 61,63696872 129,3884947 76,75152598
95 46,40148646 102,9511032 92,54961674
96 43,81949012 75,15673812 44,337248
97 53,78046359 85,87008695 50,08962336
98 41,27977392 60,49700348 50,21722956
99 52,32206122 106,8462547 57,52419348
100 41,36660384 105,0465099 78,67990606
101 47,62423286 96,62455823 84,00032537

View File

@ -0,0 +1,10 @@
[remap]
importer="csv"
type="TextFile"
[deps]
source_file="res://addons/easy_charts/file.samples/scatter (columns).csv"
[params]

View File

@ -4,7 +4,7 @@ extends EditorPlugin
func _enter_tree():
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"))
add_custom_type("Chart2D","Node2D", load("res://addons/easy_charts/Utilities/Scripts/chart2d.gd"), preload("Utilities/icons/linechart2d.svg"))
func _exit_tree():
remove_custom_type("Chart")

BIN
imgs/real_time_line.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB