<jupyter_start><jupyter_text>Prelim Notebook for 10X PBMC ATAC dataset: https://support.10xgenomics.com/single-cell-atac/datasets/1.2.0/atac_pbmc_10k_nextgemArchR installation Install from [https://github.com/settylab/ArchR](https://github.com/settylab/ArchR)```library(devtools)devtools::install_github("GreenleafLab/ArchR", ref="master", repos = BiocManager::repositories())```Update your ArchR with the customized version```R CMD INSTALL -l  ```Review the notebook `PBMC-RNA-standalone.ipynb` for setup instructions.Install MACS2 for peak celling ```conda install -c bioconda macs2 ```  Load data Download the following files:1. [ATAC fragments file](https://fh-pi-setty-m-eco-public.s3.us-west-2.amazonaws.com/single-cell-primers/scatac/atac_pbmc_10k_nextgem_fragments.tsv.gz)2. [Index for the fragments file](https://fh-pi-setty-m-eco-public.s3.us-west-2.amazonaws.com/single-cell-primers/scatac/atac_pbmc_10k_nextgem_fragments.tsv.gz.tbi)3. [Per barcode metrics](https://fh-pi-setty-m-eco-public.s3.us-west-2.amazonaws.com/single-cell-primers/scatac/atac_pbmc_10k_nextgem_singlecell.csv)Use the above files to run ArchR using the ArchR preprocessing script: https://github.com/settylab/single-cell-primers/blob/main/scripts/PBMC-ATAC-standalone-ArchR-preprocessing.R The outputs from ArchR are available to download from: `s3://fh-pi-setty-m-eco-public/single-cell-primers/scatac/ArchR/`Copy the results over to the `data/` directory using `aws s3 sync s3://fh-pi-setty-m-eco-public/single-cell-primers/scatac/ArchR/ data/pbmc_10x_atac/export/`<jupyter_code># Uncomment following line to download
# !aws s3 sync s3://fh-pi-setty-m-eco-public/single-cell-primers/scatac/ArchR/ data/pbmc_10x_atac/export/<jupyter_output><empty_output><jupyter_text>Imports<jupyter_code>import os
import pandas as pd
import numpy as np

import scanpy as sc
import pyranges as pr
import warnings
import palantir 
import phenograph
import harmony

import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
sns.set_style('ticks')
matplotlib.rcParams['figure.figsize'] = [4, 4]
matplotlib.rcParams['figure.dpi'] = 100
matplotlib.rcParams['image.cmap'] = 'Spectral_r'
warnings.filterwarnings(action="ignore", module="matplotlib", message="findfont")<jupyter_output><empty_output><jupyter_text>Utility functions<jupyter_code>def log_transform(ad, ps=0.1):
    ad.X.data = np.log2(ad.X.data + ps) - np.log2(ps)
def pyranges_from_strings(pos_list):
    # Chromosome and positions
    chr = pos_list.str.split(':').str.get(0)
    start = pd.Series(pos_list.str.split(':').str.get(1)).str.split('-').str.get(0)
    end = pd.Series(pos_list.str.split(':').str.get(1)).str.split('-').str.get(1)
    
    # Create ranges
    gr = pr.PyRanges(chromosomes=chr, starts=start, ends=end)
    
    return gr<jupyter_output><empty_output><jupyter_text>Load data  ATAC<jupyter_code>data_dir = os.path.expanduser('data/pbmc_10x_atac/export/')<jupyter_output><empty_output><jupyter_text>Load all the exported results from ArchR  Peaks data<jupyter_code># Peaks data
from scipy.io import mmread
counts = mmread(data_dir + 'peak_counts/counts.mtx')
# Cell and peak information
cells = pd.read_csv(data_dir + 'peak_counts/cells.csv', index_col=0).iloc[:, 0]
peaks = pd.read_csv(data_dir + 'peak_counts/peaks.csv', index_col=0)
peaks.index = peaks['seqnames'] + ':' + peaks['start'].astype(str) + '-' + peaks['end'].astype(str)
peaks.head()
ad = sc.AnnData(counts.T)
ad.obs_names = cells
ad.var_names = peaks.index
for col in peaks.columns:
    ad.var[col] = peaks[col]
