/// <summary> /// Creates an array of positions that are aggregated based on the given aggregation type. /// This MUST be called AFTER each time the other dimensions change. /// </summary> /// <param name="data"></param> /// <param name="dimension"></param> /// <param name="aggregation"></param> /// <returns></returns> public float[] SetAggregatedDimension(float[] yData, IATKBarAggregation aggregation) { // Extract independent arrays of the position values for the x and z dimensions Vector3[] vertices = View.GetVertices(); float[] xData = new float[vertices.Length]; float[] zData = new float[vertices.Length]; for (int i = 0; i < DataSource.DataCount; i++) { xData[i] = vertices[i].x; zData[i] = vertices[i].z; } // Get the unique "categories" of the x and z dimensions (these are technically floats) var xCategories = xData.Distinct(); var zCategories = zData.Distinct(); // LAZY HACK: Set a value in the mesh's normal.y value to designate whether to show or hide the point to prevent z-fighting and mass lag float[] masterBars = new float[DataSource.DataCount]; // Create a dictionary that will store the values assocatied with each (x, z) pairs of aggregating values (x bins * z bins = n lists) Dictionary <float, Dictionary <float, List <float> > > aggGroups = new Dictionary <float, Dictionary <float, List <float> > >(); // Iterate through each position and assign the data values to the respective (x, z) pair for (int i = 0; i < DataSource.DataCount; i++) { Dictionary <float, List <float> > innerDict; if (!aggGroups.TryGetValue(xData[i], out innerDict)) { innerDict = new Dictionary <float, List <float> >(); aggGroups[xData[i]] = innerDict; } List <float> innerList; if (!innerDict.TryGetValue(zData[i], out innerList)) { innerList = new List <float>(); innerDict[zData[i]] = innerList; masterBars[i] = 1; } // If the aggregation type is count, we don't need to use the y axis values if (aggregation == IATKBarAggregation.Count || yData == null) { innerList.Add(0); } else { innerList.Add(yData[i]); } } // LAZY HACK: Send the master values to the mesh now View.SetUVs(masterBars, IATKDimension.Y); // Create another dictionary that will store the aggregated value for each (x, z) pair group float max = 0; Dictionary <float, Dictionary <float, float> > aggregatedValues = new Dictionary <float, Dictionary <float, float> >(); foreach (float xCategory in xCategories) { foreach (float zCategory in zCategories) { // Calculate final aggregated value if (!aggGroups[xCategory].ContainsKey(zCategory)) { continue; } List <float> values = aggGroups[xCategory][zCategory]; float aggregated = 0; switch (aggregation) { case IATKBarAggregation.Count: aggregated = values.Count; break; case IATKBarAggregation.Average: aggregated = values.Average(); break; case IATKBarAggregation.Sum: aggregated = values.Sum(); break; case IATKBarAggregation.Median: values.Sort(); float mid = (values.Count - 1) / 2f; aggregated = (values[(int)(mid)] + values[(int)(mid + 0.5f)]) / 2; break; case IATKBarAggregation.Min: aggregated = values.Min(); break; case IATKBarAggregation.Max: aggregated = values.Max(); break; } // Set value Dictionary <float, float> innerDict; if (!aggregatedValues.TryGetValue(xCategory, out innerDict)) { innerDict = new Dictionary <float, float>(); aggregatedValues[xCategory] = innerDict; } innerDict[zCategory] = aggregated; // We need to normalise back into 0..1 for these specific aggregations, so we collect the max value if (aggregation == IATKBarAggregation.Count || aggregation == IATKBarAggregation.Sum) { if (max < aggregated) { max = aggregated; } } } } // Set y position based on newly aggregated values float[] positions = new float[DataSource.DataCount]; for (int i = 0; i < DataSource.DataCount; i++) { // For specific aggregations, normalise if (aggregation == IATKBarAggregation.Count || aggregation == IATKBarAggregation.Sum) { positions[i] = UtilMath.NormaliseValue(aggregatedValues[xData[i]][zData[i]], 0, max, 0, 1); } else { positions[i] = aggregatedValues[xData[i]][zData[i]]; } } return(positions); }
public void SetBarAggregation(IATKBarAggregation barAggregation) { BarAggregation = barAggregation; UpdateView(IATKProperty.Y); }