Pick individual genes

Download the notebook

Click a point to select a gene. Shift-click adds or removes genes. Scroll to zoom and drag to pan; points grow as you zoom in. The table shows the selected records; download them as CSV.

Loading chart…

Unlike brushing, point selection returns the selected rows directly—no range filtering needed. In Python, snapshot["data"] contains these records. Reloading clears the selection.

Code

The web demo uses JavaScript; run these Python hooks in the notebook.

Chart specification (Python)
import genome_spy as gs
from genome_spy.datasets._airway import airway_differential_expression

genes, domains = airway_differential_expression()
picked = gs.selection_point("picked", empty=False)
chart = (
    gs.Chart(genes)
    .mark_point(size=gs.expr("min(28 * pow(zoomLevel(), 0.75), 180)"), opacity=0.8)
    .encode(
        x=gs.X("log2fc:Q")
        .scale(domain=domains["volcano_x"], zoom=True)
        .title("log2 fold change"),
        y=gs.Y("neglog10_pvalue_plot:Q")
        .scale(domain=domains["volcano_y"], zoom=True)
        .title("−log10 p-value"),
        color=gs.when(picked).then(gs.value("#bf593b")).otherwise(gs.value("#adb7c2")),
        tooltip=["ensgene:N", "log2fc:Q", "padj:Q"],
    )
    .add_params(picked)
    .properties(width=760, height=360)
)
Python hooks
import asyncio
import html
import pandas as pd
import ipywidgets as widgets
from IPython.display import display

if old_task := globals().get("connection_task"):
    old_task.cancel()
if old_widget := globals().get("widget"):
    old_widget.close()

widget = chart.widget(inline=True, controls=False)
status = widgets.HTML("Connecting…")
table = widgets.HTML()
selected_genes = pd.DataFrame()


def show_selection(snapshot):
    global selected_genes
    selected_genes = pd.DataFrame(snapshot["data"])
    status.value = f"{len(selected_genes)} genes selected."
    columns = ["ensgene", "log2fc", "pvalue", "padj"]
    table.value = (
        selected_genes[columns].to_html(index=False, escape=True)
        if not selected_genes.empty
        else ""
    )


async def connect():
    global api, selection, stop
    try:
        api = await widget.get_embed_api()
        selection = await api.params.get_selection("picked")
        stop = await selection.subscribe(show_selection)
        show_selection(await selection.get_value())
    except Exception as error:
        status.value = html.escape(f"Connection failed: {error}")


display(widget, status, table)
connection_task = asyncio.create_task(connect())

Data use and provenance

The same illustrative airway RNA-seq analysis as Select genes: packaged Bioconnector workshop counts (CC BY-NC-SA 4.0), with paired log-count tests and adjusted p-values prepared in Python; not DESeq2.