using System.Collections.Generic;
using System.Globalization;
public class TimeseriesChart : MonoBehaviour
[Header("Data Settings")]
public TextAsset csvFile; // CSV file with time,value columns
private List<Vector2> dataPoints = new List<Vector2>();
private float minTime, maxTime;
[Header("Chart Settings")]
public LineRenderer lineRenderer;
public float lineWidth = 0.1f;
[Header("Animation Settings")]
public float animationDuration = 5f; // total time for a full t animation
[Header("Current Time Indicator")]
public GameObject dotPrefab;
private GameObject dotInstance;
private float timer = 0f;
if (dataPoints.Count > 0)
// Ensure data is sorted by time
dataPoints.Sort((a, b) => a.x.CompareTo(b.x));
minTime = dataPoints[0].x;
maxTime = dataPoints[dataPoints.Count - 1].x;
// Set up LineRenderer positions and width
lineRenderer.positionCount = dataPoints.Count;
lineRenderer.widthMultiplier = lineWidth;
// Instantiate the current time indicator
dotInstance = Instantiate(dotPrefab, transform);
// Animate t from 0 to 1 and back continuously
float t = Mathf.PingPong(timer / animationDuration, 1f);
float currentTime = Mathf.Lerp(minTime, maxTime, t);
// Update the line's gradient and the dot's position
UpdateLineColors(currentTime);
UpdateDotPosition(currentTime);
StringReader reader = new StringReader(csvFile.text);
while ((line = reader.ReadLine()) != null)
// Skip header or empty lines
if (line.StartsWith("time") || string.IsNullOrWhiteSpace(line))
// Assuming CSV format: time,value
string[] tokens = line.Split(',');
float timeValue = float.Parse(tokens[0], CultureInfo.InvariantCulture);
float value = float.Parse(tokens[1], CultureInfo.InvariantCulture);
dataPoints.Add(new Vector2(timeValue, value));
void UpdateLinePositions()
for (int i = 0; i < dataPoints.Count; i++)
Vector2 point = dataPoints[i];
// Convert 2D point to 3D (with z = 0)
lineRenderer.SetPosition(i, new Vector3(point.x, point.y, 0));
void UpdateLineColors(float currentTime)
// Calculate the ratio of current time along the overall time range
float ratio = (currentTime - minTime) / (maxTime - minTime);
// Create a gradient that changes color at the ratio point
Gradient gradient = new Gradient();
GradientColorKey[] colorKeys = new GradientColorKey[2];
GradientAlphaKey[] alphaKeys = new GradientAlphaKey[2];
// Before current time: highlighted color (white)
// After current time: faded grey
colorKeys[0] = new GradientColorKey(Color.white, ratio);
colorKeys[1] = new GradientColorKey(Color.grey, ratio);
alphaKeys[0] = new GradientAlphaKey(1f, ratio);
alphaKeys[1] = new GradientAlphaKey(1f, ratio);
gradient.SetKeys(colorKeys, alphaKeys);
lineRenderer.colorGradient = gradient;
void UpdateDotPosition(float currentTime)
// Find the segment where currentTime falls between two data points
for (int i = 0; i < dataPoints.Count - 1; i++)
if (dataPoints[i].x <= currentTime && dataPoints[i + 1].x >= currentTime)
float segmentT = (currentTime - dataPoints[i].x) / (dataPoints[i + 1].x - dataPoints[i].x);
Vector2 interpolated = Vector2.Lerp(dataPoints[i], dataPoints[i + 1], segmentT);
dotInstance.transform.position = new Vector3(interpolated.x, interpolated.y, 0);