Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 51 additions & 9 deletions src/components/BlocklyComponentPython.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ import { english } from "../locales/english.js";
import { german } from "../locales/german.js";
import * as De from "blockly/msg/de";
import * as En from "blockly/msg/en"
import co2Tutorial from "../data/co2Tutorial.js";
import co2TutorialPython from "../data/co2TutorialPython.js";

const lang = navigator.languages;
if(lang.some((l) => l.startsWith('de'))) { //Reactivate after testing
Expand Down Expand Up @@ -100,13 +100,18 @@ const BlocklyComponent = ({ setCode, isDarkMode, onUploadClick, workspaceRef })

<category name="${Blockly.Msg.Categories["DATA"]}" colour="#0396c1">
<category name="${Blockly.Msg.Categories["DOWNLOAD_DATA"]}" colour="#0396c1">
<block type="func_download"></block>
<block type="sampleDataB"></block>
<block type="read_file"></block>
<block type="func_download"></block>
<block type="sampleDataB"></block>
<block type="read_file_pandas"></block>
</category>
<category name="${Blockly.Msg.Categories["DATA_INSPECTION"]}" colour="#0396c1">
<block type="describe"></block>
<block type="display_all"></block>
<block type="head"></block>
</category>
<category name="${Blockly.Msg.Categories["DATA_MANIPULATION"]}" colour="#0396c1">
<block type="convert_column"></block>
<block type="data_shape"></block>
<block type="convert_column"></block>
<block type="get_column"></block>
<block type="slice"></block>
<block type="add_object"></block>
<block type="delete_object"></block>
Expand Down Expand Up @@ -201,11 +206,18 @@ const BlocklyComponent = ({ setCode, isDarkMode, onUploadClick, workspaceRef })


/*******
*
*
* Level 2 Toolbox
*
* This toolbox includes more advanced blocks for data handling, visualisation, and spatial analysis.
*
*
*/




const advancedToolbox = `
<xml>
<category name="${Blockly.Msg.Categories["MATH"]}" colour="#253dc7">
Expand Down Expand Up @@ -241,16 +253,33 @@ const BlocklyComponent = ({ setCode, isDarkMode, onUploadClick, workspaceRef })
<block type="sampleDataA"></block>
<block type="func_download"></block>
<block type="read_file"></block>
<block type="read_file_pandas"></block>
<block type="listdir"></block>
<block type="load_csv"></block>
<block type="load_json"></block>
<block type="request_json_data"></block>
<block type="load_raster"></block>
</category>
<category name="${Blockly.Msg.Categories["DATA_INSPECTION"]}" colour="#0396c1">
<block type="describe"></block>
<block type="data_shape"></block>
<block type="head"></block>
<block type="display_all"></block>
</category>
<category name="${Blockly.Msg.Categories["DATA_MANIPULATION"]}" colour="#0396c1">
<block type="convert_column"></block>
<block type="convert_np_to_pd"></block>
<block type="data_shape"></block>
<block type="get_column"></block>
<block type="convert_np_to_pd">
<value name="columns">
<block type="list_create">
<value name="element_0">
<block type="text">
<field name="TEXT">column1</field>
</block>
</value>
</block>
</value>
</block>
<block type="slice"></block>
<block type="stacking"></block>
<block type="group_by"></block>
Expand Down Expand Up @@ -441,6 +470,19 @@ const BlocklyComponent = ({ setCode, isDarkMode, onUploadClick, workspaceRef })
<block type="ppv_interpolation"></block>
</category>

<category name ="${Blockly.Msg.Categories["RASTER"]}" colour="#00ff80">
<block type="read_raster_data"></block>
<block type="clip_raster_bbox"></block>
<block type="save_raster"></block>
<block type="visualize_raster"></block>
<block type="raster_histogram"></block>
<block type="log_transform_raster"></block>
<block type="reclassify_raster"></block>
<block type="raster_to_point_grid"></block>
<block type="points_to_geodataframe"></block>
<block type="plot_geodataframe"></block>
</category>

<category name="${Blockly.Msg.Categories["MAPS"]}" colour="#8803c1">
<block type="GeoCoords"></block>
<block type="folium_map">
Expand Down Expand Up @@ -942,7 +984,7 @@ def idw_interpolation(xi, yi, zi, xi_interp, yi_interp, power=2):
step={stepCO2Tutorial}
nextStep={nextStepCO2Tutorial}
prevStep={prevStepCO2Tutorial}
tutorialData={co2Tutorial}
tutorialData={co2TutorialPython}
/>
</Box>
);
Expand Down
21 changes: 20 additions & 1 deletion src/components/CheckUploadedDataDialogPython.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,32 @@ import Snackbar from "@mui/material/Snackbar";
import CloseIcon from "@mui/icons-material/Close";
import ContentCopyIcon from "@mui/icons-material/ContentCopy";
import IconButton from "@mui/material/IconButton";
import { pyodideWorker } from "./workerApi.mjs";

const worker = pyodideWorker;

const CheckUploadedDataDialog = ({ open, onClose }) => {
const [files, setFiles] = useState([]);
const [filePreviews, setFilePreviews] = useState([]); // Array of { filename, table }
const [filePreviews, setFilePreviews] = useState([]);
const [expandedPreviews, setExpandedPreviews] = useState({});
const [copySuccess, setCopySuccess] = useState(false);

useEffect(() => {
const handleWorkerMessage = (event) => {
if (event.data.type === 'fileLoaded') {
setFiles(event.data.files);
globalThis.files = event.data.files;
globalThis.fileContents = event.data.contents;
}
};

worker.addEventListener('message', handleWorkerMessage);

return () => {
worker.removeEventListener('message', handleWorkerMessage);
};
}, []);

useEffect(() => {
const fetchFiles = async () => {
try {
Expand Down
69 changes: 43 additions & 26 deletions src/components/CodeOutput.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,17 +78,20 @@ const CodeOutput = ({ code, isDarkMode, setPlot }) => {
}
};

const runCode = async () => {
const runCode = async (runCodeArg) => {
const codeToRun = runCodeArg !== undefined ? runCodeArg : code;
setIsAPlot(false);
setIsAMap(false);
setShowPlot(true);
console.log('Running code...');
setOutput("Running...");
if(~code.indexOf('plt.') || ~code.indexOf('df_interp.plot')) {
code = `
let codeForExec = codeToRun;
if(~codeForExec.indexOf('plt.') || ~codeForExec.indexOf('df_interp.plot')) {
codeForExec = `
import io
import base64
import js
import pandas as pd

class Dud:
def __init__(self, *args, **kwargs) -> None:
Expand All @@ -101,16 +104,16 @@ js.document = Dud()
bytes_io = None
base64_encoded_spectrogram = None

${code}
${codeForExec}

bytes_io = io.BytesIO()
plt.savefig(bytes_io, format='jpg')
bytes_io.seek(0)
base64_encoded_spectrogram = base64.b64encode(bytes_io.read())
print(base64_encoded_spectrogram.decode('utf-8'))`
print(base64_encoded_spectrogram.decode('utf-8'))`;
}

const result = await main(code);
const result = await main(codeForExec);

/*** Create map w/ Folium ***/
const saveMap = !~code.indexOf('###DISPLAYONLY###');
Expand Down Expand Up @@ -204,19 +207,22 @@ print(base64_encoded_spectrogram.decode('utf-8'))`
}

setOutput(result);
if (typeof result === "string" && result.length > 100 && /^[A-Za-z0-9+/=\s]+$/.test(result)) {
var plotURL = '';
if (typeof result === "string" && ~result.indexOf('/9j/')) {
setIsAPlot(true);
plotURL = '/9j/' + result.split('/9j/').slice(1, 1000).join('/9j/');
try {
setPlot(result);
} catch {
setPlot(plotURL);
} catch(e) {
setPlot("");
console.error("Plot parsing error:\n", e);
}
} else {
setPlot("");
}

globalThis.getRes = () => {
return result;
return plotURL || result;
}
}
useEffect(() => {
Expand All @@ -240,30 +246,41 @@ print(base64_encoded_spectrogram.decode('utf-8'))`
try {
document.getElementsByClassName('Mui-disabled')[0].classList.remove('Mui-disabled');
} catch {}
document.getElementById('toast').style.color = '#089d08';
document.getElementById('toast').style.color = '#44a1a0';
document.querySelector('#toast p').innerHTML = 'Libraries loaded!';
document.getElementById('toast').style.animation = 'slideOut 5s ease-in-out';
setTimeout(() => document.getElementById('toast').style.display = 'none', 4950);
document.addEventListener(
"keydown",
(ev) => {
const keyName = ev.key;
if (keyName === "Control") {
return;
}
if ((ev.ctrlKey || ev.metaKey) && ev.altKey && keyName === 'Enter') {
ev.preventDefault();
runCode();
}
},
false,
);

}
}
};
findInfo();
});

const codeRef = useRef(code);

useEffect(() => {
codeRef.current = code;
}, [code]);

useEffect(() => {
const handler = (ev) => {
const keyName = ev.key;
if (keyName === "Control") return;
if ((ev.ctrlKey || ev.metaKey) && ev.altKey && keyName === 'Enter') {
ev.preventDefault();
runCodeWithLatestCode();
}
};

document.addEventListener("keydown", handler, false);
return () => document.removeEventListener("keydown", handler);
}, []);

const runCodeWithLatestCode = () => {
runCode(codeRef.current);
};

return (
<Box
sx={{
Expand All @@ -286,7 +303,7 @@ print(base64_encoded_spectrogram.decode('utf-8'))`
</Box>
<Tooltip title="Run Python Code">
<IconButton
onClick={ runCode }
onClick={ () => runCode(codeRef.current) }
disabled={ isLoading }
sx={{
bgcolor: "#33bfff",
Expand Down
14 changes: 8 additions & 6 deletions src/components/FileUploadManagerPython.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,14 @@ import CloseIcon from '@mui/icons-material/Close';
import { CheckCircle, Error, InsertDriveFile, Map, Forward } from '@mui/icons-material';
import { writeFile } from './workerApi.mjs';

globalThis.files = [];
globalThis.fileColumns = [];
globalThis.fileContents = {};
if(!globalThis.files && !globalThis.fileColumns && !globalThis.fileContents) {
globalThis.files = [];
globalThis.fileColumns = [];
globalThis.fileContents = {};
}

// Component for managing file uploads to WebR, including validation, preview, and usage instructions.
const FileUploadManager = ({ workspaceRef, isDarkMode, open, onClose }) => {
const FileUploadManager = ({ isDarkMode, open, onClose }) => {
// State variables to track upload status, file details, and UI flags
const [uploadStatus, setUploadStatus] = useState(null);
const [fileName, setFileName] = useState('');
Expand All @@ -41,7 +43,7 @@ const FileUploadManager = ({ workspaceRef, isDarkMode, open, onClose }) => {
const [filePreview, setFilePreview] = useState([]);
const [copySuccess, setCopySuccess] = useState(false);

// Handles the file upload process: reading file, writing to WebR FS, and generating preview if applicable
// Handles the file upload process: reading file and generating preview if applicable
const handleFileUpload = async (event) => {
const file = event.target.files[0];
if (!file) return;
Expand Down Expand Up @@ -99,7 +101,7 @@ const FileUploadManager = ({ workspaceRef, isDarkMode, open, onClose }) => {
} catch {
setFilePreview([['Invalid GeoJSON']]);
}
} else if (extension === 'tif') {
} else if (extension === 'tif' || extension === 'tiff') {
setFilePreview([['Raster preview not available.']]);
} else {
setFilePreview([]);
Expand Down
Loading