diff --git a/.github/workflows/cleanup-pr-images.yml b/.github/workflows/cleanup-pr-images.yml index 1e80c39..0ded687 100644 --- a/.github/workflows/cleanup-pr-images.yml +++ b/.github/workflows/cleanup-pr-images.yml @@ -22,17 +22,17 @@ jobs: echo "Cleaning up images for PR #${PR_NUMBER}..." - # Get all versions of the package + # Get all versions of the package (merge paginated arrays) VERSIONS=$(gh api \ -H "Accept: application/vnd.github+json" \ -H "X-GitHub-Api-Version: 2022-11-28" \ "/orgs/seqeralabs/packages/container/${PACKAGE_NAME}/versions" \ - --paginate 2>/dev/null || echo "[]") + --paginate 2>/dev/null | jq -s 'add // []') # Find all versions with tags ending in -pr echo "$VERSIONS" | jq -r --arg pr "pr${PR_NUMBER}" ' .[] | - select(.metadata.container.tags[] | endswith("-" + $pr)) | + select(.metadata.container.tags[]? | endswith("-" + $pr)) | .id ' | while read -r VERSION_ID; do if [[ -n "$VERSION_ID" ]]; then diff --git a/.github/workflows/docker-pr.yml b/.github/workflows/docker-pr.yml index 26c5492..981d23d 100644 --- a/.github/workflows/docker-pr.yml +++ b/.github/workflows/docker-pr.yml @@ -15,42 +15,22 @@ jobs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - name: Checkout repository - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Detect changed Dockerfiles id: changes uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3 with: filters: | - ttyd: - - 'ttyd/**' - streamlit: - - 'streamlit/**' - cellxgene: - - 'cellxgene/**' - shiny: - - 'shiny-simple-example/**' - marimo: - - 'marimo/**' + kasmvnc_qupath: + - '.seqera/**' - name: Set matrix id: set-matrix run: | CONTAINERS="[]" - if [[ "${{ steps.changes.outputs.ttyd }}" == "true" ]]; then - CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"ttyd","path":"./ttyd"}]') - fi - if [[ "${{ steps.changes.outputs.streamlit }}" == "true" ]]; then - CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"streamlit","path":"./streamlit"}]') - fi - if [[ "${{ steps.changes.outputs.cellxgene }}" == "true" ]]; then - CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"cellxgene","path":"./cellxgene"}]') - fi - if [[ "${{ steps.changes.outputs.shiny }}" == "true" ]]; then - CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"shiny","path":"./shiny-simple-example"}]') - fi - if [[ "${{ steps.changes.outputs.marimo }}" == "true" ]]; then - CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"marimo","path":"./marimo"}]') + if [[ "${{ steps.changes.outputs.kasmvnc_qupath }}" == "true" ]]; then + CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"kasmvnc-qupath","path":"./.seqera"}]') fi echo "matrix={\"container\":$CONTAINERS}" >> "$GITHUB_OUTPUT" @@ -69,21 +49,21 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Log in to the Container registry - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GHCR_TOKEN }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 + uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3 - name: Extract metadata id: meta - uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5 + uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5 with: images: ${{ env.REGISTRY }}/${{ github.repository }}/development tags: | @@ -97,8 +77,8 @@ jobs: platforms: linux/amd64 tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha,scope=${{ matrix.container.name }} - cache-to: type=gha,mode=max,scope=${{ matrix.container.name }} + cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ github.repository }}/development:${{ matrix.container.name }}-buildcache + cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ github.repository }}/development:${{ matrix.container.name }}-buildcache,mode=max - name: Get image reference for scan id: scanref @@ -106,7 +86,7 @@ jobs: echo "ref=${{ fromJSON(steps.meta.outputs.json).tags[0] }}" >> $GITHUB_OUTPUT - name: Run security scan - uses: aquasecurity/trivy-action@0.31.0 + uses: aquasecurity/trivy-action@76071ef0d7ec797419534a183b498b4d6366cf37 # v0 with: image-ref: ${{ steps.scanref.outputs.ref }} format: "table" @@ -145,7 +125,7 @@ jobs: echo "- **Commit**: \`${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY - name: Comment on PR - uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7 + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7 with: script: | const fs = require('fs'); diff --git a/.github/workflows/docker-release.yml b/.github/workflows/docker-release.yml index c3e9e16..1e44083 100644 --- a/.github/workflows/docker-release.yml +++ b/.github/workflows/docker-release.yml @@ -8,11 +8,7 @@ on: required: true type: choice options: - - ttyd - - streamlit - - cellxgene - - shiny - - marimo + - kasmvnc-qupath version: description: 'Version to release (e.g., 1.0.0)' required: true @@ -36,32 +32,28 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 - name: Set container path id: container run: | case "${{ inputs.container }}" in - ttyd) echo "path=./ttyd" >> "$GITHUB_OUTPUT" ;; - streamlit) echo "path=./streamlit" >> "$GITHUB_OUTPUT" ;; - cellxgene) echo "path=./cellxgene" >> "$GITHUB_OUTPUT" ;; - shiny) echo "path=./shiny-simple-example" >> "$GITHUB_OUTPUT" ;; - marimo) echo "path=./marimo" >> "$GITHUB_OUTPUT" ;; + kasmvnc-qupath) echo "path=./.seqera" >> "$GITHUB_OUTPUT" ;; esac - name: Log in to the Container registry - uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 + uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GHCR_TOKEN }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 + uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3 - name: Extract metadata id: meta - uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5 + uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5 with: images: ${{ env.REGISTRY }}/${{ github.repository }}/${{ inputs.container }} tags: | @@ -81,11 +73,11 @@ jobs: CONNECT_CLIENT_VERSION=${{ inputs.connect_client_version || '0.9' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} - cache-from: type=gha,scope=${{ inputs.container }} - cache-to: type=gha,mode=max,scope=${{ inputs.container }} + cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ github.repository }}/${{ inputs.container }}:buildcache + cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ github.repository }}/${{ inputs.container }}:buildcache,mode=max - name: Create GitHub Release - uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2 + uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8 # v2 with: tag_name: ${{ inputs.container }}/${{ inputs.version }} name: ${{ inputs.container }} ${{ inputs.version }} diff --git a/.seqera/Dockerfile b/.seqera/Dockerfile new file mode 100644 index 0000000..d078661 --- /dev/null +++ b/.seqera/Dockerfile @@ -0,0 +1,69 @@ +# --------------------------------------------------------------- +# 1) Multi-stage build: Pull the connect-client binary +# --------------------------------------------------------------- +ARG CONNECT_CLIENT_VERSION=0.9 +FROM public.cr.seqera.io/platform/connect-client:${CONNECT_CLIENT_VERSION} AS connect + +# --------------------------------------------------------------- +# 2) KasmVNC base image with QuPath +# --------------------------------------------------------------- +FROM lscr.io/linuxserver/baseimage-kasmvnc:ubuntujammy + +# Just for the automation at Seqera +LABEL org.opencontainers.image.source="https://github.com/seqeralabs/custom-studios-examples" + +ENV TITLE="QuPath" + +# KasmVNC performance tuning for interactive desktop streaming +ENV KASM_VNC_ENABLE_WEBP=1 +ENV KASM_VNC_JPEG_QUALITY=5 +ENV KASM_VNC_MAX_FRAME_RATE=30 +ENV KASM_VNC_THREADS=4 + +# Install dependencies for QuPath. The base image can carry stale third-party apt +# sources, so drop NodeSource before refreshing Ubuntu package indexes. +RUN rm -f /etc/apt/sources.list.d/nodesource*.list \ + && apt-get update && apt-get install -y --no-install-recommends \ + wget \ + xz-utils \ + libgl1 \ + libgtk-3-0 \ + libopenslide0 \ + libglib2.0-0 \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +# Install QuPath +ARG QUPATH_VERSION="0.6.0" +RUN wget -q https://github.com/qupath/qupath/releases/download/v${QUPATH_VERSION}/QuPath-v${QUPATH_VERSION}-Linux.tar.xz -O /tmp/qupath.tar.xz \ + && mkdir -p /opt/qupath \ + && tar -xf /tmp/qupath.tar.xz -C /opt/qupath --strip-components=1 \ + && chmod +x /opt/qupath/bin/QuPath \ + && rm /tmp/qupath.tar.xz + + +# Create the X socket directory before KasmVNC drops privileges to the abc user. +RUN sed -i '/^exec s6-setuidgid/i mkdir -p /tmp/.X11-unix && chmod 1777 /tmp/.X11-unix' /etc/s6-overlay/s6-rc.d/svc-kasmvnc/run + +# Single-app mode: application launches directly, no desktop +RUN echo "/opt/qupath/bin/QuPath" > /defaults/autostart + +# --------------------------------------------------------------- +# 3) Seqera Studios integration +# --------------------------------------------------------------- + +# Add connect-client version label to image for supported capabilities tracking +ARG CONNECT_CLIENT_VERSION +LABEL io.seqera.connect.version="${CONNECT_CLIENT_VERSION}" + +# Copy connect-client from the first stage +COPY --from=connect /usr/bin/connect-client /usr/bin/connect-client + +# Install connect-client +RUN /usr/bin/connect-client --install + +# Seqera Studios entrypoint (connect-client handles Fusion filesystem) +ENTRYPOINT ["/usr/bin/connect-client", "--entrypoint"] + +# Bridge CONNECT_TOOL_PORT to KasmVNC's CUSTOM_PORT and launch the init system +CMD ["/bin/bash", "-c", "export CUSTOM_PORT=${CONNECT_TOOL_PORT:-6901} && exec /init"] diff --git a/.seqera/studio-config.yaml b/.seqera/studio-config.yaml new file mode 100644 index 0000000..f106d81 --- /dev/null +++ b/.seqera/studio-config.yaml @@ -0,0 +1,6 @@ +schemaVersion: "0.0.1" +kind: "studio-config" +session: + template: + kind: "dockerfile" + dockerfile: "Dockerfile" diff --git a/README.md b/README.md index 6330ba8..0afa102 100644 --- a/README.md +++ b/README.md @@ -1,116 +1,70 @@ -# Custom Studios Examples +# QuPath KasmVNC Studio Environment -Example configurations for deploying custom [Seqera Studio](https://docs.seqera.io/platform-cloud/studios/overview) applications from a Git repository. +This branch contains the Seqera Studios configuration for running [QuPath](https://qupath.github.io/) with [KasmVNC](https://kasmweb.com/kasmvnc), making the QuPath desktop available through a browser in Seqera Platform. -> **Do not merge studio configurations into `master`!** Each studio has its own dedicated branch. +> This is a branch of the [custom-studios-examples](https://github.com/seqeralabs/custom-studios-examples) repository. Each branch contains a different custom Studio configuration. See the `master` branch for an overview of all available Studios. -## Repository Structure +## Quick Start -This repository uses a **branch-per-studio** model (similar to [nf-core/test-datasets](https://github.com/nf-core/test-datasets)). The `master` branch contains only this documentation. Each studio's configuration lives on its own branch with a `.seqera/` directory containing the `studio-config.yaml` and `Dockerfile` required for [launching Studios from a Git repository](https://docs.seqera.io/platform-cloud/studios/add-studio-git-repo). - -## Available Studios - -| Branch | Studio | Description | -|--------|--------|-------------| -| [`marimo`](https://github.com/seqeralabs/custom-studios-examples/tree/marimo) | Marimo | Reactive Python notebook environment | -| [`cellxgene`](https://github.com/seqeralabs/custom-studios-examples/tree/cellxgene) | CellxGene | Interactive single-cell data visualization | -| [`streamlit`](https://github.com/seqeralabs/custom-studios-examples/tree/streamlit) | Streamlit | MultiQC visualization using Streamlit | -| [`shiny`](https://github.com/seqeralabs/custom-studios-examples/tree/shiny) | R Shiny | Interactive data visualization with R Shiny | -| [`shinyngs`](https://github.com/seqeralabs/custom-studios-examples/tree/shinyngs) | Shinyngs | RNA-seq exploration with the `shinyngs` R package | -| [`ttyd`](https://github.com/seqeralabs/custom-studios-examples/tree/ttyd) | TTYD | Web-based terminal with bioinformatics tools | - -## Quick Start: Launch from Git Repository +### Add from Git Repository 1. Navigate to **Studios** > **Add Studio** in your Seqera Platform workspace 2. Select **Git repository** as the source 3. Enter the repository URL: `https://github.com/seqeralabs/custom-studios-examples` -4. Select the branch for the studio you want (e.g., `marimo`, `cellxgene`, `streamlit`, `shiny`, `shinyngs`, `ttyd`) +4. Select branch: `kasmvnc-qupath` 5. Select your compute environment 6. Click **Add** then **Start** -Each branch contains a `.seqera/` directory with: -- `studio-config.yaml` — Studio configuration pointing to the Dockerfile -- `Dockerfile` — Container definition with connect-client integration -- Any supporting files required by the Dockerfile - -## Alternative Deployment: Pre-built Images - -Each studio is also available as a pre-built container image: +### Alternative: Use Pre-built Image ``` -ghcr.io/seqeralabs/custom-studios-examples/marimo:latest -ghcr.io/seqeralabs/custom-studios-examples/cellxgene:latest -ghcr.io/seqeralabs/custom-studios-examples/streamlit:latest -ghcr.io/seqeralabs/custom-studios-examples/shiny:latest -ghcr.io/seqeralabs/custom-studios-examples/shinyngs:latest -ghcr.io/seqeralabs/custom-studios-examples/ttyd:latest +ghcr.io/seqeralabs/custom-studios-examples/kasmvnc-qupath:latest ``` -To use a pre-built image, select **Prebuilt container image** instead of **Git repository** when adding a Studio. - -## Alternative Deployment: Wave CLI - -You can also build any studio with the [Wave CLI](https://docs.seqera.io/wave/): +### Alternative: Build with Wave CLI ```bash -# Clone only the branch you need -git clone https://github.com/seqeralabs/custom-studios-examples.git --single-branch --branch - -# Build with Wave wave -f .seqera/Dockerfile --context .seqera --platform linux/amd64 --await --tower-token "$TOWER_ACCESS_TOKEN" ``` -## Cloning a Specific Studio +## Features -Due to the branch-per-studio model, we recommend cloning only the branch you need: +- QuPath 0.6.0 bioimage analysis desktop +- Browser access through LinuxServer.io KasmVNC +- Single-app mode that launches QuPath directly +- KasmVNC WebP, quality, frame-rate, and thread tuning for interactive use +- Compatible with Seqera Studios custom environments and Data Link mounts -```bash -git clone https://github.com/seqeralabs/custom-studios-examples.git --single-branch --branch -``` +> **Note:** QuPath is x86_64 only. Build and run this Studio as `linux/amd64`. -To add another branch later: +## Docker Image -```bash -git remote set-branches --add origin -git fetch -``` - -## Environment Variables - -Some studios support environment variable configuration: - -| Studio | Variable | Default | Description | -|--------|----------|---------|-------------| -| CellxGene | `DATASET_FILE` | `s3://cellxgene_datasets/pbmc3k.h5ad` | Path to .h5ad dataset | -| CellxGene | `DATASET_TITLE` | `PBMCs 3k test dataset` | Display title | -| CellxGene | `USER_DATA_DIR` | `/user-data/cellxgene` | User data storage | -| CellxGene | `ANNOTATIONS_DIR` | `/user-data/cellxgene` | Annotations storage | -| Shiny | `DATA_PATH` | `s3://shiny-inputs/data.csv` | Path to CSV data file | +The container image is available at: -Studios without listed variables (Marimo, Shinyngs, Streamlit, TTYD) work with their default configurations. +``` +ghcr.io/seqeralabs/custom-studios-examples/kasmvnc-qupath:latest +``` -## Common Features +## Local Testing -All studios in this repository: -- Use the `.seqera/` directory convention for Git-based Studio deployment -- Include the required Seqera `connect-client` for platform integration -- Support data mounting via datalinks in Studios -- Are built for `linux/amd64` platform compatibility -- Use multi-stage Docker builds with connect-client +```bash +cd .seqera +docker build --platform=linux/amd64 --build-arg CONNECT_CLIENT_VERSION=0.9 -t kasmvnc-qupath . +docker run --rm --platform linux/amd64 --shm-size=2g -p 6901:6901 --entrypoint /init kasmvnc-qupath +``` -## Documentation +QuPath will be available at http://localhost:6901. -- [Add a Studio from a Git repository](https://docs.seqera.io/platform-cloud/studios/add-studio-git-repo) -- [Custom studio environments](https://docs.seqera.io/platform-cloud/studios/custom-envs) -- [Wave CLI](https://docs.seqera.io/wave/) -- [Deploying custom applications in Seqera Studios](https://seqera.io/blog/deploy-custom-apps-studios/) +## Configuration -## Contributing +| Variable | Default | Description | +|----------|---------|-------------| +| `CONNECT_TOOL_PORT` | Set by platform | KasmVNC web port in Seqera Studios | +| `CUSTOM_PORT` | `CONNECT_TOOL_PORT` or `6901` | KasmVNC web port used by the base image | -To add a new studio: +## References -1. Create a new branch from an empty root (orphan branch): `git checkout --orphan ` -2. Add a `.seqera/` directory with `studio-config.yaml` and `Dockerfile` -3. Add a `README.md` documenting the studio -4. Push the branch -5. Update this README on `master` to list the new studio +- [Seqera Studios: Custom Environments](https://docs.seqera.io/platform-cloud/studios/custom-envs) +- [Seqera Studios: Add from Git Repository](https://docs.seqera.io/platform-cloud/studios/add-studio-git-repo) +- [QuPath Documentation](https://qupath.readthedocs.io/) +- [KasmVNC Documentation](https://kasmweb.com/kasmvnc) diff --git a/cellxgene/Dockerfile b/cellxgene/Dockerfile deleted file mode 100644 index 98cf9e7..0000000 --- a/cellxgene/Dockerfile +++ /dev/null @@ -1,85 +0,0 @@ -# --------------------------------------------------------------- -# 1) Multi-stage build: Pull the connect-client binary -# --------------------------------------------------------------- -ARG CONNECT_CLIENT_VERSION=0.9 -FROM public.cr.seqera.io/platform/connect-client:${CONNECT_CLIENT_VERSION} AS connect - -# --------------------------------------------------------------- -# 2) Additional base image for CellxGene -# --------------------------------------------------------------- -FROM python:3.10-slim - -# Just for the automation at Seqera -LABEL org.opencontainers.image.source="https://github.com/seqeralabs/custom-studios-examples" - -# Avoid interactive prompts during package install -ENV DEBIAN_FRONTEND=noninteractive - -# Add backports repository and install specific btrfs-progs version -RUN echo "deb http://deb.debian.org/debian bookworm-backports main contrib non-free-firmware" | tee -a /etc/apt/sources.list && \ - apt-get update && \ - apt-get install -y btrfs-progs=6.14-1~bpo12+1 - -# Update packages and install minimal tools -RUN apt-get update && apt-get install -y \ - build-essential \ - wget \ - && rm -rf /var/lib/apt/lists/* - -# Install CellxGene and its dependencies -RUN pip install cellxgene==1.3.0 - -# Define CellxGene dataset path and title with defaults -ENV DATASET_FILE=s3://cellxgene_datasets/pbmc3k.h5ad -ENV DATASET_TITLE="PBMCs 3k test dataset" -ENV USER_DATA_DIR=/user-data/cellxgene -ENV ANNOTATIONS_DIR=/user-data/cellxgene - -# Create user-data directory -RUN mkdir -p /user-data/cellxgene - -# Add connect-client version label to image for supported capabilties tracking -ARG CONNECT_CLIENT_VERSION -LABEL io.seqera.connect.version="${CONNECT_CLIENT_VERSION}" - -# Copy connect-client from the first stage -COPY --from=connect /usr/bin/connect-client /usr/bin/connect-client - -# "Install" connect-client (sets up any needed config) -RUN /usr/bin/connect-client --install - -# --------------------------------------------------------------- -# 3) Launch with connect-client --entrypoint (for Tower) -# --------------------------------------------------------------- -ENTRYPOINT ["/usr/bin/connect-client", "--entrypoint"] - -# --------------------------------------------------------------- -# 4) Command: Run CellxGene with cloud storage path translation -# --------------------------------------------------------------- -# The port is set by CONNECT_TOOL_PORT environment variable -# Convert cloud storage paths to local Studio paths -CMD ["/bin/bash", "-c", "bash <<'EOF'\n\ -# Function to convert cloud storage path to local Studio path\n\ -convert_path() {\n\ - local input_path=\"$1\"\n\ - if [[ \"$input_path\" =~ ^(s3|gs|az):// ]]; then\n\ - local cloud_path=${input_path#*://}\n\ - local bucket_name=${cloud_path%%/*}\n\ - local object_path=${cloud_path#*/}\n\ - echo \"/workspace/data/$bucket_name/$object_path\"\n\ - else\n\ - echo \"$input_path\"\n\ - fi\n\ -}\n\ -\n\ -DATASET_LOCAL=$(convert_path \"${DATASET_FILE}\")\n\ -USERDATA_LOCAL=$(convert_path \"${USER_DATA_DIR}\")\n\ -ANNOTATIONS_LOCAL=$(convert_path \"${ANNOTATIONS_DIR}\")\n\ -\n\ -mkdir -p \"${USERDATA_LOCAL}\" \"${ANNOTATIONS_LOCAL}\"\n\ -\n\ -/usr/local/bin/cellxgene launch --host 0.0.0.0 --port ${CONNECT_TOOL_PORT} \\\n\ - --user-generated-data-dir \"${USERDATA_LOCAL}\" \\\n\ - --annotations-dir \"${ANNOTATIONS_LOCAL}\" \\\n\ - --title \"${DATASET_TITLE}\" \"${DATASET_LOCAL}\"\n\ -EOF"] \ No newline at end of file diff --git a/cellxgene/README.md b/cellxgene/README.md deleted file mode 100644 index 73f1f9f..0000000 --- a/cellxgene/README.md +++ /dev/null @@ -1,158 +0,0 @@ -# CellxGene Studio Environment - -This example provides a custom container image for running [CellxGene](https://chanzuckerberg.github.io/cellxgene/), an interactive single-cell data visualization platform, as a Studio environment in Seqera Platform. - -## Table of Contents - -- [Overview](#overview) -- [Features](#features) -- [Files](#files) -- [Prerequisites](#prerequisites) -- [Building the Container](#building-the-container) -- [Local Testing](#local-testing) -- [Using in Seqera Studios](#using-in-seqera-studios) -- [Notes](#notes) -- [References](#references) - -## Overview - -This container is designed for use as a [custom Studio environment](https://docs.seqera.io/platform-cloud/studios/custom-envs) in Seqera Platform. It provides an interactive interface for exploring single-cell data using the CellxGene visualization platform. - -![Screenshot of CellxGene](screenshot.png) - -## Docker Image - -The container image is available at: -``` -ghcr.io/seqeralabs/custom-studios-examples/cellxgene:latest -``` - -For specific versions, use the release tag (e.g., `ghcr.io/seqeralabs/custom-studios-examples/cellxgene:v1.0.0`). - -## Features - -- CellxGene 1.3.0 visualization platform -- Support for .h5ad datasets -- Interactive single-cell data exploration -- Automatic data mounting via datalinks -- Configurable dataset path, title, and storage directories via environment variables -- Cloud storage path support with automatic translation to local Studio paths - -> [!NOTE] -> For common features shared across all examples, see the [main README](../README.md#common-features). - -## Files - -- `Dockerfile`: Container definition using multi-stage build -- `README.md`: This documentation file -- `screenshot.png`: Example screenshot of the CellxGene interface - -## Prerequisites - -> [!NOTE] -> For common prerequisites, see the [main README](../README.md#prerequisites). - -Additional requirements specific to this example: -- .h5ad format single-cell datasets - -## Building the Container - -> [!IMPORTANT] -> You must provide the `CONNECT_CLIENT_VERSION` build argument when building the container. - -To build the container locally: - -```bash -docker build --platform=linux/amd64 --build-arg CONNECT_CLIENT_VERSION=0.8 -t cellxgene-example . -``` - -## Local Testing - -To test the app locally, you need to override the entrypoint: - -```bash -docker run -p 3000:3000 --entrypoint /usr/local/bin/cellxgene cellxgene-example launch \ - --host 0.0.0.0 \ - --port 3000 \ - --user-generated-data-dir /user-data/cellxgene \ - --annotations-dir /user-data/cellxgene \ - --title "PBMCs 3k test dataset" \ - /path/to/your/dataset.h5ad -``` - -To use a specific data file, make it available at /workspace/data/cellxgene_datasets/ in the container: - -```bash -docker run -p 3000:3000 --entrypoint /usr/local/bin/cellxgene -v $(pwd)/data:/workspace/data/cellxgene_datasets cellxgene-example launch \ - --host 0.0.0.0 \ - --port 3000 \ - --user-generated-data-dir /user-data/cellxgene \ - --annotations-dir /user-data/cellxgene \ - --title "Your Dataset" \ - /workspace/data/cellxgene_datasets/your_dataset.h5ad -``` - -The app will be available at http://localhost:3000 - -## Cloud Storage Path Translation - -The container automatically converts cloud storage paths to local Studio paths. Supported providers include: - -- **Amazon S3**: `s3://bucket/path/to/dataset.h5ad` -- **Google Cloud Storage**: `gs://bucket/path/to/dataset.h5ad` -- **Azure Blob Storage**: `az://container/path/to/dataset.h5ad` - -**Examples:** -- S3: `s3://my-genomics-data/single-cell/experiment1.h5ad` → `/workspace/data/my-genomics-data/single-cell/experiment1.h5ad` -- GCS: `gs://research-bucket/datasets/pbmc3k.h5ad` → `/workspace/data/research-bucket/datasets/pbmc3k.h5ad` -- Azure: `az://data-container/studies/cellxgene.h5ad` → `/workspace/data/data-container/studies/cellxgene.h5ad` - -**Requirements:** -- Mount the cloud storage bucket/container from Data Explorer in Seqera Studios -- Provide cloud storage paths in the `DATASET_FILE` environment variable - -> [!WARNING] -> **Bucket Mounting Required**: When using cloud storage paths (`s3://`, `gs://`, `az://`), ensure the corresponding buckets are mounted in your Studio via the **Mount data** option. Unmounted buckets will cause the Studio to fail when trying to access the converted paths. - -## Using in Seqera Studios - -> [!NOTE] -> For the common deployment process, see the [main README](../README.md#deploying-to-seqera-studios). - -Additional steps specific to this example: -1. In the **Compute and Data** tab, click the **Mount data** button to mount your cloud storage bucket/container -2. Follow the common deployment process -3. Configure environment variables: - - `DATASET_FILE`: Cloud storage path to your .h5ad file - - Supports S3 (`s3://`), Google Cloud Storage (`gs://`), and Azure Blob Storage (`az://`) paths - - Example: `s3://my-genomics-data/single-cell/experiment1.h5ad` - - `DATASET_TITLE`: Title to display in the CellxGene interface - - Example: `"My Single-Cell Analysis"` - - `USER_DATA_DIR`: Path for user-generated data storage - - Default: `/user-data/cellxgene` (local directory) - - Supports cloud storage paths (automatically converted to local Studio paths) - - Example: `s3://my-bucket/user-data/cellxgene` - - `ANNOTATIONS_DIR`: Path for annotations storage - - Default: `/user-data/cellxgene` (local directory) - - Supports cloud storage paths (automatically converted to local Studio paths) - - Example: `s3://my-bucket/annotations/cellxgene` - -> [!WARNING] -> **Bucket Mounting**: If using cloud storage paths for `USER_DATA_DIR` or `ANNOTATIONS_DIR`, ensure the corresponding buckets are mounted in your Studio. Unmounted buckets will cause the Studio to fail when trying to access the converted paths. - -## Notes - -- The app uses CellxGene 1.3.0 for interactive single-cell data visualization -- User data and annotations directories can be configured via environment variables -- Default storage locations: `/user-data/cellxgene` (can be overridden with cloud storage paths) -- Specify your dataset via the DATASET_FILE environment variable -- Customize the display title via the DATASET_TITLE environment variable - -> [!NOTE] -> For common technical notes, see the [main README](../README.md#common-features). - -## References - -- [CellxGene Documentation](https://chanzuckerberg.github.io/cellxgene/) -- [Seqera Studios: Custom Environments](https://docs.seqera.io/platform-cloud/studios/custom-envs) -- [Wave Documentation](https://docs.seqera.io/platform-cloud/wave/) \ No newline at end of file diff --git a/cellxgene/screenshot.png b/cellxgene/screenshot.png deleted file mode 100644 index 301cfeb..0000000 Binary files a/cellxgene/screenshot.png and /dev/null differ diff --git a/marimo/Dockerfile b/marimo/Dockerfile deleted file mode 100644 index 2f86114..0000000 --- a/marimo/Dockerfile +++ /dev/null @@ -1,35 +0,0 @@ -# --------------------------------------------------------------- -# 1) Multi-stage build: Pull the connect-client binary -# --------------------------------------------------------------- -# Test Build -ARG CONNECT_CLIENT_VERSION=0.9 -FROM public.cr.seqera.io/platform/connect-client:${CONNECT_CLIENT_VERSION} AS connect - -# Choose a python version that you know works with your application -FROM python:3.11-slim - -# Just for the automation at Seqera -LABEL org.opencontainers.image.source="https://github.com/seqeralabs/custom-studios-examples" - -# Install uv for fast package management -COPY --from=ghcr.io/astral-sh/uv:0.4.20 /uv /bin/uv - -ENV UV_SYSTEM_PYTHON=1 - -WORKDIR /app - -# Install the requirements using uv -RUN uv pip install scikit-learn pandas altair micropip marimo==0.11.13 - -# Define the port for the marimo server -EXPOSE $CONNECT_TOOL_PORT - -ARG CONNECT_CLIENT_VERSION -LABEL io.seqera.connect.version="${CONNECT_CLIENT_VERSION}" -COPY --from=connect /usr/bin/connect-client /usr/bin/connect-client -RUN /bin/sh -c "/usr/bin/connect-client --install" -RUN echo "deb http://deb.debian.org/debian bookworm-backports main contrib non-free-firmware" | tee -a /etc/apt/sources.list -RUN apt update && apt install -y --allow-downgrades btrfs-progs=6.14-1~bpo12+1 -ENTRYPOINT ["/usr/bin/connect-client", "--entrypoint"] - -CMD marimo edit -p $CONNECT_TOOL_PORT --no-token diff --git a/marimo/README.md b/marimo/README.md deleted file mode 100644 index 8bd9a6d..0000000 --- a/marimo/README.md +++ /dev/null @@ -1,81 +0,0 @@ -# Marimo Studio Environment - -This repository provides a custom container image for running [marimo](https://marimo.io), an open-source reactive Python notebook, as a Studio environment in Seqera Platform. - -## Docker Image - -The container image is available at: -``` -ghcr.io/seqeralabs/custom-studios-examples/marimo:latest -``` - -For specific versions, use the release tag (e.g., `ghcr.io/seqeralabs/custom-studios-examples/marimo:v1.0.0`). - -## Table of Contents - -- [Overview](#overview) -- [Features](#features) -- [Prerequisites](#prerequisites) -- [Building the Container](#building-the-container) -- [Using in Seqera Studios](#using-in-seqera-studios) -- [Customizing the Environment](#customizing-the-environment) -- [Notes](#notes) -- [References](#references) - -## Overview - -This container is designed for use as a [custom Studio environment](https://docs.seqera.io/platform-cloud/studios/custom-envs) in Seqera Platform. It is based on the required Seqera base image and includes the necessary `connect-client` for compatibility. - -## Features - -- Open-source, reactive Python notebook (marimo) -- Reproducible and git-friendly -- SQL built-in, script execution, and app sharing -- Compatible with Seqera Studios custom environments - -> [!WARNING] -> Marimo does not support opening the same notebook in multiple tabs to avoid state conflicts. They have recently added a feature to allow this, but it has not been tested in Seqera Studios. - -## Prerequisites - -- [Docker](https://www.docker.com/) installed -- [Wave](https://docs.seqera.io/platform-cloud/wave/) configured in your Seqera Platform workspace (required for custom environments) -- Access to a container registry (public or Amazon ECR) if you wish to push your image - -## Building the Container - -> [!IMPORTANT] -> You must provide the `CONNECT_CLIENT_VERSION` build argument when building the container. - -To build the container locally: - -```sh -docker build --platform=linux/amd64 --build-arg CONNECT_CLIENT_VERSION=0.8 -t marimo-studio . -``` - -> [!NOTE] -> The container must use the value of the `CONNECT_TOOL_PORT` environment variable as the listening port for marimo. The Dockerfile is already configured for this. - -## Using in Seqera Studios - -1. **Push your image** to a container registry accessible by Seqera Platform. -2. In Seqera Platform, go to the **Studios** tab and click **Add Studio**. -3. Select **Prebuilt container image** as the template. -4. Enter your container image URI (e.g., `cr.your-registry.io/your-org/marimo-studio:latest`). -5. Configure compute resources and data mounts as needed. -6. Launch the Studio. - -For more details, see the [official documentation](https://docs.seqera.io/platform-cloud/studios/custom-envs). - -## Customizing the Environment - -You can further customize this environment by: - -- Adding Conda or pip packages (see [Conda package syntax](https://docs.seqera.io/platform-cloud/studios/custom-envs#conda-package-syntax)) -- Modifying the Dockerfile to include additional dependencies - -## References - -- [Seqera Studios: Custom Environments](https://docs.seqera.io/platform-cloud/studios/custom-envs) -- [marimo Documentation](https://marimo.io) -- [Wave Documentation](https://docs.seqera.io/platform-cloud/wave/) diff --git a/shiny-simple-example/Dockerfile b/shiny-simple-example/Dockerfile deleted file mode 100644 index 05d2fe5..0000000 --- a/shiny-simple-example/Dockerfile +++ /dev/null @@ -1,73 +0,0 @@ -# --------------------------------------------------------------- -# 1) Multi-stage build: Pull the connect-client binary -# --------------------------------------------------------------- -ARG CONNECT_CLIENT_VERSION=0.9 -FROM public.cr.seqera.io/platform/connect-client:${CONNECT_CLIENT_VERSION} AS connect - -# --------------------------------------------------------------- -# 2) Final stage: Ubuntu + micromamba + r-shiny -# --------------------------------------------------------------- -FROM ubuntu:22.04 - -# Just for the automation at Seqera -LABEL org.opencontainers.image.source="https://github.com/seqeralabs/custom-studios-examples" - -# Avoid interactive prompts during package install -ENV DEBIAN_FRONTEND=noninteractive - -# Update packages and install minimal tools -RUN apt-get update --yes && apt-get install --yes --no-install-recommends \ - wget \ - ca-certificates \ - bzip2 \ - && rm -rf /var/lib/apt/lists/* - -# --------------------------------------------------------------- -# Install micromamba -# --------------------------------------------------------------- -ENV MAMBA_ROOT_PREFIX=/opt/conda -RUN wget -qO- https://micromamba.snakepit.net/api/micromamba/linux-64/latest \ - | tar -xvj --strip-components=1 bin/micromamba \ - && mv micromamba /usr/local/bin/micromamba \ - && mkdir -p /opt/conda \ - && chmod -R 777 /opt/conda - -# Create a conda env with shiny and additional R packages -RUN rm -rf /opt/conda/pkgs/*.lock && \ - micromamba create -y -n shiny -c conda-forge \ - r-shiny \ - r-ggplot2 \ - r-dplyr \ - && micromamba clean --all --yes \ - && rm -rf /opt/conda/pkgs/*.lock - -# Add connect-client version label to image for supported capabilties tracking -ARG CONNECT_CLIENT_VERSION -LABEL io.seqera.connect.version="${CONNECT_CLIENT_VERSION}" - -# Copy connect-client from the first stage -COPY --from=connect /usr/bin/connect-client /usr/bin/connect-client - -# "Install" connect-client (sets up any needed config) -RUN /usr/bin/connect-client --install - -# Set a working directory for your app -WORKDIR /app - -# Define data path with default -ENV DATA_PATH=s3://shiny-inputs/data.csv - -# Copy your Shiny code and data -COPY app_plot_demo.R /app/ -COPY data.csv /app/ - -# --------------------------------------------------------------- -# 3) Launch with connect-client --entrypoint (for Tower) -# --------------------------------------------------------------- -ENTRYPOINT ["/usr/bin/connect-client", "--entrypoint"] - -# --------------------------------------------------------------- -# 4) Command: Run your Shiny app via micromamba -# --------------------------------------------------------------- -# The port is set by CONNECT_TOOL_PORT environment variable -CMD ["micromamba", "run", "-n", "shiny", "R", "-e", "shiny::runApp('/app/app_plot_demo.R', host='0.0.0.0', port=as.integer(Sys.getenv('CONNECT_TOOL_PORT')))"] \ No newline at end of file diff --git a/shiny-simple-example/README.md b/shiny-simple-example/README.md deleted file mode 100644 index 1d5488c..0000000 --- a/shiny-simple-example/README.md +++ /dev/null @@ -1,126 +0,0 @@ -# Shiny Studio Environment - -This example provides a custom container image for running a [R Shiny](https://shiny.rstudio.com/) application in Seqera Platform, demonstrating interactive data visualization capabilities. - -## Table of Contents - -- [Overview](#overview) -- [Features](#features) -- [Files](#files) -- [Prerequisites](#prerequisites) -- [Building the Container](#building-the-container) -- [Local Testing](#local-testing) -- [Using in Seqera Studios](#using-in-seqera-studios) -- [Notes](#notes) -- [References](#references) - -## Overview - -This container is designed for use as a [custom Studio environment](https://docs.seqera.io/platform-cloud/studios/custom-envs) in Seqera Platform. It provides a simple but powerful example of interactive data visualization using R Shiny. - -![Screenshot of the Shiny app](screenshot.png) - -## Docker Image - -The container image is available at: -``` -ghcr.io/seqeralabs/custom-studios-examples/shiny:latest -``` - -For specific versions, use the release tag (e.g., `ghcr.io/seqeralabs/custom-studios-examples/shiny:v1.0.0`). - -## Features - -- Advanced data visualization with multiple plot types (scatter, line, bar, box, density) -- Interactive controls and color themes -- Compatible with both local Docker testing and Seqera Studios -- Efficient package management with micromamba -- Easy data mounting via datalinks -- Configurable data path via environment variables -- Cloud storage path support with automatic translation to local Studio paths - -## Files - -- `app_plot_demo.R`: The main Shiny application -- `example_data.csv`: Sample data for the visualization -- `Dockerfile`: Container definition - -## Prerequisites - -- [Docker](https://www.docker.com/) installed -- [Wave](https://docs.seqera.io/platform-cloud/wave/) configured in your Seqera Platform workspace -- Access to a container registry (public or Amazon ECR) if you wish to push your image -- R data files in CSV format - -## Building the Container - -> [!IMPORTANT] -> You must provide the `CONNECT_CLIENT_VERSION` build argument when building the container. - -To build the container locally: - -```bash -docker build --platform=linux/amd64 --build-arg CONNECT_CLIENT_VERSION=0.8 -t shiny-simple-example . -``` - -## Local Testing - -To test the app locally, you need to override the entrypoint: - -```bash -docker run -p 3000:3000 --entrypoint micromamba shiny-simple-example run -n shiny R -e "shiny::runApp('/app/app_plot_demo.R', host='0.0.0.0', port=3000)" -``` - -To use a specific data file, make it available at /workspace/data/shiny-inputs/data.csv in the container: - -```bash -docker run -p 3000:3000 --entrypoint micromamba -v $(pwd)/../data/shiny-inputs:/workspace/data/shiny-inputs shiny-simple-example run -n shiny R -e "shiny::runApp('/app/app_plot_demo.R', host='0.0.0.0', port=3000)" -``` - -The app will be available at http://localhost:3000 - -## Cloud Storage Path Translation - -The application automatically converts cloud storage paths to local Studio paths. Supported providers include: - -- **Amazon S3**: `s3://bucket/path/to/data.csv` -- **Google Cloud Storage**: `gs://bucket/path/to/data.csv` -- **Azure Blob Storage**: `az://container/path/to/data.csv` - -**Examples:** -- S3: `s3://my-data-bucket/datasets/experiment.csv` → `/workspace/data/my-data-bucket/datasets/experiment.csv` -- GCS: `gs://research-data/analysis/results.csv` → `/workspace/data/research-data/analysis/results.csv` -- Azure: `az://data-container/studies/sample.csv` → `/workspace/data/data-container/studies/sample.csv` - -**Requirements:** -- Mount the cloud storage bucket/container from Data Explorer in Seqera Studios -- Provide cloud storage paths in the `DATA_PATH` environment variable - -## Using in Seqera Studios - -> [!NOTE] -> For the common deployment process, see the [main README](../README.md#deploying-to-seqera-studios). - -Additional steps specific to this example: -1. In the **Compute and Data** tab, click the **Mount data** button to mount your cloud storage bucket/container -2. Follow the common deployment process -3. Configure environment variables: - - `DATA_PATH`: Cloud storage path to your CSV file - - Supports S3 (`s3://`), Google Cloud Storage (`gs://`), and Azure Blob Storage (`az://`) paths - - Example: `s3://my-data-bucket/datasets/experiment.csv` - -## Notes - -- The app provides advanced data visualization with multiple plot types and interactive controls -- The Dockerfile uses micromamba for efficient package management -- The container is built for linux/amd64 platform compatibility -- Data files should be in CSV format -- Specify your data file via the DATA_PATH environment variable -- Cloud storage paths are automatically converted to local Studio paths - -## References - -- [Seqera Studios: Custom Environments](https://docs.seqera.io/platform-cloud/studios/custom-envs) -- [R Shiny Documentation](https://shiny.rstudio.com/) -- [Micromamba Documentation](https://mamba.readthedocs.io/) -- [Wave Documentation](https://docs.seqera.io/platform-cloud/wave/) diff --git a/shiny-simple-example/app_plot_demo.R b/shiny-simple-example/app_plot_demo.R deleted file mode 100644 index b5073e1..0000000 --- a/shiny-simple-example/app_plot_demo.R +++ /dev/null @@ -1,227 +0,0 @@ -library(shiny) -library(ggplot2) -library(dplyr) - -# Define UI -ui <- fluidPage( - # Custom CSS for better styling - tags$head( - tags$style(HTML(" - body { background-color: #f5f5f5; } - .well { background-color: white; border-radius: 10px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } - .panel { border-radius: 10px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); } - .panel-heading { border-radius: 10px 10px 0 0; } - .btn-primary { background-color: #4a90e2; border-color: #4a90e2; } - .btn-primary:hover { background-color: #357abd; border-color: #357abd; } - ")) - ), - - # Title panel - titlePanel("Advanced Data Visualization"), - - # Sidebar layout - sidebarLayout( - sidebarPanel( - # Data source message at the top - div(style = "margin-bottom: 20px; padding: 10px; background-color: #e8f4f8; border-radius: 5px;", - textOutput("data_source") - ), - - # Plot type selection - selectInput("plot_type", "Select Plot Type:", - choices = c("Scatter Plot" = "scatter", - "Line Plot" = "line", - "Bar Plot" = "bar", - "Box Plot" = "box", - "Density Plot" = "density"), - selected = "scatter"), - - # Color theme selection - selectInput("color_theme", "Select Color Theme:", - choices = c("Default" = "default", - "Viridis" = "viridis", - "Brewer Blues" = "blues", - "Brewer Reds" = "reds"), - selected = "default"), - - # Additional controls based on plot type - conditionalPanel( - condition = "input.plot_type == 'scatter'", - sliderInput("point_size", "Point Size:", min = 1, max = 10, value = 3), - checkboxInput("add_trend", "Add Trend Line", value = TRUE) - ), - - conditionalPanel( - condition = "input.plot_type == 'line'", - sliderInput("line_width", "Line Width:", min = 0.5, max = 3, value = 1), - checkboxInput("add_points", "Add Points", value = TRUE) - ), - - conditionalPanel( - condition = "input.plot_type == 'bar'", - sliderInput("bar_width", "Bar Width:", min = 0.1, max = 1, value = 0.7), - checkboxInput("add_error_bars", "Add Error Bars", value = TRUE) - ), - - conditionalPanel( - condition = "input.plot_type == 'box'", - checkboxInput("add_points", "Add Points", value = TRUE), - checkboxInput("add_violin", "Add Violin Plot", value = FALSE) - ), - - conditionalPanel( - condition = "input.plot_type == 'density'", - sliderInput("bandwidth", "Bandwidth:", min = 0.1, max = 2, value = 0.5), - checkboxInput("add_rug", "Add Rug Plot", value = TRUE) - ), - - # Summary statistics panel - div(style = "margin-top: 20px;", - h4("Summary Statistics"), - verbatimTextOutput("summary_stats") - ) - ), - - # Main panel - mainPanel( - # Plot output - plotOutput("plot", height = "500px"), - - # Data table - div(style = "margin-top: 20px;", - h4("Data Table"), - dataTableOutput("data_table") - ) - ) - ) -) - -# Define server logic -server <- function(input, output, session) { - # Read data - data <- reactive({ - data_path <- Sys.getenv('DATA_PATH', 's3://shiny-inputs/data.csv') - - # Convert cloud storage path to local Studio path - if (grepl('^s3://|^gs://|^az://', data_path)) { - # Remove any cloud storage prefix and convert to local path - cloud_path <- sub('^[^:]+://', '', data_path) - bucket_name <- strsplit(cloud_path, '/')[[1]][1] - object_path <- sub(paste0('^', bucket_name, '/'), '', cloud_path) - file_path <- paste0('/workspace/data/', bucket_name, '/', object_path) - } else { - # Use path as-is for local paths - file_path <- data_path - } - - if (file.exists(file_path)) { - read.csv(file_path) - } else { - # Fallback to built-in data - data.frame( - x = 1:50, - y = rnorm(50, mean = 50, sd = 10) - ) - } - }) - - # Data source message - output$data_source <- renderText({ - data_path <- Sys.getenv('DATA_PATH', 's3://shiny-inputs/data.csv') - - # Convert cloud storage path to local Studio path (same logic as data reading) - if (grepl('^s3://|^gs://|^az://', data_path)) { - cloud_path <- sub('^[^:]+://', '', data_path) - bucket_name <- strsplit(cloud_path, '/')[[1]][1] - object_path <- sub(paste0('^', bucket_name, '/'), '', cloud_path) - file_path <- paste0('/workspace/data/', bucket_name, '/', object_path) - } else { - file_path <- data_path - } - - if (file.exists(file_path)) { - paste("Using external data file:", data_path) - } else { - "Using built-in random data" - } - }) - - # Summary statistics - output$summary_stats <- renderPrint({ - summary(data()$y) - }) - - # Create plot - output$plot <- renderPlot({ - df <- data() - - # Base plot - p <- ggplot(df, aes(x = x, y = y)) - - # Add plot elements based on selection - if (input$plot_type == "scatter") { - p <- p + geom_point(size = input$point_size, aes(color = "Data Points")) - if (input$add_trend) { - p <- p + geom_smooth(method = "lm", se = TRUE, aes(color = "Trend Line")) - } - } else if (input$plot_type == "line") { - p <- p + geom_line(size = input$line_width, aes(color = "Line")) - if (input$add_points) { - p <- p + geom_point(aes(color = "Points")) - } - } else if (input$plot_type == "bar") { - p <- p + geom_bar(stat = "identity", width = input$bar_width, aes(fill = "Bars")) - if (input$add_error_bars) { - p <- p + stat_summary(fun.data = mean_se, geom = "errorbar", width = 0.2, aes(color = "Error Bars")) - } - } else if (input$plot_type == "box") { - p <- p + geom_boxplot(aes(fill = "Box Plot")) - if (input$add_points) { - p <- p + geom_jitter(width = 0.2, aes(color = "Points")) - } - if (input$add_violin) { - p <- p + geom_violin(alpha = 0.3, aes(fill = "Violin")) - } - } else if (input$plot_type == "density") { - p <- p + geom_density(adjust = input$bandwidth, aes(fill = "Density")) - if (input$add_rug) { - p <- p + geom_rug(aes(color = "Rug")) - } - } - - # Apply color theme - if (input$color_theme == "viridis") { - p <- p + scale_color_viridis_d() + scale_fill_viridis_d() - } else if (input$color_theme == "blues") { - p <- p + scale_color_brewer(palette = "Blues") + scale_fill_brewer(palette = "Blues") - } else if (input$color_theme == "reds") { - p <- p + scale_color_brewer(palette = "Reds") + scale_fill_brewer(palette = "Reds") - } else { - # Default theme - p <- p + scale_color_brewer(palette = "Set1") + scale_fill_brewer(palette = "Set1") - } - - # Add labels and theme - p <- p + - labs(title = paste("Data Visualization:", input$plot_type), - x = "X", y = "Y") + - theme_minimal() + - theme( - plot.title = element_text(size = 16, face = "bold"), - axis.title = element_text(size = 12), - axis.text = element_text(size = 10), - panel.grid.major = element_line(color = "gray90"), - panel.grid.minor = element_line(color = "gray95") - ) - - p - }) - - # Data table - output$data_table <- renderDataTable({ - data() - }) -} - -# Run the app -shinyApp(ui = ui, server = server) \ No newline at end of file diff --git a/shiny-simple-example/data.csv b/shiny-simple-example/data.csv deleted file mode 100644 index 41295f1..0000000 --- a/shiny-simple-example/data.csv +++ /dev/null @@ -1,21 +0,0 @@ -x,y -1,45 -2,52 -3,48 -4,55 -5,51 -6,58 -7,54 -8,61 -9,57 -10,64 -11,60 -12,67 -13,63 -14,70 -15,66 -16,73 -17,69 -18,76 -19,72 -20,79 \ No newline at end of file diff --git a/shiny-simple-example/example_data.csv b/shiny-simple-example/example_data.csv deleted file mode 100644 index b0c7e1b..0000000 --- a/shiny-simple-example/example_data.csv +++ /dev/null @@ -1,11 +0,0 @@ -x,y -1,45.2 -2,52.8 -3,48.9 -4,55.1 -5,51.3 -6,53.7 -7,49.8 -8,54.2 -9,50.5 -10,52.1 \ No newline at end of file diff --git a/shiny-simple-example/screenshot.png b/shiny-simple-example/screenshot.png deleted file mode 100644 index 217a583..0000000 Binary files a/shiny-simple-example/screenshot.png and /dev/null differ diff --git a/streamlit/Dockerfile b/streamlit/Dockerfile deleted file mode 100644 index 8601b99..0000000 --- a/streamlit/Dockerfile +++ /dev/null @@ -1,60 +0,0 @@ -# --------------------------------------------------------------- -# 1) Multi-stage build: Pull the connect-client binary -# --------------------------------------------------------------- -ARG CONNECT_CLIENT_VERSION=0.9 -FROM public.cr.seqera.io/platform/connect-client:${CONNECT_CLIENT_VERSION} AS connect - -# --------------------------------------------------------------- -# 2) Additional base image for Streamlit -# --------------------------------------------------------------- -FROM python:3.11-slim - -# Just for the automation at Seqera -LABEL org.opencontainers.image.source="https://github.com/seqeralabs/custom-studios-examples" - -WORKDIR /app - -RUN apt-get update && apt-get install -y \ - build-essential \ - curl \ - git \ - && rm -rf /var/lib/apt/lists/* - -# Remove any existing directory and clone fresh -RUN rm -rf /app/* && git clone https://github.com/MultiQC/example-streamlit . - -RUN pip3 install -r requirements.txt - -EXPOSE $CONNECT_TOOL_PORT - -# Add connect-client version label to image for supported capabilties tracking -ARG CONNECT_CLIENT_VERSION -LABEL io.seqera.connect.version="${CONNECT_CLIENT_VERSION}" - -# Copy connect-client from the first stage -COPY --from=connect /usr/bin/connect-client /usr/bin/connect-client - -# "Install" connect-client (sets up any needed config) -RUN /usr/bin/connect-client --install - -# --------------------------------------------------------------- -# 3) Launch with connect-client --entrypoint (for Tower) -# --------------------------------------------------------------- -ENTRYPOINT ["/usr/bin/connect-client", "--entrypoint"] - -# Add backports repository and install specific btrfs-progs version -RUN echo "deb http://deb.debian.org/debian bookworm-backports main contrib non-free-firmware" | tee -a /etc/apt/sources.list && \ - apt-get update && \ - apt-get install -y --allow-downgrades btrfs-progs=6.14-1~bpo12+1 - -# --------------------------------------------------------------- -# 4) Command: Run Streamlit MultiQC application -# --------------------------------------------------------------- -# The port is set by CONNECT_TOOL_PORT environment variable -CMD streamlit run /app/multiqc_app.py \ - --server.port=$CONNECT_TOOL_PORT \ - --server.address=0.0.0.0 \ - --server.enableCORS=false \ - --server.enableXsrfProtection=false \ - --server.enableWebsocketCompression=false \ - --browser.gatherUsageStats=false \ No newline at end of file diff --git a/streamlit/README.md b/streamlit/README.md deleted file mode 100644 index 0496720..0000000 --- a/streamlit/README.md +++ /dev/null @@ -1,113 +0,0 @@ -# Streamlit Studio Environment - -This example provides a custom container image for running a [Streamlit](https://streamlit.io/) application with MultiQC visualization in Seqera Platform. - -## Table of Contents - -- [Overview](#overview) -- [Features](#features) -- [Files](#files) -- [Prerequisites](#prerequisites) -- [Building the Container](#building-the-container) -- [Local Testing](#local-testing) -- [Using in Seqera Studios](#using-in-seqera-studios) -- [Notes](#notes) -- [References](#references) - -## Overview - -This container is designed for use as a [custom Studio environment](https://docs.seqera.io/platform-cloud/studios/custom-envs) in Seqera Platform. It provides an interactive interface for visualizing MultiQC data using Streamlit. - -![Screenshot of the Streamlit app](screenshot.png) - -## Docker Image - -The container image is available at: -``` -ghcr.io/seqeralabs/custom-studios-examples/streamlit:latest -``` - -For specific versions, use the release tag (e.g., `ghcr.io/seqeralabs/custom-studios-examples/streamlit:v1.0.0`). - -## Features - -- Streamlit-based MultiQC visualization platform -- Interactive data analysis and visualization -- Compatible with both local Docker testing and Seqera Studios -- Automatic data mounting via datalinks -- Python 3.11-based environment - -## Files - -- `Dockerfile`: Container definition using multi-stage build that clones the MultiQC example repository and its dependencies - -## Prerequisites - -- [Docker](https://www.docker.com/) installed -- [Wave](https://docs.seqera.io/platform-cloud/wave/) configured in your Seqera Platform workspace -- Access to a container registry (public or Amazon ECR) if you wish to push your image -- MultiQC data files for visualization - -## Building the Container - -> [!IMPORTANT] -> You must provide the `CONNECT_CLIENT_VERSION` build argument when building the container. - -To build the container locally: - -```bash -docker build --platform=linux/amd64 --build-arg CONNECT_CLIENT_VERSION=0.8 -t streamlit-example . -``` - -## Local Testing - -To test the app locally, you need to override the entrypoint: - -```bash -docker run -p 3000:3000 --entrypoint streamlit streamlit-example run /app/multiqc_app.py \ - --server.port=3000 \ - --server.address=0.0.0.0 \ - --server.enableCORS=false \ - --server.enableXsrfProtection=false \ - --server.enableWebsocketCompression=false \ - --browser.gatherUsageStats=false -``` - -The app will be available at http://localhost:3000 - -## Using in Seqera Studios - -> [!NOTE] -> For the common deployment process, see the [main README](../README.md#deploying-to-seqera-studios). - -Additional steps specific to this example: -1. Follow the common deployment process -2. When mounting data, ensure to mount the directories containing any required MultiQC data files using the **Mount data** option - -### Data Loading Options - -The MultiQC Streamlit app supports three data loading methods: -- **URL**: Load data directly from a web URL -- **Local Files**: Access files from your local machine -- **Server Paths**: Load files from S3 via Fusion - -When using Server Paths with data links: -1. Upload your MultiQC data (e.g., `data.zip`) to your S3 bucket -2. Create a data link (e.g., `my_multiqc_files`) pointing to that S3 path -3. The data will be available at `/workspace/data/my_multiqc_files/data.zip` -4. Use this path in the app's "Server Path" input field - -## Notes - -- The app uses Streamlit for interactive data visualization -- The Dockerfile uses a multi-stage build to include the connect-client -- The container is built for linux/amd64 platform compatibility -- The example is based on the MultiQC Streamlit application -- The container uses Python 3.11 as the base image - -## References - -- [Seqera Studios: Custom Environments](https://docs.seqera.io/platform-cloud/studios/custom-envs) -- [Streamlit Documentation](https://docs.streamlit.io/) -- [MultiQC Documentation](https://multiqc.info/) -- [Wave Documentation](https://docs.seqera.io/platform-cloud/wave/) \ No newline at end of file diff --git a/streamlit/screenshot.png b/streamlit/screenshot.png deleted file mode 100644 index f2842a9..0000000 Binary files a/streamlit/screenshot.png and /dev/null differ diff --git a/ttyd/Dockerfile b/ttyd/Dockerfile deleted file mode 100644 index 2674505..0000000 --- a/ttyd/Dockerfile +++ /dev/null @@ -1,42 +0,0 @@ -# --------------------------------------------------------------- -# 1) Multi-stage build: Pull the connect-client binary -# --------------------------------------------------------------- -ARG CONNECT_CLIENT_VERSION=0.9 -FROM public.cr.seqera.io/platform/connect-client:${CONNECT_CLIENT_VERSION} AS connect - -# Final image: Start from an arbitrary container -FROM community.wave.seqera.io/library/samtools:1.21--0d76da7c3cf7751c - -# Just for the automation at Seqera -LABEL org.opencontainers.image.source="https://github.com/seqeralabs/custom-studios-examples" - -# Set environment variables to prevent interactive prompts -ENV DEBIAN_FRONTEND=noninteractive -ENV TERM=xterm - -# Install extra dependencies and tools -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - wget \ - ca-certificates && \ - apt-get clean && \ - rm -rf /var/lib/apt/lists/* - -# Install TTYD binary -RUN wget https://github.com/tsl0922/ttyd/releases/download/1.7.7/ttyd.x86_64 \ - && mv ttyd.x86_64 /usr/local/bin/ttyd \ - && chmod +x /usr/local/bin/ttyd - -# Add connect-client version label to image for supported capabilties tracking -ARG CONNECT_CLIENT_VERSION -LABEL io.seqera.connect.version="${CONNECT_CLIENT_VERSION}" - -# Copy Connect binary and install dependencies -COPY --from=connect /usr/bin/connect-client /usr/bin/connect-client -RUN /usr/bin/connect-client --install - -# Set connect as the entrypoint -ENTRYPOINT ["/usr/bin/connect-client", "--entrypoint"] - -# Default command to run TTYD with writable mode -CMD ["/usr/bin/bash", "-c", "ttyd -W -p $CONNECT_TOOL_PORT bash"] \ No newline at end of file diff --git a/ttyd/README.md b/ttyd/README.md deleted file mode 100644 index 438bbb6..0000000 --- a/ttyd/README.md +++ /dev/null @@ -1,100 +0,0 @@ -# TTYD Studio Environment - -This example provides a custom container image for running an interactive terminal session in Seqera Studios using [TTYD](https://github.com/tsl0922/ttyd). It uses a commodity [SAMtools](https://www.htslib.org/) image from [Seqera containers](https://github.com/seqeralabs/containers) (built using the [Bioconda](https://bioconda.github.io/) SAMtools recipe) as the base, demonstrating how Studios can run arbitrary container images. - -## Table of Contents - -- [Overview](#overview) -- [Features](#features) -- [Files](#files) -- [Prerequisites](#prerequisites) -- [Building the Container](#building-the-container) -- [Local Testing](#local-testing) -- [Using in Seqera Studios](#using-in-seqera-studios) -- [Notes](#notes) -- [References](#references) - -## Overview - -This container is designed for use as a [custom Studio environment](https://docs.seqera.io/platform-cloud/studios/custom-envs) in Seqera Platform. It provides a web-based terminal interface with full write permissions and access to bioinformatics tools. - -![Screenshot of TTYD terminal](screenshot.png) - -## Docker Image - -The container image is available at: -``` -ghcr.io/seqeralabs/custom-studios-examples/ttyd:latest -``` - -For specific versions, use the release tag (e.g., `ghcr.io/seqeralabs/custom-studios-examples/ttyd:v1.0.0`). - -## Features - -- Interactive web-based terminal using TTYD 1.7.7 -- Based on [SAMtools](https://www.htslib.org/) 1.21 container from [Seqera containers](https://github.com/seqeralabs/containers) -- Full terminal access with write permissions -- Includes basic bioinformatics tools from [SAMtools](https://www.htslib.org/) via [Bioconda](https://bioconda.github.io/) - -> [!NOTE] -> For common features shared across all examples, see the [main README](../README.md#common-features). - -## Files - -- `Dockerfile`: Container definition using multi-stage build - -## Prerequisites - -> [!NOTE] -> For common prerequisites, see the [main README](../README.md#prerequisites). - -No additional prerequisites specific to this example. - -## Building the Container - -> [!IMPORTANT] -> You must provide the `CONNECT_CLIENT_VERSION` build argument when building the container. - -To build the container locally: - -```bash -docker build --platform=linux/amd64 --build-arg CONNECT_CLIENT_VERSION=0.8 -t ttyd-example . -``` - -## Local Testing - -To test the terminal locally, you need to override the entrypoint: - -```bash -docker run -p 3000:3000 --entrypoint ttyd ttyd-example -W -p 3000 bash -``` - -The terminal will be available at http://localhost:3000 - -## Using in Seqera Studios - -> [!NOTE] -> For the common deployment process, see the [main README](../README.md#deploying-to-seqera-studios). - -Additional steps specific to this example: -1. Follow the common deployment process -2. The terminal will automatically use the `CONNECT_TOOL_PORT` environment variable in Studios - -## Notes - -- The terminal uses TTYD 1.7.7 for web-based terminal access -- The terminal runs with write permissions enabled (-W flag) -- The base image includes SAMtools 1.21 and other bioinformatics tools -- The port is automatically configured via the CONNECT_TOOL_PORT environment variable in Studios - -> [!NOTE] -> For common technical notes, see the [main README](../README.md#common-features). - -## References - -- [TTYD Documentation](https://github.com/tsl0922/ttyd) -- [SAMtools Documentation](https://www.htslib.org/) -- [Seqera Containers](https://github.com/seqeralabs/containers) -- [Bioconda Documentation](https://bioconda.github.io/) -- [Seqera Studios: Custom Environments](https://docs.seqera.io/platform-cloud/studios/custom-envs) -- [Wave Documentation](https://docs.seqera.io/platform-cloud/wave/) diff --git a/ttyd/screenshot.png b/ttyd/screenshot.png deleted file mode 100644 index 1382f3e..0000000 Binary files a/ttyd/screenshot.png and /dev/null differ