/// <summary>
        /// Plots the results.
        /// </summary>
        /// <returns>The results.</returns>
        /// <param name="numBases">Number of bases.</param>
        /// <param name="signalWidth">The signal width.</param>
        /// <param name="dictionary">Dictionary.</param>
        /// <param name="coefficients">Coefficients.</param>
        /// <param name="st">Sub title.</param>
        /// <param name="plotOptions">Plotting options.</param>
        public static void PlotResults(
            int numBases, int signalWidth,
            Gaussian[][] dictionary, VectorGaussian[] coefficients,
            string st, PlotOptions plotOptions)
        {
            var coef = coefficients.Select(DistributionHelpers.IndependentApproximation).ToArray();

            PlotResults(numBases, signalWidth, dictionary, coef, st, plotOptions);
        }
        /// <summary>
        /// Plots the results.
        /// </summary>
        /// <returns>The results.</returns>
        /// <param name="numBases">Number of bases.</param>
        /// <param name="signalWidth">The signal width.</param>
        /// <param name="dictionary">Dictionary.</param>
        /// <param name="coefficients">Coefficients.</param>
        /// <param name="st">Sub title.</param>
        /// <param name="plotOptions">Plotting options.</param>
        public static void PlotResults(
            int numBases, int signalWidth,
            VectorGaussian[] dictionary, VectorGaussian[] coefficients,
            string st, PlotOptions plotOptions)
        {
            // Note the dictionary is transposed in this case
            var dict = dictionary.Select(DistributionHelpers.IndependentApproximation).ToArray().Transpose();
            var coef = coefficients.Select(DistributionHelpers.IndependentApproximation).ToArray();

            PlotResults(numBases, signalWidth, dict, coef, st, plotOptions);
        }
        /// <summary>
        /// Plots the reconstructions.
        /// </summary>
        /// <returns>The reconstructions.</returns>
        /// <param name="reconstructions">Reconstructions.</param>
        /// <param name="averageError">The average reconstruction error.</param>
        /// <param name="subTitle">Sub title.</param>
        /// <param name="normalised">Whether these are normalised reconstructions.</param>
        /// <param name="plotOptions">Plotting options.</param>
        public static void PlotReconstructions(Reconstruction[] reconstructions, double averageError, string subTitle,
                                               bool normalised, PlotOptions plotOptions)
        {
            if (plotOptions.IsImage)
            {
                PlotImageReconstructions(reconstructions, averageError, subTitle, normalised, plotOptions);
                return;
            }

            var series1 = reconstructions.Take(plotOptions.Reconstructions.NumToShow).Select(
                (ia, i) => (ISeries)(new LineSeries
            {
                Label = "signal",
                X = ia.Signal,
                Row = i / plotOptions.Reconstructions.Subplots.Columns,
                Column = i % plotOptions.Reconstructions.Subplots.Columns
            })).ToArray();
            var series2 = reconstructions.Take(plotOptions.Reconstructions.NumToShow).Select(
                (ia, i) => (ISeries)(new ErrorLineSeries
            {
                Label = "reconstruction",
                ErrorLabel = "$\\pm$s.d.",
                X = ia.Estimate.GetMeans(),
                ErrorValues = ia.Estimate.GetStandardDeviations(),
                Row = i / plotOptions.Reconstructions.Subplots.Columns,
                Column = i % plotOptions.Reconstructions.Subplots.Columns
            })).ToArray();

            IList <ISeries> series = series1.Concat(series2).ToArray();

            string n = normalised ? " (normalised)" : string.Empty;

            // var series = new[] { new LineSeries { X = x1, Row = 0 }, new LineSeries { X = x2, Row = 1 } };
            string sub     = string.IsNullOrEmpty(subTitle) ? string.Empty : $"_{subTitle.Replace(" ", "_")}";
            var    plotter = new Plotter
            {
                Title      = $"Reconstructions{n}, RMSE={averageError:N4}",
                XLabel     = "x",
                YLabel     = "y",
                Series     = series,
                Subplots   = plotOptions.Reconstructions.Subplots,
                ScriptName = Path.Combine(ScriptPath, $"Reconstructions_{n}{sub}.py"),
                FigureName = Path.Combine(FigurePath, $"Reconstructions_{n}{sub}.pdf"),
                Python     = PythonPath,
                Show       = plotOptions.Reconstructions.Show
            };

            plotter.Plot();
        }
        /// <summary>
        /// Plots the results.
        /// </summary>
        /// <returns>The results.</returns>
        /// <param name="numBases">Number of bases.</param>
        /// <param name="signalWidth">The signal width.</param>
        /// <param name="dictionary">Dictionary.</param>
        /// <param name="coefficients">Coefficients.</param>
        /// <param name="st">Sub title.</param>
        /// <param name="plotOptions">The plotting options.</param>
        /// <param name="labels">Class labels.</param>
        public static void PlotResults(
            int numBases, int signalWidth,
            Gaussian[][][] dictionary, Gaussian[][][] coefficients,
            string st, PlotOptions plotOptions, IList <string> labels)
        {
            var subplots = new Subplots
            {
                ShareX  = true,
                ShareY  = true,
                Rows    = numBases < 16 ? numBases : 4,
                Columns = numBases < 16 ? 1 : 4,
            };

            plotOptions.Dictionary.Subplots  = subplots;
            plotOptions.Dictionary.NumToShow = plotOptions.IsImage ? 1 : Math.Min(numBases, 16);

            for (var i = 0; i < dictionary.Length; i++)
            {
                string label = "Dictionary_class=" + (labels == null ? $"{i}" : labels[i]);
                if (plotOptions.IsImage)
                {
                    PlotImages(dictionary[i], signalWidth, label, plotOptions.Dictionary);
                }
                else
                {
                    PlotPosteriors(dictionary[i], label, st, plotOptions.Dictionary);
                }
            }

            if (coefficients == null)
            {
                return;
            }

            subplots.Rows    = 3;
            subplots.Columns = 2;
            plotOptions.Coefficients.NumToShow = 6;
            plotOptions.Coefficients.Subplots  = subplots;

            for (var i = 0; i < coefficients.Length; i++)
            {
                var    coefficient = coefficients[i];
                string label       = "Coefficients_class={label}" + (labels == null ? $"{i}" : labels[i]);
                PlotPosteriors(coefficient, label, st, plotOptions.Coefficients);
            }
        }
        /// <summary>
        /// Plots the results.
        /// </summary>
        /// <returns>The results.</returns>
        /// <param name="numBases">Number of bases.</param>
        /// <param name="signalWidth">The signal width.</param>
        /// <param name="dictionary">Dictionary.</param>
        /// <param name="coefficients">Coefficients.</param>
        /// <param name="st">Sub title.</param>
        /// <param name="plotOptions">The plotting options.</param>
        public static void PlotResults(
            int numBases, int signalWidth,
            Gaussian[][] dictionary, Gaussian[][] coefficients,
            string st, PlotOptions plotOptions)
        {
            var subplots = new Subplots
            {
                ShareX  = true,
                ShareY  = true,
                Rows    = numBases < 16 ? numBases : 4,
                Columns = numBases < 16 ? 1 : 4
            };

            plotOptions.Dictionary.Subplots  = subplots;
            plotOptions.Dictionary.NumToShow = plotOptions.IsImage ? 1 : Math.Min(numBases, 16);

            if (plotOptions.IsImage)
            {
                PlotImages(dictionary, signalWidth, "Dictionary", plotOptions.Dictionary);
            }
            else
            {
                PlotPosteriors(dictionary, "Dictionary", st, plotOptions.Dictionary);
            }

            if (coefficients == null)
            {
                return;
            }

            subplots.Rows    = 3;
            subplots.Columns = 2;
            plotOptions.Coefficients.NumToShow = 6;
            plotOptions.Coefficients.Subplots  = subplots;
            PlotPosteriors(coefficients, "Coefficients", st, plotOptions.Coefficients);
        }
        /// <summary>
        /// Plots the image reconstructions. Note that we assume the images are square
        /// </summary>
        /// <returns>The reconstructions.</returns>
        /// <param name="reconstructions">Reconstructions.</param>
        /// <param name="averageError">The average reconstruction error.</param>
        /// <param name="subTitle">Sub title.</param>
        /// <param name="normalised">Whether these are normalised reconstructions.</param>
        /// <param name="plotOptions">Plotting options.</param>
        public static void PlotImageReconstructions(Reconstruction[] reconstructions, double averageError,
                                                    string subTitle, bool normalised, PlotOptions plotOptions)
        {
            var series1 = reconstructions.Take(plotOptions.Reconstructions.NumToShow).Select(
                (ia, i) => (ISeries) new HintonSeries
            {
                Label  = "signal",
                Values = Reshape(Vector.Build.Dense(ia.Signal)),
                Row    = i,
                Column = 0
            }).ToArray();
            var series2 = reconstructions.Take(plotOptions.Reconstructions.NumToShow).Select(
                (ia, i) => (ISeries) new HintonSeries
            {
                Label = "reconstruction",
                // ErrorLabel = "$\\pm$s.d.",
                Values = Reshape(Vector.Build.Dense(ia.Estimate.GetMeans())),
                // ErrorValues = ia.Estimate.GetStandardDeviations(),
                Row    = i,
                Column = 1
            }).ToArray();

            IList <ISeries> series = series1.Concat(series2).ToArray();

            string n = normalised ? "(normalised)" : string.Empty;

            var subplots = new Subplots {
                Rows = plotOptions.Reconstructions.NumToShow, Columns = 2, ShareX = false, ShareY = false
            };
            string sub1    = string.IsNullOrEmpty(subTitle) ? string.Empty : $" {subTitle.Replace("_", " ")}";
            string sub2    = string.IsNullOrEmpty(subTitle) ? string.Empty : $"_{subTitle.Replace(" ", "_")}";
            string message = $"Reconstructions {n}{sub1}, avg. error={averageError:N4}";

            Console.WriteLine(message);
            var plotter = new Plotter
            {
                Title      = message,
                XLabel     = "x",
                YLabel     = "y",
                Grid       = false,
                Series     = series,
                Subplots   = subplots,
                ScriptName = Path.Combine(ScriptPath, $"Reconstructions_{n}{sub2}.py"),
                FigureName = Path.Combine(FigurePath, $"Reconstructions_{n}{sub2}.pdf"),
                Python     = PythonPath,
                Show       = plotOptions.Reconstructions.Show
            };

            plotter.Plot();
        }
        /// <summary>
        /// Plots the functions.
        /// </summary>
        /// <param name="functions">The functions to plot.</param>
        /// <param name="title">The plot title..</param>
        /// <param name="subTitle">Sub title.</param>
        /// <param name="options">The plotting options.</param>
        public static void PlotFunctions(Matrix functions, string title, string subTitle, PlotOptions options)
        {
            if (options.IsImage)
            {
                PlotImages(functions, title, options.Images);
                return;
            }

            var series  = CreateSeries(functions.ToRowArrays(), null, options.Signals);
            var plotter = new Plotter
            {
                Title      = title + (string.IsNullOrEmpty(subTitle) ? string.Empty : " " + subTitle),
                XLabel     = "x", YLabel = "y",
                Series     = series, Subplots = options.Signals.Subplots,
                ScriptName = Path.Combine(ScriptPath, title + ".py"),
                FigureName = Path.Combine(FigurePath, title + ".pdf"),
                Python     = PythonPath
            };

            plotter.Plot();
        }