Set up directory and copy over files
Check out the first few lines of the file
zcat NPC_1.chr19.pairs.gz | head | column -t
Set up environment
export PATH="/home/hgen_share/Anaconda/bin:$PATH"
export PATH="/home/hgen_share/Anaconda/envs/chip_seq_V3/bin:$PATH"
Create matrix from the pairix-indexed and sorted file with cooler cload pairix. You can cancel with Ctrl + C because this will take a while
cooler cload pairix mm10.chr19.size:10000 NPC_1.chr19.pairs.gz NPC_1.chr19.cool
Examine the output file's metadata using cooler info
cooler info NPC_1.chr19.cool
Perform matrix balancing through cooler balance
cooler balance NPC_1.chr19.cool -p 1
Look at the underlying data through cooler dump
cooler dump --join --balanced --header NPC_1.chr19.cool | sed -n '1p;12500,12520p;12521q' | column -t
Coarsen the matrix with cooler zoomify
cooler zoomify -p 1 -r 10000,100000 --balance -o NPC_1.chr19.mcool NPC_1.chr19.cool
List the contents inside the mcool file with cooler ls
cooler ls NPC_1.chr19.mcool
Visualize the results using cooler show
cooler show NPC_1.chr19.mcool::/resolutions/10000 -b -o 10kb.ice.png chr19
cooler show NPC_1.chr19.mcool::/resolutions/100000 -b -o 100kb.ice.png chr19
cooler show NPC_1.chr19.mcool::/resolutions/10000 -o 10kb.raw.png chr19
cooler show NPC_1.chr19.mcool::/resolutions/100000 -o 100kb.raw.png chr19
Download results to your local computer, specifically files ending with .png
Take the average across sub-diagonals with cooltools compute-expected
cooltools expected-cis NPC_1.chr19.mcool::/resolutions/10000 -o NPC_1.chr19.cis.tsv -p 1
Peek at the output
head NPC_1.chr19.cis.tsv | column -t
Now compute the expected value for trans matrices. See cooltools
Compute the first few eigenvectors using cooltools call-compartments with GC content as the reference for sign-flipping
cooltools eigs-cis --n-eigs 3 -o NPC_1.chr19 --phasing-track 100000.bg NPC_1.chr19.mcool::/resolutions/100000
Now compute the first few eigenvectors for trans matrices. See cooltools
Look at the outputs
cat NPC_1.chr19.cis.lam.txt
head NPC_1.chr19.cis.vecs.tsv
Use python version of cooltools
# import standard python libraries
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import os, subprocess
import cooler
import cooltools.lib.plotting
import cooltools
# read in cooler
clr = cooler.Cooler('/lustre06/project/6007495/padilr1/projects/HGEN663_W21/pub/lec12_extra/NPC.mcool::/resolutions/100000')
# generate dataframe of gc coverage in your organism, here it is mm10 or mouse
import bioframe
bins = clr.bins()[:]
mm10_genome = bioframe.load_fasta('/lustre06/project/6007495/padilr1/pipelines/hic/dcHiC/demo/dcHiC_demo/ESC_NPC_CN_100Kb/mm10_100000_goldenpathData/mm10.fa');
gc_cov = bioframe.frac_gc(bins[['chrom', 'start', 'end']], mm10_genome)
# gc_cov.to_csv('mm10_gc_cov_100kb.tsv',index=False,sep='\t') = this script can export the gc coverage dataframe into a csv file
## Cooltools also allows a view to be passed for eigendecomposition to limit to a certain set of regions. The following code creates the simplest view, of the two chromosomes in this cooler
view_df = pd.DataFrame({'chrom': clr.chromnames,
'start': 0,
'end': clr.chromsizes.values,
'name': clr.chromnames}
)
## obtain first 3 eigenvectors
cis_eigs = cooltools.eigs_cis(
clr,
gc_cov,
view_df=view_df,
n_eigs=3,
)
# cis_eigs[0] returns eigenvalues, here we focus on eigenvectors
eigenvector_track = cis_eigs[1][['chrom','start','end','E1']]
# calculate the expected cis values
cvd = cooltools.expected_cis(
clr=clr,
view_df=view_df,
)
#
Q_LO = 0.025 # ignore 2.5% of genomic bins with the lowest E1 values
Q_HI = 0.975 # ignore 2.5% of genomic bins with the highest E1 values
N_GROUPS = 38 # divide remaining 95% of the genome into 38 equisized groups, 2.5% each
# saddle then plots two matrices: one with the sum for each pair of categories, interaction_sum, and the other with the number of bins for each pair of categories, interaction_count. Typically, interaction_sum/interaction_count is visualized
interaction_sum, interaction_count = cooltools.saddle(
clr,
cvd,
eigenvector_track,
'cis',
n_bins=N_GROUPS,
qrange=(Q_LO,Q_HI),
view_df=view_df
)
# parameters and functions required to plot the saddle plot
import warnings
from cytoolz import merge
def saddleplot(
track,
saddledata,
n_bins,
vrange=None,
qrange=(0.0, 1.0),
cmap="coolwarm",
scale="log",
vmin=0.5,
vmax=2,
color=None,
title=None,
xlabel=None,
ylabel=None,
clabel=None,
fig=None,
fig_kws=None,
heatmap_kws=None,
margin_kws=None,
cbar_kws=None,
subplot_spec=None,
):
from matplotlib.gridspec import GridSpec, GridSpecFromSubplotSpec
from matplotlib.colors import Normalize, LogNorm
from matplotlib import ticker
import matplotlib.pyplot as plt
class MinOneMaxFormatter(ticker.LogFormatter):
def set_locs(self, locs=None):
self._sublabels = set([vmin % 10 * 10, vmax % 10, 1])
def __call__(self, x, pos=None):
if x not in [vmin, 1, vmax]:
return ""
else:
return "{x:g}".format(x=x)
track_value_col = track.columns[3]
track_values = track[track_value_col].values
digitized_track, binedges = cooltools.digitize(
track, n_bins, vrange=vrange, qrange=qrange
)
x = digitized_track[digitized_track.columns[3]].values.astype(int).copy()
x = x[(x > -1) & (x < len(binedges) + 1)]
groupmean = track[track.columns[3]].groupby(digitized_track[digitized_track.columns[3]]).mean()
if qrange is not None:
lo, hi = qrange
binedges = np.linspace(lo, hi, n_bins + 1)
n = saddledata.shape[0]
X, Y = np.meshgrid(binedges, binedges)
C = saddledata
if (n - n_bins) == 2:
C = C[1:-1, 1:-1]
groupmean = groupmean[1:-1]
if subplot_spec is not None:
GridSpec = partial(GridSpecFromSubplotSpec, subplot_spec=subplot_spec)
grid = {}
gs = GridSpec(
nrows=3,
ncols=3,
width_ratios=[0.2, 1, 0.1],
height_ratios=[0.2, 1, 0.1],
wspace=0.05,
hspace=0.05,
)
if fig is None:
fig_kws_default = dict(figsize=(5, 5))
fig_kws = merge(fig_kws_default, fig_kws if fig_kws is not None else {})
fig = plt.figure(**fig_kws)
if scale == "log":
norm = LogNorm(vmin=vmin, vmax=vmax)
elif scale == "linear":
norm = Normalize(vmin=vmin, vmax=vmax)
else:
raise ValueError("Only linear and log color scaling is supported")
grid["ax_heatmap"] = ax = plt.subplot(gs[4])
heatmap_kws_default = dict(cmap="coolwarm", rasterized=True)
heatmap_kws = merge(
heatmap_kws_default, heatmap_kws if heatmap_kws is not None else {}
)
img = ax.pcolormesh(X, Y, C, norm=norm, **heatmap_kws)
plt.gca().yaxis.set_visible(False)
margin_kws_default = dict(edgecolor="k", facecolor=color, linewidth=1)
margin_kws = merge(margin_kws_default, margin_kws if margin_kws is not None else {})
grid["ax_margin_y"] = plt.subplot(gs[3], sharey=grid["ax_heatmap"])
plt.barh(
binedges, height=1/len(binedges), width=groupmean, align="edge", **margin_kws
)
plt.xlim(plt.xlim()[1], plt.xlim()[0]) # fliplr
plt.ylim(hi, lo)
plt.gca().spines["top"].set_visible(False)
plt.gca().spines["bottom"].set_visible(False)
plt.gca().spines["left"].set_visible(False)
plt.gca().xaxis.set_visible(False)
grid["ax_margin_x"] = plt.subplot(gs[1], sharex=grid["ax_heatmap"])
plt.bar(
binedges, width=1/len(binedges), height=groupmean, align="edge", **margin_kws
)
plt.xlim(lo, hi)
plt.gca().spines["top"].set_visible(False)
plt.gca().spines["right"].set_visible(False)
plt.gca().spines["left"].set_visible(False)
plt.gca().xaxis.set_visible(False)
plt.gca().yaxis.set_visible(False)
grid["ax_cbar"] = plt.subplot(gs[5])
cbar_kws_default = dict(fraction=0.8, label=clabel or "")
cbar_kws = merge(cbar_kws_default, cbar_kws if cbar_kws is not None else {})
if scale == "linear" and vmin is not None and vmax is not None:
grid["ax_cbar"] = cb = plt.colorbar(img, **cbar_kws)
decimal = 10
nsegments = 5
cd_ticks = np.trunc(np.linspace(vmin, vmax, nsegments) * decimal) / decimal
cb.set_ticks(cd_ticks)
else:
print('cbar')
cb = plt.colorbar(img, format=MinOneMaxFormatter(), cax=grid["ax_cbar"], **cbar_kws)
cb.ax.yaxis.set_minor_formatter(MinOneMaxFormatter())
grid["ax_heatmap"].set_xlim(lo, hi)
grid["ax_heatmap"].set_ylim(hi, lo)
grid['ax_heatmap'].grid(False)
if title is not None:
grid["ax_margin_x"].set_title(title)
if xlabel is not None:
grid["ax_heatmap"].set_xlabel(xlabel)
if ylabel is not None:
grid["ax_margin_y"].set_ylabel(ylabel)
return grid
## finally, plot the saddle-plot
img = saddleplot(eigenvector_track,
interaction_sum/interaction_count,
N_GROUPS,
qrange=(Q_LO,Q_HI),
cbar_kws={'label':'average observed/expected contact frequency'}
);
## save figure
plt.savefig('/lustre06/project/6007495/padilr1/projects/HGEN663_W21/pub/lec12_extra/final_analysis/saddleplot/NPC.saddle.cis.100000.png')
Differential compartment analysis using dcHiC
### STEP 1 ###
### Step 1: dcHiC will create the raw PC files for each chromosome. ###
Rscript ../scripts/dchicf.r --file input.ES_NPC.txt --pcatype cis --dirovwt T --cthread 2 --pthread 4
### STEP 2 ###
### Step 2: dcHiC will select the best pc out of PC1 and PC2 for each chromosome
### by comparing each one against GC content and gene density through correlation.
Rscript ../scripts/dchicf.r --file input.ES_NPC_CN.txt --pcatype select --dirovwt T --genome mm10 --cthread 8 --pthread 4 --gfolder /lustre06/project/6007495/padilr1/pipelines/hic/dcHiC/demo/dcHiC_demo/ESC_NPC_CN_100Kb/mm10_100000_goldenpathData
### STEP 3 ###
### Step 3: dcHiC will use the selected PC and qunatile normalize them.
### This will be followed by mahalanobis distance calculation and outlier detection.
### If replicates are available, dcHiC will apply IHW (independent hypothesis weighting) to adjust the significance.
### This will create a directory "DifferentialResult" and few more subfolder.
### differential.intra_sample_group.pcOri.bedGraph shows the significance score for all the Hi-C bins.
### differential.intra_sample_group.Filtered.pcOri.bedGraph shows the filtered (padj < 0.1) the Hi-C bins.
### The differential.intra_sample_combined.*.bedGraph file shows the compartment scores and significance
### of each replicates, differential.intra_sample_group.*.bedGraph files are the subset of these.
### *.pcOri.* are files with original pc values i.e. before quantile normalized values.
### *.pcQnm.* are files with quantile normalized values.
### Note: All the differential compartment analysis is performed using *.pcQnm.* files.
### *.pcOri.* files are generated for vizualization purpose.
Rscript ../scripts/dchicf.r --file input.ES_NPC_CN.txt --pcatype analyze --dirovwt T --diffdir ES_NPC_100Kb
### STEP 4 ###
### Step 6: dcHiC will generate the standalone IGV web page.
### The step reqires "create_datauri" code provided within scripts directory.
### Please create a soft-link to your ln -s ./scripts/create_datauri ~/.local/bin/
Rscript ../scripts/dchicf.r --file input.ES_NPC.txt --pcatype viz --dirovwt T --diffdir ES_NPC_100Kb --genome mm10 --pcgroup pcOri
### STEP 5 ###
### Step 7: dcHiC will perform enrichment with the genes overlapping with the
### differential A-compartments in each sample. This step will generate a
### geneEnrichment directory under DifferentialResult/
### Under geneEnrichment directory there will sub-directories named as *_geneEnrichment.
### We recomment using the *_geneList.anchor.txt (Entrez IDs) file to perform the gene-enrichment using
### https://toppgene.cchmc.org/enrichment.jsp .
Rscript ../scripts/dchicf.r --file input.ES_NPC.txt --pcatype enrich --genome mm10 --diffdir ES_NPC_100Kb --exclA F --pcscore T --region anchor --pcgroup pcOri --gfolder mm10_100000_goldenpathData
Compute insulation score via cooltools insulation
cooltools insulation NPC_1.chr19.mcool::/resolutions/10000 100000 > NPC_1.chr19.ins.tsv
Inspect the output
head NPC_1.chr19.ins.tsv
Use the expected values computed before together with cooltools call-dots
cooltools dots NPC_1.chr19.mcool::/resolutions/10000 NPC_1.chr19.cis.tsv -o NPC_1.chr19.dots -p 1
Look at the outputs
head NPC_1.chr19.dots
Pile up the loops using coolpup.py
cut -f 1-6 NPC_1.chr19.dots > NPC_1.chr19.dots.bedpe
coolpup.py NPC_1.chr19.mcool::/resolutions/10000 NPC_1.chr19.dots.bedpe \
--features_format bedpe \
--outname NPC.cis_10000.pileup.clpy --nproc 1 \
--expected /home/hgen_share/test/NPC_1.chr19.cis.tsv
Plot the loop pile-up using plotpup.py
plotpup.py --input_pups NPC.cis_10000.pileup.clpy --output NPC.cis_10000.pileup.png
Extra: Perform differential loop analysis on union of loops using pareidolia
pareidolia -n 8 -b /lb/project/GRID/padilr1/projects/HGEN663/readpileup/union.dots.bedpe -k loops \
/lb/project/GRID/padilr1/projects/HGEN663/lec12_extra/ESC_1.mcool::resolutions/10000,/lb/project/GRID/padilr1/projects/HGEN663/lec12_extra/ESC_2.mcool::resolutions/10000,/lb/project/GRID/padilr1/projects/HGEN663/lec12_extra/ESC_3.mcool::resolutions/10000,/lb/project/GRID/padilr1/projects/HGEN663/lec12_extra/ESC_4.mcool::resolutions/10000,/lb/project/GRID/padilr1/projects/HGEN663/lec12_extra/NPC_1.mcool::resolutions/10000,/lb/project/GRID/padilr1/projects/HGEN663/lec12_extra/NPC_2.mcool::resolutions/10000,/lb/project/GRID/padilr1/projects/HGEN663/lec12_extra/NPC_3.mcool::resolutions/10000,/lb/project/GRID/padilr1/projects/HGEN663/lec12_extra/NPC_4.mcool::resolutions/10000 \
ESC,ESC,ESC,ESC,NPC,NPC,NPC,NPC \
output.pareidolia.tsv
Lastly, we can view the results of our HiC analysis in HiGlass