Passing unquoted javascript to Highcharts using toJSON - r

Using shiny and rCharts to create a dashboard app, I need to pass raw javascript (not a string) to the Highcharts object.
Given this list
series <- list(data = list(c(0, 0), c(100, 0), c(100, 100)),
type = 'polygon',
color = 'Highcharts.Color(Highcharts.getOptions().colors[0]).setOpacity(0.5).get()')
I need to generate this JSON
{series:[{
data: [[0, 0], [100, 0], [100, 100]],
type: 'polygon',
color: Highcharts.Color(Highcharts.getOptions().colors[0]).setOpacity(0.5).get()
}]
}
but I can't find any way to prevent RJSONIO or jsonlte from quoting the value of the color property
shiny providers the JS() for wrapping literal javascript but RJSONIO ignores it and jsonlite complains about a missing a asJSON method for class JS_EVAL.
Is there some other way to selective prevent quoting of toJSON output?

You need support from the rCharts author. Two approaches:
The easy approach: use the htmlwidgets framework. Then all you need to do is put your JS code in htmlwidgets::JS(). The JS code will be preserved and evaluated automatically.
The harder approach: reinvent what we have done in htmlwidgets. I don't see why anybody ever wants to do this. Anyway, in case you care about the gory details, what we did were basically:
JS() adds a class JS_EVAL to the string, and we figure out the locations of such strings (e.g. series[2].color);
On the JavaScript side, find and eval() those strings;

The reason you cannot do this with json libraries is that your code is obviously not JSON but JavaScript. A hack would be to treat the literal string as if it were json:
color <- 'Highcharts.Color(Highcharts.getOptions().colors[0]).setOpacity(0.5).get()'
class(color) <- 'json'
series <- list(data = list(c(0, 0), c(100, 0), c(100, 100)),
type = 'polygon',
color = color)
jsonlite::toJSON(series, json_verbatim = TRUE, auto_unbox = TRUE)

Related

R/exams d2l multiple choice question doesn't select correct answer

