private void configureXAxisSubdivisions(PlotView plotView)
        {
            AdaptiveInterpolation.FloatRange inputRange = this.xAxisProgression.EstimateOutputRange();
            if (inputRange == null)
            {
                DateTime firstDate = this.queryStartDateDisplay.GetDate();
                DateTime lastDate  = this.queryEndDateDisplay.GetDate();
                inputRange = new AdaptiveInterpolation.FloatRange(this.GetXCoordinate(firstDate), true, GetXCoordinate(lastDate), true);
            }

            plotView.XAxisSubdivisions = this.xAxisProgression.GetNaturalSubdivisions(inputRange.LowCoordinate, inputRange.HighCoordinate);
            plotView.MinX = inputRange.LowCoordinate;
            plotView.MaxX = inputRange.HighCoordinate;
        }
        private void showErrors(PredictionErrors errors)
        {
            PlotView         plotView            = new PlotView();
            List <Datapoint> correctValues       = new List <Datapoint>();
            List <Datapoint> predictedValues     = new List <Datapoint>();
            List <Datapoint> predictedPlusStdDev = new List <Datapoint>();

            if (!double.IsInfinity(errors.MinAllowedValue))
            {
                plotView.MinY = errors.MinAllowedValue;
            }
            if (!double.IsInfinity(errors.MaxAllowedValue))
            {
                plotView.MaxY = errors.MaxAllowedValue;
            }
            DateTime referenceDate = new DateTime(2000, 1, 1);

            foreach (PredictionError error in errors.All)
            {
                double x = error.When.Subtract(referenceDate).TotalSeconds;
                correctValues.Add(new Datapoint(x, error.ActualMean, 1));
                predictedValues.Add(new Datapoint(x, error.Predicted.Mean, 1));
                predictedPlusStdDev.Add(new Datapoint(x, error.Predicted.Mean + error.Predicted.StdDev, 1));
            }
            plotView.AddSeries(correctValues, false);
            plotView.AddSeries(predictedValues, false);
            plotView.AddSeries(predictedPlusStdDev, false);

            ImageLayout     imageLayout = new ImageLayout(plotView, LayoutScore.Get_UsedSpace_LayoutScore(1));
            TextblockLayout legend      = new TextblockLayout("Prediction errors over time. Green: actual value. Blue: predicted value. White: prediction mean + stddev.");

            LayoutChoice_Set layout = new Vertical_GridLayout_Builder()
                                      .AddLayout(imageLayout)
                                      .AddLayout(legend)
                                      .BuildAnyLayout();

            this.layoutStack.AddLayout(layout, "errors");
        }
        public void UpdateParticipationsPlot()
        {
            DateTime start = DateTime.Now;

            if (!this.queryStartDateDisplay.IsDateValid() || !this.queryEndDateDisplay.IsDateValid())
            {
                return;
            }
            // draw the ParticipationProgression
            List <Participation> participations = this.yAxisActivity.Participations;
            DateTime             firstDate      = this.queryStartDateDisplay.GetDate();
            DateTime             lastDate       = this.queryEndDateDisplay.GetDate();
            //double firstCoordinate = this.GetXCoordinate(firstDate);
            //double lastCoordinate = this.GetXCoordinate(lastDate);
            List <Datapoint> cumulativeParticipationDurations = new List <Datapoint>();
            List <Datapoint> cumulativeEffectivenesses        = new List <Datapoint>();
            List <Datapoint> cumulativeSuggestionCounts       = new List <Datapoint>();
            List <double>    suggestionDates = new List <double>();

            PlotView newPlot = new PlotView();


            newPlot.MinX = 0;
            newPlot.MaxX = 1;

            double x1, x2, cumulativeParticipationSeconds, cumulativeEffectiveness, cumulativeSuggestionCount;

            x1 = 0;

            if (this.xAxisProgression != null)
            {
                this.configureXAxisSubdivisions(newPlot);
            }
            if (newPlot.MinX.HasValue)
            {
                x1 = newPlot.MinX.Value;
            }


            List <DateTime> startXs = new List <DateTime>(participations.Count);
            List <DateTime> endXs   = new List <DateTime>(participations.Count);

            // figure out which dates we care about
            int numActiveIntervals        = 0;
            int numIncludedParticipations = 0;

            foreach (Participation participation in participations)
            {
                // update some data about cumulative participation duration
                // make sure this participation is relevant
                if (participation.EndDate.CompareTo(firstDate) >= 0 && participation.StartDate.CompareTo(lastDate) <= 0)
                {
                    startXs.Add(this.MaxDate(firstDate, participation.StartDate));
                    endXs.Add(this.MinDate(participation.EndDate, lastDate));

                    // update some data about cumulative num suggestions
                    // this is slightly hacky - really there should be a method that just returns a list of every Suggestion for an Activity
                    if (participation.Suggested)
                    {
                        // double-check that the participation was suggested more recently than the start DateTime
                        if (participation.StartDate.CompareTo(participation.StartDate) >= 0)
                        {
                            suggestionDates.Add(this.GetXCoordinate(participation.StartDate));
                        }
                    }
                }
            }
            startXs.Sort();
            endXs.Sort();
            cumulativeParticipationSeconds = 0;
            cumulativeEffectiveness        = 0;
            DateTime prevDate = firstDate;

            while (endXs.Count > 0 || startXs.Count > 0)
            {
                DateTime participationStart;
                DateTime participationEnd;
                if (startXs.Count > 0)
                {
                    if (endXs.Count > 0)
                    {
                        participationStart = startXs[0];
                        participationEnd   = endXs[0];
                    }
                    else
                    {
                        participationStart = startXs[0];
                        participationEnd   = lastDate; // something larger that will be ignored
                    }
                }
                else
                {
                    participationEnd   = endXs[0];
                    participationStart = lastDate;      // something larger that will be ignored
                }
                if (participationStart.CompareTo(participationEnd) < 0)
                {
                    x2 = this.GetXCoordinate(participationStart);
                    double weight = x2 - x1;
                    // add datapoints denoting the start of the idle interval
                    cumulativeParticipationDurations.Add(new Datapoint(x1, cumulativeParticipationSeconds, weight));
                    cumulativeEffectivenesses.Add(new Datapoint(x1, cumulativeEffectiveness, weight));
                    // update cumulatives
                    cumulativeParticipationSeconds += weight * numActiveIntervals;
                    if (numActiveIntervals > 0)
                    {
                        Distribution efficiency = this.overallEfficiency_summarizer.GetValueDistributionForDates(prevDate, lastDate, true, false);
                        if (efficiency.Weight > 0)
                        {
                            cumulativeEffectiveness += efficiency.Mean * weight * numActiveIntervals;
                        }
                    }
                    numActiveIntervals++;
                    numIncludedParticipations++;
                    // add datapoints denoting the end of the idle interval
                    cumulativeParticipationDurations.Add(new Datapoint(x2, cumulativeParticipationSeconds, weight));
                    cumulativeEffectivenesses.Add(new Datapoint(x2, cumulativeEffectiveness, weight));
                    startXs.RemoveAt(0);
                    prevDate = participationStart;
                }
                else
                {
                    x2 = this.GetXCoordinate(participationEnd);
                    double weight = x2 - x1;
                    // add datapoints denoting the start of the active interval
                    cumulativeParticipationDurations.Add(new Datapoint(x1, cumulativeParticipationSeconds, weight));
                    cumulativeEffectivenesses.Add(new Datapoint(x1, cumulativeEffectiveness, weight));
                    cumulativeParticipationSeconds += weight * numActiveIntervals;
                    Distribution efficiency = this.overallEfficiency_summarizer.GetValueDistributionForDates(prevDate, lastDate, true, false);
                    if (efficiency.Weight > 0)
                    {
                        cumulativeEffectiveness += efficiency.Mean * weight * numActiveIntervals;
                    }
                    numActiveIntervals--;
                    // add datapoints denoting the end of the active interval
                    cumulativeParticipationDurations.Add(new Datapoint(x2, cumulativeParticipationSeconds, weight));
                    cumulativeEffectivenesses.Add(new Datapoint(x2, cumulativeEffectiveness, weight));
                    endXs.RemoveAt(0);
                    prevDate = participationEnd;
                }
                x1 = x2;
            }

            double cumulativeParticipationHours = cumulativeParticipationSeconds / 3600;
            double hoursPerTick = this.computeTickInterval(cumulativeParticipationHours);
            double spacePerTick = hoursPerTick * 3600;

            // rescale cumulativeParticipationDurations to total 1
            if (cumulativeParticipationSeconds != 0)
            {
                foreach (Datapoint item in cumulativeParticipationDurations)
                {
                    item.Output = item.Output / cumulativeParticipationSeconds;
                }
                spacePerTick = spacePerTick / cumulativeParticipationSeconds;
            }

            // rescale cumulativeEffectivenesses to total 1
            if (cumulativeEffectiveness != 0)
            {
                foreach (Datapoint item in cumulativeEffectivenesses)
                {
                    item.Output = item.Output / cumulativeEffectiveness;
                }
            }

            // We also want to plot the number of times that the activity was suggested
            cumulativeSuggestionCount = 0;
            foreach (ListItemStats <DateTime, WillingnessSummary> item in this.yAxisActivity.ConsiderationProgression.AllItems)
            {
                // make sure the participation is within the requested window
                if (item.Key.CompareTo(firstDate) >= 0 && item.Key.CompareTo(lastDate) <= 0)
                {
                    double x = this.GetXCoordinate(item.Key);
                    if (item.Value.NumSkips > 0)
                    {
                        // found a skip
                        suggestionDates.Add(x);
                    }
                }
            }
            suggestionDates.Sort();
            foreach (double x in suggestionDates)
            {
                cumulativeSuggestionCounts.Add(new Datapoint(x, cumulativeSuggestionCount, 1));
                cumulativeSuggestionCount += 1;
                cumulativeSuggestionCounts.Add(new Datapoint(x, cumulativeSuggestionCount, 1));
            }

            // rescale cumulativeSuggestionCounts to total 1
            if (cumulativeSuggestionCount != 0)
            {
                foreach (Datapoint item in cumulativeSuggestionCounts)
                {
                    item.Output /= cumulativeSuggestionCount;
                }
            }

            newPlot.AddSeries(cumulativeParticipationDurations, this.showTimeSpentTrend, this.showTimeSpent, 0);
            newPlot.AddSeries(cumulativeSuggestionCounts, false, this.showNumSuggestions, 2);
            newPlot.AddSeries(cumulativeEffectivenesses, false, this.showEffectiveness, 3);

            // assign y-axis tick marks
            if (spacePerTick > 0)
            {
                double        y      = 0;
                List <double> yTicks = new List <double>();
                while (y < 1)
                {
                    yTicks.Add(y);
                    y += spacePerTick;
                }
                newPlot.YAxisSubdivisions = yTicks;
            }

            this.participationsContent = newPlot;
            this.participationsView.SetContent(new ImageLayout(newPlot, LayoutScore.Get_UsedSpace_LayoutScore(1)));

            DateTime end = DateTime.Now;

            System.Diagnostics.Debug.WriteLine("spent " + end.Subtract(start) + " to update partipations plot");

            this.UpdateParticipationStatsView(cumulativeParticipationSeconds, numIncludedParticipations);

            // debugging
            //this.SetContent(this.participationsView.GetContent());
        }
        public void UpdateRatingsPlot()
        {
            DateTime start = DateTime.Now;

            if (!this.queryStartDateDisplay.IsDateValid() || !this.queryEndDateDisplay.IsDateValid())
            {
                return;
            }
            // draw the RatingProgression
            RatingProgression     ratingProgression = this.yAxisActivity.RatingProgression;
            List <AbsoluteRating> ratings           = ratingProgression.GetRatingsInDiscoveryOrder();
            DateTime         startDate = this.queryStartDateDisplay.GetDate();
            DateTime         endDate   = this.queryEndDateDisplay.GetDate();
            List <Datapoint> points    = new List <Datapoint>();

            // make a plot
            PlotView newPlot = new PlotView();

            newPlot.MinX = 0;
            newPlot.MaxX = endDate.Subtract(startDate).TotalDays;
            newPlot.MinY = 0;
            newPlot.MaxY = 1;

            if (this.xAxisProgression != null)
            {
                this.configureXAxisSubdivisions(newPlot);
            }

            newPlot.YAxisSubdivisions = new List <double> {
                0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1
            };

            // compute the rating at each relevant date
            foreach (AbsoluteRating rating in ratings)
            {
                if (rating.Date != null)
                {
                    double x = this.GetXCoordinate((DateTime)rating.Date);
                    // calculate y
                    double y = rating.Score;
                    // make sure we want to include it in the plot (and therefore the regression line)
                    if (x >= newPlot.MinX && x <= newPlot.MaxX)
                    {
                        points.Add(new Datapoint(x, y, 1));
                    }
                }
            }
            newPlot.AddSeries(points, this.showRatingsTrend, this.showRatings, 0);

            // compute a smoothed version of the ratings so we can show which activities are actually worth doing
            // (for example, sleeping might feel boring but might increase later happiness)
            TimeSpan totalDuration = endDate.Subtract(startDate);
            List <ScoreSummarizer> ratingSummarizers = new List <ScoreSummarizer>();

            ratingSummarizers.Add(this.overallRating_summarizer);
            ratingSummarizers.Add(this.overallEfficiency_summarizer);
            foreach (ExponentialRatingSummarizer ratingSummarizer in ratingSummarizers)
            {
                double           i;
                ScoreSummary     ratingSummary   = new ScoreSummary(endDate);
                List <Datapoint> smoothedRatings = new List <Datapoint>();
                double           maxY            = 0;
                for (i = 1; i >= 0; i -= 0.001)
                {
                    TimeSpan currentDuration = new TimeSpan((long)((double)totalDuration.Ticks * (double)i));
                    DateTime when            = startDate.Add(currentDuration);
                    if (when.CompareTo(ratingSummarizer.EarliestKnownDate) < 0)
                    {
                        break;
                    }
                    ratingSummary.Update(ratingSummarizer, when, endDate);
                    if (ratingSummary.Item.Weight > 0)
                    {
                        double x = this.GetXCoordinate(when);
                        double y = ratingSummary.Item.Mean;
                        if (!double.IsNaN(y))
                        {
                            if (ratingSummarizer == this.overallEfficiency_summarizer)
                            {
                                // rescale so that the typical value for this rating summarizer (1) is moved to match the typical value for the other plotted values (0.5)
                                y /= 2;
                            }
                            if (y > maxY)
                            {
                                maxY = y;
                            }
                            smoothedRatings.Add(new Datapoint(x, y, 1));
                        }
                    }
                }
                smoothedRatings.Reverse();
                // if the plot overflowed, rescale it to fit
                if (maxY > 1)
                {
                    foreach (Datapoint datapoint in smoothedRatings)
                    {
                        datapoint.Output = datapoint.Output / maxY;
                    }
                }
                if (ratingSummarizer == this.overallRating_summarizer)
                {
                    newPlot.AddSeries(smoothedRatings, false, this.showOverallHappiness, 2);
                }
                else
                {
                    newPlot.AddSeries(smoothedRatings, this.showEfficiencyTrend, this.showEfficiency, 3);
                }
            }

            DateTime end = DateTime.Now;

            this.ratingsView.SetContent(new ImageLayout(newPlot, LayoutScore.Get_UsedSpace_LayoutScore(1)));

            System.Diagnostics.Debug.WriteLine("spent " + end.Subtract(start) + " to update ratings plot");
        }