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

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more