I use the following to create a D2L exam from the "capital.Rmd" example (I converted the question to schoice)
exams2blackboard("capitals.Rmd", n =3, name = "testquiz" )
After I upload the testquiz.zip file, I notice that the correct answer must be manually chosen on the D2L platform.
I was wondering if there is a workaround.
Many Thanks,
Umut
If you want the correct solution to be selected, do not use the Import option from the Question Library or from the Quiz itself. Use the Import/Export/Copy Components under the Course Admin tab.
If you import the questions through the following steps, BrightSpace correctly picks the right solution. It’s a bit longer but seems to correctly choose the solution.
Under the Course Admin tab of your course, go to
'Import/Export/Copy Components' -> ‘Import Components’ -> Start -> (drag and drop the ZIP file)
Click ‘Advanced Options…’
This step will take a few minutes for large files; if you do not click
Advanced Options, then the import will automatically import the
questions into the 'Question Library' and will generate a Quiz with the
imported questions; you do not want this.
-> Continue -> Continue -> at this point choose 'Question Library' from the section 'Select Components to Import'
I would not choose ‘Quizzes’ because it automatically creates a quiz
and makes it available to students. It has the unfortunate side-effect
of making ALL the questions available, which means all the versions of
various dynamic questions; this is not something we want.
-> Continue -> Continue. This stage takes a few minutes for large
imports.
Now the Questions are available in the Question Library and can be used to generate new quizzes. Each question has the correct answer selected already. This works for ‘schoice’ and ‘mchoice’ versions of questions. Currently, plots are not imported, though, still trying to figure out why.
This problem is new to me. In earlier versions of Brightspace/D2L the import of single-choice and multiple-choice exercises via exams2blackboard() worked well. Possibly, D2L changed in the meantime given that neither the current release version from CRAN nor the development version from R-Forge work for you.
D2L also supports other import formats and we did play around with some of these. See the following discussions in the R/exams forum on R-Forge:
https://R-Forge.R-project.org/forum/forum.php?thread_id=33404&forum_id=4377&group_id=1337
https://R-Forge.R-project.org/forum/forum.php?thread_id=33657&forum_id=4377&group_id=1337
Notably we tried to use the XML-based QTI 2.1 format that seems to be employed by D2L internally. However, D2L apparently uses a particular custom flavor of QTI 2.1. It should be possible to reverse engineer that and improve exams2qti21() correspondingly but so far (to the best of my knowledge) no one put the time and effort into this that would be needed.
For simple single/multiple choice questions a CSV-based exchange format can also be used. I have put together a very basic exams2d2l() function that was posted in the threads above and that I'm also including below. It can set up the CSV file for a single exercise like the capitals.Rmd exercise that you use above. For plain text exercises like that it seems to work well but not for more complex elements (graphics, code, math, etc.).
exams2d2l <- function(file, dir = ".", ## n = 1L, nsamp = NULL disabled for now
name = NULL, quiet = TRUE, edir = NULL, tdir = NULL, sdir = NULL, verbose = FALSE,
resolution = 100, width = 4, height = 4, svg = FALSE,
encoding = "", converter = NULL, ...)
{
## for Rnw exercises use "ttm" converter otherwise "pandoc" converter
if(any(tolower(tools::file_ext(unlist(file))) == "rmd")) {
if(is.null(converter)) converter <- "pandoc"
} else {
if(is.null(converter)) converter <- "ttm"
}
## output directory or display on the fly
## output name processing
if(is.null(name)) name <- tools::file_path_sans_ext(basename(file))
## set up .html transformer and writer function
htmltransform <- make_exercise_transform_html(converter = converter, ...)
## create exam with HTML text
rval <- xexams(file,
driver = list(sweave = list(quiet = quiet, pdf = FALSE, png = !svg, svg = svg,
resolution = resolution, width = width, height = height, encoding = encoding),
read = NULL, transform = htmltransform, write = NULL),
dir = dir, edir = edir, tdir = tdir, sdir = sdir, verbose = verbose)
## currently: only a single exercise
rval <- rval[[1L]][[1L]]
## put together CSV
cleanup <- function(x) gsub('"', '""', paste(x, collapse = "\n"), fixed = TRUE)
rval <- c(
'NewQuestion,MC,,,',
sprintf('ID,"%s",,,', cleanup(rval$metainfo$file)),
sprintf('Title,"%s",,,', cleanup(rval$metainfo$name)),
sprintf('QuestionText,"%s",,,', cleanup(rval$question)),
sprintf('Points,%s,,,', if(is.null(rval$metainfo$points)) 1 else rval$metainfo$points),
'Difficulty,1,,,',
'Image,,,,',
paste0('Option,', ifelse(rval$metainfo$solution, 100, 0), ',"', cleanup(rval$questionlist), '",,"', cleanup(rval$solutionlist), '"'),
'Hint,,,,',
sprintf('Feedback,"%s",,,', cleanup(rval$solution))
)
writeLines(rval, file.path(dir, paste0(name, ".csv")))
invisible(rval)
}

How to create many Bokeh figures with multiprocessing?

