You can use any CanvasItem derived node (for example an empty Node2D) with a script for fine grained control. Just call update() every time you want to redraw the canvas item. Then in the _draw() callback you can use all the draw_*() methods.
Documentation: https://docs.godotengine.org/en/stable/classes/class_canvasitem.html
Example:
extends Node2D
func _process():
update() # Redraw every frame
func _draw():
var radius = sin(OS.get_ticks_msec() / 1000) * 50 + 10
draw_line(Vector2.ZERO, radius, Color.white)