mirror of
https://github.com/Relintai/pandemonium_engine_easy_charts.git
synced 2025-03-26 19:02:14 +01:00
commit
a3e79b3643
11
.gitignore
vendored
11
.gitignore
vendored
@ -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
|
||||
*~
|
||||
|
30
README.md
30
README.md
@ -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.
|
||||

|
||||
[*Startup Company*](https://store.steampowered.com/app/606800/Startup_Company/)
|
||||
|
||||

|
||||
[*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
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
##### 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.
|
||||
|
@ -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
|
@ -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"]
|
@ -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),
|
@ -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
|
||||
|
@ -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__ = {
|
@ -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()
|
||||
|
@ -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()
|
||||
|
||||
|
@ -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
|
@ -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:
|
||||
|
@ -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()
|
@ -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():
|
||||
|
@ -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)
|
@ -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"]
|
||||
|
317
addons/easy_charts/ScatterChart/scatter_chart.gd
Normal file
317
addons/easy_charts/ScatterChart/scatter_chart.gd
Normal 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)
|
@ -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
|
||||
|
||||
|
@ -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 |
@ -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
|
@ -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()
|
@ -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.
|
@ -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 }
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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 }
|
@ -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"
|
||||
|
@ -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,10 +0,0 @@
|
||||
[remap]
|
||||
|
||||
importer="csv"
|
||||
type="TextFile"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/easy_charts/file.samples/2_columns.csv"
|
||||
[params]
|
||||
|
@ -1,10 +0,0 @@
|
||||
[remap]
|
||||
|
||||
importer="csv"
|
||||
type="TextFile"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/easy_charts/file.samples/datas.csv"
|
||||
[params]
|
||||
|
@ -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,10 +0,0 @@
|
||||
[remap]
|
||||
|
||||
importer="csv"
|
||||
type="TextFile"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/easy_charts/file.samples/datas2.csv"
|
||||
[params]
|
||||
|
@ -1,10 +0,0 @@
|
||||
[remap]
|
||||
|
||||
importer="csv"
|
||||
type="TextFile"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/easy_charts/file.samples/datas_on_columns.csv"
|
||||
[params]
|
||||
|
@ -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,10 +0,0 @@
|
||||
[remap]
|
||||
|
||||
importer="csv"
|
||||
type="TextFile"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/easy_charts/file.samples/datas_on_rows.csv"
|
||||
[params]
|
||||
|
@ -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,10 +0,0 @@
|
||||
[remap]
|
||||
|
||||
importer="csv"
|
||||
type="TextFile"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/easy_charts/file.samples/gei_jam#2columns.csv"
|
||||
[params]
|
||||
|
@ -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,10 +0,0 @@
|
||||
[remap]
|
||||
|
||||
importer="csv"
|
||||
type="TextFile"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/easy_charts/file.samples/godot_engine_italia_jam#2.csv"
|
||||
[params]
|
||||
|
@ -0,0 +1,10 @@
|
||||
[remap]
|
||||
|
||||
importer="csv"
|
||||
type="TextFile"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/easy_charts/file.samples/linechart (columns).csv"
|
||||
[params]
|
||||
|
10
addons/easy_charts/file.samples/linechart (rows).csv.import
Normal file
10
addons/easy_charts/file.samples/linechart (rows).csv.import
Normal file
@ -0,0 +1,10 @@
|
||||
[remap]
|
||||
|
||||
importer="csv"
|
||||
type="TextFile"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/easy_charts/file.samples/linechart (rows).csv"
|
||||
[params]
|
||||
|
@ -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
|
|
10
addons/easy_charts/file.samples/scatter (columns).csv.import
Normal file
10
addons/easy_charts/file.samples/scatter (columns).csv.import
Normal file
@ -0,0 +1,10 @@
|
||||
[remap]
|
||||
|
||||
importer="csv"
|
||||
type="TextFile"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/easy_charts/file.samples/scatter (columns).csv"
|
||||
[params]
|
||||
|
@ -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
BIN
imgs/real_time_line.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 156 KiB |
Loading…
Reference in New Issue
Block a user