void Visualize()
    {
        idx         = 0;
        vDataPoints = new List <GameObject>(); // vDataPoints is a list of GameOjbects (prefix 'v' is for visualized)

        // mapping each type to a material index assuming number of unique types is less than number of materials
        int materialIndex = 0;
        Dictionary <string, int> typeToColor = new Dictionary <string, int>();

        foreach (DataPoint dataPoint in dataPoints)
        {
            if (!typeToColor.ContainsKey(dataPoint.type))
            {
                typeToColor.Add(dataPoint.type, materialIndex);
                materialIndex++;
            }
        }

        /*
         * order is a list of datapoints in the order of removal by steepest descent
         * it's easier to imagine order as dataPoints but with a different ordering of elements
         * this order of elements matters because it's the order of the traversal of the visualization method.
         *
         * TODO change from list to array because size is known beforehand
         */
        List <DataPoint> order = new List <DataPoint>();

        while (dataPoints.Any()) // FIXME SteepestDescent returns NaN when there are no unique coordinates in dataPoints
        {
            if (dataPoints.Count == 1)
            {
                order.Add(dataPoints.Last());
                break;
            }

            double init_x = dataPoints[0].x, init_y = dataPoints[0].y; // initial point is first point

            Vector2[] steps = SteepestDescent.Run(dataPoints, init_x, init_y, 0.03, 300);

            int nearest = GetNearest(dataPoints, steps.Last());
            order.Add(dataPoints[nearest]);
            dataPoints.RemoveAt(nearest); // TODO optimize using dictionary or boolean visited array
        }

        // instantiate datapoints
        foreach (DataPoint dataPoint in order)
        {
            double     y        = SteepestDescent.CauchyTotalPotential(order, dataPoint.x, dataPoint.y);
            double     x        = dataPoint.x;
            double     z        = dataPoint.y;
            Vector3    position = new Vector3(XZ_Scale * (float)x, Y_Scale * (float)y, XZ_Scale * (float)z);
            GameObject vPoint   = Instantiate(rockPrefab, position, Quaternion.identity);

            int colorIndex = typeToColor[dataPoint.type];
            vPoint.GetComponent <MeshRenderer>().material = colors[colorIndex];

            vDataPoints.Add(vPoint);
        }

        // instaniate trail
        trail = Instantiate(trailPrefab, Vector3.zero, Quaternion.identity);

        StartCoroutine(Animate());
    }