ad.X = ad.X.tocsr()
ad<jupyter_output><empty_output><jupyter_text>SVD<jupyter_code>ad.obsm['X_svd'] = pd.read_csv(data_dir + 'svd.csv', index_col=0).loc[ad.obs_names, : ].values<jupyter_output><empty_output><jupyter_text>Metadata<jupyter_code>cell_meta = pd.read_csv(data_dir + 'cell_metadata.csv', index_col=0).loc[ad.obs_names, : ]
for col in cell_meta.columns:
    ad.obs[col] = cell_meta[col].values
ad<jupyter_output><empty_output><jupyter_text>Gene scores<jupyter_code># Gene scores
gene_scores = pd.read_csv(data_dir + 'gene_scores.csv', index_col=0).T
ad.obsm['GeneScores'] = gene_scores.loc[ad.obs_names, :].values
ad.uns['GeneScoresColums'] = gene_scores.columns.values
ad<jupyter_output><empty_output><jupyter_text>Preprocessing<jupyter_code># Leiden and UMAP
warnings.filterwarnings('ignore')
sc.pp.neighbors(ad, use_rep='X_svd')
sc.tl.umap(ad)
sc.tl.leiden(ad)
warnings.filterwarnings('default')
# Phenograph
ad.obs['phenograph'], _, _ = phenograph.cluster(ad.obsm['X_svd'])
ad.obs['phenograph'] = ad.obs['phenograph'].astype(str)<jupyter_output>Finding 30 nearest neighbors using minkowski metric and 'auto' algorithm
Neighbors computed in 5.360898017883301 seconds
Jaccard graph constructed in 3.641019105911255 seconds
Wrote graph to binary file in 0.18222999572753906 seconds
Running Louvain modularity optimization
After 1 runs, maximum modularity is Q = 0.861838
After 4 runs, maximum modularity is Q = 0.86289
Louvain completed 24 runs in 6.305092096328735 seconds
Sorting communities by size, please wait ...
PhenoGraph completed in 16.97426199913025 seconds<jupyter_text>Visualizations<jupyter_code>sc.pl.scatter(ad, basis='umap', color=['leiden', 'phenograph'])<jupyter_output>/usr/local/anaconda3/envs/singlecell/lib/python3.8/site-packages/anndata/_core/anndata.py:1228: FutureWarning: The `inplace` parameter in pandas.Categorical.reorder_categories is deprecated and will be removed in a future version. Reordering categories will always return a new Categorical object.
  c.reorder_categories(natsorted(c.categories), inplace=True)
... storing 'Sample' as categorical
/usr/local/anaconda3/envs/singlecell/lib/python3.8/site-packages/anndata/_core/anndata.py:1228: FutureWarning: The `inplace` parameter in pandas.Categorical.reorder_categories is deprecated and will be removed in a future version. Reordering categories will always return a new Categorical object.
  c.reorder_categories(natsorted(c.categories), inplace=True)
... storing 'Clusters' as categorical
/usr/local/anaconda3/envs/singlecell/lib/python3.8/site-packages/anndata/_core/anndata.py:1228: FutureWarning: The `inplace` parameter in pandas.Categorical.reorder_categories is deprecated and will be remo[...]<jupyter_text>Save<jupyter_code>ad
ad.write(data_dir + '../../pbmc_10k_atac.h5ad')<jupyter_output><empty_output><jupyter_text>Coverage plots  Functions<jupyter_code>import tabix
import subprocess

