Beispiel #1
0
        protected virtual async Task <GroupedBarChart> ProjectChart(Filter <Criterion> filter, TimeInterval timeInterval,
                                                                    CompositeGroupedProjection <TProjection> projection, Summary <TProjection, float> summary,
                                                                    string drilldownAction, string drilldownController)
        {
            Console.WriteLine($"Filter count: {filter.Criteria?.Count() ?? 0}");
            Console.WriteLine($"Time interval: {timeInterval.Start} to {timeInterval.End}");
            Console.WriteLine($"Projection: {projection}");
            Console.WriteLine($"Summary: {summary}");
            Console.WriteLine($"DD Action: {drilldownAction}");
            Console.WriteLine($"DD Controller: {drilldownController}");
            // For each time interval, add a datum to the dataset
            var rawData = await apiAccess.PullKeyDeviceActivity(timeInterval.Start, timeInterval.End);

            // Parse string to JObject
            var rootObject = JObject.Parse(rawData);

            if (!rootObject.TryGetValue("Data", out var dataArrayToken))
            {
                throw new JsonArgumentException();
            }

            // Convert data array token to JEnumerable and
            // filter out unwanted data
            var dataArray = dataArrayToken.AsJEnumerable();

            dataArray = filter.FilterData(dataArray);


            // Project each token to a value, and store
            // the value in the associated category's
            // collection
            var projectedData = new Dictionary <string, Collection <IDictionary <string, TProjection> > >();

            foreach (var token in dataArray)
            {
                if (token.Type != JTokenType.Object)
                {
                    throw new JsonArgumentException();
                }
                try{
                    var kvp = projection.Project((JObject)token);
                    // If the dataset does not yet exist, add it
                    if (!projectedData.ContainsKey(kvp.Key))
                    {
                        projectedData.Add(kvp.Key, new Collection <IDictionary <string, TProjection> >());
                    }

                    // Add the value to the dataset's collection
                    projectedData[kvp.Key].Add(kvp.Value);
                } catch (JsonArgumentException) {}
            }

            // Summarize each category of each dataset into a summary value,
            // such as a mean, median, maximum, etc.
            var summaryValues = new Dictionary <string, IDictionary <string, float> >();

            foreach (var datasetKvp in projectedData)
            {
                summaryValues.Add(datasetKvp.Key, new Dictionary <string, float>());
                // We must assume every inner dictionary has the same keys.
                // Otherwise, some datasets may have more / less summary values
                // than others. We must summarize the list of all values associated
                // with each given key, across every inner dictionary.

                var first = datasetKvp.Value.First();

                // Summarize each category within the dataset
                foreach (var category in first)
                {
                    // For each category in this dataset,
                    // find every inner dictionary which
                    // contains a value for the category.
                    // Then, get said value of each inner
                    // dictionary, compiled into an enumerable.
                    // Lastly, summarize that enumerable with
                    // the summary model provided.
                    summaryValues[datasetKvp.Key].Add(
                        category.Key,
                        summary.Summarize(datasetKvp.Value.Where(
                                              innerDict => innerDict.ContainsKey(category.Key))
                                          .Select(innerDict => innerDict[category.Key])));
                }
            }

            // Construct an ordered list of subLabels for the inner data points.
            // This order must be maintained across all datasets, so this
            // list can be used as the ordering of keys.
            var subLabels = summaryValues.Any() ? summaryValues.First().Value.Select(kvp => kvp.Key).ToList() : new List <string>();

            // Each dataset gets its own color
            int backgroundHue = 0;
            int borderHue     = 0;
            var hueIncrement  = summaryValues.Count() == 0 ? 0 : 360 / summaryValues.Count();

            // Construct a list of bar groups using the summaryValues and the subLabels as a
            // guide for inner key ordering. Note: Select() preserves ordering, so using
            // subLabels.Select() will allow a projection of values preserving
            // the inner ordering.
            var drilldownActions     = subLabels.Select(subLabel => drilldownAction).ToList();
            var drilldownControllers = subLabels.Select(subLabel => drilldownController).ToList();
            var barGroups            = summaryValues.Select(kvp => new BarGroup()
            {
                Label                    = kvp.Key,
                BackgroundColor          = $"hsla({PostIncHue(ref backgroundHue, hueIncrement)}, {BarGroup.BackgroundSaturation}, {BarGroup.BackgroundLightness}, {BarGroup.BackgroundAlpha})",
                BorderColor              = $"hsla({PostIncHue(ref borderHue, hueIncrement)}, {BarGroup.BorderSaturation}, {BarGroup.BorderLightness}, {BarGroup.BorderAlpha})",
                Values                   = subLabels.Select(label => (int)kvp.Value[label]).ToList(),
                DrilldownActions         = drilldownActions,
                DrilldownControllers     = drilldownControllers,
                DrilldownQueryParameters = subLabels.Select(subLabel => (object)new {
                    preFilter = filter,
                    filter    = new Filter <ProjectionCriterion <string, CategoryProjection <IDictionary <string, TProjection> > > >(
                        new List <ProjectionCriterion <string, CategoryProjection <IDictionary <string, TProjection> > > >()
                    {
                        new ProjectionCriterion <string, CategoryProjection <IDictionary <string, TProjection> > >(
                            new CategoryProjection <IDictionary <string, TProjection> >(projection),
                            kvp.Key
                            )
                    }
                        ), // Drilldown data should match the same dataset (filter)
                    summary,
                    timeSeries = new TimeSeries(new List <TimeInterval>()
                    {
                        new TimeInterval(DateTime.ParseExact("2019-06-01", "yyyy-MM-dd", CultureInfo.InvariantCulture),
                                         DateTime.ParseExact("2019-06-30", "yyyy-MM-dd", CultureInfo.InvariantCulture), "June"),
                        new TimeInterval(DateTime.ParseExact("2019-07-01", "yyyy-MM-dd", CultureInfo.InvariantCulture),
                                         DateTime.ParseExact("2019-07-31", "yyyy-MM-dd", CultureInfo.InvariantCulture), "July"),
                        new TimeInterval(DateTime.ParseExact("2019-08-01", "yyyy-MM-dd", CultureInfo.InvariantCulture),
                                         DateTime.ParseExact("2019-08-31", "yyyy-MM-dd", CultureInfo.InvariantCulture), "August"),
                        new TimeInterval(DateTime.ParseExact("2019-09-01", "yyyy-MM-dd", CultureInfo.InvariantCulture),
                                         DateTime.ParseExact("2019-09-30", "yyyy-MM-dd", CultureInfo.InvariantCulture), "September")
                    }),
                    projection = new CompositeValueProjection <TProjection>(projection, subLabel)
                }).ToList()
            }).ToList();

            return(new GroupedBarChart()
            {
                BarGroups = barGroups,
                Labels = subLabels
            });
        }
Beispiel #2
0
        public virtual async Task <IViewComponentResult> InvokeAsync(Summary <TProjection, float> summary, Filter <Criterion> filter,
                                                                     TimeInterval timeInterval, CompositeGroupedProjection <TProjection> projection, string drilldownAction,
                                                                     string drilldownController, bool pivot = false)
        {
            var barChart = await ProjectChart(filter, timeInterval, projection, summary, drilldownAction, drilldownController);

            return(View(pivot ? barChart.Pivot() : barChart));
        }