Skip to content

UX/UI Improvements #451

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 10 commits into
base: scalability
Choose a base branch
from
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
Binary file modified go_server/main.exe
Binary file not shown.
2 changes: 1 addition & 1 deletion pythonCode/submodules/MEDimage
Submodule MEDimage updated 57 files
+2 −2 .github/workflows/python-app.yml
+1 −1 .github/workflows/python-publish.yml
+0 −143 .gitignore
+1 −5 .readthedocs.yaml
+21 −674 LICENSE.md
+1 −1 MEDimage/__init__.py
+0 −840 MEDimage/biomarkers/BatchExtractorTexturalFilters.py
+0 −1 MEDimage/biomarkers/__init__.py
+120 −143 MEDimage/biomarkers/int_vol_hist.py
+0 −299 MEDimage/filters/TexturalFilter.py
+0 −1 MEDimage/filters/__init__.py
+0 −19 MEDimage/filters/apply_filter.py
+0 −1,738 MEDimage/filters/textural_filters_kernels.py
+1 −1 MEDimage/learning/DataCleaner.py
+29 −26 MEDimage/learning/DesignExperiment.py
+7 −8 MEDimage/learning/Normalization.py
+15 −6 MEDimage/learning/RadiomicsLearner.py
+649 −212 MEDimage/learning/Results.py
+0 −694 MEDimage/learning/Stats.py
+0 −1 MEDimage/learning/__init__.py
+3 −17 MEDimage/learning/ml_utils.py
+1 −1 MEDimage/processing/segmentation.py
+47 −34 MEDimage/wrangling/DataManager.py
+13 −20 README.md
+1 −1 docs/Installation.rst
+1 −3 docs/conf.py
+0 −1,439 docs/extraction_config.rst
+ docs/figures/ExperimentNameBreakdown.png
+ docs/figures/HeatmapDepicted.png
+ docs/figures/HistogramExample.png
+ docs/figures/LearningWorkflow.png
+ docs/figures/MEDimage-app-be.png
+ docs/figures/MEDimage-app-depicted.png
+ docs/figures/MEDimage-app-dm.png
+ docs/figures/TreeExample.png
+ docs/figures/pakcage-overview.png
+4 −24 docs/index.rst
+9 −52 docs/tutorials.rst
+27 −31 environment.yml
+4 −2 notebooks/tutorial/DataManager-Tutorial.ipynb
+28 −56,509 notebooks/tutorial/Learning-Tutorial.ipynb
+0 −470 notebooks/tutorial/learning/FEATURES/radiomics__T2F(gliomaTumorAuto)__intensity.csv
+0 −1 notebooks/tutorial/learning/FEATURES/radiomics__T2F(gliomaTumorAuto)__intensity.txt
+0 −470 notebooks/tutorial/learning/FEATURES/radiomics__T2F(gliomaTumorAuto)__morph.csv
+0 −1 notebooks/tutorial/learning/FEATURES/radiomics__T2F(gliomaTumorAuto)__morph.txt
+0 −470 notebooks/tutorial/learning/FEATURES/radiomics__T2F(gliomaTumorAuto)__texture.csv
+0 −1 notebooks/tutorial/learning/FEATURES/radiomics__T2F(gliomaTumorAuto)__texture.txt
+227 −0 notebooks/tutorial/learning/Glioma__LGG_IDH__outcomes.csv
+1 −5 notebooks/tutorial/learning/settings/ml_design.json
+18 −0 notebooks/tutorial/learning/settings/ml_fset_selection.json
+8 −0 notebooks/tutorial/learning/settings/ml_imbalance.json
+6 −3 notebooks/tutorial/learning/settings/ml_variables.json
+25 −33 pyproject.toml
+24 −30 requirements.txt
+8 −8 scripts/download_data.py
+3 −4 setup.py
+18 −87 tests/test_extraction.py
18 changes: 17 additions & 1 deletion renderer/components/dbComponents/InputToolsComponent.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import SimpleCleaningToolsDB from "./inputToolsDB/simpleCleaningToolsDB"
import SubsetCreationToolsDB from "./inputToolsDB/subsetCreationToolsDB"
import TransformColumnToolsDB from "./inputToolsDB/transformColumnToolsDB"
import { getCollectionData } from "./utils"