I would like to speed up figure generation in Bokeh by multiprocessing:
jobs = []
for label in list(peakLabels):
args = {'data': rt_proj_data[label],
'label': label,
'tools': tools,
'colors': itertools.cycle(palette),
'files': files,
'highlight': highlight}
jobs.append(args)
pool = Pool(processes=cpu_count())
m = Manager()
q = m.Queue()
plots = pool.map_async(plot_peaks_parallel, jobs)
pool.close()
pool.join()
def plot_peaks_parallel(args):
data = args['data']
label = args['label']
colors = args['colors']
tools = args['tools']
files = args['files']
highlight = args['highlight']
p = figure(title=f'Peak: {label}',
x_axis_label='Retention Time',
y_axis_label='Intensity',
tools=tools)
...
return p
Though I ran into this error:
MaybeEncodingError: Error sending result: '[Figure(id='1078', ...)]'. Reason: 'PicklingError("Can't pickle at 0x7fc7df0c0ea0>: attribute lookup ColumnDataSource. on bokeh.models.sources failed")'
Can I do something to the object p, so that it becomes pickleable?
Individual Bokeh objects are not serializable in isolation, including with pickle. The smallest meaningful unit of serialization in Bokeh is the Document, which is a specific collection of Bokeh objects guaranteed to be complete with respect to following references. However, I would be surprised if pickle works with Document either (AFAIK you are the first person to ask about it since the project started, it's never been a priority, or even looked into that I know of). Instead, I would suggest if you want to do something like this, to use Bokeh's own JSON serialization functions, such as json_item:
# python code
p_serialized = json.dumps(json_item(p))
This will properly serialize p in the context of the Document it is a part of. Then you can pass this to your page templates to display with the Bokeh JS embed API:
# javascript code
p = JSON.parse(p_serialized);
Bokeh.embed.embed_item(p, "mydiv")

Remove sections of a string or parse data?

I have a long string of data and I'm trying to pick out one small piece of it. The position in the string changes all the time. A sample of the data is below. I have researched strip and parse, but I'm thinking strip is the wrong choice, but parse might do it.
Data: {'DriverCarSLFirstRPM': 6000.0, 'DriverCarFuelMaxLtr': 44.987, 'DriverCarMaxFuelPct': 0.3, 'Drivers': [{'CarIsAI': 0, 'LicSubLevel': 1, 'TeamID': 0}
I'm trying to get the value for DriverCarFuelMaxLtr. Should I be trying to strip the data before and after that value, or is there a way to seperate the file at the commas and then read the values?
Your JSON was invalid to start with.
This has now been validated:
{
"DriverCarSLFirstRPM": 6000.0,
"DriverCarFuelMaxLtr": 44.987,
"DriverCarMaxFuelPct": 0.3,
"Drivers": [{
"CarIsAI": 0,
"LicSubLevel": 1,
"TeamID": 0
}]
}
This should help you get started:
import json
data = '{"DriverCarSLFirstRPM": 6000.0, "DriverCarFuelMaxLtr": 44.987,"DriverCarMaxFuelPct": 0.3,"Drivers": [{"CarIsAI": 0,"LicSubLevel": 1,"TeamID": 0}]}'
info = json.loads(data)
# To get the value of "DriverCarFuelMaxLtr"
print(info.get('DriverCarFuelMaxLtr'))
Output: 44.987
It looks like you have a stringified json object. You could look into Json.loads().
Or if I am mistaken and for some reason you can not transform it into a dictionary I would just use regex (regular expressions).
If you don't know about regex you can look at this guide and learn how to use them in python.

gvisScatterChart - hAxis.title and vAxis.title not appearing on the plot

hAxis.title and vAxis.title options don't seem to set the axis titles for gvisScatterChart in the package googleVis.
plot(gvisScatterChart(data.frame(x = 3, y = 4), options=list(hAxis.title = 'foo')))
"foo" doesn't appear as the horizontal axis title.
You're supposed to pass options to hAxis in a dictionary-looking JSON object format:
plot(gvisScatterChart(data.frame(x = 3, y = 4), options=list(hAxis="{title:'foo'}")))
See the examples at the bottom of the help page and this under hAxis:
a JSON object. Default null. An object with members to configure various horizontal axis elements. To specify properties of this object, you can use object literal notation, as shown here:
{title: 'Hello', titleTextStyle: {color: '#FF0000'}}

gvisScatterChart define series dynamically

I am dynamically creating a couple of gvisScatterCharts. I want to define the colors of each line, which I can do using series and the color attribute. There is nothing like an order or a fix number by which I can predefine the colors. So I want to create an array of attributes parallel to my colors and just place it at series=myColors.
The problem is that gVis expects a string like:
series="[{color: 'black', visibleInLegend: false}]",
As soon as I create a string using the paste function gVis doesn't accept them any more and just shows a blank page as chart. (Even when marking the " using \")
Is this a bug or am I doing something wrong?
This is not a bug, just as said in the help it expects a JSON string so you need to build JSON string.
Using RJSONIO you can build the JSON option using toJSON
library(googleVis)
library(RJSONIO)
myColor <- 'grey' ## my dynamic color, here I fix but you can read it ,e.g
## from a chart config file or whatever you want
isLegend <- TRUE ## a boolean value
myseriesOptions <- toJSON(list(list(color=myColor),list(visibleInLegend=isLegend)))
For example
Scatter2 <- gvisScatterChart(women,
options=list(legend="none",
lineWidth=2, pointSize=0,
title="Women", vAxis="{title:'weight (lbs)'}",
hAxis="{title:'height (in)'}",
width=300, height=300,
series = myseriesOptions ))
plot(Scatter2)
PS : We can use fromJSON to get the R form of the string to construct, e.g
fromJSON("{title:'mytitle'}") ## the ouptut is a list
$itl
NULL
cat(toJSON(list(title='mytitle'))) ## I construct my list and I use toJSON
## I get my origin json form
{
"title": "mytitle"
}

Resources