CINXE.COM
index
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> <meta charset="utf-8"> <meta name="generator" content="quarto-1.6.42"> <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> <title>index</title> <style> code{white-space: pre-wrap;} span.smallcaps{font-variant: small-caps;} div.columns{display: flex; gap: min(4vw, 1.5em);} div.column{flex: auto; overflow-x: auto;} div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} ul.task-list{list-style: none;} ul.task-list li input[type="checkbox"] { width: 0.8em; margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ vertical-align: middle; } .display.math{display: block; text-align: center; margin: 0.5rem auto;} </style> <script src="site_libs/clipboard/clipboard.min.js"></script> <script src="site_libs/quarto-html/tabby.min.js"></script> <script src="site_libs/quarto-html/popper.min.js"></script> <script src="site_libs/quarto-html/tippy.umd.min.js"></script> <script src="site_libs/quarto-html/anchor.min.js"></script> <link href="site_libs/quarto-html/tippy.css" rel="stylesheet"> <link href="site_libs/quarto-html/light-border.css" rel="stylesheet"> <link href="site_libs/quarto-html/quarto-html-5276476b5bdb9cfe1f92c505466e0bf3.min.css" rel="stylesheet" append-hash="true" data-mode="light"> <link href="site_libs/quarto-html/quarto-syntax-highlighting-2f5df379a58b258e96c21c0638c20c03.css" rel="stylesheet" id="quarto-text-highlighting-styles"> <link rel="stylesheet" href="style/base/colors.css"> <link rel="stylesheet" href="style/base/fonts.css"> <link rel="stylesheet" href="style/base/layout.css"> <link rel="stylesheet" href="style/base/typography.css"> <link rel="stylesheet" href="style/components/blockquote.css"> <link rel="stylesheet" href="style/components/breadcrumbs.css"> <link rel="stylesheet" href="style/components/buttons.css"> <link rel="stylesheet" href="style/components/code.css"> <link rel="stylesheet" href="style/components/dropdown.css"> <link rel="stylesheet" href="style/components/gallery.css"> <link rel="stylesheet" href="style/components/lists.css"> <link rel="stylesheet" href="style/components/tables.css"> <link rel="stylesheet" href="style/sections/announcement.css"> <link rel="stylesheet" href="style/sections/header.css"> <link rel="stylesheet" href="style/sections/footer.css"> <link rel="stylesheet" href="style/sections/sidebar.css"> </head> <body> <div class="announcement announcement-brand"> </div> <header id="site-masthead" class="site-masthead"> <div class="header-size"> <!-- Logo Section --> <div class="header-logo"> <a href="https://bioconductor.org"> <img src="./images/bioconductor-logo.svg" class="masthead-logo" alt="Bioconductor Training Home"> </a> </div> <!-- Navigation Section --> <nav class="header-nav"> <div class="nav-links"> <a class="format-bold mobile-link" href="./">Home</a> <a class="format-bold mobile-link" href="./resources/resources.html">Resources</a> <a class="format-bold mobile-link" href="./workshops/2025-03-Nairobi/index.html">Workshops</a> <div class="dropdown"> <a class="format-bold mobile-link" href="./carpentry/index.html">Carpentry</a> <div class="dropdown-content"> <a href="./carpentry/instructors.html">Instructors</a> <a href="./carpentry/workshops.html">Workshops</a> </div> </div> </div> </nav> <!-- Mobile Navigation --> <div class="nav-mobile"> <h6 class="anchored">Menu</h6> <div class="hamburger"> <span class="bar"></span> <span class="bar"></span> <span class="bar"></span> </div> </div> </div> </header> <div class="container"> <h1 id="the-bioconductor-training-committee">The Bioconductor training committee</h1> <p>The Bioconductor training committee is a collaborative effort to consolidate Bioconductor-focused training material and establish a community of Bioconductor trainers. We define a curriculum and implement online lessons for beginner and more advanced R users who want to learn to analyse their data with Bioconductor packages.</p> <p>The Bioconductor training committee reports to the Bioconductor <a href="http://bioconductor.org/about/community-advisory-board/">Community Advisory Board</a>. It is currently chaired by Charlotte Soneson and Laurent Gatto. There’s no formal joining process or minimum commitment required — simply attend one of the monthly meetings (announced on the Google group, see below) or engage in our discussions to become a part of our community.</p> <p>This meta-repository is used for general discussions. The respective lessons are developed as modules in their own repositories.</p> <h2 id="publications" class="anchored">Publications</h2> <ul> <li>Learning and teaching biological data science in the Bioconductor community by Drnevich, Tan et al. (<a href="https://arxiv.org/abs/2410.01351">2024 preprint</a>)</li> </ul> <h2 id="modules" class="anchored">Modules</h2> <ul> <li><p><a href="https://carpentries-incubator.github.io/bioc-intro/">bioc-intro</a> The <strong>Data science</strong> lesson is based on the <a href="https://datacarpentry.org/lessons/#ecology-workshop">Carpentries Ecology Curriculum</a>. There are no pre-requisites for this module, and the materials assume no prior knowledge about R and Bioconductor. It introduces R, RStudio, teaches data cleaning, management, analysis, and visualisation and introduces some Bioconductor concepts. Notes are collated in <code>bioc-intro.md</code> in this repo.</p></li> <li><p><a href="https://carpentries-incubator.github.io/bioc-rnaseq/">bioc-rnaseq</a> <strong>Analysis and interpretation of bulk RNA sequencing data with Bioconductor</strong> shows how to use Bioconductor packages to analyse bulk RNA-seq data. It expects good familiarity with R and the Bioconductor project.</p></li> <li><p><a href="https://carpentries-incubator.github.io/bioc-scrnaseq/">bioc-scrnaseq</a> <strong>Analysis and interpretation of single-cell RNA sequencing data with Bioconductor</strong> shows how to use Bioconductor packages for essential single-cell analysis steps including quality control, cell type annotation, multi-sample analysis, working with large data, and integration with public data. Pre-requisites include familiarity with R and Bioconductor. Familiarity with bulk RNA-seq data analysis is beneficial, but not strictly required.</p></li> <li><p><a href="https://carpentries-incubator.github.io/bioc-project/">bioc-project</a> The <strong>Bioconductor project</strong> lesson provides an introduction to the Bioconductor project such as the Bioconductor home page, packages, package landing pages, and package vignettes, where to find help, Bioconductor workflows, Bioconductor release schedule and versions, some core infrastructure, … It is meant to be use in combination with other modules as part of a wider workshop.</p></li> </ul> <h3 id="new-lessons" class="anchored">New lessons</h3> <p>If you are interested in contributing new lessons or Carpentry modules, feel free to get in touch with the teaching committee via slack of the google group (see below). We would be happy to discuss and/or contribute to anything related to the lesson design, general help with the long-term maintenance, dissemination of the lesson, or any help/topic you can think of.</p> <h2 id="material-design-and-maintenance" class="anchored">Material design and maintenance</h2> <h3 id="lesson-design" class="anchored">Lesson design</h3> <ul> <li>Use RStudio for teaching.</li> <li>If possible, finish lessons with a <em>Next steps</em> section to highlight other relevant Bioconductor lessons. Similarly, in the Summary and Setup section, refer to other Bioconductor lessons that cover the pre-requisites.</li> <li>Whenever relevant, use Bioconductor recommended/maintained classes.</li> <li>Package installation: favour <code>BiocManager::install()</code> for all packages.</li> <li>The bioc-intro lesson, which is based on the Ecology lesson, focuses on the tidyverse.</li> </ul> <h3 id="maintenance" class="anchored">Maintenance</h3> <p><strong>Maintenance team</strong> Each Bioconductor lesson has at least one maintainer, and more generally a team of instructors that built and adviser on the maintenance of the lesson collaboratively. The maintainer is the person that takes responsibility for merging the PRs and fixing build issues if/when they happen. The Carpentries Curriculum Advisory Committee Consultation Rubric provides a template as to how to address changes to the lessons.</p> <p><strong>Contributing and handling minor changes</strong> For minor changes such as typos or simple rephrasing can be submitted directly through a Github pull request. The lesson maintainer can assess the PR, ask for clarifications or amendments and eventually merge the pull request.</p> <p><strong>Contributing and handling big changes</strong> For more substantial changes, we advise to first open an issue to discuss these changes with the maintainer, the team that created the lesson, and other instructors that have experience teaching the episode. A pull request for such a more substantial change (and here, we deliberately don’t define them explicitly and leave it to the lesson maintainer to assess the importance), would be discussed in (1) the Github pull request and/or (2) on the bioconductor-teaching google group and/or, if necessary (3) during a Bioconductor teaching monthly meeting. For the latter, it would be recommended that at least 2 to 3 people that were part in the design of the lesson and/or that have teaching experience would be present in addition to the lesson maintainer. The PR submitter is also welcome to join the discussion.</p> <h2 id="notes-and-meetings" class="anchored">Notes and meetings</h2> <ul> <li>Collaborative <a href="https://docs.google.com/document/d/1s2QMk5XA-uhBVprAO3ZDk1Yfv1cnUWLp9zdvYq9Feu4/edit#">Google doc</a>.</li> </ul> <h2 id="discussions" class="anchored">Discussions</h2> <ul> <li>The <code>education-and-training</code> channel on the <a href="https://slack.bioconductor.org/">Bioconductor community slack</a>.</li> <li>The <a href="https://groups.google.com/g/bioconductor-teaching/">Google group</a> (low-traffic, mainly used to send a reminder for the monthly meeting).</li> </ul> <h2 id="events" class="anchored">Events</h2> <p>Explore upcoming opportunities and past Bioconductor workshops and training sessions on our <a href="https://www.bioconductor.org/help/events/">events page</a>. Interested in sharing your own Bioconductor training event with the community? Learn how to add your event directly through this page.</p> <h2 id="contact" class="anchored">Contact</h2> <p>If you are interested in this project and want to get in touch or participate, please contact the group via the Google group or individual members on slack or by email.</p> </div> <footer> <div class="footer-container"> <div class="footer-content"> <p>© 2003 - 2025 Bioconductor | Join the Bioconductor Community</p> <div class="footer-socials"> <a href="https://slack.bioconductor.org/" target="_blank"><img alt="Slack Logo" src="./images/icons/slack.png"></a> <a href="https://www.youtube.com/user/bioconductor" target="_blank"><img alt="YouTube Logo" src="./images/icons/svgs/youtube.svg"></a> <a href="https://www.linkedin.com/company/bioconductor/" target="_blank"><img alt="LinkedIn Logo" src="./images/icons/svgs/linkedin.svg"></a> <a href="https://bsky.app/profile/bioconductor.bsky.social" target="_blank"><img alt="Bluesky Logo" src="./images/icons/svgs/bluesky.svg"></a> <a href="https://genomic.social/@bioconductor" target="_blank"><img alt="Mastodon Logo" src="./images/icons/svgs/mastodon.svg"></a> <a href="https://blog.bioconductor.org/" target="_blank"><img alt="Blog Logo" src="./images/icons/svgs/arrow-circle-right-white.svg"></a> </div> </div> </div> </footer> <script id="quarto-html-after-body" type="application/javascript"> window.document.addEventListener("DOMContentLoaded", function (event) { const toggleBodyColorMode = (bsSheetEl) => { const mode = bsSheetEl.getAttribute("data-mode"); const bodyEl = window.document.querySelector("body"); if (mode === "dark") { bodyEl.classList.add("quarto-dark"); bodyEl.classList.remove("quarto-light"); } else { bodyEl.classList.add("quarto-light"); bodyEl.classList.remove("quarto-dark"); } } const toggleBodyColorPrimary = () => { const bsSheetEl = window.document.querySelector("link#quarto-bootstrap"); if (bsSheetEl) { toggleBodyColorMode(bsSheetEl); } } toggleBodyColorPrimary(); const tabsets = window.document.querySelectorAll(".panel-tabset-tabby") tabsets.forEach(function(tabset) { const tabby = new Tabby('#' + tabset.id); }); const icon = ""; const anchorJS = new window.AnchorJS(); anchorJS.options = { placement: 'right', icon: icon }; anchorJS.add('.anchored'); const isCodeAnnotation = (el) => { for (const clz of el.classList) { if (clz.startsWith('code-annotation-')) { return true; } } return false; } const onCopySuccess = function(e) { // button target const button = e.trigger; // don't keep focus button.blur(); // flash "checked" button.classList.add('code-copy-button-checked'); var currentTitle = button.getAttribute("title"); button.setAttribute("title", "Copied!"); let tooltip; if (window.bootstrap) { button.setAttribute("data-bs-toggle", "tooltip"); button.setAttribute("data-bs-placement", "left"); button.setAttribute("data-bs-title", "Copied!"); tooltip = new bootstrap.Tooltip(button, { trigger: "manual", customClass: "code-copy-button-tooltip", offset: [0, -8]}); tooltip.show(); } setTimeout(function() { if (tooltip) { tooltip.hide(); button.removeAttribute("data-bs-title"); button.removeAttribute("data-bs-toggle"); button.removeAttribute("data-bs-placement"); } button.setAttribute("title", currentTitle); button.classList.remove('code-copy-button-checked'); }, 1000); // clear code selection e.clearSelection(); } const getTextToCopy = function(trigger) { const codeEl = trigger.previousElementSibling.cloneNode(true); for (const childEl of codeEl.children) { if (isCodeAnnotation(childEl)) { childEl.remove(); } } return codeEl.innerText; } const clipboard = new window.ClipboardJS('.code-copy-button:not([data-in-quarto-modal])', { text: getTextToCopy }); clipboard.on('success', onCopySuccess); if (window.document.getElementById('quarto-embedded-source-code-modal')) { const clipboardModal = new window.ClipboardJS('.code-copy-button[data-in-quarto-modal]', { text: getTextToCopy, container: window.document.getElementById('quarto-embedded-source-code-modal') }); clipboardModal.on('success', onCopySuccess); } var localhostRegex = new RegExp(/^(?:http|https):\/\/localhost\:?[0-9]*\//); var mailtoRegex = new RegExp(/^mailto:/); var filterRegex = new RegExp("https:\/\/training\.bioconductor\.org"); var isInternal = (href) => { return filterRegex.test(href) || localhostRegex.test(href) || mailtoRegex.test(href); } // Inspect non-navigation links and adorn them if external var links = window.document.querySelectorAll('a[href]:not(.nav-link):not(.navbar-brand):not(.toc-action):not(.sidebar-link):not(.sidebar-item-toggle):not(.pagination-link):not(.no-external):not([aria-hidden]):not(.dropdown-item):not(.quarto-navigation-tool):not(.about-link)'); for (var i=0; i<links.length; i++) { const link = links[i]; if (!isInternal(link.href)) { // undo the damage that might have been done by quarto-nav.js in the case of // links that we want to consider external if (link.dataset.originalHref !== undefined) { link.href = link.dataset.originalHref; } } } function tippyHover(el, contentFn, onTriggerFn, onUntriggerFn) { const config = { allowHTML: true, maxWidth: 500, delay: 100, arrow: false, appendTo: function(el) { return el.parentElement; }, interactive: true, interactiveBorder: 10, theme: 'light-border', placement: 'bottom-start', }; if (contentFn) { config.content = contentFn; } if (onTriggerFn) { config.onTrigger = onTriggerFn; } if (onUntriggerFn) { config.onUntrigger = onUntriggerFn; } window.tippy(el, config); } const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]'); for (var i=0; i<noterefs.length; i++) { const ref = noterefs[i]; tippyHover(ref, function() { // use id or data attribute instead here let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href'); try { href = new URL(href).hash; } catch {} const id = href.replace(/^#\/?/, ""); const note = window.document.getElementById(id); if (note) { return note.innerHTML; } else { return ""; } }); } const xrefs = window.document.querySelectorAll('a.quarto-xref'); const processXRef = (id, note) => { // Strip column container classes const stripColumnClz = (el) => { el.classList.remove("page-full", "page-columns"); if (el.children) { for (const child of el.children) { stripColumnClz(child); } } } stripColumnClz(note) if (id === null || id.startsWith('sec-')) { // Special case sections, only their first couple elements const container = document.createElement("div"); if (note.children && note.children.length > 2) { container.appendChild(note.children[0].cloneNode(true)); for (let i = 1; i < note.children.length; i++) { const child = note.children[i]; if (child.tagName === "P" && child.innerText === "") { continue; } else { container.appendChild(child.cloneNode(true)); break; } } if (window.Quarto?.typesetMath) { window.Quarto.typesetMath(container); } return container.innerHTML } else { if (window.Quarto?.typesetMath) { window.Quarto.typesetMath(note); } return note.innerHTML; } } else { // Remove any anchor links if they are present const anchorLink = note.querySelector('a.anchorjs-link'); if (anchorLink) { anchorLink.remove(); } if (window.Quarto?.typesetMath) { window.Quarto.typesetMath(note); } if (note.classList.contains("callout")) { return note.outerHTML; } else { return note.innerHTML; } } } for (var i=0; i<xrefs.length; i++) { const xref = xrefs[i]; tippyHover(xref, undefined, function(instance) { instance.disable(); let url = xref.getAttribute('href'); let hash = undefined; if (url.startsWith('#')) { hash = url; } else { try { hash = new URL(url).hash; } catch {} } if (hash) { const id = hash.replace(/^#\/?/, ""); const note = window.document.getElementById(id); if (note !== null) { try { const html = processXRef(id, note.cloneNode(true)); instance.setContent(html); } finally { instance.enable(); instance.show(); } } else { // See if we can fetch this fetch(url.split('#')[0]) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); const note = htmlDoc.getElementById(id); if (note !== null) { const html = processXRef(id, note); instance.setContent(html); } }).finally(() => { instance.enable(); instance.show(); }); } } else { // See if we can fetch a full url (with no hash to target) // This is a special case and we should probably do some content thinning / targeting fetch(url) .then(res => res.text()) .then(html => { const parser = new DOMParser(); const htmlDoc = parser.parseFromString(html, "text/html"); const note = htmlDoc.querySelector('main.content'); if (note !== null) { // This should only happen for chapter cross references // (since there is no id in the URL) // remove the first header if (note.children.length > 0 && note.children[0].tagName === "HEADER") { note.children[0].remove(); } const html = processXRef(null, note); instance.setContent(html); } }).finally(() => { instance.enable(); instance.show(); }); } }, function(instance) { }); } let selectedAnnoteEl; const selectorForAnnotation = ( cell, annotation) => { let cellAttr = 'data-code-cell="' + cell + '"'; let lineAttr = 'data-code-annotation="' + annotation + '"'; const selector = 'span[' + cellAttr + '][' + lineAttr + ']'; return selector; } const selectCodeLines = (annoteEl) => { const doc = window.document; const targetCell = annoteEl.getAttribute("data-target-cell"); const targetAnnotation = annoteEl.getAttribute("data-target-annotation"); const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation)); const lines = annoteSpan.getAttribute("data-code-lines").split(","); const lineIds = lines.map((line) => { return targetCell + "-" + line; }) let top = null; let height = null; let parent = null; if (lineIds.length > 0) { //compute the position of the single el (top and bottom and make a div) const el = window.document.getElementById(lineIds[0]); top = el.offsetTop; height = el.offsetHeight; parent = el.parentElement.parentElement; if (lineIds.length > 1) { const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]); const bottom = lastEl.offsetTop + lastEl.offsetHeight; height = bottom - top; } if (top !== null && height !== null && parent !== null) { // cook up a div (if necessary) and position it let div = window.document.getElementById("code-annotation-line-highlight"); if (div === null) { div = window.document.createElement("div"); div.setAttribute("id", "code-annotation-line-highlight"); div.style.position = 'absolute'; parent.appendChild(div); } div.style.top = top - 2 + "px"; div.style.height = height + 4 + "px"; div.style.left = 0; let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter"); if (gutterDiv === null) { gutterDiv = window.document.createElement("div"); gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter"); gutterDiv.style.position = 'absolute'; const codeCell = window.document.getElementById(targetCell); const gutter = codeCell.querySelector('.code-annotation-gutter'); gutter.appendChild(gutterDiv); } gutterDiv.style.top = top - 2 + "px"; gutterDiv.style.height = height + 4 + "px"; } selectedAnnoteEl = annoteEl; } }; const unselectCodeLines = () => { const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"]; elementsIds.forEach((elId) => { const div = window.document.getElementById(elId); if (div) { div.remove(); } }); selectedAnnoteEl = undefined; }; // Handle positioning of the toggle window.addEventListener( "resize", throttle(() => { elRect = undefined; if (selectedAnnoteEl) { selectCodeLines(selectedAnnoteEl); } }, 10) ); function throttle(fn, ms) { let throttle = false; let timer; return (...args) => { if(!throttle) { // first call gets through fn.apply(this, args); throttle = true; } else { // all the others get throttled if(timer) clearTimeout(timer); // cancel #2 timer = setTimeout(() => { fn.apply(this, args); timer = throttle = false; }, ms); } }; } // Attach click handler to the DT const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); for (const annoteDlNode of annoteDls) { annoteDlNode.addEventListener('click', (event) => { const clickedEl = event.target; if (clickedEl !== selectedAnnoteEl) { unselectCodeLines(); const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active'); if (activeEl) { activeEl.classList.remove('code-annotation-active'); } selectCodeLines(clickedEl); clickedEl.classList.add('code-annotation-active'); } else { // Unselect the line unselectCodeLines(); clickedEl.classList.remove('code-annotation-active'); } }); } const findCites = (el) => { const parentEl = el.parentElement; if (parentEl) { const cites = parentEl.dataset.cites; if (cites) { return { el, cites: cites.split(' ') }; } else { return findCites(el.parentElement) } } else { return undefined; } }; var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]'); for (var i=0; i<bibliorefs.length; i++) { const ref = bibliorefs[i]; const citeInfo = findCites(ref); if (citeInfo) { tippyHover(citeInfo.el, function() { var popup = window.document.createElement('div'); citeInfo.cites.forEach(function(cite) { var citeDiv = window.document.createElement('div'); citeDiv.classList.add('hanging-indent'); citeDiv.classList.add('csl-entry'); var biblioDiv = window.document.getElementById('ref-' + cite); if (biblioDiv) { citeDiv.innerHTML = biblioDiv.innerHTML; } popup.appendChild(citeDiv); }); return popup.innerHTML; }); } } }); </script> </body></html>