import matplotlib.gridspec as gridspec
from matplotlib.patches import Rectangle
from matplotlib.collections import PatchCollection
def compute_coverage(fragments_file, region, barcodes, out_prefix, 
                     smooth=None, normalize=False, frag_type='All'):

    # Read file
    tb = tabix.open(fragments_file)
    # Query region
    records = tb.querys(region)

    # Bed file
    bed_file = open(out_prefix + '.bed', 'w')

    # Iterate and write bed file
    for record in records:
        if record[3] in barcodes:
            # Write to bed file if the read is NFR
            if frag_type == 'NFR' and int(record[2]) - int(record[1]) > 145:
                continue 
            if frag_type == 'NUC' and int(record[2]) - int(record[1]) <= 145:
                continue 
            
            # Write to bed file
            line = record[0] + '\t' + record[1] + '\t' + record[2] + '\n'
            bed_file.writelines(line)

    # Close bed file
    bed_file.close()

    # Region to bed
    line = region.replace(':', '\t').replace('-', '\t') + '\n'
    bed_file = open(out_prefix + '.region.bed', 'w')
    bed_file.writelines(line)
    bed_file.close()

    # Coverage
    out_file = open(out_prefix + '.coverage.bed', 'w')
    args = ['bedtools', 'coverage', '-a', out_prefix + '.region.bed', '-b',
            out_prefix + '.bed', '-d']
    subprocess.call(args, stdout=out_file)
    out_file.close()

    # Read coverage
    df = pd.read_csv(out_prefix + '.coverage.bed', sep='\t', header=None)
    coverage = pd.Series(df[4].values, index=df[1] + df[3] - 1)
    coverage.attrs['chr'] = df[0][0]

    # Smooth if specified
    if smooth:
        coverage = coverage.rolling(smooth).mean()
        coverage[coverage.isnull()] = coverage.iloc[smooth]

    if normalize:
        norm = 100 / len(barcodes)
        coverage = coverage * norm

    # Clean up
    os.unlink(out_prefix + '.bed')
    os.unlink(out_prefix + '.coverage.bed')
    os.unlink(out_prefix + '.region.bed')

    return coverage
# Plot coverage
def _plot_coverage(coverage, track_name='Coverage', ax=None, color='#ff7f00',
                   min_coverage=0, ylim=None, fill=True):
    if ax is None:
        plt.figure()
        ax = plt.gca()

    # Plot and fill
    values = coverage
    values[values <= min_coverage] = 0
    if fill:
        ax.plot(coverage.index, values, color='black', linewidth=0.05)
        ax.fill_between(coverage.index, 0, values, color=color)
        ax.set_ylabel(track_name)
    else:
        ax.plot(coverage.index, values, color=color)

    # Scale
    if ylim is not None:
        ax.set_ylim(ylim)
    sns.despine(ax=ax)

    
# BED plot
def _plot_bed(plot_peaks, track_name="Bed", ax=None, facecolor='#ff7f00'):

    if ax is None:
        plt.figure()
        ax = plt.gca()
    
    rects = []
    if len(plot_peaks) > 0:
        for s, e in zip(plot_peaks.Start, plot_peaks.End):
            rects.append(Rectangle((s, -0.3), e - s, 0.6))

    # Add rectangles
    # Dummy scatter
    pc = PatchCollection(rects, facecolor=facecolor, edgecolor='black')
    ax.add_collection(pc)

    # Axis annotation
    ax.set_ylim([-1, 1])
    sns.despine(ax=ax, bottom=True)
    ax.set_yticks([])
    ax.set_ylabel(track_name)
    ax.axes.get_xaxis().set_visible(False)


# Gene plot
def _plot_gene(genes, ax=None, track_name='Genes', facecolor='#377eb8',
               exon_height=0.6, utr_height=0.25):
    # Setup plot
    if ax is None:
        plt.figure()
        ax = plt.gca()

    for gene in np.unique(genes.gene_name):
        gene_pr = genes[genes.gene_name == gene]

        # Plot lines
        gs, ge = gene_pr[gene_pr.Feature == 'gene'].Start.values[0], gene_pr[gene_pr.Feature == 'gene'].End.values[0]
        ax.plot([gs, ge], [0, 0], color='black')
        ax.set_ylim([-1, 1])
        ax.text((gs + ge) / 2,
                -(exon_height + utr_height), gene, horizontalalignment='center')

        # UTRs
        utrs = gene_pr[gene_pr.Feature.astype(str).str.contains('utr')]
        if len(utrs) > 0:
            rects = []
            for s, e in zip(utrs.Start, utrs.End):
                rects.append(Rectangle((s, -utr_height / 2), e - s, utr_height))
            ax.add_collection(PatchCollection(rects, facecolor=facecolor, edgecolor='black'))

        # CDS
        cds = gene_pr[gene_pr.Feature.astype(str).str.contains('CDS')]
        if len(cds) == 0:
            cds = gene_pr[gene_pr.Feature.astype(str).str.contains('exon')]
        rects = []
        for s, e in zip(cds.Start, cds.End):
            rects.append(Rectangle((s, -exon_height / 2), e - s, exon_height))
        ax.add_collection(PatchCollection(rects, facecolor=facecolor, edgecolor='black'))

        # Arrow indicating direction
        rs, re = ax.get_xlim()
        if gene_pr.stranded:
            s, e = cds.Start.values[0], cds.End.values[0]
            if gene_pr.Strand.values[0] == '+':
                ax.plot([s, e], np.repeat(-0.65, 2), color='red', linewidth=1, alpha=1)
                ax.plot([e - (re - rs) / 100, e], [-0.95, -0.65], color='red', linewidth=1, alpha=1)
                ax.plot([e - (re - rs) / 100, e], [-0.35, -0.65], color='red', linewidth=1, alpha=1)
            else:
                ax.plot([s, e], np.repeat(-0.65, 2), color='red', linewidth=1, alpha=1)
                ax.plot([s + (re - rs) / 100, s], [-0.95, -0.65], color='red', linewidth=1, alpha=1)
                ax.plot([s + (re - rs) / 100, s], [-0.35, -0.65], color='red', linewidth=1, alpha=1)

    # Axis clean up
    ax.set_ylabel(track_name)
    sns.despine(ax=ax)
    ax.set_yticks([])
