diff --git a/public/images/albums/2026-03-31-post-med3pa-article/featured.png b/public/images/albums/2026-03-31-post-med3pa-article/featured.png new file mode 100644 index 0000000..1af66c7 Binary files /dev/null and b/public/images/albums/2026-03-31-post-med3pa-article/featured.png differ diff --git a/public/images/albums/2026-first-med3pa-presentation/certificat.png b/public/images/albums/2026-first-med3pa-presentation/certificat.png new file mode 100644 index 0000000..d7e6793 Binary files /dev/null and b/public/images/albums/2026-first-med3pa-presentation/certificat.png differ diff --git a/public/images/albums/2026-med3pa-article/featured.png b/public/images/albums/2026-med3pa-article/featured.png new file mode 100644 index 0000000..1af66c7 Binary files /dev/null and b/public/images/albums/2026-med3pa-article/featured.png differ diff --git a/public/images/albums/2026-rsn-med3pa-presentation/presentation.jpeg b/public/images/albums/2026-rsn-med3pa-presentation/presentation.jpeg new file mode 100644 index 0000000..a2221ac Binary files /dev/null and b/public/images/albums/2026-rsn-med3pa-presentation/presentation.jpeg differ diff --git a/public/images/albums/research-medimage/medimage-overview.png b/public/images/albums/research-mediml/mediml-overview.png similarity index 100% rename from public/images/albums/research-medimage/medimage-overview.png rename to public/images/albums/research-mediml/mediml-overview.png diff --git a/public/images/team/moustafa-amine-bezzahi/avatar-128.avif b/public/images/team/moustafa-amine-bezzahi/avatar-128.avif index 210ca36..68ade6f 100644 Binary files a/public/images/team/moustafa-amine-bezzahi/avatar-128.avif and b/public/images/team/moustafa-amine-bezzahi/avatar-128.avif differ diff --git a/public/images/team/moustafa-amine-bezzahi/avatar-128.jpg b/public/images/team/moustafa-amine-bezzahi/avatar-128.jpg index d9eabde..d2fdf81 100644 Binary files a/public/images/team/moustafa-amine-bezzahi/avatar-128.jpg and b/public/images/team/moustafa-amine-bezzahi/avatar-128.jpg differ diff --git a/public/images/team/moustafa-amine-bezzahi/avatar-128.webp b/public/images/team/moustafa-amine-bezzahi/avatar-128.webp index 70123f0..7c490ef 100644 Binary files a/public/images/team/moustafa-amine-bezzahi/avatar-128.webp and b/public/images/team/moustafa-amine-bezzahi/avatar-128.webp differ diff --git a/public/images/team/moustafa-amine-bezzahi/avatar-160.avif b/public/images/team/moustafa-amine-bezzahi/avatar-160.avif index b07f71f..8089f21 100644 Binary files a/public/images/team/moustafa-amine-bezzahi/avatar-160.avif and b/public/images/team/moustafa-amine-bezzahi/avatar-160.avif differ diff --git a/public/images/team/moustafa-amine-bezzahi/avatar-160.jpg b/public/images/team/moustafa-amine-bezzahi/avatar-160.jpg index 2785aab..0348a28 100644 Binary files a/public/images/team/moustafa-amine-bezzahi/avatar-160.jpg and b/public/images/team/moustafa-amine-bezzahi/avatar-160.jpg differ diff --git a/public/images/team/moustafa-amine-bezzahi/avatar-160.webp b/public/images/team/moustafa-amine-bezzahi/avatar-160.webp index 293546d..8737767 100644 Binary files a/public/images/team/moustafa-amine-bezzahi/avatar-160.webp and b/public/images/team/moustafa-amine-bezzahi/avatar-160.webp differ diff --git a/public/images/team/moustafa-amine-bezzahi/avatar-256.avif b/public/images/team/moustafa-amine-bezzahi/avatar-256.avif index 8c10915..b8284cc 100644 Binary files a/public/images/team/moustafa-amine-bezzahi/avatar-256.avif and b/public/images/team/moustafa-amine-bezzahi/avatar-256.avif differ diff --git a/public/images/team/moustafa-amine-bezzahi/avatar-256.jpg b/public/images/team/moustafa-amine-bezzahi/avatar-256.jpg index 3dd5d12..2074ec0 100644 Binary files a/public/images/team/moustafa-amine-bezzahi/avatar-256.jpg and b/public/images/team/moustafa-amine-bezzahi/avatar-256.jpg differ diff --git a/public/images/team/moustafa-amine-bezzahi/avatar-256.webp b/public/images/team/moustafa-amine-bezzahi/avatar-256.webp index e93190c..829f3a6 100644 Binary files a/public/images/team/moustafa-amine-bezzahi/avatar-256.webp and b/public/images/team/moustafa-amine-bezzahi/avatar-256.webp differ diff --git a/public/images/team/moustafa-amine-bezzahi/avatar-80.avif b/public/images/team/moustafa-amine-bezzahi/avatar-80.avif index 0ee63e7..d2480c6 100644 Binary files a/public/images/team/moustafa-amine-bezzahi/avatar-80.avif and b/public/images/team/moustafa-amine-bezzahi/avatar-80.avif differ diff --git a/public/images/team/moustafa-amine-bezzahi/avatar-80.jpg b/public/images/team/moustafa-amine-bezzahi/avatar-80.jpg index 8ab2573..9634e3c 100644 Binary files a/public/images/team/moustafa-amine-bezzahi/avatar-80.jpg and b/public/images/team/moustafa-amine-bezzahi/avatar-80.jpg differ diff --git a/public/images/team/moustafa-amine-bezzahi/avatar-80.webp b/public/images/team/moustafa-amine-bezzahi/avatar-80.webp index 7fe718e..3245534 100644 Binary files a/public/images/team/moustafa-amine-bezzahi/avatar-80.webp and b/public/images/team/moustafa-amine-bezzahi/avatar-80.webp differ diff --git a/public/publications/2025-tcairem-SAHBI-presentation/Poster_MEDfl_T-cairem.pdf b/public/publications/2025-tcairem-SAHBI-presentation/Poster_MEDfl_T-cairem.pdf new file mode 100644 index 0000000..25cd3c7 Binary files /dev/null and b/public/publications/2025-tcairem-SAHBI-presentation/Poster_MEDfl_T-cairem.pdf differ diff --git a/public/publications/2025-tcairem-SAHBI-presentation/TCAIREM_Ouael_SAHBI_MEDfl.pdf b/public/publications/2025-tcairem-SAHBI-presentation/TCAIREM_Ouael_SAHBI_MEDfl.pdf new file mode 100644 index 0000000..d7ea228 Binary files /dev/null and b/public/publications/2025-tcairem-SAHBI-presentation/TCAIREM_Ouael_SAHBI_MEDfl.pdf differ diff --git a/public/publications/2026-first-med3pa-presentation/Lefebvre_olivier_kafefak_2026.pdf b/public/publications/2026-first-med3pa-presentation/Lefebvre_olivier_kafefak_2026.pdf new file mode 100644 index 0000000..bc3c1e4 Binary files /dev/null and b/public/publications/2026-first-med3pa-presentation/Lefebvre_olivier_kafefak_2026.pdf differ diff --git a/public/publications/2026-rsn-med3pa-presentation/Lefebvre_olivier_rsn_2026.pdf b/public/publications/2026-rsn-med3pa-presentation/Lefebvre_olivier_rsn_2026.pdf new file mode 100644 index 0000000..a803f0c Binary files /dev/null and b/public/publications/2026-rsn-med3pa-presentation/Lefebvre_olivier_rsn_2026.pdf differ diff --git a/src/components/FilterMenu/FilterMenu.jsx b/src/components/FilterMenu/FilterMenu.jsx new file mode 100644 index 0000000..ffd99e3 --- /dev/null +++ b/src/components/FilterMenu/FilterMenu.jsx @@ -0,0 +1,74 @@ +import { useEffect, useRef, useState } from "react"; +import { SlidersHorizontal } from "lucide-react"; +import { cn } from "../../lib/utils"; + +/** + * Round glass button that opens a checklist of filter options. + */ +export default function FilterMenu({ options, active, onToggle, label, className }) { + const [isOpen, setIsOpen] = useState(false); + const menuRef = useRef(null); + + useEffect(() => { + const handleClick = (event) => { + if (!menuRef.current) return; + if (menuRef.current.contains(event.target)) return; + setIsOpen(false); + }; + + if (isOpen) { + document.addEventListener("mousedown", handleClick); + } + + return () => document.removeEventListener("mousedown", handleClick); + }, [isOpen]); + + return ( + <> + {isOpen && ( +
setIsOpen(false)} aria-hidden="true" /> + )} +
+ +
+
+ {options.map((option) => { + const isActive = active.includes(option); + return ( + + ); + })} +
+
+
+ + ); +} diff --git a/src/components/RevealList/RevealList.css b/src/components/RevealList/RevealList.css new file mode 100644 index 0000000..9e1f143 --- /dev/null +++ b/src/components/RevealList/RevealList.css @@ -0,0 +1,56 @@ +/* + * "See more" reveal animation + */ + +.reveal-list-extra { + display: grid; + grid-template-rows: 0fr; + overflow: hidden; + opacity: 0; + transform: translateY(-8px); + visibility: hidden; + transition: + grid-template-rows 420ms cubic-bezier(0.16, 1, 0.3, 1), + opacity 220ms ease, + transform 420ms cubic-bezier(0.16, 1, 0.3, 1), + visibility 0s linear 420ms; +} + +/* + * A grid item in a 0fr track keeps an automatic minimum size unless its own + * overflow is clipped. + */ +.reveal-list-extra > div { + min-height: 0; + overflow: hidden; +} + +.reveal-list.is-open .reveal-list-extra { + grid-template-rows: 1fr; + opacity: 1; + transform: translateY(0); + visibility: visible; + transition-delay: var(--reveal-list-delay, 0ms); +} + +.reveal-list-toggle:hover { + text-decoration: underline; + text-decoration-thickness: 2px; + text-underline-offset: 4px; +} + +.reveal-list-toggle:focus-visible { + border-radius: 2px; + outline: 2px solid currentcolor; + outline-offset: 3px; +} + +@media (prefers-reduced-motion: reduce) { + .reveal-list-extra { + transition-duration: 0.01ms; + } + + .reveal-list.is-open .reveal-list-extra { + transition-delay: 0ms; + } +} diff --git a/src/components/RevealList/RevealList.jsx b/src/components/RevealList/RevealList.jsx new file mode 100644 index 0000000..419e521 --- /dev/null +++ b/src/components/RevealList/RevealList.jsx @@ -0,0 +1,69 @@ +import { Children, cloneElement, isValidElement, useId, useState } from "react"; +import { cn } from "../../lib/utils"; +import "./RevealList.css"; + +const STAGGER_MS = 45; + +/** + * Shows the first `visibleCount` children and hides the rest behind a + * "See more" toggle, revealing them with a staggered slide-down. + */ +export default function RevealList({ + children, + visibleCount = 3, + moreLabel = "See more", + lessLabel = "See less", + className, + toggleClassName, +}) { + const [isOpen, setIsOpen] = useState(false); + const listId = useId(); + + const items = Children.toArray(children); + const hiddenCount = Math.max(0, items.length - visibleCount); + + return ( + <> + + + {hiddenCount > 0 && ( + + )} + + ); +} diff --git a/src/content/community/news/2026-03-31-post-med3pa-article.md b/src/content/community/news/2026-03-31-post-med3pa-article.md new file mode 100644 index 0000000..19de503 --- /dev/null +++ b/src/content/community/news/2026-03-31-post-med3pa-article.md @@ -0,0 +1,15 @@ +![MED3pa article featured image](/images/albums/2026-03-31-post-med3pa-article/featured.png) + +Congratulations to [Olivier Lefebvre](/team/olivier-lefebvre) and +[Martin Vallières](/team/martin-vallieres) for the publication of their paper entitled +"Predictive performance precision analysis in medicine: identification of low-confidence predictions +at patient and profile levels (MED3pa I)" in the +_Journal of the American Medical Informatics Association (JAMIA)_. + +The article can be found at: +[https://doi.org/10.1093/jamia/ocag034](https://doi.org/10.1093/jamia/ocag034) + +## Links + +- [Details](/publications/predictive-performance-precision-analysis-in-medicine-identification-of-low-confidence-predictions-at-patient-and-profile-levels-med3pa-i-2026) +- [Article link](https://doi.org/10.1093/jamia/ocag034) diff --git a/src/content/community/research/project-active/index.md b/src/content/community/research/project-active/index.md index 89ed2bb..2ef12ff 100644 --- a/src/content/community/research/project-active/index.md +++ b/src/content/community/research/project-active/index.md @@ -20,7 +20,7 @@ banner: ### General - [Development of the _MEDomics_ platform](/research/medomics-platform) -- [Development of the _MEDimage_ package](/research/medimage) +- [Development of the _MEDiml_ package](/research/mediml) ### Doctorate diff --git a/src/content/community/research/project-active/medimage/index.md b/src/content/community/research/project-active/mediml/index.md similarity index 51% rename from src/content/community/research/project-active/medimage/index.md rename to src/content/community/research/project-active/mediml/index.md index afb84c3..ec2b4fe 100644 --- a/src/content/community/research/project-active/medimage/index.md +++ b/src/content/community/research/project-active/mediml/index.md @@ -1,5 +1,5 @@ --- -title: "Project: Development of the MEDimage package" +title: "Project: Development of the MEDiml package" type: book @@ -11,7 +11,7 @@ authors: - Mohammed Benabbassi --- -![Schematic diagram of the MEDimage package](/images/albums/research-medimage/medimage-overview.png "Schematic diagram of the MEDimage package") +![Schematic diagram of the MEDiml package](/images/albums/research-mediml/mediml-overview.png "Schematic diagram of the MEDiml package") ## Status @@ -33,10 +33,10 @@ General ## Description -[MEDimage](https://github.com/MahdiAll99/MEDimage) is an _open-source_ software for medical image processing and radiomic calculations. It was created by our laboratory in collaboration with the international consortium of medical scientists (). The software is based on the Python programming language and built with different layers of flexibility via modules, classes and parameters option that allow to load, process, medical images and calculate radiomic features from them. The intrinsic workflow of MEDimage is designed to be adequate to these tasks and offers a [documentation](https://www.mediml.app) rich in tutorials, demonstrations and instructions that are able to introduce novice users to the software. With this software, we aim to provide an open-source platform tested, maintained and standardized with the international norms defined by the [IBSI](https://theibsi.github.io/) for easy and reproducible image processing and radiomics extraction. +[MEDiml](https://github.com/MEDomicsLab/MEDiml) is an _open-source_ software for medical image processing and radiomic calculations. It was created by our laboratory in collaboration with the international consortium of medical scientists (). The software is based on the Python programming language and built with different layers of flexibility via modules, classes and parameters option that allow to load, process, medical images and calculate radiomic features from them. The intrinsic workflow of MEDiml is designed to be adequate to these tasks and offers a [documentation](https://www.mediml.app) rich in tutorials, demonstrations and instructions that are able to introduce novice users to the software. With this software, we aim to provide an open-source platform tested, maintained and standardized with the international norms defined by the [IBSI](https://theibsi.github.io/) for easy and reproducible image processing and radiomics extraction. Here is a video made by our intern [Corentin Gauthier](/team/corentin-gauthier) -which presents what he realized during his internship as well as the MEDimage project. +which presents what he realized during his internship as well as the MEDiml project.

diff --git a/src/content/community/research/project-active/medomics_platform/index.md b/src/content/community/research/project-active/medomics_platform/index.md index 73351fa..6a5d510 100644 --- a/src/content/community/research/project-active/medomics_platform/index.md +++ b/src/content/community/research/project-active/medomics_platform/index.md @@ -86,7 +86,7 @@ General [//]: # 'the following data analysis techniques should increase the impact of the "multi-omics" prediction models that are ' [//]: # "built from these databases:" [//]: # -[//]: # "1. _Image analysis_: extraction of radiomic features allows us to better characterize tumor heterogeneity. The [MEDimage](/research/medimage) package is the dedicated component for this task." +[//]: # "1. _Image analysis_: extraction of radiomic features allows us to better characterize tumor heterogeneity. The [MEDiml](/research/mediml) package is the dedicated component for this task." [//]: # "2. _Machine learning_: some learning techniques allow us to better combine data from different categories (such as multi-omics)." [//]: # "3. _Deep learning_: the multitude of deep neural network architectures offers several possibilities for the automatic learning of different tasks in medicine. The performance of some networks is sometimes superior to that of humans." [//]: # "4. _Automatic text processing_: automatic processing and coding of textual reports from electronic patient records would allow for better integration of information relevant to multi-omics modeling throughout the patient management period." diff --git a/src/content/community/research/project-completed/radiomics-complexity/index.md b/src/content/community/research/project-completed/radiomics-complexity/index.md index e6ae67b..f269549 100644 --- a/src/content/community/research/project-completed/radiomics-complexity/index.md +++ b/src/content/community/research/project-completed/radiomics-complexity/index.md @@ -35,7 +35,7 @@ increasing complexity in the precision oncology spectrum. ## Issue and objective -Recent advances in "omics" technology have created opportunities to characterize biological processes correlated with tumor phenotypes. We anticipate that integrative modeling of available oncology data will provide the ability to make accurate tumor phenotype predictions, which in turn would allow for better monitoring and tailoring of patient-specific treatments (i.e. "precision oncology"). To potentially improve radiomic analysis (i.e.: Quantitative extraction of useful data from all types of medical images), radiomic features of the tumor region can be extracted from medical images filtered with different types of filters (e.g.: texture filtering or texture smoothing). These features can be extracted using the [MEDimage](/research/medimage) package, but they expose different levels of complexity, which leads us to investigate in this project, the spectrum of complexity of medical images for the resolving of several problems in precision oncology and study the changes in these different levels of complexity from an image modality to another. +Recent advances in "omics" technology have created opportunities to characterize biological processes correlated with tumor phenotypes. We anticipate that integrative modeling of available oncology data will provide the ability to make accurate tumor phenotype predictions, which in turn would allow for better monitoring and tailoring of patient-specific treatments (i.e. "precision oncology"). To potentially improve radiomic analysis (i.e.: Quantitative extraction of useful data from all types of medical images), radiomic features of the tumor region can be extracted from medical images filtered with different types of filters (e.g.: texture filtering or texture smoothing). These features can be extracted using the [MEDiml](/research/mediml) package, but they expose different levels of complexity, which leads us to investigate in this project, the spectrum of complexity of medical images for the resolving of several problems in precision oncology and study the changes in these different levels of complexity from an image modality to another. ## Database diff --git a/src/content/publications/kafefak-presentation-first-publication-award-2026.md b/src/content/publications/kafefak-presentation-first-publication-award-2026.md new file mode 100644 index 0000000..e0d1c71 --- /dev/null +++ b/src/content/publications/kafefak-presentation-first-publication-award-2026.md @@ -0,0 +1,43 @@ +![First Publication Award certificate](/images/albums/2026-first-med3pa-presentation/certificat.png) + +## Date + +2026-04-29 + +## Authors + +- [Olivier Lefebvre](/team/olivier-lefebvre) + +## Summary + +Olivier Lefebvre received the First Publication Award from the Faculty of Science, which highlights publications that distinguished themselves both within their field and among all entries submitted for the competition. The award was presented during the Kaféfak conference, where he was invited to give a three-minute presentation to make his research accessible to a broad audience. A $200 prize accompanies the award. + +## Abstract + +**Objectives** + +Artificial Intelligence models are increasingly used in health care, yet global performance metrics can mask variations in reliability across individual patients or subgroups with shared attributes, called patient profiles. This study introduces predictive performance precision analysis in medicine (MED3pa), a method that identifies when models are less reliable, allowing clinicians to better assess model limitations. + +**Materials and Methods** + +We propose a framework that estimates predictive confidence using 3 combined approaches: individualized (IPC), aggregated (APC), and mixed predictive confidence (MPC). Individualized predictive confidence estimates confidence for each patient, APC assesses it across profiles, and MPC combines both. We evaluate our method on 4 datasets: 1 simulated, 2 public, and 1 private clinical dataset. Metrics by declaration rate curves show how performance changes when retaining only the most confident predictions, while interpretable decision trees reveal profiles with higher or lower model confidence. + +**Results** + +We demonstrate our method in internal, temporal, and external validation settings, as well as through a clinical example. In internal validation, limiting predictions to the 93% most confident cases improved sensitivity by 14.3% and the area under the receiver operating characteristic curve by 5.1%. In the clinical example, MED3pa identified a patient profile with high misclassification risk, demonstrating its potential for safer deployment. + +**Discussion** + +By identifying low-confidence predictions, our framework improves model reliability in clinical settings. It can be integrated into decision support systems to help clinicians make more informed decisions. Confidence thresholds help balance model performance with the proportion of patients for whom predictions are considered reliable. + +**Conclusion** + +Better leveraging confidence in model predictions could improve reliability and trustworthiness, supporting safer and more effective use in health care. + +## Poster + + + +## Links + +- [Awarded paper in JAMIA](https://doi.org/10.1093/jamia/ocag034) diff --git a/src/content/publications/predictive-performance-precision-analysis-in-medicine-identification-of-low-confidence-predictions-at-patient-and-profile-levels-med3pa-i-2026.md b/src/content/publications/predictive-performance-precision-analysis-in-medicine-identification-of-low-confidence-predictions-at-patient-and-profile-levels-med3pa-i-2026.md new file mode 100644 index 0000000..2120a5a --- /dev/null +++ b/src/content/publications/predictive-performance-precision-analysis-in-medicine-identification-of-low-confidence-predictions-at-patient-and-profile-levels-med3pa-i-2026.md @@ -0,0 +1,55 @@ +![Journal of the American Medical Informatics Association (JAMIA)](/images/albums/2026-med3pa-article/featured.png) + +## Date + +2026-03-31 + +## Authors + +- [Olivier Lefebvre](/team/olivier-lefebvre)1 +- [Félix Camirand Lemyre](https://www.usherbrooke.ca/mathematiques/nous-joindre/personnel/corps-professoral/professeurs/felix-camirand-lemyre)2 +- [Jean-François Éthier](https://www.usherbrooke.ca/recherche/specialistes/details/jean-francois.ethier)3 +- [Ludmila Amriou](/team/ludmila-amriou)4 +- [Lyna Hiba Chikouche](/team/lyna-hiba-chikouche)4 +- [Dan Poenaru](https://www.mcgill.ca/pediatricsurgery/dan-poenaru)5,6 +- [Martin Vallières](/team/martin-vallieres)1,7 + +1 Computer science department, Université de Sherbrooke, Sherbrooke (QC), Canada + +2 Mathematics department, Université de Sherbrooke, Sherbrooke (QC), Canada + +3 Medicine department, Université de Sherbrooke, Sherbrooke (QC), Canada + +4 Department of Higher Studies (CS), École nationale Supérieure d’Informatique, Alger, 16309, Algeria + +5 Department of Pediatric Surgery, Montreal Children’s Hospital, Montreal, QC H4A 3J1, Canada + +6 Centre for Outcomes Research and Evaluation, Research Institute of the McGill University Health Centre, Montreal, QC H4A 3J1, Canada + +7 Medical Physics Unit, Department of Oncology, McGill University, Montreal, QC H3A 0G4, Canada + +## Abstract + +**Objectives** + +Artificial Intelligence models are increasingly used in health care, yet global performance metrics can mask variations in reliability across individual patients or subgroups with shared attributes, called patient profiles. This study introduces predictive performance precision analysis in medicine (MED3pa), a method that identifies when models are less reliable, allowing clinicians to better assess model limitations. + +**Materials and Methods** + +We propose a framework that estimates predictive confidence using 3 combined approaches: individualized (IPC), aggregated (APC), and mixed predictive confidence (MPC). Individualized predictive confidence estimates confidence for each patient, APC assesses it across profiles, and MPC combines both. We evaluate our method on 4 datasets: 1 simulated, 2 public, and 1 private clinical dataset. Metrics by declaration rate curves show how performance changes when retaining only the most confident predictions, while interpretable decision trees reveal profiles with higher or lower model confidence. + +**Results** + +We demonstrate our method in internal, temporal, and external validation settings, as well as through a clinical example. In internal validation, limiting predictions to the 93% most confident cases improved sensitivity by 14.3% and the area under the receiver operating characteristic curve by 5.1%. In the clinical example, MED3pa identified a patient profile with high misclassification risk, demonstrating its potential for safer deployment. + +**Discussion** + +By identifying low-confidence predictions, our framework improves model reliability in clinical settings. It can be integrated into decision support systems to help clinicians make more informed decisions. Confidence thresholds help balance model performance with the proportion of patients for whom predictions are considered reliable. + +**Conclusion** + +Better leveraging confidence in model predictions could improve reliability and trustworthiness, supporting safer and more effective use in health care. + +## Links + +- [Paper in JAMIA](https://doi.org/10.1093/jamia/ocag034) diff --git a/src/content/publications/scientific-days-rsn-2026.md b/src/content/publications/scientific-days-rsn-2026.md new file mode 100644 index 0000000..2e554d0 --- /dev/null +++ b/src/content/publications/scientific-days-rsn-2026.md @@ -0,0 +1,44 @@ +![Olivier Lefebvre presenting at the RSN Scientific Days](/images/albums/2026-rsn-med3pa-presentation/presentation.jpeg) + +## Date + +2026-03-31 + +## Authors + +- [Olivier Lefebvre](/team/olivier-lefebvre) + +## Summary + +Olivier Lefebvre presented his research during the **Réseau Santé Numérique (RSN) Scientific Day** at Université Laval. He delivered a seven-minute presentation highlighting the key contributions of his work and its implications for the development of reliable and trustworthy machine-learning models in healthcare. The talk offered an accessible overview of his methodological advances and their relevance to real-world clinical applications. + +## Abstract + +**Objectives** + +Artificial Intelligence models are increasingly used in health care, yet global performance metrics can mask variations in reliability across individual patients or subgroups with shared attributes, called patient profiles. This study introduces predictive performance precision analysis in medicine (MED3pa), a method that identifies when models are less reliable, allowing clinicians to better assess model limitations. + +**Materials and Methods** + +We propose a framework that estimates predictive confidence using 3 combined approaches: individualized (IPC), aggregated (APC), and mixed predictive confidence (MPC). Individualized predictive confidence estimates confidence for each patient, APC assesses it across profiles, and MPC combines both. We evaluate our method on 4 datasets: 1 simulated, 2 public, and 1 private clinical dataset. Metrics by declaration rate curves show how performance changes when retaining only the most confident predictions, while interpretable decision trees reveal profiles with higher or lower model confidence. + +**Results** + +We demonstrate our method in internal, temporal, and external validation settings, as well as through a clinical example. In internal validation, limiting predictions to the 93% most confident cases improved sensitivity by 14.3% and the area under the receiver operating characteristic curve by 5.1%. In the clinical example, MED3pa identified a patient profile with high misclassification risk, demonstrating its potential for safer deployment. + +**Discussion** + +By identifying low-confidence predictions, our framework improves model reliability in clinical settings. It can be integrated into decision support systems to help clinicians make more informed decisions. Confidence thresholds help balance model performance with the proportion of patients for whom predictions are considered reliable. + +**Conclusion** + +Better leveraging confidence in model predictions could improve reliability and trustworthiness, supporting safer and more effective use in health care. + +## Presentation + + + +## Links + +- [Event Details](https://event.fourwaves.com/jsrsn/pages) +- [Related paper in JAMIA](https://doi.org/10.1093/jamia/ocag034) diff --git a/src/data/news.json b/src/data/news.json index a280f69..c8b6779 100644 --- a/src/data/news.json +++ b/src/data/news.json @@ -1,4 +1,20 @@ [ + { + "year": "2026", + "months": [ + { + "month": "March", + "items": [ + { + "title": "Publication of the article “Predictive performance precision analysis in medicine: identification of low-confidence predictions at patient and profile levels (MED3pa I)”", + "slug": "2026-03-31-post-med3pa-article", + "contributors": ["Olivier Lefebvre", "Martin Vallières"], + "markdown": "community/news/2026-03-31-post-med3pa-article.md" + } + ] + } + ] + }, { "year": "2025", "months": [ diff --git a/src/data/publications.json b/src/data/publications.json index 7143216..79fa22b 100644 --- a/src/data/publications.json +++ b/src/data/publications.json @@ -1,4 +1,44 @@ [ + { + "year": "2026", + "items": [ + { + "title": "Kaféfak Presentation - First Publication Award", + "slug": "kafefak-presentation-first-publication-award-2026", + "contributors": ["Olivier Lefebvre"], + "journal": "Université de Sherbrooke, Faculté des sciences", + "link": "https://doi.org/10.1093/jamia/ocag034", + "markdown": "publications/kafefak-presentation-first-publication-award-2026.md", + "type": "Presentations", + "date": "2026-04-29" + }, + { + "title": "Predictive performance precision analysis in medicine: identification of low-confidence predictions at patient and profile levels (MED3pa I)", + "slug": "predictive-performance-precision-analysis-in-medicine-identification-of-low-confidence-predictions-at-patient-and-profile-levels-med3pa-i-2026", + "contributors": [ + "Olivier Lefebvre", + "Ludmila Amriou", + "Lyna Hiba Chikouche", + "Martin Vallières" + ], + "journal": "Journal of the American Medical Informatics Association (JAMIA)", + "link": "https://doi.org/10.1093/jamia/ocag034", + "markdown": "publications/predictive-performance-precision-analysis-in-medicine-identification-of-low-confidence-predictions-at-patient-and-profile-levels-med3pa-i-2026.md", + "type": "Journal Papers", + "date": "2026-03-31" + }, + { + "title": "Scientific Days RSN", + "slug": "scientific-days-rsn-2026", + "contributors": ["Olivier Lefebvre"], + "journal": "Réseau Santé Numérique (RSN)", + "link": "https://event.fourwaves.com/jsrsn/pages", + "markdown": "publications/scientific-days-rsn-2026.md", + "type": "Presentations", + "date": "2026-03-31" + } + ] + }, { "year": "2025", "items": [ diff --git a/src/data/research-projects.json b/src/data/research-projects.json index 4a7f2fb..11733ea 100644 --- a/src/data/research-projects.json +++ b/src/data/research-projects.json @@ -36,14 +36,14 @@ "markdown": "community/research/project-active/medomics_platform/index.md" }, { - "title": "Development of the MEDimage package", - "slug": "medimage", + "title": "Development of the MEDiml package", + "slug": "mediml", "summary": "Open-source Python software for medical image processing and IBSI-compliant radiomics extraction.", "status": "Active", "track": "General", "coverImage": { - "url": "/images/albums/research-medimage/medimage-overview.png", - "alt": "Schematic diagram of the MEDimage package" + "url": "/images/albums/research-mediml/mediml-overview.png", + "alt": "Schematic diagram of the MEDiml package" }, "researchers": [ "clarisse-cheng", @@ -52,7 +52,7 @@ "martin-vallieres", "mohammed-benabbassi" ], - "markdown": "community/research/project-active/medimage/index.md" + "markdown": "community/research/project-active/mediml/index.md" }, { "title": "Predictive Performance Precision Analysis in Medicine (MED3pa)", diff --git a/src/data/team.json b/src/data/team.json index 41175ef..5d85301 100644 --- a/src/data/team.json +++ b/src/data/team.json @@ -164,6 +164,42 @@ "cv": "" } }, + { + "name": "Mahdi Ait Lhaj Loutfi", + "position": "Ph. D. Biological & Biomedical Engineering", + "slug": "mahdi-ait-lhaj-loutfi", + "email": "mahdi.aitlhajloutfi@mail.mcgill.ca", + "image": "/images/team/mahdi-ait-lhaj-loutfi/avatar.jpg", + "expertise": ["Python", "Medical imaging", "Radiomics", "Artificial intelligence"], + "education": [ + { + "course": "Ph. D. Biological & Biomedical Engineering", + "institution": "McGill University, Montreal, Canada", + "year": "2026-" + }, + { + "course": "M. Sc. Computer science", + "institution": "Université de Sherbrooke, Sherbrooke, Canada", + "year": "2021-2024" + }, + { + "course": "B. Sc. Computer science", + "institution": "", + "year": "" + } + ], + "bio": "Mahdi Ait Lhaj Loutfi is a Ph. D. student in Biological & Biomedical Engineering at McGill University and a member of the MEDomicsLab, where he works on the development of the MEDomics platform. He completed his master’s degree in 2024, with a research project focused on exploring the complexity of radiomic features. In his Ph. D., he continues exploring the potential of radiomics in improving medical diagnosis and treatments. He is also the main architect and maintainer of the MEDiml package, a vital component of MEDomics.", + "note": "PhD Student", + "socials": { + "linkedin": "https://www.linkedin.com/in/mahdi-ait-lhaj-loutfi-332014253/", + "orcid": "", + "scholar": "", + "researchgate": "", + "github": "https://github.com/MahdiAll99", + "stackoverflow": "", + "cv": "" + } + }, { "name": "Elodie Gillard", "position": "M. Sc. Radiation sciences and medical imaging", @@ -273,63 +309,32 @@ } }, { - "name": "Anthonin Falk", - "position": "Intern in AI / Imaging", - "slug": "anthonin-falk", - "email": "anthonin.falk@gmail.com", - "image": "/images/team/anthonin-falk/avatar.jpg", - "expertise": [ - "Medical imaging", - "Artificial intelligence", - "Machine Learning", - "Computer science for healthcare" - ], - "education": [ - { - "course": "General Engineering Diploma", - "institution": "École Centrale de Nantes, Nantes, France", - "year": "2022-2025" - } - ], - "bio": "Anthonin Falk is completing an internship in artificial intelligence applied to medical imaging from April to September 2025. He is working on reducing the complexity and improving the interpretability of a predictive model designed to determine which patients are most likely to suffer side effects during radiotherapy treatment.", - "note": "Research Assistant / Intern", - "socials": { - "linkedin": "http://www.linkedin.com/in/anthonin-falk", - "orcid": "", - "scholar": "", - "researchgate": "", - "github": "https://github.com/S3vy", - "stackoverflow": "", - "cv": "" - } - }, - { - "name": "Mahdi Ait Lhaj Loutfi", - "position": "ML / Imaging", - "slug": "mahdi-ait-lhaj-loutfi", - "email": "Mahdi.Ait.Lhaj.Loutfi@USherbrooke.ca", - "image": "/images/team/mahdi-ait-lhaj-loutfi/avatar.jpg", - "expertise": ["Python", "Medical imaging", "Radiomics", "Artificial intelligence"], + "name": "Moustafa Amine Bezzahi", + "position": "M. Sc. Software Engineering", + "slug": "moustafa-amine-bezzahi", + "email": "moustafa.amine.bezzahi@usherbrooke.ca", + "image": "/images/team/moustafa-amine-bezzahi/avatar.jpg", + "expertise": ["Deep learning", "Computer vision", "Medical Imaging", "Digital Health"], "education": [ { - "course": "M. Sc. Computer science", + "course": "M. Sc. Software Engineering", "institution": "Université de Sherbrooke, Sherbrooke, Canada", - "year": "2021-2024" + "year": "2025-2027" }, { - "course": "B. Sc. Computer science", - "institution": "", - "year": "" + "course": "Engineering Degree, M. Sc. Computer science", + "institution": "Higher National School of Computer Science, Algiers, Algeria", + "year": "2019-2024" } ], - "bio": "Mahdi Ait Lhaj Loutfi is a research professional in the MEDomicsLab, where he works on the development of the MEDomics platform. He completed his master’s degree in 2024, with a research project focused on exploring the complexity of radiomic features. He is also the main architect and maintainer of the MEDimage package, a vital component of MEDomicsLab.", - "note": "Research Assistant / Intern", + "bio": "Moustafa has been a Master’s student in the MEDomicsLab since 2025. Prior to this, he completed a research internship from November 2023 to August 2024. During his internship, he developed a pipeline for the automatic detection and characterization of small renal masses using CT imaging datasets. He is currently focused on identifying optimal segmentation strategies and developing multitask classification models. In addition, he is building an end-to-end application designed to support radiologists and urologists in urological oncology decision-making. This tool is intended to be integrated into the MEDomics platform.", + "note": "MSc Student", "socials": { - "linkedin": "https://www.linkedin.com/in/mahdi-ait-lhaj-loutfi-332014253/", + "linkedin": "", "orcid": "", "scholar": "", "researchgate": "", - "github": "https://github.com/MahdiAll99", + "github": "https://github.com/mus-bz", "stackoverflow": "", "cv": "" } @@ -385,6 +390,37 @@ { "year": "2025", "members": [ + { + "name": "Anthonin Falk", + "position": "Intern in AI / Imaging", + "slug": "anthonin-falk", + "email": "anthonin.falk@gmail.com", + "image": "/images/team/anthonin-falk/avatar.jpg", + "expertise": [ + "Medical imaging", + "Artificial intelligence", + "Machine Learning", + "Computer science for healthcare" + ], + "education": [ + { + "course": "General Engineering Diploma", + "institution": "École Centrale de Nantes, Nantes, France", + "year": "2022-2025" + } + ], + "bio": "Anthonin Falk completed an internship in artificial intelligence applied to medical imaging from April to September 2025. He was working on reducing the complexity and improving the interpretability of a predictive model designed to determine which patients are most likely to suffer side effects during radiotherapy treatment.", + "note": "Former Member", + "socials": { + "linkedin": "http://www.linkedin.com/in/anthonin-falk", + "orcid": "", + "scholar": "", + "researchgate": "", + "github": "https://github.com/S3vy", + "stackoverflow": "", + "cv": "" + } + }, { "name": "Brahim Fakri", "position": "Research professional", @@ -679,37 +715,6 @@ "cv": "" } }, - { - "name": "Moustafa Amine Bezzahi", - "position": "Intern", - "slug": "moustafa-amine-bezzahi", - "email": "hm_bezzahi@esi.dz", - "image": "/images/team/moustafa-amine-bezzahi/avatar.jpg", - "expertise": [ - "Artificiel Intelligence", - "Computer vision", - "Digital Health", - "Medical Imaging" - ], - "education": [ - { - "course": "Engineering Degree, M. Sc. Computer science", - "institution": "Higher National School of Computer Science, Algiers, Algeria", - "year": "2019-2024" - } - ], - "bio": "Moustafa did an internship at MEDomicsLab UdeS from November 2023 till August 2024. He Worked on automatic detection of small renal masses using CHUS Medical Imaging dataset. He was supervised by Dr Patrick Richard and Pr Martin Vallières.", - "note": "Former Member", - "socials": { - "linkedin": "", - "orcid": "", - "scholar": "", - "researchgate": "", - "github": "https://github.com/mus-bz", - "stackoverflow": "", - "cv": "" - } - }, { "name": "Sarah Denis", "position": "Research professional", diff --git a/src/lib/memberActivity.js b/src/lib/memberActivity.js new file mode 100644 index 0000000..2c6b877 --- /dev/null +++ b/src/lib/memberActivity.js @@ -0,0 +1,129 @@ +import eventsData from "../data/events.json"; +import newsData from "../data/news.json"; +import publicationsData from "../data/publications.json"; +import researchProjects from "../data/research-projects.json"; + +/** + * Everything a team member shows up in, newest first. + */ + +const MONTHS = [ + "january", + "february", + "march", + "april", + "may", + "june", + "july", + "august", + "september", + "october", + "november", + "december", +]; + +/** Lowercase, de-accent and strip punctuation so "Guillaume Cléroux" matches "guillaume cleroux". */ +const normalizeName = (value) => + value + .normalize("NFKD") + .replace(/\p{Diacritic}/gu, "") + .toLowerCase() + .replace(/[^a-z0-9]+/g, " ") + .trim(); + +const credits = (contributors, name) => + (contributors ?? []).some((contributor) => normalizeName(contributor) === normalizeName(name)); + +/** + * Community slugs are date-prefixed (`2026-03-31-post-med3pa-article`). Fall back to the + * year/month headings the item is filed under when a slug carries no date. + */ +const resolveDate = (slug, year, month) => { + const fromSlug = /^(\d{4})-(\d{2})-(\d{2})/.exec(slug); + if (fromSlug) return `${fromSlug[1]}-${fromSlug[2]}-${fromSlug[3]}`; + + const monthIndex = MONTHS.indexOf(String(month ?? "").toLowerCase()); + if (monthIndex !== -1) return `${year}-${String(monthIndex + 1).padStart(2, "0")}-01`; + + return /^\d{4}$/.test(String(year)) ? `${year}-01-01` : null; +}; + +const formatDate = (date) => { + if (!date) return null; + const parsed = new Date(`${date}T00:00:00Z`); + if (Number.isNaN(parsed.getTime())) return null; + return parsed.toLocaleDateString("en-CA", { + year: "numeric", + month: "short", + timeZone: "UTC", + }); +}; + +const collectTimeline = (data, name, kind, basePath) => { + const entries = []; + for (const yearGroup of data) { + for (const monthGroup of yearGroup.months ?? []) { + for (const item of monthGroup.items ?? []) { + if (!credits(item.contributors, name)) continue; + entries.push({ + kind, + title: item.title, + to: `${basePath}/${item.slug}`, + date: resolveDate(item.slug, yearGroup.year, monthGroup.month), + }); + } + } + } + return entries; +}; + +const collectPublications = (name) => { + const entries = []; + for (const yearGroup of publicationsData) { + for (const item of yearGroup.items ?? []) { + if (!credits(item.contributors, name)) continue; + entries.push({ + kind: "Publication", + title: item.title, + to: `/publications/${item.slug}`, + date: item.date ?? resolveDate(item.slug, yearGroup.year), + }); + } + } + return entries; +}; + +const collectProjects = (slug) => + researchProjects + .filter((project) => (project.researchers ?? []).includes(slug)) + .map((project) => ({ + kind: "Project", + title: project.title, + to: `/research/${project.slug}`, + date: null, + })); + +/** + * @param {{ slug: string, name: string }} member + * @returns {Array<{ kind: string, title: string, to: string, date: string|null, dateLabel: string|null }>} + */ +export const getMemberActivity = (member) => { + if (!member?.name) return []; + + const entries = [ + ...collectPublications(member.name), + ...collectTimeline(newsData, member.name, "News", "/community/news"), + ...collectTimeline(eventsData, member.name, "Event", "/community/events"), + ...collectProjects(member.slug), + ]; + + // Dated entries newest first; undated projects trail them, alphabetically. + entries.sort((a, b) => { + if (a.date && b.date) return b.date.localeCompare(a.date); + if (a.date) return -1; + if (b.date) return 1; + return a.title.localeCompare(b.title); + }); + + return entries.map((entry) => ({ ...entry, dateLabel: formatDate(entry.date) })); +}; diff --git a/src/pages/PublicationsPage/PublicationsPage.jsx b/src/pages/PublicationsPage/PublicationsPage.jsx index 4b3f690..b6d7739 100644 --- a/src/pages/PublicationsPage/PublicationsPage.jsx +++ b/src/pages/PublicationsPage/PublicationsPage.jsx @@ -1,21 +1,26 @@ import { useEffect, useMemo, useRef, useState } from "react"; -import { SlidersHorizontal } from "lucide-react"; import { useTranslations } from "../../lib/translations"; import pubData from "../../data/publications.json"; import { cn } from "../../lib/utils"; import EntryRow, { EntryRowBody, EntryRowTitle } from "../../components/EntryRow/EntryRow.jsx"; +import FilterMenu from "../../components/FilterMenu/FilterMenu.jsx"; import PageShell, { PageTitle } from "../../components/PageShell/PageShell.jsx"; +const PUBLICATION_TYPES = ["Journal Papers", "Conference Papers", "Preprints", "Presentations"]; + export default function PublicationsPage() { const { t } = useTranslations(); const [activeYear, setActiveYear] = useState(pubData[0]?.year ?? ""); - const [isFilterOpen, setIsFilterOpen] = useState(false); const [isFocused, setIsFocused] = useState(false); const sectionRefs = useRef({}); - const filterRef = useRef(null); - const publicationTypes = ["Journal Papers", "Conference Papers", "Preprints", "Presentations"]; - const [activeTypes, setActiveTypes] = useState(publicationTypes); + const [activeTypes, setActiveTypes] = useState(PUBLICATION_TYPES); + // Never let the selection empty out: the last active type stays active. + const toggleType = (type) => + setActiveTypes((prev) => { + if (!prev.includes(type)) return [...prev, type]; + return prev.length === 1 ? prev : prev.filter((item) => item !== type); + }); const typeOrder = { "Journal Papers": 0, @@ -73,30 +78,6 @@ export default function PublicationsPage() { return () => window.removeEventListener("scroll", handleScroll); }, [activeYear, filteredGroups]); - useEffect(() => { - const handleClick = (event) => { - if (!filterRef.current) return; - if (filterRef.current.contains(event.target)) return; - setIsFilterOpen(false); - }; - - if (isFilterOpen) { - document.addEventListener("mousedown", handleClick); - } - - return () => document.removeEventListener("mousedown", handleClick); - }, [isFilterOpen]); - - const toggleType = (type) => { - setActiveTypes((prev) => { - if (prev.includes(type)) { - if (prev.length === 1) return prev; - return prev.filter((item) => item !== type); - } - return [...prev, type]; - }); - }; - return ( sectionRefs.current[id]?.scrollIntoView({ behavior: "smooth" }), }} > - {isFilterOpen && ( -

setIsFilterOpen(false)} - aria-hidden="true" - /> - )}
@@ -154,45 +128,12 @@ export default function PublicationsPage() { {yearGroup.year} {yearIndex === 0 && ( -
- -
-
- {publicationTypes.map((type) => { - const isActive = activeTypes.includes(type); - return ( - - ); - })} -
-
-
+ )}
diff --git a/src/pages/TeamMemberDetail/TeamMemberDetail.jsx b/src/pages/TeamMemberDetail/TeamMemberDetail.jsx index 1cbc7a5..e95f622 100644 --- a/src/pages/TeamMemberDetail/TeamMemberDetail.jsx +++ b/src/pages/TeamMemberDetail/TeamMemberDetail.jsx @@ -1,9 +1,18 @@ -import { useState } from "react"; +import { useMemo, useState } from "react"; import { Link, useParams } from "react-router-dom"; -import { ArrowLeft, Mail, Award, BookOpen, Copy } from "lucide-react"; +import { ArrowLeft, Mail, Award, BookOpen, Copy, Activity } from "lucide-react"; import teamData from "../../data/team.json"; import { useTranslations } from "../../lib/translations"; +import { getMemberActivity } from "../../lib/memberActivity"; import AvatarImage from "../../components/AvatarImage/AvatarImage"; +import EntryRow, { EntryRowBody, EntryRowTitle } from "../../components/EntryRow/EntryRow.jsx"; +import FilterMenu from "../../components/FilterMenu/FilterMenu.jsx"; +import RevealList from "../../components/RevealList/RevealList.jsx"; + +/** Order the Latest filter lists its options in, and the order rows tie-break on. */ +const ACTIVITY_KINDS = ["Publication", "News", "Event", "Project"]; + +const VISIBLE_ACTIVITY_COUNT = 3; const SOCIAL_ITEMS = [ { key: "linkedin", label: "LinkedIn" }, @@ -30,6 +39,29 @@ export default function TeamMemberDetail() { } } + const [isCopied, setIsCopied] = useState(false); + const activity = useMemo(() => (member ? getMemberActivity(member) : []), [member]); + + // Only offer the kinds this member actually has something in. + const availableKinds = useMemo( + () => ACTIVITY_KINDS.filter((kind) => activity.some((entry) => entry.kind === kind)), + [activity] + ); + const [activeKinds, setActiveKinds] = useState(ACTIVITY_KINDS); + const visibleActivity = useMemo( + () => activity.filter((entry) => activeKinds.includes(entry.kind)), + [activity, activeKinds] + ); + + // Guard against emptying the list. `activeKinds` spans every kind so the + // choice carries between profiles, but only the kinds this member has can + // keep the list non-empty, so those are what the guard counts. + const toggleKind = (kind) => + setActiveKinds((prev) => { + const next = prev.includes(kind) ? prev.filter((item) => item !== kind) : [...prev, kind]; + return availableKinds.some((available) => next.includes(available)) ? next : prev; + }); + if (!member) { return (
@@ -46,7 +78,6 @@ export default function TeamMemberDetail() { .map((part) => part[0]) .join(""); const socials = member.socials ?? {}; - const [isCopied, setIsCopied] = useState(false); return (
@@ -69,7 +100,7 @@ export default function TeamMemberDetail() { size={128} loading="eager" className="rounded-full" - imgClassName="grayscale rounded-full" + imgClassName="rounded-full" /> ) : (
@@ -199,6 +230,46 @@ export default function TeamMemberDetail() {
) : null} + + {activity.length > 0 && ( +
+
+

+ + {t("team.latest", "Latest")} +

+ {availableKinds.length > 1 && ( + + )} +
+ + {visibleActivity.map((entry) => ( + + +
+ + {entry.kind} + + {entry.dateLabel && {entry.dateLabel}} +
+ + {entry.title} + +
+
+ ))} +
+
+ )}