# Drawing a line graph depending on the value of a variable

Attention Topic was automatically imported from the old Question2Answer platform.

I’m making a mock stock/share trading game, and I’m thinking to implement a little window that draws a line graph displaying values of a variable that is changing price. How would I use Line2D, or any other part of the Godot engine to achieve this?

You can use somthing like this:

``````extends Line2D

export var graph_width : float = 100
export var graph_height : float = 100

func create_graph(values : Array) -> void:
var length : int = len(values)
assert(length > 0 and (values[0] is int or values[0] is float))

var points_ : PoolVector2Array

var maximum : float = values[0]
var minimum : float = values[0]

for value in values:
assert(value is int or value is float)
if value > maximum:
maximum = value
if value < minimum:
minimum = value

for index in range(length):
points_.append(Vector2(
lerp(0.0, graph_width, index / float(length - 1)),
lerp(graph_height, 0.0, (values[index] - minimum) / (maximum - minimum))))

points = points_

create_graph([1, 3, 7, 6, 6, 8, 9, 7, 11, 13])
``````

This will create a graph from Line2D in a given space (graph_height/width)
If you want ths specify minimum and maximum by yourself, you need to expand this a little bit.

Sorry, a question. Would I attach this in a script to a Line2D Node, or the Scene node. I put this in a script linked to a Line2D Node and nothing showed.

CatRass | 2020-05-26 08:58

You can easily see this in the first line of the script. if it extends Line2D, then you have to attach this to a Line2D.

It should show something out of the box, if you don’t change anything. In the ready-method it sets up an example.

Make sure, it is in in your current viewport/in view of your camera.
It does NOT show anything in the editor!

whiteshampoo | 2020-05-26 09:42

Ok thank you, I’m not sure what went wrong last time. Is it possible that it updates the graph every time a new value is generated? Since the prices constantly change I want it to change the graph accordingly

CatRass | 2020-05-26 10:11

It generates the graph from an array. It does not memorize it. you have to add your new prize to an array, or rewrite the code, so it remebers old prizes and just adds the new prize (maybe the better solution)

whiteshampoo | 2020-05-26 10:28

I see. How would I do this? Since the numbers are randomly generated there isn’t a formula I can put into the Line2D so it can generate the same numbers

CatRass | 2020-05-26 10:30

``````extends Line2D

export var graph_width : float = 100
export var graph_height : float = 100
export var graph_max_points : int = 0 # Zero for unlimited graph-points

var graph : Array

func create_graph() -> void:
var length : int = len(graph)
assert(length > 0 and graph[0] is float)

var points_ : PoolVector2Array

var maximum : float = graph[0]
var minimum : float = graph[0]

if length == 1:
graph.append(graph[0])
length += 1

for value in graph:
assert(value is float)
if value > maximum:
maximum = value
if value < minimum:
minimum = value

for index in range(length):
points_.append(Vector2(
lerp(0.0, graph_width, index / float(length - 1)),
lerp(graph_height, 0.0, (graph[index] - minimum) / (maximum - minimum))))

points = points_

func pop_values() -> void:
if graph_max_points != 0:
if len(graph) > graph_max_points:
graph.pop_front()
pop_values()

func add_value(value : float) -> void:
graph.append(value)
pop_values()

create_graph()
``````

Please try to implement such stuff by yourself.
It’s not that hard, and you’ll learn alot
The best way to get better faster is trial and error.

EDIT:
Most important thing for a beginner is to read and understand the code, if you want to copy stuff from help-boards! If you want to use it and don’t understand how it works, please ask. That saves you alot of time and more questions later on.

whiteshampoo | 2020-05-26 10:50

Thank you for being so helpful. I played around with it, and it seems to be working. I’m mostly asking questions since I’ve tried a few tutorials but I don’t think I learn much from tutorials, so I thought learning through questions should work. Any tips on how to learn and master Godot?
Also if you’re curious, my code is as follows:

``````extends Line2D

export var graph_width : float = 100
export var graph_height : float = 100
export var graph_max_points : int = 0 # Zero for unlimited graph-points

var graph : Array

func create_graph() -> void:
var length : int = len(graph)
assert(length > 0 and graph[0] is float)

var points_ : PoolVector2Array

var maximum : float = graph[0]
var minimum : float = graph[0]

if length == 1:
graph.append(graph[0])
length += 1

for value in graph:
assert(value is float)
if value > maximum:
maximum = value
if value < minimum:
minimum = value

for index in range(length):
points_.append(Vector2(
lerp(0.0, graph_width, index / float(length - 1)),
lerp(graph_height, 0.0, (graph[index] - minimum) / (maximum - minimum))))

points = points_

func pop_values() -> void:
if graph_max_points != 0:
if len(graph) > graph_max_points:
graph.pop_front()
pop_values()

func add_value(value : float) -> void:
graph.append(value)
pop_values()

var balance = 10

const MINIMUM_PRICE = 100 # no stock will be priced cheaper than this
const FACTOR = 2 # the highest possible price will be 2x your balance

func update_price(price : float) -> void:
print("Price changes")

func _on_Timer_timeout():
randomize()
var price = generate_stock_price()
update_price(price)
create_graph()

randomize()
var price = generate_stock_price()
update_price(price)

func generate_stock_price():
var price = rand_range(MINIMUM_PRICE, balance * FACTOR)
return price
``````