def plot_coverage(barcode_groups, region, fragments_file,
                  peak_groups=None, genes=None, highlight_peaks=None,
                  min_coverage=0, smooth=None, common_scale=False,
                  plot_cov_size=2, plot_bed_size=0.75, collapsed=False,
                  coverage_colors=None, fig_width=15, frag_type='All', normalize=True):

    # Determine coverages
    coverages = dict()
    for k in barcode_groups.index:
        iter_norm = normalize
        if k == 'Single-cell':
            iter_norm = False
        coverages[k] = compute_coverage(fragments_file, region, barcode_groups[k],
                                        '/tmp/test', smooth, iter_norm, frag_type)
    # Plot
    n_rows = len(coverages)
    size = plot_cov_size * n_rows
    ratios = np.repeat(1, n_rows)
    if collapsed:
        n_rows = 1
        size = plot_cov_size * 4
        ratios = np.repeat(4, 1)
    if peak_groups is not None:
        size += plot_bed_size * len(peak_groups)
        n_rows += len(peak_groups)
        ratios = np.append(ratios, np.repeat(plot_bed_size / plot_cov_size, len(peak_groups)))
    if genes is not None:
        size += plot_bed_size
        n_rows += 1
        ratios = np.append(ratios, plot_bed_size / plot_cov_size)

    # Colors
    if coverage_colors is None:
        coverage_colors = pd.Series(sns.color_palette('Set2', len(coverages)).as_hex(),
                                    index=barcode_groups.index)

    # Y min and max
    ylim = None
    if common_scale:
        ymin = np.inf
        ymax = -np.inf
        for row in barcode_groups.index:
            if row == 'Single-cell':
                continue
            ymin = np.min([ymin, np.min(coverages[row])])
            ymax = np.max([ymax, np.max(coverages[row])])
        ylim = [ymin, ymax]


    # Region pyranges
    pr_region = pr.from_dict({'Chromosome': [region.split(':')[0]],
                              'Start': [int(region.split(':')[1].split('-')[0])],
                              'End': [int(region.split('-')[1])]})
    if highlight_peaks is not None:
        highlight_peaks = highlight_peaks.overlap(pr_region)
        
    # Plot
    fig = plt.figure(figsize=[fig_width, size])
    gs = gridspec.GridSpec(n_rows, 1, height_ratios=ratios, figure=fig)

    # Coverages
    plot_index = 0
    if collapsed:
        ax = fig.add_subplot(gs[plot_index, 0])
        ax.set_xlim([pr_region.Start[0], pr_region.End[0]])
        plot_index += 1

    for row in barcode_groups.index:
        # Create subplot
        if not collapsed:
            ax = fig.add_subplot(gs[plot_index, 0])
            ax.set_xlim([pr_region.Start[0], pr_region.End[0]])
            plot_index += 1

        iter_ylim = ylim
        if row == 'Single-cell':
            iter_ylim = [0, 2]
        _plot_coverage(coverages[row], row, ax, coverage_colors[row],
                       min_coverage, iter_ylim, not collapsed)

        # Highlight peaks
        if highlight_peaks is not None:
            for s, e in zip(highlight_peaks.Start, highlight_peaks.End):
                rect = Rectangle((s, 0), e - s, ax.get_ylim()[1],
                                 color='black', alpha=0.07, zorder=1000)
                ax.add_patch(rect)

        # Reset axis
        if plot_index != n_rows:
            ax.set_xticks([])


    # Region pyranges
    pr_region = pr.from_dict({'Chromosome': [region.split(':')[0]],
                              'Start': [int(region.split(':')[1].split('-')[0])],
                              'End': [int(region.split('-')[1])]})

    # Peaks
    if peak_groups is not None:
        for row in peak_groups.index:
            plot_peaks = peak_groups[row].overlap(pr_region)

            ax = fig.add_subplot(gs[plot_index, 0])
            ax.set_xlim([pr_region.Start[0], pr_region.End[0]])
            plot_index += 1

            _plot_bed(plot_peaks, row, ax)

    # Genes
    if genes is not None:
        genes = genes.overlap(pr_region)
        genes.End[genes.End > pr_region.End[0]] = pr_region.End[0]
        genes.Start[genes.Start < pr_region.Start[0]] = pr_region.Start[0]


        # Setup plot
        ax = fig.add_subplot(gs[plot_index, 0])
        ax.set_xlim([pr_region.Start[0], pr_region.End[0]])
        plot_index += 1

        _plot_gene(genes, ax, track_name='Genes')

        # Axis clean up
        ax.set_ylabel('Genes')
        sns.despine(ax=ax)
        ax.set_yticks([])


    # Clean up axis annotation
    ax.axes.get_xaxis().set_visible(True)
    locs = ax.get_xticks()[[0, -1]]
    locs[0] += 10000
    locs[1] -= 10000
    ax.set_xticks(locs)
    ax.set_xticklabels([str(int(t)) for t in ax.get_xticks()])
    ax.set_xlabel(region.split(':')[0])<jupyter_output><empty_output><jupyter_text>GTF<jupyter_code># Download hg19 gtf file from ENSEMBL (https://www.ensembl.org) and replace with the path
