From 2e4950bed96b861344cef3150c44fd95428b6248 Mon Sep 17 00:00:00 2001 From: chrishendra93 Date: Fri, 23 Apr 2021 03:34:58 +0000 Subject: [PATCH] remove unused files and fix issue with dataprep --- build/lib/m6anet/__init__.py | 0 build/lib/m6anet/scripts/__init__.py | 0 build/lib/m6anet/scripts/dataprep.py | 381 --------------------------- build/lib/m6anet/scripts/helper.py | 133 ---------- build/lib/m6anet/utils/__init__.py | 0 build/lib/m6anet/utils/misc.py | 47 ---- dist/m6anet-0.0.1-py3.6.egg | Bin 20008 -> 0 bytes dist/m6anet-0.0.1-py3.7.egg | Bin 1331 -> 0 bytes m6anet.egg-info/PKG-INFO | 51 ---- m6anet.egg-info/SOURCES.txt | 32 --- m6anet.egg-info/dependency_links.txt | 1 - m6anet.egg-info/entry_points.txt | 6 - m6anet.egg-info/requires.txt | 8 - m6anet.egg-info/top_level.txt | 1 - m6anet/scripts/dataprep.py | 4 +- sample_labels.csv.gz | Bin 690 -> 0 bytes 16 files changed, 2 insertions(+), 662 deletions(-) delete mode 100644 build/lib/m6anet/__init__.py delete mode 100644 build/lib/m6anet/scripts/__init__.py delete mode 100644 build/lib/m6anet/scripts/dataprep.py delete mode 100644 build/lib/m6anet/scripts/helper.py delete mode 100644 build/lib/m6anet/utils/__init__.py delete mode 100644 build/lib/m6anet/utils/misc.py delete mode 100644 dist/m6anet-0.0.1-py3.6.egg delete mode 100644 dist/m6anet-0.0.1-py3.7.egg delete mode 100644 m6anet.egg-info/PKG-INFO delete mode 100644 m6anet.egg-info/SOURCES.txt delete mode 100644 m6anet.egg-info/dependency_links.txt delete mode 100644 m6anet.egg-info/entry_points.txt delete mode 100644 m6anet.egg-info/requires.txt delete mode 100644 m6anet.egg-info/top_level.txt delete mode 100644 sample_labels.csv.gz diff --git a/build/lib/m6anet/__init__.py b/build/lib/m6anet/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/build/lib/m6anet/scripts/__init__.py b/build/lib/m6anet/scripts/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/build/lib/m6anet/scripts/dataprep.py b/build/lib/m6anet/scripts/dataprep.py deleted file mode 100644 index 85ccbf3..0000000 --- a/build/lib/m6anet/scripts/dataprep.py +++ /dev/null @@ -1,381 +0,0 @@ -import argparse -import numpy as np -import pandas as pd -import os -import multiprocessing -import ujson -from operator import itemgetter -from collections import defaultdict -from itertools import groupby -from io import StringIO - -from . import helper -from .constants import M6A_KMERS, NUM_NEIGHBORING_FEATURES -from ..utils import misc - - -def get_args(): - parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) - - optional = parser._action_groups.pop() - required = parser.add_argument_group('required arguments') - - # Required arguments - required.add_argument('--eventalign', dest='eventalign', help='eventalign filepath, the output from nanopolish.',required=True) - required.add_argument('--out_dir', dest='out_dir', help='output directory.',required=True) - - optional.add_argument('--n_processes', dest='n_processes', help='number of processes to run.',type=int, default=1) - optional.add_argument('--chunk_size', dest='chunk_size', help='number of lines from nanopolish eventalign.txt for processing.',type=int, default=1000000) - optional.add_argument('--readcount_min', dest='readcount_min', help='minimum read counts per gene.',type=int, default=1) - optional.add_argument('--readcount_max', dest='readcount_max', help='maximum read counts per gene.',type=int, default=1000) - optional.add_argument('--index', dest='index', help='with this argument the program will index eventalign.txt first.',default=False,action='store_false') #todo - optional.add_argument('--n_neighbors', dest='n_neighbors', help='number of neighboring features to extract.',type=int, default=NUM_NEIGHBORING_FEATURES) - - parser._action_groups.append(optional) - return parser.parse_args() - -def partition_into_continuous_positions(arr, window_size=1): - arr = arr[np.argsort(arr["transcriptomic_position"])] - float_features = ['dwell_time', 'norm_std', 'norm_mean'] - float_dtypes = [('norm_mean', ' 2 * window_size + 1] - -def filter_by_kmer(partition, kmers, window_size): - feature_arr, kmer_arr, tx_id_arr, tx_pos_arr = partition - kmers_5 = kmer_arr[:, (2 * window_size + 1) // 2] - mask = np.isin(kmers_5, kmers) - filtered_feature_arr = feature_arr[mask, :] - filtered_kmer_arr = kmer_arr[mask, :] - filtered_tx_pos_arr = tx_pos_arr[mask] - filtered_tx_id_arr = tx_id_arr[mask] - - if len(filtered_kmer_arr) == 0: - return [] - else: - return filtered_feature_arr, filtered_kmer_arr, filtered_tx_id_arr, filtered_tx_pos_arr - -def filter_partitions(partitions, window_size, kmers): - windowed_partition = [create_features(partition, window_size) for partition in partitions] - filtered_by_kmers = [filter_by_kmer(partition, kmers, window_size) for partition in windowed_partition] - final_partitions = [x for x in filtered_by_kmers if len(x) > 0] - return final_partitions - -def roll(to_roll, window_size=1): - nex = np.concatenate([np.roll(to_roll, i, axis=0) for i in range(-1, - window_size - 1, -1)], - axis=1) - prev = np.concatenate([np.roll(to_roll, i, axis=0) for i in range(window_size, 0, -1)], axis=1) - return np.concatenate((prev, to_roll, nex), axis=1)[window_size: -window_size, :] - -def create_features(partition, window_size=1): - float_arr, kmer_arr, tx_id_arr, tx_pos_arr = partition - return roll(float_arr, window_size), roll(kmer_arr, window_size), \ - tx_id_arr[window_size: -window_size], tx_pos_arr[window_size: -window_size] - -def filter_events(events, window_size, kmers): - events = partition_into_continuous_positions(events) - events = filter_partitions(events, window_size, kmers) - return events - -def combine_sequence(kmers): - kmer = kmers[0] - for _kmer in kmers[1:]: - kmer += _kmer[-1] - return kmer - -def index(eventalign_result,pos_start,out_paths,locks): - eventalign_result = eventalign_result.set_index(['contig','read_index']) - pos_end=pos_start - with locks['index'], open(out_paths['index'],'a') as f_index: - for index in list(dict.fromkeys(eventalign_result.index)): - transcript_id,read_index = index - pos_end += eventalign_result.loc[index]['line_length'].sum() - f_index.write('%s,%d,%d,%d\n' %(transcript_id,read_index,pos_start,pos_end)) - pos_start = pos_end - -def parallel_index(eventalign_filepath,chunk_size,out_dir,n_processes): - # Create output paths and locks. - out_paths,locks = dict(),dict() - for out_filetype in ['index']: - out_paths[out_filetype] = os.path.join(out_dir,'eventalign.%s' %out_filetype) - locks[out_filetype] = multiprocessing.Lock() - # TO DO: resume functionality for index creation - - with open(out_paths['index'],'w') as f: - f.write('transcript_id,read_index,pos_start,pos_end\n') # header - - - # Create communication queues. - task_queue = multiprocessing.JoinableQueue(maxsize=n_processes * 2) - - # Create and start consumers. - consumers = [helper.Consumer(task_queue=task_queue,task_function=index,locks=locks) for i in range(n_processes)] - for p in consumers: - p.start() - - ## Load tasks into task_queue. A task is eventalign information of one read. - eventalign_file = open(eventalign_filepath,'r') - pos_start = len(eventalign_file.readline()) #remove header - chunk_split = None - index_features = ['contig','read_index','line_length'] - for chunk in pd.read_csv(eventalign_filepath, chunksize=chunk_size,sep='\t'): - chunk_complete = chunk[chunk['read_index'] != chunk.iloc[-1]['read_index']] - chunk_concat = pd.concat([chunk_split,chunk_complete]) - chunk_concat_size = len(chunk_concat.index) - ## read the file at where it left off because the file is opened once ## - lines = [len(eventalign_file.readline()) for i in range(chunk_concat_size)] - chunk_concat['line_length'] = np.array(lines) - task_queue.put((chunk_concat[index_features],pos_start,out_paths)) - pos_start += sum(lines) - chunk_split = chunk[chunk['read_index'] == chunk.iloc[-1]['read_index']] - ## the loop above leaves off w/o adding the last read_index to eventalign.index - chunk_split_size = len(chunk_split.index) - lines = [len(eventalign_file.readline()) for i in range(chunk_split_size)] - chunk_split['line_length'] = np.array(lines) - task_queue.put((chunk_split[index_features],pos_start,out_paths)) - - # Put the stop task into task_queue. - task_queue = helper.end_queue(task_queue,n_processes) - - # Wait for all of the tasks to finish. - task_queue.join() - -def combine(events_str): - f_string = StringIO(events_str) - eventalign_result = pd.read_csv(f_string,delimiter='\t',names=['contig','position','reference_kmer','read_index','strand','event_index','event_level_mean','event_stdv','event_length','model_kmer','model_mean','model_stdv','standardized_level','start_idx','end_idx']) - f_string.close() - cond_successfully_eventaligned = eventalign_result['reference_kmer'] == eventalign_result['model_kmer'] - if cond_successfully_eventaligned.sum() != 0: - - eventalign_result = eventalign_result[cond_successfully_eventaligned] - - keys = ['read_index','contig','position','reference_kmer'] # for groupby - eventalign_result['length'] = pd.to_numeric(eventalign_result['end_idx'])-pd.to_numeric(eventalign_result['start_idx']) - eventalign_result['sum_norm_mean'] = pd.to_numeric(eventalign_result['event_level_mean']) * eventalign_result['length'] - eventalign_result['sum_norm_std'] = pd.to_numeric(eventalign_result['event_stdv']) * eventalign_result['length'] - eventalign_result['sum_dwell_time'] = pd.to_numeric(eventalign_result['event_length']) * eventalign_result['length'] - - eventalign_result = eventalign_result.groupby(keys) - sum_norm_mean = eventalign_result['sum_norm_mean'].sum() - sum_norm_std = eventalign_result["sum_norm_std"].sum() - sum_dwell_time = eventalign_result["sum_dwell_time"].sum() - - start_idx = eventalign_result['start_idx'].min() - end_idx = eventalign_result['end_idx'].max() - total_length = eventalign_result['length'].sum() - - eventalign_result = pd.concat([start_idx,end_idx],axis=1) - eventalign_result['norm_mean'] = (sum_norm_mean/total_length).round(1) - eventalign_result["norm_std"] = sum_norm_std / total_length - eventalign_result["dwell_time"] = sum_dwell_time / total_length - eventalign_result.reset_index(inplace=True) - - - eventalign_result['transcript_id'] = [contig.split('.')[0] for contig in eventalign_result['contig']] #### CHANGE MADE #### - #eventalign_result['transcript_id'] = eventalign_result['contig'] - - eventalign_result['transcriptomic_position'] = pd.to_numeric(eventalign_result['position']) + 2 # the middle position of 5-mers. - # eventalign_result = misc.str_encode(eventalign_result) -# eventalign_result['read_id'] = [read_name]*len(eventalign_result) - - # features = ['read_id','transcript_id','transcriptomic_position','reference_kmer','norm_mean','start_idx','end_idx'] - # features_dtype = np.dtype([('read_id', 'S36'), ('transcript_id', 'S15'), ('transcriptomic_position', ' 1: - data_dict[read_index] = data - readcount += 1 - if readcount > readcount_max: - break - if readcount>=readcount_min: - task_queue.put((tx_id,data_dict,n_neighbors,out_paths)) # Blocked if necessary until a free slot is available. - - - # Put the stop task into task_queue. - task_queue = helper.end_queue(task_queue,n_processes) - - # Wait for all of the tasks to finish. - task_queue.join() - -## with open(out_paths['log'],'a+') as f: -## f.write('Total %d genes.\n' %len(gene_ids_processed)) -## f.write(helper.decor_message('successfully finished')) - -def preprocess_tx(tx_id,data_dict,n_neighbors,out_paths,locks): # todo - """ - Convert transcriptomic to genomic coordinates for a gene. - - Parameters - ---------- - tx_id: str - Transcript ID. - data_dict: {read_id:events_array} - Events for each read. - features: [str] # todo - A list of features to collect from the reads that are aligned to each genomic coordinate in the output. - Returns - ------- - dict - A dict of all specified features collected for each genomic coordinate. - """ - - # features = ['read_id','transcript_id','transcriptomic_position','reference_kmer','norm_mean','start_idx','end_idx'] # columns in the eventalign file per read. - - # Concatenate - if len(data_dict) == 0: - return - - features_arrays = [] - reference_kmer_arrays = [] - transcriptomic_positions_arrays = [] - - for read_id,events_per_read in data_dict.items(): - # print(read_id) - events_per_read = filter_events(events_per_read, n_neighbors, M6A_KMERS) - for event_per_read in events_per_read: - features_arrays.append(event_per_read[0]) - reference_kmer_arrays.append([combine_sequence(kmer) for kmer in event_per_read[1]]) - transcriptomic_positions_arrays.append(event_per_read[3]) - - if len(features_arrays) == 0: - return - else: - features_arrays = np.concatenate(features_arrays) - reference_kmer_arrays = np.concatenate(reference_kmer_arrays) - transcriptomic_positions_arrays = np.concatenate(transcriptomic_positions_arrays) - assert(len(features_arrays) == len(reference_kmer_arrays) == len(transcriptomic_positions_arrays)) - # Sort and split - - idx_sorted = np.argsort(transcriptomic_positions_arrays) - positions, index = np.unique(transcriptomic_positions_arrays[idx_sorted], return_index = True,axis=0) #'chr', - features_arrays = np.split(features_arrays[idx_sorted], index[1:]) - reference_kmer_arrays = np.split(reference_kmer_arrays[idx_sorted], index[1:]) - - # Prepare - # print('Reformating the data for each genomic position ...') - data = defaultdict(dict) - - - # for each position, make it ready for json dump - for position, features_array, reference_kmer_array in zip(positions, features_arrays, reference_kmer_arrays): - kmer = set(reference_kmer_array) - assert(len(kmer) == 1) - if (len(set(reference_kmer_array)) == 1) and ('XXXXX' in set(reference_kmer_array)) or (len(features_array) == 0): - continue - - data[int(position)] = {kmer.pop(): features_array.tolist()} - - # write to file. - log_str = '%s: Data preparation ... Done.' %(tx_id) - with locks['json'], open(out_paths['json'],'a') as f, \ - locks['index'], open(out_paths['index'],'a') as g, \ - locks['readcount'], open(out_paths['readcount'],'a') as h: - - for pos, dat in data.items(): - pos_start = f.tell() - f.write('{') - f.write('"%s":{"%d":' %(tx_id,pos)) - ujson.dump(dat, f) - f.write('}}\n') - pos_end = f.tell() - - # with locks['index'], open(out_paths['index'],'a') as f: - g.write('%s,%d,%d,%d\n' %(tx_id,pos,pos_start,pos_end)) - - # with locks['readcount'], open(out_paths['readcount'],'a') as f: #todo: repeats no. of tx >> don't want it. - n_reads = 0 - for kmer, features in dat.items(): - n_reads += len(features) - h.write('%s,%d,%d\n' %(tx_id,pos,n_reads)) - - with locks['log'], open(out_paths['log'],'a') as f: - f.write(log_str + '\n') - - -def main(): - args = get_args() - # - n_processes = args.n_processes - eventalign_filepath = args.eventalign - chunk_size = args.chunk_size - out_dir = args.out_dir - readcount_min = args.readcount_min - readcount_max = args.readcount_max - index = args.index - n_neighbors = args.n_neighbors - misc.makedirs(out_dir) #todo: check every level. - - # (1) For each read, combine multiple events aligned to the same positions, the results from nanopolish eventalign, into a single event per position. - eventalign_log_filepath = os.path.join(out_dir,'eventalign.log') - # if not helper.is_successful(eventalign_log_filepath) and not resume: #some slight hack to skip index creation again after it is successful - if not index: - parallel_index(eventalign_filepath,chunk_size,out_dir,n_processes) - parallel_preprocess_tx(eventalign_filepath,out_dir,n_processes,readcount_min,readcount_max, n_neighbors) #TO DO: RESUME FUNCTION - -if __name__ == '__main__': - main() diff --git a/build/lib/m6anet/scripts/helper.py b/build/lib/m6anet/scripts/helper.py deleted file mode 100644 index 658dc00..0000000 --- a/build/lib/m6anet/scripts/helper.py +++ /dev/null @@ -1,133 +0,0 @@ -import gzip -import multiprocessing -import numpy -import os -import pandas -from functools import reduce -from collections import defaultdict - - -class EventalignFile: - - def __init__(self, fn): - self._fn = fn - self._open() - - def _open(self): - fn = self._fn - if os.path.splitext(fn)[1] == '.gz': - self._handle = gzip.open(fn) - self._decode_method = bytes.decode - else: - self._handle = open(fn) - self._decode_method = str - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_value, exc_traceback): - self.close() - - def close(self): - self._handle.close() - - def readline(self): - self._handle.readline() - - def __iter__(self): - return self - - def __next__(self): - return self._decode_method(next(self._handle)) - - -def decor_message(text,opt='simple'): - text = text.upper() - if opt == 'header': - return text - else: - return '--- ' + text + ' ---\n' - -def end_queue(task_queue,n_processes): - for _ in range(n_processes): - task_queue.put(None) - return task_queue - -def get_ids(f_index,data_info): #todo - df_list = [] - - for condition_name, run_names in data_info.items(): - list_of_set_ids = [] - for run_name in run_names: - list_of_set_ids += [set(f_index[run_name].keys())] - # ids = reduce(lambda x,y: x.intersection(y), list_of_set_ids) - ids = reduce(lambda x,y: x.union(y), list_of_set_ids) - df_list += [pandas.DataFrame({'ids':list(ids),condition_name:[1]*len(ids)})] - df_merged = reduce(lambda left,right: pandas.merge(left,right,on=['ids'], how='outer'), df_list).fillna(0).set_index('ids') - return sorted(list(df_merged[df_merged.sum(axis=1) >= 2].index)) # At least two conditions. - -## tmp: to remove -# def get_gene_ids(config_filepath): # arguments are not used. -# import os,pandas -# from ..diffmod.configurator import Configurator -# # config_filepath = '/ploy_ont_workspace/github/experiments/Release_v1_0/config_manuscript/gmm_HEK293T-KO_HEK293T-WT_HEPG2-WT_K562-WT_A549-WT_MCF7-WT_reps_v01.ini' -# config = Configurator(config_filepath) -# paths = config.get_paths() -# info = config.get_info() -# criteria = config.get_criteria() -# df_gt_ids = pandas.read_csv('/ploy_ont_workspace/out/Release_v1_0/statCompare/data/mapping_gt_ids.csv') -# gene_ids = set(df_gt_ids['g_id'].unique()) -# read_count_sum_min,read_count_sum_max = criteria['read_count_min'],criteria['read_count_max'] -# df_read_count = {} -# for run_name in set(info['run_names']): -# read_count_filepath = os.path.join(paths['data_dir'],run_name,'summary','read_count_per_gene.csv') -# df_read_count[run_name] = pandas.read_csv(read_count_filepath).set_index('g_id') - -# for run_name in set(info['run_names']): -# df_read_count[run_name].reset_index(inplace=True) -# cond = df_read_count[run_name]['n_reads'] >= criteria['read_count_min'] -# cond &= df_read_count[run_name]['n_reads'] <= criteria['read_count_max'] -# gene_ids = gene_ids.intersection(set(df_read_count[run_name].loc[cond,'g_id'].values)) - -# gene_ids = sorted(list(gene_ids)) -# return gene_ids -## - -class Consumer(multiprocessing.Process): - """ For parallelisation """ - - def __init__(self,task_queue,task_function,locks=None,result_queue=None): - multiprocessing.Process.__init__(self) - self.task_queue = task_queue - self.locks = locks - self.task_function = task_function - self.result_queue = result_queue - - def run(self): - proc_name = self.name - while True: - next_task_args = self.task_queue.get() - if next_task_args is None: - self.task_queue.task_done() - break - result = self.task_function(*next_task_args,self.locks) - self.task_queue.task_done() - if self.result_queue is not None: - self.result_queue.put(result) - -def read_last_line(filepath): # https://stackoverflow.com/questions/3346430/what-is-the-most-efficient-way-to-get-first-and-last-line-of-a-text-file/3346788 - if not os.path.exists(filepath): - return - with open(filepath, "rb") as f: - first = f.readline() # Read the first line. - if first == b'': - return - f.seek(-2, os.SEEK_END) # Jump to the second last byte. - while f.read(1) != b"\n": # Until EOL is found... - f.seek(-2, os.SEEK_CUR) # ...jump back the read byte plus one more. - last = f.readline() # Read last line. - return last - -def is_successful(filepath): - return read_last_line(filepath) == b'--- SUCCESSFULLY FINISHED ---\n' - diff --git a/build/lib/m6anet/utils/__init__.py b/build/lib/m6anet/utils/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/build/lib/m6anet/utils/misc.py b/build/lib/m6anet/utils/misc.py deleted file mode 100644 index 495f2cb..0000000 --- a/build/lib/m6anet/utils/misc.py +++ /dev/null @@ -1,47 +0,0 @@ -import numpy as np -import os - - -def makedirs(main_dir, sub_dirs=None, opt='depth'): - if not os.path.exists(main_dir): - os.makedirs(main_dir) - filepaths = dict() - if sub_dirs is not None: - if opt == 'depth': - path = main_dir - for sub_dir in sub_dirs: - path = os.path.join(path, sub_dir) - filepaths[sub_dir] = path - # if not os.path.exists(path): - try: # Use try-catch for the case of multiprocessing. - os.makedirs(path) - except: - pass - - else: # opt == 'breadth' - for sub_dir in sub_dirs: - path = os.path.join(main_dir, sub_dir) - filepaths[sub_dir] = path - # if not os.path.exists(path): - try: # Use try-catch for the case of multiprocessing. - os.makedirs(path) - except: - pass - - return filepaths - - -def str_decode(df): - str_df = df.select_dtypes([np.object]) - str_df = str_df.stack().str.decode('utf-8').unstack() - for col in str_df: - df[col] = str_df[col] - return df - - -def str_encode(df): - str_df = df.select_dtypes([np.object]) - str_df = str_df.stack().str.encode('utf-8').unstack() - for col in str_df: - df[col] = str_df[col] - return df diff --git a/dist/m6anet-0.0.1-py3.6.egg b/dist/m6anet-0.0.1-py3.6.egg deleted file mode 100644 index d0ae01cc2c03bddb806d894a8fc652afe2071c53..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20008 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 diff --git a/dist/m6anet-0.0.1-py3.7.egg b/dist/m6anet-0.0.1-py3.7.egg deleted file mode 100644 index 0f12520459d8297e54bd9508ed328a6f132e4806..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1331 zcmWIWW@Zs#U|`^2I9|dW=y807@;pW$mzjY<5JVL#(yhR%Pbo;SK*UetW>F^~{5$oa*m^!MbGErr4&iN2*zb+0xF9c%S8v&(N?TVYV_WO(@t3y9*-v2JY?)%lF za>*jIRfP0j&iiH;QN+28Gq`VoO8g4PigTTZm45{9Z`yfNZvl7XUt8X%dR+5PyH7Fw z-Ffkr&^4jEQ@npP#mgW2$d~c+*OfVYXBXBT+41$@i=Z374F9^$e0`fEWaEzH6z7lj zCb=vT)0X^wrzR;4I4-Im54c05EDB&(DE%{h_^|bFp zEk9jN-3!_)o}4oEKI5%>(c9Pm`q?wyr?2yWD7*gkOY!I96F9!{^A?ryUejKwad3jS zr>@6YZ_l&d>w3~{L&;QCnFYGViD{`| zKQc0jFyqdMK-<8ep%FyEV-l7v1H4hSqeneNGXq0I<5^&+!?hzN1auRS9Sw>k7-(or zWkNCmTa=+2g&t!FqZT6@g&u$C#vr>06#6jG&?pB?O>jS<#05SxKv4k$4UM75X22pQ Uz?+o~q=XF!rvU@59h7Vt0R2S0rvLx| diff --git a/m6anet.egg-info/PKG-INFO b/m6anet.egg-info/PKG-INFO deleted file mode 100644 index f44b043..0000000 --- a/m6anet.egg-info/PKG-INFO +++ /dev/null @@ -1,51 +0,0 @@ -Metadata-Version: 1.2 -Name: m6anet -Version: 0.0.1 -Summary: m6anet is a python package for detection of m6a modifications from Nanopore direct RNA sequencing data. -Home-page: https://github.com/GoekeLab/m6anet -Author: Christopher Hendra -Maintainer-email: christopher.hendra@u.nus.edu -License: MIT -Description: # m6anet - ![alt text](https://github.com/GoekeLab/m6anet/blob/master/figures/m6anet_logo.png "m6anet") - - m6anet is a python tool to detect m6a modifications from Nanopore Direct RNA Sequencing data - - ### Installation - - m6anet requires [Python3](https://www.python.org) to run. - - To install our xpore package and its dependencies, run - - ```sh - $ git clone git@github.com:GoekeLab/m6anet.git - $ python setup.py install - $ pip install -r requirements.txt - ``` - - See our documentation [here](https://m6anet.readthedocs.io/)! - - ### Citing m6Anet - - If you use m6Anet in your research, please use the following DOI for citation: - - [![DOI](https://zenodo.org/badge/281866292.svg)](https://zenodo.org/badge/latestdoi/281866292) - - Christopher Hendra, & Yuk Kei Wan. (2021, April 15). GoekeLab/m6anet: Pre-release (Version Pre-release). Zenodo. http://doi.org/10.5281/zenodo.4692776 - - ### Contributors - - This package is developed and maintaned by [Christopher Hendra](https://github.com/chrishendra93) and [Jonathan Göke](https://github.com/jonathangoeke). If you want to contribute, please leave an issue. Thank you. - ### License - MIT - - -Platform: UNKNOWN -Classifier: Development Status :: 1 - Planning -Classifier: License :: OSI Approved :: MIT License -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3.8 -Classifier: Topic :: Software Development :: Libraries -Classifier: Topic :: Scientific/Engineering :: Bio-Informatics -Classifier: Intended Audience :: Science/Research -Requires-Python: >=3.8 diff --git a/m6anet.egg-info/SOURCES.txt b/m6anet.egg-info/SOURCES.txt deleted file mode 100644 index cd133ea..0000000 --- a/m6anet.egg-info/SOURCES.txt +++ /dev/null @@ -1,32 +0,0 @@ -README.md -setup.py -m6anet/__init__.py -m6anet.egg-info/PKG-INFO -m6anet.egg-info/SOURCES.txt -m6anet.egg-info/dependency_links.txt -m6anet.egg-info/entry_points.txt -m6anet.egg-info/requires.txt -m6anet.egg-info/top_level.txt -m6anet/model/__init__.py -m6anet/model/model.py -m6anet/model/configs/model_configs/prod_pooling.toml -m6anet/model/model_blocks/__init__.py -m6anet/model/model_blocks/blocks.py -m6anet/model/model_blocks/pooling_blocks.py -m6anet/model/model_states/prod_pooling_pr_auc.pt -m6anet/model/norm_factors/norm_dict.joblib -m6anet/scripts/__init__.py -m6anet/scripts/compute_normalization_factors.py -m6anet/scripts/constants.py -m6anet/scripts/dataprep.py -m6anet/scripts/helper.py -m6anet/scripts/run_inference.py -m6anet/scripts/train.py -m6anet/utils/__init__.py -m6anet/utils/builder.py -m6anet/utils/data_utils.py -m6anet/utils/misc.py -m6anet/utils/training_utils.py -m6anet/utils/loss_functions/__init__.py -m6anet/utils/loss_functions/test_loss.py -m6anet/utils/loss_functions/train_loss.py \ No newline at end of file diff --git a/m6anet.egg-info/dependency_links.txt b/m6anet.egg-info/dependency_links.txt deleted file mode 100644 index 8b13789..0000000 --- a/m6anet.egg-info/dependency_links.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/m6anet.egg-info/entry_points.txt b/m6anet.egg-info/entry_points.txt deleted file mode 100644 index eee080a..0000000 --- a/m6anet.egg-info/entry_points.txt +++ /dev/null @@ -1,6 +0,0 @@ -[console_scripts] -m6anet-compute_norm_factors = m6anet.scripts.compute_normalization_factors:main -m6anet-dataprep = m6anet.scripts.dataprep:main -m6anet-run_inference = m6anet.scripts.run_inference:main -m6anet-train = m6anet.scripts.train:main - diff --git a/m6anet.egg-info/requires.txt b/m6anet.egg-info/requires.txt deleted file mode 100644 index b59ce7d..0000000 --- a/m6anet.egg-info/requires.txt +++ /dev/null @@ -1,8 +0,0 @@ -numpy>=1.18.0 -pandas>=0.25.3 -scikit-learn>=0.24.1 -scipy>=1.4.1 -ujson -torch>=1.6.0 -toml>=0.10.2 -tqdm diff --git a/m6anet.egg-info/top_level.txt b/m6anet.egg-info/top_level.txt deleted file mode 100644 index abe232c..0000000 --- a/m6anet.egg-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -m6anet diff --git a/m6anet/scripts/dataprep.py b/m6anet/scripts/dataprep.py index ea0e214..ee9c8cd 100644 --- a/m6anet/scripts/dataprep.py +++ b/m6anet/scripts/dataprep.py @@ -28,7 +28,7 @@ def get_args(): optional.add_argument('--chunk_size', dest='chunk_size', help='number of lines from nanopolish eventalign.txt for processing.',type=int, default=1000000) optional.add_argument('--readcount_min', dest='readcount_min', help='minimum read counts per gene.',type=int, default=1) optional.add_argument('--readcount_max', dest='readcount_max', help='maximum read counts per gene.',type=int, default=1000) - optional.add_argument('--index', dest='index', help='with this argument the program will index eventalign.txt first.',default=False,action='store_false') #todo + optional.add_argument('--index', dest='index', help='with this argument the program will index eventalign.txt first.',default=False,action='store_true') optional.add_argument('--n_neighbors', dest='n_neighbors', help='number of neighboring features to extract.',type=int, default=NUM_NEIGHBORING_FEATURES) parser._action_groups.append(optional) @@ -373,7 +373,7 @@ def main(): # (1) For each read, combine multiple events aligned to the same positions, the results from nanopolish eventalign, into a single event per position. eventalign_log_filepath = os.path.join(out_dir,'eventalign.log') # if not helper.is_successful(eventalign_log_filepath) and not resume: #some slight hack to skip index creation again after it is successful - if index: + if not index: parallel_index(eventalign_filepath,chunk_size,out_dir,n_processes) parallel_preprocess_tx(eventalign_filepath,out_dir,n_processes,readcount_min,readcount_max, n_neighbors) #TO DO: RESUME FUNCTION diff --git a/sample_labels.csv.gz b/sample_labels.csv.gz deleted file mode 100644 index a71c6784a23fd991397f3ef1d06d4a8c6ad0e853..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 690 zcmV;j0!{rNiwFoI6DeN;|7>AmWo&aUV{>)@j8?mj+dvHL^DPHq`PxS*7=gPqQNJ*9 zG2-Ix3OoOwmAotI0%>%rDK0sj8S?smdHa2TdHZ<1U2nfGkK4z4zCSLHzxQw7fBYQW z_=!>ZI-kjW9?tz~$g16+*Q>p_&TYg6=kvM5owD*qoQB|tJIfX&_kDlr^Hw@#3SLT> z4>qM6GHrx$5RI;rOpYxN{cc=x>|#fhsr-=7Qy_d-DAslfb!#NGJaH&pQvbOP+5|;R zr&muIW9PJDC$I;JQ`qSMlVD*gu0O&qTAA5Yo<9iW)~-hdYI5k|He6BH+Knh3k8$T? z4tNnT+f|&&m+&JIU;9whhuM>QrH{11f=~Fl8i|39&g#RAD-4nC zYAc->l1CX#MR0R+s{$!XwGF7ZXsIC$Bs7@Llp&2ZHNU)<#u9hBc>CJYHA&9gdZ*lq&r=LE}&c#<60- zsE__Ij!TLAhOne7-44ebE!yb8N>~=)>;_wAFf%13G_kojV?xSZd5iG$?g@Ky*{Fmt zZf&r&bd1tP`yzJQc+4B9%yGi87AK4d<*DUUI1G+l8NkpklGH8~p9Ln(EFIoOh+((fQ41&0pP z`OFnXHowYO0{h*3%RVsr@4Vi-nAj6w>gtqim$SlCO^jQ*xFwKTZa#vuWszHmh|i1X Yic~_c()|Mf0RR630Art&yQd8R06+9nx&QzG