import { shell } from "electron"
/**
* @description
* This component provides calls all the other components to build the input tools.
Expand Down Expand Up @@ -94,6 +94,22 @@ const InputToolsComponent = ({ data, exportOptions, refreshData, columns, transf
<div style={panelContainerStyle}>
<div style={{ textAlign: "center", marginTop: "20px", marginBottom: "20px" }}>
<h1>Database Input Tools</h1>
<div style={{ textAlign: "center", marginBottom: "20px", maxWidth: "800px", margin: "0 auto" }}>
<p>
This module provides essential tools for preprocessing and structuring datasets
before machine learning. It allows users to clean, transform, and organize data efficiently.
</p>
<p className="gitbook-link">
📖 Learn how to use these tools in our
<u
onClick={() => shell.openExternal("https://medomics-udes.gitbook.io/medomicslab-docs/tutorials/design/input-module")}
style={{ color: "#0056b3", textDecoration: "none", cursor: "pointer" }}
> documentation. 🔗
</u>
</p>

</div>

</div>
{!data ? (
<Card
Expand Down
2 changes: 2 additions & 0 deletions renderer/components/learning/input.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,8 @@ const Input = ({ name, settingInfos, currentValue, onInputChange, disabled = fal
</>
)



// for all the other types of input (basically a string input for now)
default:
return (
Expand Down
2 changes: 1 addition & 1 deletion renderer/components/learning/nodesTypes/datasetNode.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ const DatasetNode = ({ id, data }) => {
</>
}
// Link to documentation
nodeLink={"https://medomics-udes.gitbook.io/medomicslab-docs/tutorials/development/learning-module"}
nodeLink={"https://medomics-udes.gitbook.io/medomicslab-docs/tutorials/development/learning-module#id-1.-available-nodes"}
/>
</>
)
Expand Down
2 changes: 1 addition & 1 deletion renderer/components/learning/nodesTypes/loadModelNode.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,7 @@ const LoadModelNode = ({ id, data }) => {
</>
}
// Link to documentation
nodeLink={"https://medomics-udes.gitbook.io/medomicslab-docs/tutorials/development/learning-module"}
nodeLink={"https://medomics-udes.gitbook.io/medomicslab-docs/tutorials/development/learning-module#id-1.-available-nodes"}
/>
</>
)
Expand Down
2 changes: 1 addition & 1 deletion renderer/components/learning/nodesTypes/selectionNode.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ const SelectionNode = ({ id, data, type }) => {
</>
}
// Link to documentation
nodeLink={"https://medomics-udes.gitbook.io/medomicslab-docs/tutorials/development/learning-module"}
nodeLink={"https://medomics-udes.gitbook.io/medomicslab-docs/tutorials/development/learning-module#id-1.-available-nodes"}
/>
</>
)
Expand Down
2 changes: 1 addition & 1 deletion renderer/components/learning/nodesTypes/standardNode.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ const StandardNode = ({ id, data }) => {
</>
}
// Link to documentation
nodeLink={"https://medomics-udes.gitbook.io/medomicslab-docs/tutorials/development/learning-module"}
nodeLink={"https://medomics-udes.gitbook.io/medomicslab-docs/tutorials/development/learning-module#id-1.-available-nodes"}
/>
</>
)
Expand Down
7 changes: 7 additions & 0 deletions renderer/components/learning/workflow.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,13 @@ const Workflow = ({ setWorkflowType, workflowType }) => {
newNode.data.internal.subflowId = !associatedNode ? groupNodeId.id : associatedNode
newNode.data.internal.hasWarning = { state: false }

setTimeout(() => {
if (nodes.length === 0 && reactFlowInstance) {
setViewport({ x: 200, y: 300, zoom: 0.9 }); // reduce the zoom when drag and droping first nodes
}
}, 0);


return newNode
}

Expand Down
121 changes: 76 additions & 45 deletions renderer/components/mainPages/application.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import ModulePage from "./moduleBasics/modulePage"
import { Col, Row, Stack } from "react-bootstrap"
import Input from "../learning/input"
import { Button } from "primereact/button"
import { SelectButton } from "primereact/selectbutton"
import { requestBackend } from "../../utilities/requests"
import { useContext } from "react"
import { WorkspaceContext } from "../workspace/workspaceContext"
Expand All @@ -18,7 +19,7 @@ import { getCollectionColumns, insertMEDDataObjectIfNotExists } from "../mongoDB
import DataTableFromDB from "../dbComponents/dataTableFromDB"
import { randomUUID } from "crypto"
import { toast } from "react-toastify"

import { shell } from "electron"
/**
*
* @param {string} pageId The id of the page
Expand All @@ -34,27 +35,24 @@ import { toast } from "react-toastify"
*
* @returns {React.Component} The entry component
*/

