Skip to content

Commit

Permalink
Merge pull request #148 from flatironinstitute/data.R-improvements
Browse files Browse the repository at this point in the history
Improve data.R integration
  • Loading branch information
WardBrian authored Jul 25, 2024
2 parents 0d59626 + badb9d8 commit 15d99a8
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,22 +38,33 @@ const DataGenerationChildWindow: FunctionComponent<
const consoleRef = useRef<HTMLDivElement | null>(null);

const handleSetData = useCallback(
(data: any) => {
update({
type: "editFile",
content: JSON.stringify(data, null, 2),
filename: ProjectKnownFiles.DATAFILE,
});
update({ type: "commitFile", filename: ProjectKnownFiles.DATAFILE });
// Use "stan-playground" prefix to distinguish from console output of the running code
writeConsoleOutToDiv(
consoleRef,
"[stan-playground] Data updated",
"stdout",
);
(newData: unknown) => {
const dataJson = JSON.stringify(newData, null, 2);

if (dataJson !== data.dataFileContent) {
update({
type: "editFile",
content: dataJson,
filename: ProjectKnownFiles.DATAFILE,
});
update({ type: "commitFile", filename: ProjectKnownFiles.DATAFILE });
// Use "stan-playground" prefix to distinguish from console output of the running code
writeConsoleOutToDiv(
consoleRef,
"[stan-playground] Data updated",
"stdout",
);
} else {
writeConsoleOutToDiv(
consoleRef,
"[stan-playground] Data unchanged",
"stdout",
);
}
},
[update, consoleRef],
[update, consoleRef, data.dataFileContent],
);

const EditorComponent =
language === "python" ? DataPyFileEditor : DataRFileEditor;
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ const DataPyFileEditor: FunctionComponent<Props> = ({
const toolbarItems: ToolbarItem[] = useMemo(
() =>
getDataGenerationToolbarItems({
name: "pyodide",
status,
runnable: fileContent === editedFileContent,
onRun: handleRun,
Expand Down
72 changes: 27 additions & 45 deletions gui/src/app/pages/HomePage/DataGenerationWindow/DataRFileEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import {
useMemo,
useState,
} from "react";
import { WebR } from "webr";
import { RString, WebR } from "webr";
import getDataGenerationToolbarItems from "./getDataGenerationToolbarItems";
import TextEditor, { ToolbarItem } from "@SpComponents/TextEditor";
import { writeConsoleOutToDiv } from "@SpPyodide/AnalysisPyFileEditor";

type Props = {
fileName: string;
Expand Down Expand Up @@ -60,64 +61,44 @@ const DataRFileEditor: FunctionComponent<Props> = ({
try {
const webR = await loadWebRInstance();

const shelter = await new webR.Shelter();

setStatus("running");
const rCode =
`
# Create a list to store printed statements
print_log <- list()
# Check if original print function is already saved
if (!exists("sp_original_print")) {
# Save the original print function
sp_original_print <- print
}
# Override the print function
print <- function(..., sep = " ", collapse = NULL) {
# Capture the printed output
printed_output <- paste(..., sep = sep, collapse = collapse)
# Append to the print log
print_log <<- c(print_log, printed_output)
# Call the original print function
sp_original_print(printed_output)
}
# redirect install.packages to webr's version
webr::shim_install()
\n\n
` +
fileContent +
"\n\n" +
`
result <- list(data = data, print_log = print_log)
json_result <- jsonlite::toJSON(result, pretty = TRUE, auto_unbox = TRUE)
json_result
if (typeof(data) != "list") {
stop("[stan-playground] data must be a list")
}
.SP_DATA <- jsonlite::toJSON(data, pretty = TRUE, auto_unbox = TRUE)
.SP_DATA
`;
const resultJson = await webR.evalRString(rCode);
const result = JSON.parse(resultJson);

if (setData && result.data) {
setData(result.data);
}
if (outputDiv.current && result.print_log) {
result.print_log.forEach((x: string) => {
const divElement = document.createElement("div");
divElement.style.color = "blue";
const preElement = document.createElement("pre");
divElement.appendChild(preElement);
preElement.textContent = x;
outputDiv.current?.appendChild(divElement);
try {
const ret = await shelter.captureR(rCode);
ret.output.forEach(({ type, data }) => {
if (type === "stdout" || type === "stderr") {
writeConsoleOutToDiv(outputDiv, data, type);
}
});

const result = JSON.parse(await (ret.result as RString).toString());
if (setData) {
setData(result);
}
} finally {
shelter.purge();
}
setStatus("completed");
} catch (e: any) {
console.error(e);
if (outputDiv.current) {
const divElement = document.createElement("div");
divElement.style.color = "red";
const preElement = document.createElement("pre");
divElement.appendChild(preElement);
preElement.textContent = e.toString();
outputDiv.current.appendChild(divElement);
}
writeConsoleOutToDiv(outputDiv, e.toString(), "stderr");
setStatus("failed");
}
}, [editedFileContent, fileContent, status, setData, outputDiv]);
Expand All @@ -131,6 +112,7 @@ json_result
const toolbarItems: ToolbarItem[] = useMemo(
() =>
getDataGenerationToolbarItems({
name: "WebR",
status,
runnable: fileContent === editedFileContent,
onRun: handleRun,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import { Help, PlayArrow } from "@mui/icons-material";

const getDataGenerationToolbarItems = (o: {
status: PyodideWorkerStatus;
name: string;
runnable: boolean;
onRun: () => void;
onHelp: () => void;
}): ToolbarItem[] => {
const { status, onRun, runnable, onHelp } = o;
const { status, onRun, runnable, onHelp, name } = o;
const ret: ToolbarItem[] = [];
ret.push({
type: "button",
Expand All @@ -29,7 +30,7 @@ const getDataGenerationToolbarItems = (o: {
let label: string;
let color: string;
if (status === "loading") {
label = "Loading pyodide...";
label = `Loading ${name}...`;
color = "blue";
} else if (status === "running") {
label = "Running...";
Expand Down

0 comments on commit 15d99a8

Please sign in to comment.