Did I do it right?

CatRass | 2020-05-26 11:02

You probably shouldn’t do your stock-math in the Line2D. Thats just for drawing. Remove the “_ready” method from my example, and close the Line2D-script, until you face problems. Add your Graph-Node (Line2D) as a child (or wherever you need it to be). In you “main-game-script” (wahtever) you should reference the Line2D:

``````onready var Graph : Line2D = \$Path_to_Line2D # Change this!
``````

Then you can call the methods via Graph:

``````func _on_Timer_timeout():
randomize()
var price = generate_stock_price()
update_price(price)
Graph.create_graph()
``````

(untested!)

Every Node/Script should only do what you expect it to do. A line-graph from your stock-prices should not generate prices! it should only display it and nothing else.

BTW:
You can also simplify one method:

``````func generate_stock_price():
return rand_range(MINIMUM_PRICE, balance * FACTOR)
``````

whiteshampoo | 2020-05-26 11:16

Thank you so much for the help, appreciate it, and thank you for the explanation :>

CatRass | 2020-05-26 11:20

You’re welcome

whiteshampoo | 2020-05-26 11:23

Hi, I’m back and I tried implementing the code you set and it’s returning a few errors. Is there a way I could put the stock math in a separate scene, and reference it in other scripts?

CatRass | 2020-05-27 00:46

Can you share you project folder? Its hard to help without your Node-Tree and Code :x

whiteshampoo | 2020-05-27 07:42

CatRass | 2020-05-27 07:47

workupload - Are you a human?

Please read all the “new” code carefully and try to understand everyting!
Btw, i tweaked the timer to be much faster, so i/you can see the result faster…

I put some love in it, and i would be really disappointed if it would be wasted
Btw you should probably use 1D-Noise for your pricing. Its KIND of random, but much smoother and more believable.

whiteshampoo | 2020-05-27 08:34

Hello, it’s me again! I’ve done some reading on 1D-Noise and I’m not entirely sure how to use this for more accurate pricing. Could you explain how I’d be able to use it?

CatRass | 2020-05-29 09:38

## Game_UI.gd:

``````extends Node2D

const MINIMUM_PRICE = 100.0 # no stock will be priced cheaper than this
const FACTOR = 2.0 # the highest possible price will be 2x your balance
const PROGRESS = 1.0 # adds to noise_progress

var balance : float = 10.0
var price : float = MINIMUM_PRICE
var noise : OpenSimplexNoise
var noise_progress : float = 0.0

onready var pricelabel : Label = \$PriceLabel
onready var graph : Line2D = \$Graph

randomize()

noise = OpenSimplexNoise.new()
noise.seed = randi()

# --- tweak this to your needs ---
noise.octaves = 4
noise.period = 20.0
noise.persistence = 0.8
# --------------------------------

generate_stock_price()

func generate_stock_price():
var noise_modify : float = (balance * (FACTOR / 2.0))
price = MINIMUM_PRICE + noise_modify
price += noise.get_noise_1d(noise_progress) * noise_modify
noise_progress += PROGRESS
pricelabel.update_price(price)
graph.create_graph()

func _on_Timer_timeout():
generate_stock_price()

func _on_Button_pressed():
get_tree().change_scene("res://Title Screen/title_screen.tscn")
``````

## Graph.gd

(i made some mistakes, here is a better (working) version)

``````extends Line2D

export var graph_width : float = 100
export var graph_height : float = 100
export var graph_max_points : int = 0 # Zero for unlimited graph-points
export var grow : bool = false

var graph : Array

func create_graph() -> void:
var length : int = len(graph)
assert(length > 0 and graph[0] is float and graph_max_points >= 0)

var points_ : PoolVector2Array = []

var maximum : float = graph[0]
var minimum : float = graph[0]

if length == 1:
graph.append(graph[0])
length += 1

for value in graph:
assert(value is float)
if value > maximum:
maximum = value
if value < minimum:
minimum = value

if minimum == maximum:
minimum -= 1.0
maximum += 1.0

for index in range(length):
points_.append(Vector2(
0.0,
lerp(graph_height, 0.0, (graph[index] - minimum) / (maximum - minimum))))
if grow and graph_max_points:
points_[-1].x = lerp(0.0, graph_width, index / float(graph_max_points - 1))
else:
points_[-1].x = lerp(0.0, graph_width, index / float(length - 1))

points = points_

func pop_values() -> void:
if graph_max_points != 0:
if len(graph) > graph_max_points:
graph.pop_front()
pop_values()

func add_value(value : float) -> void:
graph.append(value)
pop_values()
``````

Just copy&paste it. It should be pretty easy to understand what i changed, and how it works.

If you want to understand the OpenSimplexNoise, i would recommand you, to create a noise-texture, and play with the values in the inspector. There you see a live-preview of what you would get. Just imagine a line from left to right in the texture. Thats what the 1D-Noise whould be. black is -1.0, grey is 0.0 and white is 1.0. Darker grey is then somthing between -1.0 and 0.0.

whiteshampoo | 2020-05-29 10:17

Hello, it’s me again! I implemented a saving and loading mechanic, and want to make sure the stock price would be saved and loaded too. It saves, and it’s in the save file, but it doesn’t get loaded. Would the problem be with the variable itself or the way price is generated?

CatRass | 2020-06-01 23:20