Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ repos:
- id: yamllint
exclude: pre-commit-config.yaml
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: "v0.15.10"
rev: "v0.15.11"
hooks:
- id: ruff-format
- id: ruff-check
Expand Down
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<img width="600" src="https://raw.githubusercontent.com/wayscience/ome-arrow/main/docs/src/_static/logo.png?raw=true">
<img width="600" src="https://raw.githubusercontent.com/wayscience/ome-arrow/main/docs/src/_static/ome-arrow-with-text.png?raw=true">

![PyPI - Version](https://img.shields.io/pypi/v/ome-arrow)
[![Build Status](https://github.com/wayscience/ome-arrow/actions/workflows/run-tests.yml/badge.svg?branch=main)](https://github.com/wayscience/ome-arrow/actions/workflows/run-tests.yml?query=branch%3Amain)
Expand Down Expand Up @@ -198,6 +198,8 @@ Please see our [contributing documentation](https://github.com/wayscience/ome-ar
OME Arrow is used or inspired by the following projects, check them out!

- [`napari-ome-arrow`](https://github.com/WayScience/napari-ome-arrow): enables you to view OME Arrow and related images.
- [`nViz`](https://github.com/WayScience/nViz): focuses on ingesting and visualizing various 3D image data.
- [`CytoDataFrame`](https://github.com/cytomining/CytoDataFrame): provides a DataFrame-like experience for viewing feature and microscopy image data within Jupyter notebook interfaces and creating OME Parquet files.
- [`coSMicQC`](https://github.com/cytomining/coSMicQC): performs quality control on microscopy feature datasets, visualized using CytoDataFrames.
- [`pycytominer`](https://github.com/cytomining/pycytominer): supports feature profiling, normalization, and downstream analysis workflows for image-based profiling datasets.
- [`iceberg-bioimage`](https://github.com/WayScience/iceberg-bioimage): defines warehouse-oriented patterns for connecting bioimage formats and analytical tables at scale.
- [`CytoTable`](https://github.com/cytomining/CytoTable): converts image-based profiling outputs into analysis-ready tabular formats such as Parquet.
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
title: Poster (modified)
author: Carlos Scheidegger, Dave Bunten
version: 1.0.0
quarto-required: ">=1.4.415"
contributes:
formats:
typst:
template-partials:
- typst-template.typ
- typst-show.typ
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Typst custom formats typically consist of a 'typst-template.typ' (which is
// the source code for a typst template) and a 'typst-show.typ' which calls the
// template's function (forwarding Pandoc metadata values as required)
//
// This is an example 'typst-show.typ' file (based on the default template
// that ships with Quarto). It calls the typst function named 'article' which
// is defined in the 'typst-template.typ' file.
//
// If you are creating or packaging a custom typst template you will likely
// want to replace this file and 'typst-template.typ' entirely. You can find
// documentation on creating typst templates here and some examples here:
// - https://typst.app/docs/tutorial/making-a-template/
// - https://github.com/typst/templates

#show: doc => poster(
$if(title)$ title: [$title$], $endif$
// TODO: use Quarto's normalized metadata.
$if(poster-authors)$ authors: [$poster-authors$], $endif$
$if(departments)$ departments: [$departments$], $endif$
$if(size)$ size: "$size$", $endif$

// Institution logo.
$if(institution-logo)$ univ_logo: "$institution-logo$", $endif$

// Footer text.
// For instance, Name of Conference, Date, Location.
// or Course Name, Date, Instructor.
$if(footer-text)$ footer_text: [$footer-text$], $endif$

// Any URL, like a link to the conference website.
$if(footer-url)$ footer_url: [$footer-url$], $endif$

// Emails of the authors.
$if(footer-emails)$ footer_email_ids: [$footer-emails$], $endif$

// Color of the footer.
$if(footer-color)$ footer_color: "$footer-color$", $endif$

// DEFAULTS
// ========
// For 3-column posters, these are generally good defaults.
// Tested on 36in x 24in, 48in x 36in, and 36in x 48in posters.
// For 2-column posters, you may need to tweak these values.
// See ./examples/example_2_column_18_24.typ for an example.

// Any keywords or index terms that you want to highlight at the beginning.
$if(keywords)$ keywords: ($for(keywords)$"$it$"$sep$, $endfor$), $endif$

// Number of columns in the poster.
$if(num-columns)$ num_columns: $num-columns$, $endif$

// University logo's scale (in %).
$if(univ-logo-scale)$ univ_logo_scale: $univ-logo-scale$, $endif$

// University logo's column size (in in).
$if(univ-logo-column-size)$ univ_logo_column_size: $univ-logo-column-size$, $endif$

// Title and authors' column size (in in).
$if(title-column-size)$ title_column_size: $title-column-size$, $endif$

// Poster title's font size (in pt).
$if(title-font-size)$ title_font_size: $title-font-size$, $endif$

// Authors' font size (in pt).
$if(authors-font-size)$ authors_font_size: $authors-font-size$, $endif$

// Footer's URL and email font size (in pt).
$if(footer-url-font-size)$ footer_url_font_size: $footer-url-font-size$, $endif$

// Footer's text font size (in pt).
$if(footer-text-font-size)$ footer_text_font_size: [$footer-text-font-size$], $endif$
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

footer_text_font_size is forwarded as a bracketed content value ([$footer-text-font-size$]), but the template casts it with int(...). This will likely fail at render time unless it’s a plain numeric value. Pass the raw metadata value (without brackets) so it can be parsed/cast correctly.

Suggested change
$if(footer-text-font-size)$ footer_text_font_size: [$footer-text-font-size$], $endif$
$if(footer-text-font-size)$ footer_text_font_size: $footer-text-font-size$, $endif$

Copilot uses AI. Check for mistakes.
Comment on lines +67 to +71
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, let's locate and examine the file
find . -type f -name "typst-show.typ" -o -path "*quarto-ext/poster*" -type f | head -20

Repository: WayScience/ome-arrow

Length of output: 346


🏁 Script executed:

# Read the typst-show.typ file to see the context around lines 67-71
cat -n ./docs/presentations/2026-OME-community-meeting/_extensions/quarto-ext/poster/typst-show.typ | head -80

Repository: WayScience/ome-arrow

Length of output: 3534


🏁 Script executed:

# Also examine the typst-template.typ to understand the poster function definition
cat -n ./docs/presentations/2026-OME-community-meeting/_extensions/quarto-ext/poster/typst-template.typ

Repository: WayScience/ome-arrow

Length of output: 7202


Remove brackets from footer_text_font_size parameter to match other numeric font-size parameters.

Line 71 inconsistently wraps the value in Typst content brackets [...], unlike the adjacent footer_url_font_size on line 68 and all other numeric parameters. The poster() function expects a numeric string (converted via int() on line 36 of typst-template.typ), not a content block. This will cause type conversion to fail when the parameter is used.

🐛 Proposed fix
-  $if(footer-text-font-size)$ footer_text_font_size: [$footer-text-font-size$], $endif$
+  $if(footer-text-font-size)$ footer_text_font_size: $footer-text-font-size$, $endif$
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Footer's URL and email font size (in pt).
$if(footer-url-font-size)$ footer_url_font_size: $footer-url-font-size$, $endif$
// Footer's text font size (in pt).
$if(footer-text-font-size)$ footer_text_font_size: [$footer-text-font-size$], $endif$
// Footer's URL and email font size (in pt).
$if(footer-url-font-size)$ footer_url_font_size: $footer-url-font-size$, $endif$
// Footer's text font size (in pt).
$if(footer-text-font-size)$ footer_text_font_size: $footer-text-font-size$, $endif$
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@docs/presentations/2026-OME-community-meeting/_extensions/quarto-ext/poster/typst-show.typ`
around lines 67 - 71, The footer_text_font_size parameter is incorrectly wrapped
in Typst content brackets; update the assignment in typst-show.typ so
footer_text_font_size uses a plain numeric value like footer_url_font_size
(remove the surrounding [...] from the $if(footer-text-font-size)$ branch),
ensuring the poster() call (and its int() conversion in typst-template.typ)
receives a numeric string; modify the $if...$ block referencing
footer_text_font_size to mirror the footer_url_font_size pattern.


doc,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
#let poster(
// set variables for use throughout
// note: some are referenced from `.qmd` file
size: "'36x24' or '48x36''",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
python - <<'PY'
from pathlib import Path
import re

path = Path("docs/presentations/2026-OME-community-meeting/_extensions/quarto-ext/poster/typst-template.typ")
text = path.read_text()
match = re.search(r'size:\s*"([^"]+)"', text)
if not match:
    raise SystemExit("No default size found")

value = match.group(1)
if not re.fullmatch(r"\d+x\d+", value):
    raise SystemExit(f"Default size is not parseable as WIDTHxHEIGHT: {value!r}")

print(f"Default size is parseable: {value}")
PY

Repository: WayScience/ome-arrow

Length of output: 132


🏁 Script executed:

cat -n "docs/presentations/2026-OME-community-meeting/_extensions/quarto-ext/poster/typst-template.typ"

Repository: WayScience/ome-arrow

Length of output: 7202


Use a parseable default poster size.

The default size value is descriptive text, but lines 26-28 parse it as numeric WIDTHxHEIGHT. If metadata omits size, rendering will fail because int("'36") cannot parse the quoted default.

🔧 Proposed fix
-  size: "'36x24' or '48x36''",
+  size: "48x36",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
size: "'36x24' or '48x36''",
size: "48x36",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@docs/presentations/2026-OME-community-meeting/_extensions/quarto-ext/poster/typst-template.typ`
at line 4, The default value for the metadata key size is currently a quoted
descriptive string that cannot be parsed as WIDTHxHEIGHT; update the default to
a parseable poster size (for example "36x24" without extra quotes or descriptive
text) so the code that parses WIDTHxHEIGHT (lines referencing size parsing) can
safely call int() on the split parts; locate the size declaration in
typst-template.typ (the size: "'36x24' or '48x36''" entry) and replace it with a
simple parseable default like "36x24" (or choose one valid option) so downstream
parsing of WIDTH and HEIGHT succeeds.

title: "Paper Title",
authors: "Author Names (separated by commas)",
departments: "Department Name",
univ_logo: "Logo Path",
footer_text: " ",
footer_url: "Footer URL",
footer_email_ids: "Email IDs (separated by commas)",
footer_color: "Hex Color Code",
keywords: (),
num_columns: "4",
univ_logo_scale: "140",
univ_logo_column_size: "10",
title_column_size: "33",
title_font_size: "42",
authors_font_size: "32",
footer_url_font_size: "40",
footer_text_font_size: "40",
body
) = {
// initialize template display formatting
set text(font: "Lato", size: 26pt)
let sizes = size.split("x")
let width = int(sizes.at(0)) * 1in
let height = int(sizes.at(1)) * 1in
univ_logo_scale = int(univ_logo_scale) * 1%
title_font_size = int(title_font_size) * 1pt
authors_font_size = int(authors_font_size) * 1pt
num_columns = int(num_columns)
univ_logo_column_size = int(univ_logo_column_size) * 1in
title_column_size = int(title_column_size) * 1in
footer_url_font_size = int(footer_url_font_size) * 1pt
footer_text_font_size = int(footer_text_font_size) * 1pt

// create overall page output
set page(
// total dimensions
width: width,
height: height,
// margin on all sides
margin:
(top: .8in, left: .8in, right: .8in, bottom: 1.8in),
// footer section
footer: [
#set align(center)
#set text(42pt)
#block(
fill: rgb(footer_color),
width: 100%,
inset: 20pt,
radius: 10pt,
// adds text to footer
[
Comment on lines +49 to +56
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fill: rgb(footer_color) is passed a string from Quarto metadata (e.g., "CBE9E1" in the poster front matter). Typst’s rgb(...) typically expects numeric channels or a color literal, so this may fail unless you normalize the value (e.g., require #RRGGBB in metadata or prepend # before converting).

Copilot uses AI. Check for mistakes.
#text(font: "Lato", size: footer_url_font_size, footer_url)
#h(1fr)
#text(size: footer_text_font_size, smallcaps(footer_text))
#h(1fr)
#text(font: "Lato", size: footer_url_font_size, footer_email_ids)
]
)
]
)

// set math display properties
set math.equation(numbering: "(1)")
show math.equation: set block(spacing: 0.65em)

set enum(indent: 10pt, body-indent: 9pt)
set list(indent: 10pt, body-indent: 9pt)

// set the heading numbering system
set heading(numbering: "I.A.1.")
show heading: it => context {
// Get numbering tuple for *this* heading at the current location.
let levels = counter(heading).at(here())
let deepest = if levels != () { levels.last() } else { 1 }

// defines how sub-headers display
set text(25pt, weight: 400)

// sub-header level 0
if it.level == 0 [
#set text(style: "italic")
#v(32pt, weak: true)
#if it.numbering != none {
numbering("i.", deepest)
h(7pt, weak: true)
}
#it.body

// sub-header level 1
] else if it.level == 1 [
#v(10pt, weak: true)
#set align(left)
#set text({ 44pt }, weight: 600, font: "Vollkorn", fill: rgb("#2A6F63"))
#v(45pt, weak: true)
#if it.numbering != none {
numbering("I.", deepest)
h(7pt, weak: true)
}
#it.body
#v(25pt, weak: true)
#line(length: 100%, stroke: rgb(200, 200, 200))
#v(25pt, weak: true)

// all other headers
] else [
#set text({ 36pt }, weight: 600, font: "Vollkorn", fill: rgb("#3E877A"), style: "italic")
#if it.level == 2 {
Comment on lines +96 to +112
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#set text({ 44pt }, ...) / #set text({ 36pt }, ...) appear to pass a content block as the font size. set text expects a length (or size: named arg), so this likely won’t type-check in Typst. Use a numeric length directly (e.g., 44pt) or size: 44pt / size: 36pt.

Copilot uses AI. Check for mistakes.
numbering("⧈ a)", deepest)
[ ]
}
#it.body
#v(40pt, weak: true)
]
}

// header grid
align(left,
grid(
// add one more column at the start for the left-side image
rows: (auto, auto),
columns: (210pt, title_column_size, univ_logo_column_size),
column-gutter: 25pt,
row-gutter: 30pt,

// left-side image cell
grid.cell(
pad(top: -18pt,
image("images/ome-arrow-logo.png", width: 210pt),
),
rowspan: 3,
align: left,
Comment on lines +124 to +136
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The header grid declares rows: (auto, auto) but later uses rowspan: 3 for multiple cells. With only two rows defined, this is likely invalid (or at least inconsistent) and may cause the Typst template to fail to compile. Consider defining three rows (e.g., title/authors/departments) or adjusting the rowspan values to match the declared grid shape.

Copilot uses AI. Check for mistakes.
),

// main title
grid.cell(
[
#show "➶": it => text(weight: 800, fill: rgb("#000000"))[#it]
#set par(linebreaks: "simple")
#text(
font: ("Vollkorn", "Apple Symbols", "Zapf Dingbats", "Arial Unicode MS"),
weight: 500,
size: title_font_size,
fill: rgb("#2A6F63"),
)[#title]
],
align: left,
),

// university logo on the far right
grid.cell(
pad(top: 2pt, pad( left: 20pt,
image(univ_logo, width: 130%),
)),
Comment on lines +156 to +158
Copy link

Copilot AI Apr 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pad(...) call appears malformed: pad(top: 2pt, pad(left: 20pt, ...)) nests a second pad( as if it were a named argument, which Typst won’t parse. Use a single pad call with multiple named parameters (e.g., top, left) around the image.

Suggested change
pad(top: 2pt, pad( left: 20pt,
image(univ_logo, width: 130%),
)),
pad(top: 2pt, left: 20pt,
image(univ_logo, width: 130%),
),

Copilot uses AI. Check for mistakes.
rowspan: 3,
align: right,
),

// author display
pad(top: 5pt, text(size: 28pt, authors)),

// department and notes display
pad(top: 5pt, text(size: 26pt, emph(departments)))
)
)

// spacing between the header and body
v(40pt)

// set main body display
show: columns.with(num_columns, gutter: 60pt)
// paragraph display properties
set par(leading: 10pt,
justify: false,
first-line-indent: 0em,
linebreaks: "optimized"
)

// Style inline code spans from markdown backticks.
show raw.where(block: false): set text(weight: 700, fill: rgb("#1E4F8C"))

// Style hyperlinks with a yellow/orange tone by default.
show link: set text(fill: rgb("#A85A00"))

// Configure figures.
show figure: it => block({
// Display a backdrop rectangle.
it.body

// Display caption.
if it.has("caption") {
set align(left)
v(if it.has("gap") { it.gap } else { 24pt }, weak: true)
let fig_levels = counter(figure).at(here())
let fig_num = if fig_levels != () { fig_levels.last() } else { 1 }
[
#text(weight: "bold")[Figure #fig_num:]
#h(6pt)
#text(weight: "regular")[#it.caption.body]
]
}

})

// adds body content to page
body
}
19 changes: 19 additions & 0 deletions docs/presentations/2026-OME-community-meeting/abstract.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# 2026 OME Community Meeting - OME-Arrow

## Authors

Dave Bunten, Jenna Tomkinson, Michael Lippincott, Cameron Mattson, Julia B. Curd, and Gregory P. Way

## Title

OME-Arrow: Unifying Images, Metadata, and Morphology in an Interoperable Data Model for High-Content Imaging

## Abstract

Modern bioimaging workflows combine images, metadata, and derived measurements across many tools, but these components are often stored in incompatible formats and disconnected systems. This fragmentation makes it difficult to join data, reproduce analyses, and scale from small experiments to large, multi-sample studies.

OME-Arrow is a data model and toolkit for working with bioimaging data in modern analytical environments, where data are processed in code, queried with SQL, and analyzed across tools such as Python and R. It brings images, metadata, and derived measurements into a single structure organized as linked tables, rather than leaving them split across separate files and systems. This allows imaging data to be directly joined, filtered, and analyzed using familiar operations, enabling image-derived measurements, metadata, and experimental context to be queried together in a single system. In contrast to existing workflows, where these relationships must be manually reconstructed across files and tools, OME-Arrow makes them explicit and queryable.

OME-Arrow builds on Open Microscopy Environment (OME) conventions and represents data using Apache Arrow, a columnar in-memory data format designed for fast analytics and efficient data sharing across programming languages. It supports ingestion from formats such as TIFF, OME-Zarr, and NumPy, and export to Arrow-native formats (e.g., Parquet, Lance, Vortex) as well as OME-TIFF and OME-Zarr. Data can be processed directly in standalone workflows using these formats, enabling local analysis, scripting, and integration with tools such as SQL engines and DuckDB. For larger-scale use cases, the same data can be organized into an Apache Iceberg-style table structure, which supports dataset versioning, schema evolution, and concurrent access across systems. These two modes use the same underlying data model, allowing workflows to scale from local analysis to warehouse environments without restructuring data. The library also provides lazy scan-style access for large datasets, supports tensor-based pathways for machine learning, and integrates with napari-ome-arrow for advanced visualization and CytoDataFrame for feature-centric analysis within Jupyter notebook environments.

These capabilities enable end-to-end image-based profiling workflows in which raw images, single-cell features, and experimental metadata are analyzed together without intermediate data reshaping. In pediatric cancer research settings, this supports direct querying across imaging data and derived measurements, enabling researchers to relate cellular morphology to perturbations such as compounds, genetic modifications, or treatment conditions. By making these relationships explicit and queryable, OME-Arrow reduces the need for custom data integration steps and improves the consistency of downstream analyses. This approach is being applied to pediatric cancer datasets in collaboration with Alex’s Lemonade Stand Foundation, where integrated access to imaging and profiling data supports systematic exploration of phenotype–treatment relationships and more reproducible analytical workflows.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file not shown.
Loading
Loading