gtf = pr.read_gtf('/fh/fast/setty_m/grp/gtfs/hg19.gtf')<jupyter_output><empty_output><jupyter_text>Fragments file<jupyter_code># Download the fragments file and replace the path
fragments_file = '/fh/fast/setty_m/grp/public-datasets/10x_pbmc_10k_scatac/atac_pbmc_10k_nextgem_fragments.tsv.gz'
# Cell names should be consistent with fragments file
ad.obs['FragSample'] = ad.obs_names.str.split('#').str.get(1)<jupyter_output><empty_output><jupyter_text>Barcode groups<jupyter_code># A track for each cluster
barcode_groups = pd.Series(dtype=object)
for cat in ['0', '1', '2', '4', '7', '10', '14', '17']:
    barcode_groups[f'Clstr {cat}'] = ad.obs['FragSample'][ad.obs['phenograph'] == cat].values<jupyter_output><empty_output><jupyter_text>Peaks<jupyter_code>peak_groups = pd.Series()
peak_groups['Peaks'] = pyranges_from_strings(ad.var_names)<jupyter_output><ipython-input-51-48a45130fc55>:1: DeprecationWarning: The default dtype for empty Series will be 'object' instead of 'float64' in a future version. Specify a dtype explicitly to silence this warning.
  peak_groups = pd.Series()<jupyter_text>Plot<jupyter_code># Pax5 locus 
region = 'chr21:36,160,098-36,421,595'.replace(',', '')
pr_region = pr.from_dict({'Chromosome': [region.split(':')[0]],
                              'Start': [int(region.split(':')[1].split('-')[0])],
                              'End': [int(region.split('-')[1])]})

genes = gtf.intersect(pr_region)
cluster_colors = pd.Series(ad.uns['phenograph_colors'], index=ad.obs['phenograph'].values.categories)
cluster_colors.index = 'Clstr ' + cluster_colors.index
cluster_colors = cluster_colors[barcode_groups.index]
plot_coverage(barcode_groups, region, fragments_file, 
              peak_groups, genes=genes, highlight_peaks=None,
              common_scale=True, smooth=1, coverage_colors=cluster_colors, 
             fig_width=10,  plot_cov_size = 1.25, frag_type='NFR', normalize=True)<jupyter_output><empty_output><jupyter_text>Motifs   Peak sequences<jupyter_code>peaks_pr = pyranges_from_strings(ad.var_names)<jupyter_output><empty_output><jupyter_text>Export<jupyter_code>motifs_dir = 'data/pbmc_10x_atac/motifs/'
