Public
Edited
Apr 3, 2024
3 forks
9 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
viewof genomeSpy = embed(spec)
Insert cell
Insert cell
spec = ({
// By default, GenomeSpy fills the container element. In an Observable notebook
// the height must be specified explicitly.
height: 600,

// Which genome assembly to use to concatenate the chromosomes onto the genomic axis (locus scale)
genome: { name: "hg18" },

// Use this url as a base url for all data files. The base url can be redefined deeper in
// the view hierarchy.
baseUrl: "https://genomespy.app/examples/ASCAT/",

// Because the three tracks share the same data, we define them here at the top level view.
// Views deeper in the hierarchy inherit the data.
data: { url: "segments_S96.tsv" },

// To get linked zooming and panning, the child views (tracks) need to have a shared scale on their x channel
resolve: { scale: { x: "shared" } },

// Using vertical concatenation to get a layout like in genome browsers
vconcat: [
// Let's import an ideogram track from another notebook
makeIdeogramTrack("hg18"),

{
// Scale sharing must be repeated here
resolve: { scale: { x: "shared" } },

// The three child views (tracks) inherit the following encoding. Notice that we are using
// a nested vconcat here to prevent the encoding from leaking to the imported views
// (cytobands and genes).
encoding: {
x: {
// The "chrom" and "pos" properties allow for specifying genomic coordinates conveniently.
chrom: "chr",
pos: "startpos",

// The "locus" scale is optimized for displaying zero-based, half-open genomic coordinates.
type: "locus",
axis: {
title: null,
chromGrid: true,
grid: true,
gridDash: [1, 5]
}
},
x2: {
chrom: "chr",
pos: "endpos"
}
},

// The following tracks are defined as separate notebook cells below
vconcat: [copyNumberTrack, logRTrack, bafTrack]
},

// Gene annotations
makeGeneAnnotationTrack("hg18")
]
})
Insert cell
Insert cell
copyNumberTrack = ({
name: "copyNumberTrack",
layer: [
{
title: "nMinor",
mark: {
type: "rule",
// A minimum length (in pixels) ensures visibility of short segments even when zoomed out
minLength: 2.0,
// Offset the mark three pixels downwards
yOffset: -3.0
},
encoding: {
// x and x2 are not repeated here. They are inherited from the root.
y: {
field: "nMinor",
type: "quantitative",
scale: {
// The scale domain is from zero to six copies
domain: [0, 6],
// Add some padding to the scale to ensure that the offsetted rules are visible
padding: 0.04,
// The scale is clamped, i.e., values that exceed the domain extent stick at the boundary.
clamp: true
},
axis: {
// Only whole numbers, please
tickMinStep: 1.0
}
},
// The width of the rule in pixels
size: { value: 5 },
color: { value: "#88d27a" }
}
},
{
title: "nMajor",
mark: {
type: "rule",
minLength: 2.0,
// Offset to the opposite direction
yOffset: 3.0
},
encoding: {
y: {
field: "nMajor",
type: "quantitative",
scale: {
// The domain must be repeated here. Otherwise GenomeSpy extracts the domain from the data.
domain: [0, 6]
}
},
size: { value: 5 },
color: {
field: "nMajor",
type: "quantitative",
scale: {
// Here we use a piecewise scale to emphasize copy-numbers by color when they exceed
// the maximum (six). Remember that the scale was clamped – now the clamped values are shown
// in darker red.
domain: [0, 6, 10],
range: ["#f06850", "#f06850", "#5F0F0F"]
}
}
}
}
]
})
Insert cell
Insert cell
logRTrack = ({
name: "logRTrack",
layer: [
{
// We override the inherited segmentation data here by replacing it with the raw SNP probe values
data: { url: "raw_S96.tsv" },

title: "Single probe",

mark: {
type: "point",
// We use semi-geometric zooming, i.e., the point size grows as the view is zoomed in.
// The following property specifies the zoom level where the final point size (configured in encoding)
// is reached.
geometricZoomBound: 4
},

encoding: {
x: {
chrom: "chr",
pos: "pos",
type: "locus"
},
y: { field: "logR", type: "quantitative", title: null },
color: { value: "#7090c0" },
size: { value: 100 },
opacity: { value: 0.25 }
}
},
{
// This view inherits the segmentation data

title: "Mean LogR",
mark: {
type: "rule",
minLength: 3.0
},
encoding: {
y: {
field: "logRMean",
type: "quantitative",
title: "LogR"
},
size: { value: 3 },
color: { value: "black" }
}
}
]
})
Insert cell
Insert cell
bafTrack = ({
name: "bafTrack",

layer: [
{
// Again, we override the inherited data. The data file is actually the same as in the Log R track,
// but GenomeSpy loads and parses it only once.
data: { url: "raw_S96.tsv" },

// Include only the segments that have a B-allele frequency
transform: [{ type: "filter", expr: "datum.baf !== null" }],

title: "Single probe",

mark: {
type: "point",
geometricZoomBound: 4
},

encoding: {
x: {
chrom: "chr",
pos: "pos",
type: "locus"
},
y: { field: "baf", type: "quantitative", title: null },
color: { value: "#7090c0" },
size: { value: 100 },
opacity: { value: 0.3 }
}
},
{
title: "Mean BAF",
mark: {
type: "rule",
minLength: 3.0
},
encoding: {
y: {
field: "bafMean",
type: "quantitative",
scale: { domain: [0, 1] },
title: "B-allele frequency"
},
size: { value: 3 },
color: { value: "black" }
}
},
{
title: "Mean BAF",
mark: {
type: "rule",
minLength: 3.0
},
encoding: {
y: {
// B-allele frequencies are bi-modal and mirrored. Thus, we draw the segments two times:
// once normally and once mirrored.
expr: "1 - datum.bafMean",
type: "quantitative",
title: null
},
size: { value: 3 },
color: { value: "black" }
}
}
]
})
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more