const Entry = ({ pageId, setRequestSettings, chosenModel, modelMetadata, updateWarnings, mode, setMode, setIsValid2Predict, inputsData, setInputsData }) => {
const [inputTypeChecked, setInputTypeChecked] = useState(false)
const [chosenDataset, setChosenDataset] = useState(null)
const [datasetHasWarning, setDatasetHasWarning] = useState({ state: true, tooltip: "No dataset selected" })
const [isColsValid, setIsColsValid] = useState(false)

// when the inputs data change, update the isValid2Predict
const inputOptions = [
{ label: "Manual Sample Entry", value: "unique" },
{ label: "Test File Input", value: "table" }
]

useEffect(() => {
if (modelMetadata) {
let columns = modelMetadata.columns
const columns = modelMetadata.columns
let isValid = true

columns.forEach((columnName) => {
if (columnName != modelMetadata.target) {
if (inputsData[columnName]) {
if (typeof inputsData[columnName] == "object") {
if (!inputsData[columnName][0]) {
isValid = false
}
}
} else {
if (columnName !== modelMetadata.target) {
if (!inputsData[columnName] || (typeof inputsData[columnName] === "object" && !inputsData[columnName][0])) {
isValid = false
}
}
Expand All @@ -63,34 +61,23 @@ const Entry = ({ pageId, setRequestSettings, chosenModel, modelMetadata, updateW
}
}, [inputsData])

// when the chosen dataset changes, update the warnings
useEffect(() => {
updateWarnings(chosenDataset, setDatasetHasWarning)
}, [chosenDataset])

// when inputTypeChecked changes, update the mode
useEffect(() => {
setMode(inputTypeChecked ? "table" : "unique")
inputTypeChecked ? setIsValid2Predict(!datasetHasWarning.state) : setIsValid2Predict(isColsValid)
}, [inputTypeChecked])

// when the datasetHasWarning changes, update the isValid2Predict
useEffect(() => {
mode == "table" && setIsValid2Predict(!datasetHasWarning.state)
}, [datasetHasWarning])

// when the isColsValid changes, update the isValid2Predict
useEffect(() => {
mode == "unique" && setIsValid2Predict(isColsValid)
}, [isColsValid])
if (mode === "table") {
setIsValid2Predict(!datasetHasWarning.state)
} else {
setIsValid2Predict(isColsValid)
}
}, [mode, datasetHasWarning, isColsValid])

// when the chosen model changes, update the model metadata
useEffect(() => {
setInputsData({})
updateWarnings(chosenDataset, setDatasetHasWarning)
}, [chosenModel])

// when the inputs data change, update the request settings
useEffect(() => {
setRequestSettings({
model: chosenModel,
Expand All @@ -100,44 +87,54 @@ const Entry = ({ pageId, setRequestSettings, chosenModel, modelMetadata, updateW
})
}, [chosenModel, chosenDataset, inputsData, mode])

/**
*
* @param {Object} inputUpdate The input update
*/
const handleInputUpdate = (inputUpdate) => {
let newInputsData = { ...inputsData }
newInputsData[inputUpdate.name] = [inputUpdate.value]
const newInputsData = { ...inputsData, [inputUpdate.name]: [inputUpdate.value] }
setInputsData(newInputsData)
}

/**
*
* @param {Object} inputUpdate The input update
*/
const onDatasetChange = (inputUpdate) => {
setChosenDataset(inputUpdate.value)
}

return (
<>
<ToggleButton onLabel="File entry" offLabel="Columns entry" onIcon="pi pi-file-import" offIcon="pi pi-th-large" checked={inputTypeChecked} onChange={(e) => setInputTypeChecked(e.value)} />
{!inputTypeChecked ? (
<div className="mb-3" style={{ width: "100%" }}>
<div style={{ width: "100%", display: "flex" }}>
<SelectButton
className="select-button-full"
value={mode}
onChange={(e) => setMode(e.value)}
options={inputOptions}
optionLabel="label"
dataKey="value"
unselectable={false}
style={{ width: "100%" }}
/>
</div>
<div className="mt-2" style={{ fontStyle: "italic", fontSize: "0.9rem" }}>
{inputOptions.find((opt) => opt.value === mode)?.description}
</div>
</div>

{mode === "unique" && (
<div className="columns-filling">
{modelMetadata.columns.map((columnName, index) => {
if (columnName != modelMetadata.target) {
if (columnName !== modelMetadata.target) {
return (
<Input
key={index}
name={columnName}
settingInfos={{ type: "string", tooltip: "" }}
currentValue={inputsData[columnName] ? inputsData[columnName] : ""}
currentValue={inputsData[columnName] ?? ""}
onInputChange={handleInputUpdate}
/>
)
}
})}
</div>
) : (
)}

{mode === "table" && (
<div className="data-input-tag-right">
{datasetHasWarning.state && (
<>
Expand All @@ -163,6 +160,7 @@ const Entry = ({ pageId, setRequestSettings, chosenModel, modelMetadata, updateW
)
}


/**
*
* @param {String} pageId The id of the page
Expand Down Expand Up @@ -357,7 +355,40 @@ const ApplicationPageWithModulePage = ({ pageId = "application-456" }) => {
<>
<ModulePage pageId={pageId} shadow>
<div style={{ padding: "0.5rem" }}>

<div className="application-introduction">

<h2>🚀 Model Deployment</h2>

<p>
This module allows users to deploy a machine learning model for inference.
First, you'll have to choose a model. Then, you can select between two input methods:
</p>

<p>
<span className="app-tool-name">→ Manual Sample Entry:</span> Fill in the required feature values manually to test a single sample.
</p>

<p>
<span className="app-tool-name">→ Test File Input:</span> Upload a dataset file (CSV format) to run batch predictions on multiple samples.
</p>

<div>
<p>
📖 Learn more about this tool in our{' '}
<u
onClick={() => shell.openExternal("https://medomics-udes.gitbook.io/medomicslab-docs/tutorials/deployment/application-module")}
style={{ color: "#0056b3", textDecoration: "none", cursor: "pointer" }}
>
documentation. 🔗
</u>
</p>
</div>

</div>

<ApplicationPage pageId={pageId} />

</div>
</ModulePage>
</>
Expand Down
28 changes: 27 additions & 1 deletion renderer/components/mainPages/evaluation.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,38 @@
import React from "react"
import ModulePage from "./moduleBasics/modulePage"
import EvaluationPageContent from "../evaluation/evaluationPageContent"
import { shell } from 'electron'

const EvaluationPage = ({ pageId = "evaluation-456" }) => {
return (
<>
<ModulePage pageId={pageId} shadow className="EvaluationPage">
<EvaluationPageContent />

{/* Titre à gauche avec espace en bas */}
<h2 style={{ textAlign: "left", marginBottom: "18px" }}>🧪 Model Evaluation</h2>

{/* Description centrée */}
<div style={{ maxWidth: "700px", margin: "0 auto", textAlign: "center" }}>
<p>
This module allows you to evaluate the performance of your trained models by generating detailed reports, visualizing key metrics, and analyzing predictions.
</p>

<p style={{ marginTop: "10px" }}>
Learn more about this process in our{' '}
<u
onClick={() => shell.openExternal("https://medomics-udes.gitbook.io/medomicslab-docs/tutorials/development/evaluation-module")}
style={{ color: "#0056b3", textDecoration: "none", cursor: "pointer" }}
>
documentation. 🔗
</u>
</p>
</div>

{/* Espace ajouté avant le formulaire */}
<div style={{ marginTop: "40px" }}>
<EvaluationPageContent />
</div>

</ModulePage>
</>
)
Expand Down
25 changes: 25 additions & 0 deletions renderer/components/mainPages/exploratory.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { ErrorRequestContext } from "../generalPurpose/errorRequestContext"
import DTale from "../exploratory/dtale"
import SweetViz from "../exploratory/sweetViz"
import YDataProfiling from "../exploratory/yDataProfiling"
import { shell } from 'electron'

/**
*
Expand All @@ -17,6 +18,30 @@ const ExploratoryPage = () => {
return (
<>
<div className="exploratory">
<h2>🔍 Exploratory Data Analysis (EDA)</h2>
<p>
Before training a machine learning model, it is essential to explore and understand the dataset.
This page provides three powerful tools, each with a unique role in data exploration:
</p>

<p><span className="eda-tool-name">➡ SweetViz :</span> Generates automated reports with dataset characteristics,
feature distributions, correlations, and comparisons. Helps quickly detect outliers, missing values, and potential biases.</p>

<p><span className="eda-tool-name">➡ Y-Data Profiling :</span> Performs a deep statistical audit to analyze feature types,
missing values, and relationships, helping detect preprocessing issues before model training.</p>

<p><span className="eda-tool-name">➡ D-Tale :</span> Provides a spreadsheet-like interactive interface for filtering,
sorting, visualizing, and modifying data in real time.</p>

<p className="gitbook-link">
📖 Learn how to use these tools in our
<u
onClick={() => shell.openExternal("https://medomics-udes.gitbook.io/medomicslab-docs/tutorials/design/exploratory-module")}
style={{ color: "#0056b3", textDecoration: "none", cursor: "pointer" }}
> documentation. 🔗
</u>
</p>

<SweetViz pageId="SweetViz" port={port} setError={setError} />
<YDataProfiling pageId="ydata-profiling" port={port} setError={setError} />
<DTale pageId="D-Tale" port={port} setError={setError} />
Expand Down
Loading