os.makedirs(motifs_dir, exist_ok=True)
peaks_df = pd.DataFrame()
# Positionns
peaks_df['chrom'] = peaks_pr.Chromosome
peaks_df['chromStart'] = peaks_pr.Start
peaks_df['chromEnd'] = peaks_pr.End

# summit
peaks_df['summit']  = 250

# Score
peaks_df['score'] = 1

# Names
peaks_df['name'] = peaks_df['chrom'].astype(str) + ':' + peaks_df['chromStart'].astype(str) + '-' + peaks_df['chromEnd'].astype(str)

peaks_df.to_csv(motifs_dir + 'peaks.bed', sep='\t', index=None, header=True)<jupyter_output><empty_output><jupyter_text>Sequences Run this in R``` Install and install SeqGL from here: https://github.com/ManuSetty/SeqGLlibrary(SeqGL)span <- 150org <- 'hg19' Peaks directorymotifs.dir <- 'data/pbmc_10x_atac/motifs/'peaks.file <- sprintf("%s/peaks.bed", motifs.dir) Load peaks regions <- read.table (peaks.file, stringsAsFactors=FALSE, header=TRUE)all.regions <- GRanges (regions[,'chrom'], IRanges (regions[,'chromStart'], regions[,'chromEnd']),    score=regions[,'score'], summit=regions[,'summit'], name=regions[,'name'])start (all.regions) <- end (all.regions) <- start (all.regions) + all.regions$summit - 1all.regions <- resize (all.regions, fix='center', span) Identify sequences and flag any sequences with Nseqs <- SeqGL:::get.seqs (SeqGL:::load.bsgenome (org), all.regions)names(seqs) <- all.regions$name Save writeXStringSet(seqs, sprintf("%s/all_seqs.fa", motifs.dir))```  FIMO Install FIMO from here: https://meme-suite.org/meme/doc/fimo.html ```fimo  -oc fimo  /fh/fast/setty_m/grp/motif_databases/CIS-BP_2.00/Homo_sapiens.meme all_seqs.fa ```  Matrix<jupyter_code>import tqdm

fimo_res = 'data/10x_pbmc_10k_scatac/fimo/fimo.tsv'
# Create matrix
# Motif information 
motifs = pd.Series()
motif_index = 0

# Peak index
peak_index = pd.Series(range(len(ad.var_names)), index=ad.var_names)

# Values
num_records = int(subprocess.run(['wc', '-l', fimo_res], stdout=subprocess.PIPE).stdout.decode().split(' ')[0]) - 5
x = np.zeros(num_records)
y = np.zeros(num_records)
values = np.zeros(num_records)

# Read file
rec_index = 0
for line in tqdm.tqdm(open(fimo_res, 'r')):
    # Skip first line 
    split = line.split('\t')
    if split[0] == 'motif_id':
        continue
    
    if len(split) == 1:
        break
        
    # Update motifs if necessary
    if split[1] not in motifs:
        motifs[split[1]] = motif_index
        motif_index += 1

    # Update record
    x[rec_index] = peak_index[split[2]]
    y[rec_index] = motifs[split[1]]
    values[rec_index] = float(split[6])
    rec_index += 1
# Sparse matrix
from scipy.sparse import csr_matrix
pwm_scores = csr_matrix((values, (x, y)), (ad.shape[1], motif_index))
pwm_ad = sc.AnnData(pwm_scores)
pwm_ad.obs_names = ad.var_names
pwm_ad.var_names = motifs.index
pwm_ad.write(motifs_dir + 'fimo_pwm_scores.h5ad')

pwm_ad<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.14280501710376284, 'fraction_numerical': 0.02161915621436716, 'mean_word_length': 3.434870550161812, 'pattern_counts': {'":': 0, '<': 93, '<?xml version=': 0, '>': 83, 'https://': 10, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '20', 'dir': 'jupyter-structured-clean-dedup', 'id': '558683', 'license': 'MIT', 'n_tokens_mistral': 8316, 'n_tokens_neox': 7848, 'n_words': 1474, 'path': 'notebooks/PBMC-ATAC-standalone.ipynb', 'repo_name': 'settylab/single-cell-primers', 'size': '21925'}