Forum Discussion
R Custom Visual - Setting colours for each value in a field/column
capabilities.json:
{
"dataRoles": [
{
"displayName": "Column Groups",
"description": "Grouping to be used on the x-axis of the column chart.",
"kind": "Grouping",
"name": "columnGroups"
},
{
"displayName": "Column Overlay Groups",
"description": "Within each value of Column Groups, the columns to overlay on each other.",
"kind": "Grouping",
"name": "overlayGroups"
},
{
"displayName": "Stacking Groups",
"description": "Optional stacking of columns within Column and Overlay Groups.",
"kind": "Grouping",
"name": "stackingGroups"
},
{
"displayName": "Heights",
"description": "Heights of each column.",
"kind": "GroupingOrMeasure",
"name": "heights"
}
],
"dataViewMappings": [
{
"conditions": [
{
"columnGroups": {
"max": 1
},
"overlayGroups": {
"max": 1
},
"stackingGroups": {
"max": 1
},
"heights": {
"max": 1
}
}
],
"scriptResult": {
"dataInput": {
"table": {
"rows": {
"select": [
{
"for": {
"in": "columnGroups"
}
},
{
"for": {
"in": "overlayGroups"
}
},
{
"for": {
"in": "stackingGroups"
}
},
{
"for": {
"in": "heights"
}
}
],
"dataReductionAlgorithm": {
"top": {}
}
}
}
},
"script": {
"scriptProviderDefault": "R",
"scriptOutputType": "html",
"source": {
"objectName": "rcv_script",
"propertyName": "source"
},
"provider": {
"objectName": "rcv_script",
"propertyName": "provider"
}
}
}
}
],
"objects": {
"rcv_script": {
"properties": {
"provider": {
"type": {
"text": true
}
},
"source": {
"type": {
"scripting": {
"source": true
}
}
}
}
},
"settings_overlay_params": {
"displayName": "Settings",
"description": "Column overlay settings",
"properties": {
"alphaMin": {
"displayName": "Alpha Bottom",
"description": "Alpha setting for bottom-most column",
"type": {
"numeric": true
}
},
"overlay": {
"displayName": "Degree of overlay",
"description": "How much should columns overlay 0.0 = no overlay, 1.0 = completely overlay",
"type": {
"numeric": true
}
},
"alphaMax": {
"displayName": "Alpha Top",
"description": "Alpha setting for top-most column",
"type": {
"numeric": true
}
}
}
},
"settings_datacolour_params": {
"displayName": "Data Colours",
"description": "Base colours for columns",
"properties": {
"fill": {
"displayName": "Column colours",
"description": "Specify a colour for each value in the overlay group",
"type": {
"fill": {
"solid": {
"color": true
}
}
}
}
}
}
},
"suppressDefaultTitle": true
}settings.ts:
"use strict";
import { dataViewObjectsParser } from "powerbi-visuals-utils-dataviewutils";
import DataViewObjectsParser = dataViewObjectsParser.DataViewObjectsParser;
export class VisualSettings extends DataViewObjectsParser {
public settings_overlay_params: settings_overlay_params = new settings_overlay_params();
public settings_datacolour_params: settings_datacolour_params = new settings_datacolour_params();
}
export class settings_overlay_params {
public alphaMin: number = 0.4;
public alphaMax: number = 0.8;
public overlay: number = 0.2;
}
export class settings_datacolour_params {
public columnColour: string = "orange";
}- Anonymous7 years agoNot applicable
source('./r_files/flatten_HTML.r') ############### Library Declarations ############### libraryRequireInstall("ggplot2"); libraryRequireInstall("plotly"); libraryRequireInstall("stringr"); libraryRequireInstall("reshape2"); libraryRequireInstall("ggplotify"); libraryRequireInstall("grid"); libraryRequireInstall("readxl"); #################################################### #Enable debugging in RStudio fileRda = "C:/Users/biedermannf/Temp/tempData.Rda" if(file.exists(dirname(fileRda))) { if(Sys.getenv("RSTUDIO")!="") load(file= fileRda) else save(list = ls(all.names = TRUE), file=fileRda) } ###############Internal function definitions################# # Functions used only for this visual ############################################################# ############################################################# # Set up parameters/report variables ############################################################# validToPlot <- TRUE # Data if(!exists("columnGroups")){ columnGroups <- NULL validToPlot <- FALSE } if(!exists("overlayGroups") && validToPlot){ # Set up a dummy variable with a single value overlayGroups <- data.frame(OG = factor(rep("Dummy Value", length(columnGroups[, 1])), levels = "Dummy Value")) } if(!exists("stackingGroups")){ stackingGroups <- NULL } if(!exists("heights")){ heights <- NULL validToPlot <- FALSE } ############################################################# # Column grouping parameters ############################################################# # Default the column group labels to be slanted at 45 degrees # and split into lines 30 chars wide. x.axis.offset.labels <- FALSE x.axis.labels.srt <- 45 x.axis.hjust <- 1 x.axis.maxwidth <- 30 # overlapping column parameters # Min and max alpha - bottom column will have min alpha, # graduating to max alpha for top column alphaMin <- 0.2 if(exists("settings_overlay_params_alphaMin")){ alphaMin <- min(1.0, max(0.0, settings_overlay_params_alphaMin)) } alphaMax <- 0.8 if(exists("settings_overlay_params_alphaMax")){ alphaMax <- min(1.0, max(0.0,settings_overlay_params_alphaMax)) } overlay <- 0.8 if(exists("settings_overlay_params_overlay")){ overlay <- min(1.0, max(0.0, settings_overlay_params_overlay)) } ############################################################# # Stacking parameters ############################################################# ############################################################# # Check inputs if((!exists("columnGroups") ||!exists("heights"))) # invalid input { validToPlot <- FALSE } if(validToPlot){ # Set up variables to hold the names of the supplied data columns (there'll only be one column in each incoming data frame) cGrpsName <- names(columnGroups)[[1]] oGrpsName <- names(overlayGroups)[[1]] heightsName <- names(heights)[[1]] # Set up column groups columnGroups[, cGrpsName] <- str_wrap(columnGroups[, cGrpsName], width = 30) colGrps <- factor(columnGroups, levels = unique(columnGroups), ordered = T) # Set up overlay groups oGrps <- NULL nGrps <- 1 if(exists("overlayGroups")){ oGrps <- levels(overlayGroups[, oGrpsName]) nGrps <- length(oGrps) } columnWidth <- 0.9 / (nGrps - (nGrps - 1) * overlay) } if(validToPlot){ # Base ggplot g <- ggplot(data=data.frame(columnGroups, overlayGroups, heights), aes(x = get(cGrpsName), y = get(heightsName), fill = get(oGrpsName))) # Loop through each overlay group (there should be at least a dummy group here) and add to plot for(i in 1:nGrps){ g <- g + geom_col(data = data.frame(columnGroups, overlayGroups, heights)[overlayGroups[, oGrpsName] == oGrps[i], ], aes(x = get(cGrpsName), y = get(heightsName), fill = get(oGrpsName)), width = columnWidth, position = position_nudge(x = 0.9*((i-1)/(nGrps-1)-1/2) + columnWidth * (1/2-(i-1)/(nGrps-1))) ) } if(nGrps == 1){ # Don't produce a legend as it'll just display "Dummy Value" # ToDo: this won't necessarily be the case if data coming only has one value in a supplied overlayGroups column - needs to be fixed g <- g + theme(legend = element_blank()) # Set the colours of the columns g <- g + scale_fill_manual(values=alpha(c("springgreen4", "cornflowerblue"), c(alphaMin, alphaMax)), breaks = oGrps) } else { # Set the colours of the columns g <- g + scale_fill_manual(values=alpha(c("springgreen4", "cornflowerblue"), seq(alphaMin, alphaMax, length = nGrps)), breaks = oGrps) # Add the correct axis labelling g <- g + labs(x = cGrpsName, y = heightsName); # Rotate the x axis text labels (if required) g <- g + theme(axis.text.x = element_text(size = 6, angle = x.axis.labels.srt, hjust = x.axis.hjust, vjust = 1), legend.title = element_blank(), axis.title.x = element_blank()); } # g <- g + theme(plot.margin = unit(c(0, 0, 0, 0), "native")) # plotly doesn't currently like mucking around with grobs - leave it commented out for now. # if (x.axis.offset.labels == TRUE){ # # Adjust alternate tick lengths to be longer # gg <- ggplotGrob(g) # xaxis <- gg$grobs[[which(gg$layout$name == "axis-b")]] # # Get the tick marks and tick mark labels # ticks <- xaxis$children[[2]] # # Get the tick marks # marks = ticks$grobs[[1]] # # change the length in an alternating way # long <- unit.c(unit(1, "npc") - unit(18, "pt"), unit(1, "npc")) # short <- unit.c(unit(1, "npc") - unit(4, "pt"), unit(1, "npc")) # # update the length # marks$y = unit.c(rep(unit.c(short, long), 4), short) # # Put the tick marks back into the plot # ticks$grobs[[1]] <- marks # xaxis$children[[2]] <- ticks # gg$grobs[[which(gg$layout$name == "axis-b")]] <- xaxis # g <- as.ggplot(gg) # } } else { g <- ggplot() + theme(axis.line = element_blank()) + labs(title = "Invalid data - cannot produce plot") } p <- ggplotly(g); #################################################### ############# Create and save widget ############### internalSaveWidget(p, 'out.html'); ####################################################- dm-p7 years agoSuper UserCheers, Anonymous - I'll set up a project as per your supplied files and I'll report back as soon as I can with findings.
Daniel :)- dm-p7 years agoSuper User
Hi Anonymous,
I've set up a visual project with your files and sample data, and everything seems to be running okay.
The challenge now is having unpacked how the R visuals work vs. TypeScript, the approach used for these visuals doesn't seem to work in the same way as for R (to my knowledge).
Usually, you have full access to the dataRoles in the dataView when the visual renders, and you use this information to build your list for the properties pane, using enumerateObjectInstances to push them in. When using R, the whole result of the execution is provided as the scriptResult, e.g.:
The above dataView is from the developer visual for the R project. For TypeScript visuals, you'd get data in the metadata object and whichever dataViewMapping you were using, e.g. table.
I've decoded the payloadBase64 and this is essentially the JavaScript and HTML to render the visual, post-processing with R. What this looks like is we can add simple properties to the pane but any data-bound ones come with a separate challenge; there doesn't seem to be suitable hook in a similar place to the TypeScript workflow and I was hoping that there might be, so I apologise if I got your hopes up.
I'll yield the floor to someone else, but it might be better to get in touch with the custom visuals team directly to see if they can definitively comfirm your question - you can email them at [email protected]
I'd be keen to hear if anyone else can solve this, or if the team have any advice on how it can be managed in the R visuals.
Regards,
Daniel