#' Display density on 2D plot
#'
#'
#' Function to show density for a set of observations on a field created by two
#' variables. The plot is constructed primarily for displaying density of
#' 2D-stochastic neighbour embedding fields, but can be used for any sets of
#' two known for the same observations. As the number of datapoints is often
#' very high, the files would, if saved as pdf of another vector based file
#' type become big. For this reason, the plots are saved as jpeg and no axes or
#' anything alike are added, to simplify usage in publications.
#' @param xYData A dataframe or matrix with two columns. Each row contains
#' information about the x and y positition in the field for that observation.
#' @param plotName A name that is common to all density plots created. It can
#' be the groups name, e.g. 'Malaria patients' or 'Clusters'. If only one plot
#' is created, the name is still taken from here.
#' @param idsVector Optional. Vector with the same length as xYData containing
#' information about the id of each observation. If provided, density plots for
#' each individual id and all ids together are produced.
#' @param colorScale This gives the specific color for the densest part of the
#' plot(s). It has three possible values:
#' \describe{
#'     \item{A specific color, e.g. 'red' or '#FF0000'}{If no idsVector
#'     provided}
#'     \item{A color scale from dColorVector}{If idsVector provided. See
#'     \code{\link{dColorVector}} for alternatives.}
#'     \item{"default"}{"One color (blue) if no idsVector is provided, and
#'     otherwise the viridis color scale.}
#' }
#' @param densContour If density contours should be created for the plot(s) or
#' not. Defaults to TRUE. If a density object, as generated by dContours, is
#' included, this will be used for the internal scaling of the plot, allowing
#' for density distribution checks of different subcompartments of the data with
#' the same scaling.
#' @param title If there should be a title displayed on the plotting field. As
#' the plotting field is saved as a png, this title cannot be removed as an
#' object afterwards, as it is saved as coloured pixels. To simplify usage for
#' publication, the default is FALSE, as the files are still named, eventhough
#' no title appears on the plot.
#' @param plotDir If different from the current directory. If not "." and
#' non-existent, the function creates it. Default is "." if idsVector is not
#' specified and otherwise paste0("Density plots for ", plotName, "s").
#' @param bandColor The color of the contour bands. Defaults to black.
#' @param dotSize Simply the size of the dots. The default makes the dots
#' smaller the more observations that are included.
#' @param createOutput For testing purposes. Defaults to TRUE. If FALSE, no
#' output is generated.
#' @seealso \code{\link{dColorPlot}}, \code{\link{dResidualPlot}},
#' \code{\link{dWilcox}}, \code{\link{dColorVector}}
#' @return Plots showing the densities of the specific xYData (subset) displayed
#' as color on the field created by the same xYData (subset).
#' @examples
#'
#' # Load some data
#' data(testData)
#' \dontrun{
#' # Load or create the dimensions that you want to plot the result over.
#' # uwot::umap recommended due to speed, but tSNE or other method would
#' # work as fine.
#' data(testDataSNE)
#'
#' # Plot all data together
#' dDensityPlot(xYData = testDataSNE$Y)
#'
#' # Now each depeche cluster is plotted separately and together.
#'
#' # Run the clustering function. For more rapid example execution,
#' # a depeche clustering of the data is included
#' # testDataDepeche <- depeche(testData[,2:15])
#' data(testDataDepeche)
#'
#' dDensityPlot(
#'     xYData = testDataSNE$Y,
#'     idsVector = testDataDepeche$clusterVector,
#'     plotName = "cluster"
#' )
#' }
#' @export dDensityPlot
dDensityPlot <- function(xYData, colorScale = "default",
                         plotName = "All_density", idsVector,
                         densContour = TRUE, title = FALSE, plotDir = "default",
                         bandColor = "black",
                         dotSize = 500 / sqrt(nrow(xYData)),
                         createOutput = TRUE) {
    if (plotDir == "default") {
        if (missing(idsVector)) {
            plotDir <- "."
        } else {
            plotDir <- paste0("Density plots for ", plotName, "s")
        }
    }

    if (plotDir != ".") {
        dir.create(plotDir)
    }

    if (is.matrix(xYData)) {
        xYData <- as.data.frame(xYData)
    }

    # Create the density matrix for xYData.
    if (is.logical(densContour)) {
        if (densContour) {
            densContour <- dContours(xYData)
        }
    }

    if (missing(idsVector)) {
        color <- ifelse(colorScale == "default", "blue", colorScale)

        dDensityPlotCoFunction(
            xYData = xYData, color = color,
            plotName = plotName,
            densContour = densContour,
            bandColor = bandColor, dotSize = dotSize,
            title = title, plotDir = plotDir,
            createOutput = createOutput
        )
    } else {
        if (colorScale == "default") {
            colorScale <- "viridis"
        }

        uniqueIds <- sort(unique(idsVector))
        colors <- dColorVector(x = uniqueIds, colorScale = colorScale)

        for (i in seq_along(uniqueIds)) {
            dDensityPlotCoFunction(
                xYData = xYData[idsVector == uniqueIds[i], ],
                color = colors[i],
                plotName = paste(plotName, uniqueIds[i],
                    "density",
                    sep = " "
                ),
                densContour = densContour, bandColor = bandColor,
                dotSize = dotSize, title = title, plotDir = plotDir,
                createOutput = createOutput
            )
        }
        dDensityPlotCoFunction(
            xYData = xYData, idsVector = idsVector,
            uniqueIds = uniqueIds, color = colors,
            plotName = plotName, densContour = densContour,
            bandColor = bandColor, dotSize = dotSize,
            title = title, plotDir = plotDir,
            createOutput = createOutput
        )
        # Legend creation
        colorIdsDataFrame <- data.frame(colors, uniqueIds,
            stringsAsFactors = FALSE
        )
        if (createOutput) {
            pdf(file.path(plotDir, paste0(plotName, "_legend.pdf")))
            plot.new()
            legend("center",
                legend = colorIdsDataFrame[, 2],
                col = colorIdsDataFrame[, 1],
                cex = 7.5 / length(uniqueIds), pch = 19
            )
            dev.off()
        }
    }
}
