diff options
19 files changed, 456 insertions, 144 deletions
diff --git a/wqflask/base/data_set.py b/wqflask/base/data_set.py index cab708ef..1457ba8d 100644 --- a/wqflask/base/data_set.py +++ b/wqflask/base/data_set.py @@ -131,7 +131,7 @@ Publish or ProbeSet. E.g. ProbeSetFreeze.Name = "{0}" """.format(name) - results = g.db.execute(geno_query).fetchall() + results = g.db.execute(mrna_expr_query).fetchall() if len(results): self.datasets[name] = "ProbeSet" Redis.set("dataset_structure", json.dumps(self.datasets)) @@ -165,12 +165,11 @@ Publish or ProbeSet. E.g. geno_query = """ SELECT - GenoFreezeId + GenoFreeze.Id FROM GenoFreeze WHERE GenoFreeze.Name = "{0}" - {1} """.format(name) results = g.db.execute(geno_query).fetchall() diff --git a/wqflask/utility/redis_tools.py b/wqflask/utility/redis_tools.py index 0754e16f..ca42f7b7 100644 --- a/wqflask/utility/redis_tools.py +++ b/wqflask/utility/redis_tools.py @@ -78,3 +78,93 @@ def check_verification_code(code): else: return None flash("Invalid code: Password reset code does not exist or might have expired!", "error") + +def get_user_groups(user_id): + #ZS: Get the groups where a user is an admin or a member and return lists corresponding to those two sets of groups + admin_group_ids = [] #ZS: Group IDs where user is an admin + user_group_ids = [] #ZS: Group IDs where user is a regular user + groups_list = Redis.hgetall("groups") + for key in groups_list: + group_ob = json.loads(groups_list[key]) + group_admins = set(group_ob['admins']) + group_users = set(group_ob['users']) + if user_id in group_admins: + admin_group_ids.append(group_ob['id']) + elif user_id in group_users: + user_group_ids.append(group_ob['id']) + else: + continue + + return admin_group_ids, user_group_ids + +def get_group_info(group_id): + group_json = Redis.hget("groups", group_id) + group_info = None + if group_json: + group_info = json.loads(group_json) + + return group_info + +def create_group(admin_member_ids, user_member_ids = [], group_name = ""): + group_id = str(uuid.uuid4()) + new_group = { + "id" : group_id, + "admins": admin_member_ids, + "users" : user_member_ids, + "name" : group_name, + "created_timestamp": datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p'), + "changed_timestamp": datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p') + } + + Redis.hset("groups", group_id, new_group) + + return new_group + +def delete_group(user_id, group_id): + #ZS: If user is an admin of a group, remove it from the groups hash + group_info = get_group_info(group_id) + if user_id in group_info["admins"]: + Redis.hdel("groups", group_id) + return get_user_groups(user_id) + else: + None + +def add_users_to_group(user_id, group_id, user_emails = [], admins = False): #ZS "admins" is just to indicate whether the users should be added to the groups admins or regular users set + group_info = get_group_info(group_id) + if user_id in group_info["admins"]: #ZS: Just to make sure that the user is an admin for the group, even though they shouldn't be able to reach this point unless they are + if admins: + group_users = set(group_info["admins"]) + else: + group_users = set(group_info["users"]) + + for email in user_emails: + user_id = get_user_id("email_address", email) + group_users.add(user_id) + + if admins: + group_info["admins"] = list(group_users) + else: + group_info["users"] = list(group_users) + + group_info["changed_timestamp"] = datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p') + Redis.hset("groups", group_id, json.dumps(group_info)) + return group_info + else: + return None + +def remove_users_from_group(user_id, users_to_remove_ids, group_id, user_type = "users"): #ZS: User type is because I assume admins can remove other admins + group_info = get_group_info(group_id) + if user_id in group_info["admins"]: + group_users = set(group_info[user_type]) + group_users -= set(users_to_remove_ids) + group_info[user_type] = list(group_users) + group_info["changed_timestamp"] = datetime.datetime.utcnow().strftime('%b %d %Y %I:%M%p') + Redis.hset("groups", group_id, json.dumps(group_info)) + +def change_group_name(user_id, group_id, new_name): + group_info = get_group_info(group_id) + if user_id in group_info["admins"]: + group_info["name"] = new_name + return group_info + else: + return None
\ No newline at end of file diff --git a/wqflask/wqflask/gsearch.py b/wqflask/wqflask/gsearch.py index 3d9b508a..04e3d578 100644 --- a/wqflask/wqflask/gsearch.py +++ b/wqflask/wqflask/gsearch.py @@ -75,7 +75,10 @@ class GSearch(object): this_trait['group'] = line[1] this_trait['tissue'] = line[2] this_trait['symbol'] = line[6] - this_trait['description'] = line[7].decode('utf-8', 'replace') + if line[7]: + this_trait['description'] = line[7].decode('utf-8', 'replace') + else: + this_trait['description'] = "N/A" this_trait['location_repr'] = 'N/A' if (line[8] != "NULL" and line[8] != "") and (line[9] != 0): this_trait['location_repr'] = 'Chr%s: %.6f' % (line[8], float(line[9])) diff --git a/wqflask/wqflask/marker_regression/display_mapping_results.py b/wqflask/wqflask/marker_regression/display_mapping_results.py index 2a53b60e..f70bc555 100644 --- a/wqflask/wqflask/marker_regression/display_mapping_results.py +++ b/wqflask/wqflask/marker_regression/display_mapping_results.py @@ -265,14 +265,12 @@ class DisplayMappingResults(object): else: self.colorCollection = [self.LRS_COLOR] + self.dataset.group.genofile = self.genofile_string.split(":")[0] if self.mapping_method == "reaper" and self.manhattan_plot != True: self.genotype = self.dataset.group.read_genotype_file(use_reaper=True) else: self.genotype = self.dataset.group.read_genotype_file() - #if self.mapping_method == "rqtl_geno" and self.genotype.filler == True: - # self.genotype = self.genotype.read_rdata_output(self.qtlresults) - #Darwing Options try: if self.selectedChr > -1: @@ -1761,9 +1759,9 @@ class DisplayMappingResults(object): break if all_int: - max_lrs_width = canvas.stringWidth("%d" % LRS_LOD_Max, font=LRSScaleFont) + 30 + max_lrs_width = canvas.stringWidth("%d" % LRS_LOD_Max, font=LRSScaleFont) + 40 else: - max_lrs_width = canvas.stringWidth("%2.1f" % LRS_LOD_Max, font=LRSScaleFont) + 20 + max_lrs_width = canvas.stringWidth("%2.1f" % LRS_LOD_Max, font=LRSScaleFont) + 30 #draw the "LRS" or "LOD" string to the left of the axis canvas.drawString(self.LRS_LOD, xLeftOffset - max_lrs_width - 15*(zoom-1), \ @@ -1899,13 +1897,16 @@ class DisplayMappingResults(object): this_chr = str(self.ChrList[self.selectedChr][1]+1) if self.selectedChr == -1 or str(qtlresult['chr']) == this_chr: - if self.plotScale != "physic" and self.genotype.filler == True: - if self.selectedChr != -1: - start_cm = self.genotype[self.selectedChr - 1][0].cM - Xc = startPosX + (qtlresult['Mb'] - start_cm)*plotXScale - else: - start_cm = self.genotype[previous_chr_as_int][0].cM - Xc = startPosX + ((qtlresult['Mb']-start_cm-startMb)*plotXScale)*(((qtlresult['Mb']-start_cm-startMb)*plotXScale)/((qtlresult['Mb']-start_cm-startMb+self.GraphInterval)*plotXScale)) + if self.plotScale != "physic" and self.mapping_method == "reaper" and not self.manhattan_plot: + Xc = startPosX + (qtlresult['cM']-startMb)*plotXScale + if hasattr(self.genotype, "filler"): + if self.genotype.filler: + if self.selectedChr != -1: + start_cm = self.genotype[self.selectedChr - 1][0].cM + Xc = startPosX + (qtlresult['Mb'] - start_cm)*plotXScale + else: + start_cm = self.genotype[previous_chr_as_int][0].cM + Xc = startPosX + ((qtlresult['Mb']-start_cm-startMb)*plotXScale)*(((qtlresult['Mb']-start_cm-startMb)*plotXScale)/((qtlresult['Mb']-start_cm-startMb+self.GraphInterval)*plotXScale)) else: Xc = startPosX + (qtlresult['Mb']-startMb)*plotXScale diff --git a/wqflask/wqflask/marker_regression/rqtl_mapping.py b/wqflask/wqflask/marker_regression/rqtl_mapping.py index f3d9a70e..e4a4d127 100644 --- a/wqflask/wqflask/marker_regression/rqtl_mapping.py +++ b/wqflask/wqflask/marker_regression/rqtl_mapping.py @@ -3,6 +3,8 @@ import rpy2.robjects.numpy2ri as np2r import numpy as np import json +from flask import g + from base.webqtlConfig import TMPDIR from base.trait import GeneralTrait from base.data_set import create_dataset @@ -31,7 +33,7 @@ def get_trait_data_type(trait_db_string): # Run qtl mapping using R/qtl -def run_rqtl_geno(vals, samples, dataset, method, model, permCheck, num_perm, perm_strata_list, do_control, control_marker, manhattan_plot, pair_scan, cofactors): +def run_rqtl_geno(vals, samples, dataset, mapping_scale, method, model, permCheck, num_perm, perm_strata_list, do_control, control_marker, manhattan_plot, pair_scan, cofactors): logger.info("Start run_rqtl_geno"); ## Get pointers to some common R functions r_library = ro.r["library"] # Map the library function @@ -56,7 +58,13 @@ def run_rqtl_geno(vals, samples, dataset, method, model, permCheck, num_perm, pe # genofilelocation = locate(crossname + ".RData", "genotype/rdata") # cross_object = read_cross_from_rdata(genofilelocation) # Map the local GENOtoCSVR function #except: - generate_cross_from_geno(dataset) + + if mapping_scale == "morgan": + scale_units = "cM" + else: + scale_units = "Mb" + + generate_cross_from_geno(dataset, scale_units) GENOtoCSVR = ro.r["GENOtoCSVR"] # Map the local GENOtoCSVR function crossfilelocation = TMPDIR + crossname + ".cross" if dataset.group.genofile: @@ -124,11 +132,9 @@ def run_rqtl_geno(vals, samples, dataset, method, model, permCheck, num_perm, pe perm_data_frame = scanone(cross_object, pheno_col = "the_pheno", n_perm = num_perm, model=model, method=method) perm_output, suggestive, significant = process_rqtl_perm_results(num_perm, perm_data_frame) # Functions that sets the thresholds for the webinterface - the_scale = check_mapping_scale(genofilelocation) - return perm_output, suggestive, significant, process_rqtl_results(result_data_frame, dataset.group.species), the_scale + return perm_output, suggestive, significant, process_rqtl_results(result_data_frame, dataset.group.species) else: - the_scale = check_mapping_scale(genofilelocation) - return process_rqtl_results(result_data_frame, dataset.group.species), the_scale + return process_rqtl_results(result_data_frame, dataset.group.species) def generate_cross_from_rdata(dataset): rdata_location = locate(dataset.group.name + ".RData", "genotype/rdata") @@ -140,20 +146,17 @@ def generate_cross_from_rdata(dataset): } """ % (rdata_location)) -def generate_cross_from_geno(dataset): # TODO: Need to figure out why some genofiles have the wrong format and don't convert properly +def generate_cross_from_geno(dataset, scale_units): # TODO: Need to figure out why some genofiles have the wrong format and don't convert properly ro.r(""" trim <- function( x ) { gsub("(^[[:space:]]+|[[:space:]]+$)", "", x) } - getGenoCode <- function(header, name = 'unk'){ mat = which(unlist(lapply(header,function(x){ length(grep(paste('@',name,sep=''), x)) })) == 1) return(trim(strsplit(header[mat],':')[[1]][2])) } - GENOtoCSVR <- function(genotypes = '%s', out = 'cross.csvr', phenotype = NULL, sex = NULL, verbose = FALSE){ header = readLines(genotypes, 40) # Assume a geno header is not longer than 40 lines toskip = which(unlist(lapply(header, function(x){ length(grep("Chr\t", x)) })) == 1)-1 # Major hack to skip the geno headers - type <- getGenoCode(header, 'type') if(type == '4-way'){ genocodes <- c('1','2','3','4') @@ -166,12 +169,15 @@ def generate_cross_from_geno(dataset): # TODO: Need to figure out why som if(is.null(sex)) sex <- rep('m', (ncol(genodata)-4)) # If there isn't a sex phenotype, treat all as males outCSVR <- rbind(c('Pheno', '', '', phenotype), # Phenotype c('sex', '', '', sex), # Sex phenotype for the mice - cbind(genodata[,c('Locus','Chr', 'cM')], genodata[, 5:ncol(genodata)])) # Genotypes + cbind(genodata[,c('Locus','Chr', '%s')], genodata[, 5:ncol(genodata)])) # Genotypes write.table(outCSVR, file = out, row.names=FALSE, col.names=FALSE,quote=FALSE, sep=',') # Save it to a file require(qtl) if(type == '4-way'){ cat('Loading in as 4-WAY\n') cross = read.cross(file=out, 'csvr', genotypes=genocodes, crosstype="4way", convertXdata=FALSE) # Load the created cross file using R/qtl read.cross + }else if(type == 'f2'){ + cat('Loading in as F2\n') + cross = read.cross(file=out, 'csvr', genotypes=genocodes, crosstype="f2") # Load the created cross file using R/qtl read.cross }else{ cat('Loading in as normal\n') cross = read.cross(file=out, 'csvr', genotypes=genocodes) # Load the created cross file using R/qtl read.cross @@ -182,7 +188,7 @@ def generate_cross_from_geno(dataset): # TODO: Need to figure out why som } return(cross) } - """ % (dataset.group.genofile)) + """ % (dataset.group.genofile, scale_units)) def add_perm_strata(cross, perm_strata): col_string = 'c("the_strata")' @@ -400,18 +406,14 @@ def process_rqtl_results(result, species_name): # TODO: how to make this return qtl_results -def check_mapping_scale(genofile_location): - scale = "physic" - with open(genofile_location, "r") as geno_fh: - for line in geno_fh: - if line[0] == "@" or line[0] == "#": +def get_trait_data_type(trait_db_string): + # Get a trait's type (numeric, categorical, etc) from the DB + the_query = "SELECT value FROM TraitMetadata WHERE type='trait_data_type'" + results_json = g.db.execute(the_query).fetchone() - if "@scale" in line: - scale = line.split(":")[1].strip() - break - else: - continue - else: - break + results_ob = json.loads(results_json[0]) - return scale
\ No newline at end of file + if trait_db_string in results_ob: + return results_ob[trait_db_string] + else: + return "numeric" diff --git a/wqflask/wqflask/marker_regression/run_mapping.py b/wqflask/wqflask/marker_regression/run_mapping.py index 589be702..5f7710ab 100644 --- a/wqflask/wqflask/marker_regression/run_mapping.py +++ b/wqflask/wqflask/marker_regression/run_mapping.py @@ -124,7 +124,7 @@ class RunMapping(object): self.samples.append(sample) self.vals.append(value) - self.num_vals = start_vars['num_vals'] + self.num_vals = len(self.vals) #ZS: Check if genotypes exist in the DB in order to create links for markers @@ -156,6 +156,8 @@ class RunMapping(object): self.transform = "" self.score_type = "LRS" #ZS: LRS or LOD self.mapping_scale = "physic" + if "mapping_scale" in start_vars: + self.mapping_scale = start_vars['mapping_scale'] self.num_perm = 0 self.perm_output = [] self.bootstrap_results = [] @@ -255,9 +257,9 @@ class RunMapping(object): #if start_vars['pair_scan'] == "true": # self.pair_scan = True if self.permCheck and self.num_perm > 0: - self.perm_output, self.suggestive, self.significant, results, self.mapping_scale = rqtl_mapping.run_rqtl_geno(self.vals, self.samples, self.dataset, self.method, self.model, self.permCheck, self.num_perm, perm_strata, self.do_control, self.control_marker, self.manhattan_plot, self.pair_scan, self.covariates) + self.perm_output, self.suggestive, self.significant, results= rqtl_mapping.run_rqtl_geno(self.vals, self.samples, self.dataset, self.mapping_scale, self.method, self.model, self.permCheck, self.num_perm, perm_strata, self.do_control, self.control_marker, self.manhattan_plot, self.pair_scan, self.covariates) else: - results, self.mapping_scale = rqtl_mapping.run_rqtl_geno(self.vals, self.samples, self.dataset, self.method, self.model, self.permCheck, self.num_perm, perm_strata, self.do_control, self.control_marker, self.manhattan_plot, self.pair_scan, self.covariates) + results = rqtl_mapping.run_rqtl_geno(self.vals, self.samples, self.dataset, self.mapping_scale, self.method, self.model, self.permCheck, self.num_perm, perm_strata, self.do_control, self.control_marker, self.manhattan_plot, self.pair_scan, self.covariates) elif self.mapping_method == "reaper": if "startMb" in start_vars: #ZS: Check if first time page loaded, so it can default to ON if "additiveCheck" in start_vars: @@ -429,7 +431,7 @@ class RunMapping(object): with Bench("Trimming Markers for Table"): self.trimmed_markers = trim_markers_for_table(results) - chr_lengths = get_chr_lengths(self.mapping_scale, self.dataset, self.qtl_results) + chr_lengths = get_chr_lengths(self.mapping_scale, self.mapping_method, self.dataset, self.qtl_results) #ZS: For zooming into genome browser, need to pass chromosome name instead of number if self.dataset.group.species == "mouse": @@ -643,7 +645,7 @@ def geno_db_exists(this_dataset): except: return "False" -def get_chr_lengths(mapping_scale, dataset, qtl_results): +def get_chr_lengths(mapping_scale, mapping_method, dataset, qtl_results): chr_lengths = [] if mapping_scale == "physic": for i, the_chr in enumerate(dataset.species.chromosomes.chromosomes): @@ -666,8 +668,12 @@ def get_chr_lengths(mapping_scale, dataset, qtl_results): this_chr = chr_as_num highest_pos = 0 else: - if float(result['Mb']) > highest_pos: - highest_pos = float(result['Mb']) + if mapping_method == "reaper": + if float(result['cM']) > highest_pos: + highest_pos = float(result['cM']) + else: + if float(result['Mb']) > highest_pos: + highest_pos = float(result['Mb']) return chr_lengths diff --git a/wqflask/wqflask/show_trait/export_trait_data.py b/wqflask/wqflask/show_trait/export_trait_data.py index 7ca4a4c0..107f87c6 100644 --- a/wqflask/wqflask/show_trait/export_trait_data.py +++ b/wqflask/wqflask/show_trait/export_trait_data.py @@ -4,11 +4,17 @@ import simplejson as json from pprint import pformat as pf +from base.trait import GeneralTrait +from base import data_set + def export_sample_table(targs): sample_data = json.loads(targs['export_data']) trait_name = targs['trait_display_name'] - final_sample_data = [] + + meta_data = get_export_metadata(targs['trait_id'], targs['dataset']) + + final_sample_data = meta_data for sample_group in ['primary_samples', 'other_samples']: for row in sample_data[sample_group]: @@ -18,6 +24,28 @@ def export_sample_table(targs): return trait_name, final_sample_data +def get_export_metadata(trait_id, dataset_name): + dataset = data_set.create_dataset(dataset_name) + this_trait = GeneralTrait(dataset=dataset, + name=trait_id, + cellid=None, + get_qtl_info=False) + + metadata = [] + if dataset.type == "Publish": + metadata.append(["Phenotype ID: " + trait_id]) + metadata.append(["Phenotype URL: " + "http://genenetwork.org/show_trait?trait_id=" + trait_id + "&dataset=" + dataset_name]) + metadata.append(["Group: " + dataset.group.name]) + metadata.append(["Phenotype: " + this_trait.description_display.replace(",", "\",\"")]) + metadata.append(["Authors: " + this_trait.authors]) + metadata.append(["Title: " + this_trait.title]) + metadata.append(["Journal: " + this_trait.journal]) + metadata.append(["Dataset Link: http://gn1.genenetwork.org/webqtl/main.py?FormID=sharinginfo&InfoPageName=" + dataset.name]) + metadata.append([]) + + return metadata + + def dict_to_sorted_list(dictionary): sorted_list = [item for item in dictionary.iteritems()] sorted_list = sorted(sorted_list, cmp=cmp_samples) diff --git a/wqflask/wqflask/show_trait/show_trait.py b/wqflask/wqflask/show_trait/show_trait.py index 8883e627..072d7f8c 100644 --- a/wqflask/wqflask/show_trait/show_trait.py +++ b/wqflask/wqflask/show_trait/show_trait.py @@ -22,6 +22,7 @@ from base import webqtlConfig from base import webqtlCaseData from wqflask.show_trait.SampleList import SampleList from utility import webqtlUtil, Plot, Bunch, helper_functions +from utility.tools import locate_ignore_error from base.trait import GeneralTrait from base import data_set from db import webqtlDatabaseFunction @@ -72,16 +73,16 @@ class ShowTrait(object): #ZS: Get verify/rna-seq link URLs try: - blatsequence = self.this_trait.blatseq + blatsequence = self.this_trait.sequence if not blatsequence: #XZ, 06/03/2009: ProbeSet name is not unique among platforms. We should use ProbeSet Id instead. query1 = """SELECT Probe.Sequence, Probe.Name - FROM Probe, ProbeSet, ProbeSetFreeze, ProbeSetXRef - WHERE ProbeSetXRef.ProbeSetFreezeId = ProbeSetFreeze.Id AND - ProbeSetXRef.ProbeSetId = ProbeSet.Id AND - ProbeSetFreeze.Name = '%s' AND - ProbeSet.Name = '%s' AND - Probe.ProbeSetId = ProbeSet.Id order by Probe.SerialOrder""" % (self.this_trait.dataset.name, self.this_trait.name) + FROM Probe, ProbeSet, ProbeSetFreeze, ProbeSetXRef + WHERE ProbeSetXRef.ProbeSetFreezeId = ProbeSetFreeze.Id AND + ProbeSetXRef.ProbeSetId = ProbeSet.Id AND + ProbeSetFreeze.Name = '%s' AND + ProbeSet.Name = '%s' AND + Probe.ProbeSetId = ProbeSet.Id order by Probe.SerialOrder""" % (self.this_trait.dataset.name, self.this_trait.name) seqs = g.db.execute(query1).fetchall() if not seqs: raise ValueError @@ -97,10 +98,10 @@ class ShowTrait(object): query2 = """SELECT Probe.Sequence, Probe.Name FROM Probe, ProbeSet, ProbeSetFreeze, ProbeSetXRef WHERE ProbeSetXRef.ProbeSetFreezeId = ProbeSetFreeze.Id AND - ProbeSetXRef.ProbeSetId = ProbeSet.Id AND - ProbeSetFreeze.Name = '%s' AND - ProbeSet.Name = '%s' AND - Probe.ProbeSetId = ProbeSet.Id order by Probe.SerialOrder""" % (self.this_trait.dataset.name, self.this_trait.name) + ProbeSetXRef.ProbeSetId = ProbeSet.Id AND + ProbeSetFreeze.Name = '%s' AND + ProbeSet.Name = '%s' AND + Probe.ProbeSetId = ProbeSet.Id order by Probe.SerialOrder""" % (self.this_trait.dataset.name, self.this_trait.name) seqs = g.db.execute(query2).fetchall() for seqt in seqs: @@ -120,8 +121,8 @@ class ShowTrait(object): self.UCSC_BLAT_URL = "" self.UTHSC_BLAT_URL = "" except: - self.UCSC_BLAT_URL = "" - self.UTHSC_BLAT_URL = "" + self.UCSC_BLAT_URL = "" + self.UTHSC_BLAT_URL = "" if self.dataset.type == "ProbeSet": self.show_probes = "True" @@ -170,6 +171,14 @@ class ShowTrait(object): self.genofiles = self.dataset.group.get_genofiles() + if "QTLReaper" or "R/qtl" in dataset.group.mapping_names: #ZS: No need to grab scales from .geno file unless it's using a mapping method that reads .geno files + if self.genofiles: + self.scales_in_geno = get_genotype_scales(self.genofiles) + else: + self.scales_in_geno = get_genotype_scales(self.dataset.group.name + ".geno") + else: + self.scales_in_geno = {} + self.has_num_cases = has_num_cases(self.this_trait) self.stats_table_width, self.trait_table_width = get_table_widths(self.sample_groups, self.has_num_cases) @@ -239,9 +248,12 @@ class ShowTrait(object): #hddn['control_marker'] = self.nearest_marker1+","+self.nearest_marker2 hddn['do_control'] = False hddn['maf'] = 0.05 + hddn['mapping_scale'] = "physic" hddn['compare_traits'] = [] hddn['export_data'] = "" hddn['export_format'] = "excel" + if len(self.scales_in_geno) < 2: + hddn['mapping_scale'] = self.scales_in_geno[self.scales_in_geno.keys()[0]][0] # We'll need access to this_trait and hddn in the Jinja2 Template, so we put it inside self self.hddn = hddn @@ -251,6 +263,7 @@ class ShowTrait(object): short_description = short_description, unit_type = trait_units, dataset_type = self.dataset.type, + scales_in_geno = self.scales_in_geno, data_scale = self.dataset.data_scale, sample_group_types = self.sample_group_types, sample_lists = sample_lists, @@ -597,4 +610,77 @@ def get_categorical_variables(this_trait, sample_list): if num_distinct < 10: categorical_var_list.append(sample_list.attributes[attribute].name) - return categorical_var_list
\ No newline at end of file + return categorical_var_list + +def get_genotype_scales(genofiles): + geno_scales = {} + if type(genofiles) is list: + for the_file in genofiles: + file_location = the_file['location'] + geno_scales[file_location] = get_scales_from_genofile(file_location) + else: + geno_scales[genofiles] = get_scales_from_genofile(genofiles) + + return geno_scales + +def get_scales_from_genofile(file_location): + geno_path = locate_ignore_error(file_location, 'genotype') + + if not geno_path: #ZS: This is just to allow the code to run when + return [["physic", "Mb"]] + cm_and_mb_cols_exist = True + cm_column = None + mb_column = None + with open(geno_path, "r") as geno_fh: + for i, line in enumerate(geno_fh): + if line[0] == "#" or line[0] == "@": + if "@scale" in line: #ZS: If the scale is made explicit in the metadata, use that + scale = line.split(":")[1].strip() + if scale == "morgan": + return [["morgan", "cM"]] + else: + return [["physic", "Mb"]] + else: + continue + if line[:3] == "Chr": + first_marker_line = i + 1 + if line.split("\t")[2].strip() == "cM": + cm_column = 2 + elif line.split("\t")[3].strip() == "cM": + cm_column = 3 + if line.split("\t")[2].strip() == "Mb": + mb_column = 2 + elif line.split("\t")[3].strip() == "Mb": + mb_column = 3 + break + + #ZS: This attempts to check whether the cM and Mb columns are 'real', since some .geno files have one column be a copy of the other column, or have one column that is all 0s + cm_all_zero = True + mb_all_zero = True + cm_mb_all_equal = True + for i, line in enumerate(geno_fh): + if first_marker_line <= i < first_marker_line + 10: #ZS: I'm assuming there won't be more than 10 markers where the position is listed as 0 + if cm_column: + cm_val = line.split("\t")[cm_column].strip() + if cm_val != "0": + cm_all_zero = False + if mb_column: + mb_val = line.split("\t")[mb_column].strip() + if mb_val != "0": + mb_all_zero = False + if cm_column and mb_column: + if cm_val != mb_val: + cm_mb_all_equal = False + else: + if i > first_marker_line + 10: + break + + #ZS: This assumes that both won't be all zero, since if that's the case mapping shouldn't be an option to begin with + if mb_all_zero: + return [["morgan", "cM"]] + elif cm_mb_all_equal: + return [["physic", "Mb"]] + elif cm_and_mb_cols_exist: + return [["physic", "Mb"], ["morgan", "cM"]] + else: + return [["physic", "Mb"]] diff --git a/wqflask/wqflask/static/new/javascript/show_trait.js b/wqflask/wqflask/static/new/javascript/show_trait.js index d94a2347..785e5332 100644 --- a/wqflask/wqflask/static/new/javascript/show_trait.js +++ b/wqflask/wqflask/static/new/javascript/show_trait.js @@ -518,7 +518,7 @@ submit_special = function(url) { return $("#trait_data_form").submit(); }; -var corr_input_list = ['corr_type', 'trait_id', 'dataset', 'group', 'tool_used', 'form_url', 'corr_sample_method', 'corr_samples_group', 'corr_dataset', 'min_expr', +var corr_input_list = ['corr_type', 'primary_samples', 'trait_id', 'dataset', 'group', 'tool_used', 'form_url', 'corr_sample_method', 'corr_samples_group', 'corr_dataset', 'min_expr', 'corr_return_results', 'loc_chr', 'min_loc_mb', 'max_loc_mb', 'p_range_lower', 'p_range_upper'] $(".corr_compute").on("click", (function(_this) { diff --git a/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js b/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js index 478ed87e..7176a0da 100644 --- a/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js +++ b/wqflask/wqflask/static/new/javascript/show_trait_mapping_tools.js @@ -165,6 +165,7 @@ url = "/loading"; $('input[name=method]').val("rqtl_geno"); $('input[name=selected_chr]').val($('#chr_rqtl_geno').val()); + $('input[name=mapping_scale]').val($('#scale_rqtl_geno').val()); $('input[name=genofile]').val($('#genofile_rqtl_geno').val()); $('input[name=num_perm]').val($('input[name=num_perm_rqtl_geno]').val()); $('input[name=categorical_vars]').val(js_data.categorical_vars) @@ -210,6 +211,7 @@ url = "/loading"; $('input[name=method]').val("reaper"); $('input[name=selected_chr]').val($('#chr_reaper').val()); + $('input[name=mapping_scale]').val($('#scale_reaper').val()); $('input[name=genofile]').val($('#genofile_reaper').val()); $('input[name=num_perm]').val($('input[name=num_perm_reaper]').val()); $('input[name=control_marker]').val($('input[name=control_reaper]').val()); @@ -289,4 +291,21 @@ return toggle_enable_disable("#suggestive_lrs"); }); + $('#genofile_rqtl_geno').change(function() { + geno_location = $(this).children("option:selected").val().split(":")[0] + $('#scale_rqtl_geno').empty() + the_scales = js_data.scales_in_geno[geno_location] + for (var i = 0; i < the_scales.length; i++){ + $('#scale_rqtl_geno').append($("<option></option>").attr("value", the_scales[i][0]).text(the_scales[i][1])); + } + }); + $('#genofile_reaper').change(function() { + geno_location = $(this).children("option:selected").val().split(":")[0] + $('#scale_reaper').empty() + the_scales = js_data.scales_in_geno[geno_location] + for (var i = 0; i < the_scales.length; i++){ + $('#scale_reaper').append($("<option></option>").attr("value", the_scales[i][0]).text(the_scales[i][1])); + } + }); + }).call(this); diff --git a/wqflask/wqflask/templates/admin/group_manager.html b/wqflask/wqflask/templates/admin/group_manager.html index 1c536cb2..ac5c1350 100644 --- a/wqflask/wqflask/templates/admin/group_manager.html +++ b/wqflask/wqflask/templates/admin/group_manager.html @@ -6,40 +6,71 @@ <div class="container"> <div class="page-header"> - + <h1>Manage Groups</h1> </div> - <form> - <div class="control-group"> - <b>Group Name: </b> - <div class="input-append"> - <input type="text" name="group_name"> - <button type="submit" class="btn btn-primary">Save</button> - </div> + <form action="/manage/groups" method="POST"> + <div class="container" style="margin-bottom: 30px;"> + <div><h3>Admin Groups</h3></div> + <hr> + <table id="admin_groups" class="table table-hover"> + <thead> + <tr> + <th></th> + <th>Index</th> + <th>Name</th> + <th># Members</th> + <th>Created</th> + <th>Last Changed</th> + </tr> + </thead> + <tbody> + {% for group in admin_groups %} + <tr> + <td><input type="checkbox" name="read" value="{{ group.id }}"></td> + <td>{{ loop.index }}</td> + <td>{{ group.name }}</td> + <td>{{ group.admins|length + group.users|length }}</td> + <td>{{ group.created_timestamp }}</td> + <td>{{ group.changed_timestamp }}</td> + </tr> + {% endfor %} + </tbody> + </table> + </div> + <hr> + <div class="container"> + <div><h3>User Groups</h3></div> + <hr> + <table id="user_groups" class="table table-hover"> + <thead> + <tr> + <th></th> + <th>Index</th> + <th>Name</th> + <th># Members</th> + <th>Created</th> + <th>Last Changed</th> + </tr> + </thead> + <tbody> + {% for group in user_groups %} + <tr> + <td><input type="checkbox" name="read" value="{{ group.id }}"></td> + <td>{{ loop.index }}</td> + <td>{{ group.name }}</td> + <td>{{ group.admins|length + group.users|length }}</td> + <td>{{ group.created_timestamp }}</td> + <td>{{ group.changed_timestamp }}</td> + </tr> + {% endfor %} + </tbody> + </table> </div> - - <table id="dataset_list" class="table table-hover"> - <thead> - <tr> - <th>Read</th> - <th>Type</th> - <th>ID</th> - <th>Name</th> - <th>Full Name</th> - </tr> - </thead> - {% for dataset in datasets %} - <tr> - <td><input type="checkbox" name="read" value="{{ dataset.type }}:{{ dataset.name }}"></td> - <td>{{ dataset.type }}</td> - <td>{{ dataset.id }}</td> - <td>{{ dataset.name }}</td> - <td>{{ dataset.fullname }}</td> - </tr> - {% endfor %} - </table> </form> </div> + + <!-- End of body --> {% endblock %} @@ -47,33 +78,41 @@ {% block js %} <script language="javascript" type="text/javascript" src="/static/new/packages/DataTables/js/jquery.js"></script> <script language="javascript" type="text/javascript" src="{{ url_for('js', filename='DataTables/js/jquery.dataTables.min.js') }}"></script> - <script language="javascript" type="text/javascript" src="/static/packages/DT_bootstrap/DT_bootstrap.js"></script> + <script language="javascript" type="text/javascript" src="/static/packages/TableTools/media/js/TableTools.min.js"></script> <script language="javascript" type="text/javascript" src="/static/packages/underscore/underscore-min.js"></script> <script type="text/javascript" charset="utf-8"> $(document).ready( function () { - console.time("Creating table"); - $('#dataset_list').dataTable( { - "sDom": "Tftipr", - "oTableTools": { - "aButtons": [ - "copy", - "print", - { - "sExtends": "collection", - "sButtonText": 'Save <span class="caret" />', - "aButtons": [ "csv", "xls", "pdf" ] - } - ], - "sSwfPath": "/static/packages/TableTools/media/swf/copy_csv_xls_pdf.swf" + $('#admin_groups, #user_groups').dataTable( { + "drawCallback": function( settings ) { + $('#admin_groups tr').click(function(event) { + if (event.target.type !== 'checkbox') { + $(':checkbox', this).trigger('click'); + } + }); }, - "iDisplayLength": 50, - "bLengthChange": true, + "columns": [ + { "type": "natural" }, + { "type": "natural" }, + { "type": "natural" }, + { "type": "natural" }, + { "type": "natural" }, + { "type": "natural" } + ], + "columnDefs": [ { + "targets": 0, + "orderable": false + } ], + "order": [[1, "asc" ]], + "sDom": "Ztr", + "iDisplayLength": -1, + "autoWidth": true, "bDeferRender": true, - "bSortClasses": false + "bSortClasses": false, + "paging": false, + "orderClasses": true } ); - console.timeEnd("Creating table"); }); </script> {% endblock %} diff --git a/wqflask/wqflask/templates/collections/view.html b/wqflask/wqflask/templates/collections/view.html index 34734a01..60a1a081 100644 --- a/wqflask/wqflask/templates/collections/view.html +++ b/wqflask/wqflask/templates/collections/view.html @@ -8,7 +8,7 @@ {% block content %} <!-- Start of body --> - <div class="container" style="min-width: 1250px;"> + <div class="container" style="min-width: 2050px;"> <h1> <span id="collection_name">{{ uc.name }}</span> <input type="text" name="new_collection_name" style="font-size: 20px; display: none; width: 500px;" class="form-control" placeholder="{{ uc.name }}"> @@ -122,9 +122,9 @@ </a> </TD> {% if this_trait.symbol %} - <TD data-export="{{ this_trait.symbol }}">{{ this_trait.symbol }}</TD> + <TD title="{{ this_trait.symbol }}" data-export="{{ this_trait.symbol }}">{% if this_trait.symbol|length > 20 %}{{ this_trait.symbol[:20] }}...{% else %}{{ this_trait.symbol }}{% endif %}</TD> {% elif this_trait.abbreviation %} - <TD data-export="{{ this_trait.abbreviation }}">{{ this_trait.abbreviation }}</TD> + <TD title="{{ this_trait.abbreviation }}" data-export="{{ this_trait.abbreviation }}">{% if this_trait.abbreviation|length > 20 %}{{ this_trait.abbreviation[:20] }}...{% else %}{{ this_trait.abbreviation }}{% endif %}</TD> {% else %} <TD data-export="N/A">N/A</TD> {% endif %} @@ -190,7 +190,7 @@ { "type": "natural", "width": 50 }, { "type": "natural" }, { "type": "natural", "width": 120 }, - { "type": "natural", "width": 120 }, + { "type": "natural" }, { "type": "natural" }, { "type": "natural", "width": 130 }, { "type": "natural", "width": 35 }, diff --git a/wqflask/wqflask/templates/correlation_page.html b/wqflask/wqflask/templates/correlation_page.html index b696a3fa..23136257 100644 --- a/wqflask/wqflask/templates/correlation_page.html +++ b/wqflask/wqflask/templates/correlation_page.html @@ -126,7 +126,7 @@ {% for trait in correlation_results %} <tr> <td><INPUT TYPE="checkbox" NAME="searchResult" class="checkbox trait_checkbox" style="padding-right: 0px;" VALUE="{{ data_hmac('{}:{}'.format(trait.name, trait.dataset.name)) }}"></td> - <td data-export="{{ loop.index }}" style="padding-left: 8px; padding-right: 0px; padding-top: 4px; align: center;">{{ loop.index }}</td> + <td data-export="{{ loop.index }}" style="padding-left: 8px; padding-right: 0px; padding-top: 4px; align: right;">{{ loop.index }}</td> <td data-export="{{ trait.name }}"> <a href="{{ url_for('show_trait_page', trait_id = trait.name, @@ -159,6 +159,11 @@ <td data-export="{{ trait.LRS_location_repr }}" align="right">{{ trait.LRS_location_repr }}</td> <td data-export={% if trait.additive != "" %}"{{ '%0.3f' % trait.additive|float }}"{% else %}"N/A"{% endif %} align="right">{% if trait.additive != "" %}{{ '%0.3f' % trait.additive|float }}{% else %}N/A{% endif %}</td> {% elif target_dataset.type == "Publish" %} + {% if trait.abbreviation %} + <TD title="{{ trait.abbreviation }}" data-export="{{ trait.abbreviation }}">{% if trait.abbreviation|length > 20 %}{{ trait.abbreviation[:20] }}...{% else %}{{ trait.abbreviation }}{% endif %}</TD> + {% else %} + <TD data-export="{{ trait.abbreviation }}">N/A</TD> + {% endif %} <td data-export="{{ trait.description_display }}">{{ trait.description_display }}</td> <td data-export="{{ trait.authors }}">{{ trait.authors }}</td> <td data-export="{{ trait.pubmed_text }}"> @@ -398,6 +403,7 @@ { "type": "natural" }, { "type": "natural" }, { "type": "natural" }, + { "type": "natural" }, { "type": "natural", "width": "20%" }, { "type": "natural", "width": "12%" }, { "orderDataType": "dom-innertext" }, diff --git a/wqflask/wqflask/templates/mapping_results.html b/wqflask/wqflask/templates/mapping_results.html index 8699343f..b4429b46 100644 --- a/wqflask/wqflask/templates/mapping_results.html +++ b/wqflask/wqflask/templates/mapping_results.html @@ -274,7 +274,11 @@ {% endif %} <td align="right">{{marker.chr}}</td> {% if plotScale != "physic" %} + {% if 'cM' in marker %} + <td align="right">{{ '%0.3f' | format(marker.cM|float) }}</td> + {% else %} <td align="right">{{ '%0.3f' | format(marker.Mb|float) }}</td> + {% endif %} {% else %} <td align="right">{{ '%0.6f' | format(marker.Mb|float) }}</td> {% endif %} diff --git a/wqflask/wqflask/templates/show_trait_details.html b/wqflask/wqflask/templates/show_trait_details.html index 20dee54e..62268a54 100644 --- a/wqflask/wqflask/templates/show_trait_details.html +++ b/wqflask/wqflask/templates/show_trait_details.html @@ -212,7 +212,7 @@ <a href="#redirect"> <button type="button" id="add_to_collection" class="btn btn-primary" title="Add to collection">Add</button> </a> - {% if this_trait.dataset.type == 'ProbeSet' %} + {% if this_trait.dataset.type == 'ProbeSet' or this_trait.dataset.type == 'Geno' %} {% if this_trait.symbol != None %} <a target="_blank" href="http://gn1.genenetwork.org/webqtl/main.py?cmd=sch&gene={{ this_trait.symbol }}&alias=1&species={{ dataset.group.species }}"> <button type="button" class="btn btn-default" title="Find similar expression data">Find</button> diff --git a/wqflask/wqflask/templates/show_trait_mapping_tools.html b/wqflask/wqflask/templates/show_trait_mapping_tools.html index 777d4a2d..a2416ced 100755 --- a/wqflask/wqflask/templates/show_trait_mapping_tools.html +++ b/wqflask/wqflask/templates/show_trait_mapping_tools.html @@ -121,6 +121,16 @@ </div> {% if genofiles and genofiles|length>0 %} <div class="mapping_method_fields form-group"> + <label for="scale_select" style="text-align: right;" class="col-xs-3 control-label">Map Scale</label> + <div style="margin-left:20px;" class="col-xs-2 controls"> + <select id="scale_reaper" class="form-control" style="width: 80px;"> + {% for item in scales_in_geno[genofiles[0]['location']] %} + <option value="{{ item[0] }}">{{ item[1] }}</option> + {% endfor %} + </select> + </div> + </div> + <div class="mapping_method_fields form-group"> <label style="text-align: right;" for="genofiles" class="col-xs-3 control-label">Genotypes</label> <div style="margin-left:20px;" class="col-xs-4 controls"> <select id="genofile_reaper" class="form-control"> @@ -225,7 +235,17 @@ </select> </div> </div> - {% if genofiles and genofiles|length>0 %} + {% if genofiles and genofiles|length > 0 %} + <div class="mapping_method_fields form-group"> + <label for="scale_select" style="text-align: right;" class="col-xs-3 control-label">Map Scale</label> + <div style="margin-left:20px;" class="col-xs-2 controls"> + <select id="scale_rqtl_geno" class="form-control" style="width: 80px;"> + {% for item in scales_in_geno[genofiles[0]['location']] %} + <option value="{{ item[0] }}">{{ item[1] }}</option> + {% endfor %} + </select> + </div> + </div> <div class="mapping_method_fields form-group"> <label style="text-align:right;" for="genofiles" class="col-xs-3 control-label">Genotypes</label> <div style="margin-left:20px;" class="col-xs-4 controls"> @@ -379,7 +399,7 @@ <dt style="padding-top: 20px;">GEMMA</dt> <dd>Maps traits with correction for kinship among samples using a linear mixed model method, and also allows users to fit multiple covariates such as sex, age, treatment, and genetic markers (<a href="https://www.ncbi.nlm.nih.gov/pubmed/24531419">PMID: 2453419</a>, and <a href="https://github.com/genetics-statistics/GEMMA"> GitHub code</a>). GEMMA incorporates the Leave One Chromosome Out (LOCO) method to ensure that the correction for kinship does not remove useful genetic variance near each marker. Markers can be filtered to include only those with minor allele frequencies (MAF) above a threshold. The default MAF is 0.05.</dd> {% elif mapping_method == "R/qtl" %} - <dt style="margin-top: 20px;">R/qtl</dt> + <dt style="margin-top: 20px;">R/qtl (version 1.44.9</dt> <dd>The original R/qtl mapping package that supports classic experimental crosses including 4-parent F2 intercrosses (e.g., NIA ITP UM-HET3). R/qtl is ideal for populations that do not have complex kinship or admixture (<a href="https://www.ncbi.nlm.nih.gov/pubmed/12724300">PMID: 12724300</a>). Both R/qtl as implemented here, and R/qtl2 (<a href="https://www.ncbi.nlm.nih.gov/pubmed/30591514">PMID: 30591514</a>) are available as <a href="https://kbroman.org/pages/software.html">R suites</a>.</dd> {% elif mapping_method == "QTLReaper" %} <dt style="margin-top: 20px;">Haley-Knott Regression</dt> diff --git a/wqflask/wqflask/user_manager.py b/wqflask/wqflask/user_manager.py index ce76e0e8..a871e91a 100644 --- a/wqflask/wqflask/user_manager.py +++ b/wqflask/wqflask/user_manager.py @@ -356,7 +356,7 @@ def get_cookie(): g.user_session = UserSession() g.cookie_session = AnonUser() -@app.after_request +#@app.after_request def set_cookie(response): if not request.cookies.get(g.cookie_session.cookie_name): response.set_cookie(g.cookie_session.cookie_name, g.cookie_session.cookie) @@ -538,7 +538,7 @@ def basic_info(): ip_address = request.remote_addr, user_agent = request.headers.get('User-Agent')) -@app.route("/manage/verify_email") +#@app.route("/manage/verify_email") def verify_email(): user = DecodeUser(VerificationEmail.key_prefix).user user.confirmed = json.dumps(basic_info(), sort_keys=True) @@ -552,7 +552,7 @@ def verify_email(): response.set_cookie(UserSession.cookie_name, session_id_signed) return response -@app.route("/n/password_reset", methods=['GET']) +#@app.route("/n/password_reset", methods=['GET']) def password_reset(): """Entry point after user clicks link in E-mail""" logger.debug("in password_reset request.url is:", request.url) @@ -576,7 +576,7 @@ def password_reset(): else: return redirect(url_for("login")) -@app.route("/n/password_reset_step2", methods=('POST',)) +#@app.route("/n/password_reset_step2", methods=('POST',)) def password_reset_step2(): """Handle confirmation E-mail for password reset""" logger.debug("in password_reset request.url is:", request.url) @@ -620,7 +620,7 @@ class DecodeUser(object): logger.debug("data is:", data) return model.User.query.get(data['id']) -@app.route("/n/login", methods=('GET', 'POST')) +#@app.route("/n/login", methods=('GET', 'POST')) def login(): lu = LoginUser() login_type = request.args.get("type") @@ -630,7 +630,7 @@ def login(): else: return lu.standard_login() -@app.route("/n/login/github_oauth2", methods=('GET', 'POST')) +#@app.route("/n/login/github_oauth2", methods=('GET', 'POST')) def github_oauth2(): from utility.tools import GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET code = request.args.get("code") @@ -661,7 +661,7 @@ def github_oauth2(): url = "/n/login?type=github&uid="+user_details["user_id"] return redirect(url) -@app.route("/n/login/orcid_oauth2", methods=('GET', 'POST')) +#@app.route("/n/login/orcid_oauth2", methods=('GET', 'POST')) def orcid_oauth2(): from uuid import uuid4 from utility.tools import ORCID_CLIENT_ID, ORCID_CLIENT_SECRET, ORCID_TOKEN_URL, ORCID_AUTH_URL @@ -841,7 +841,7 @@ class LoginUser(object): db_session.add(login_rec) db_session.commit() -@app.route("/n/logout") +#@app.route("/n/logout") def logout(): logger.debug("Logging out...") UserSession().delete_session() @@ -852,7 +852,7 @@ def logout(): return response -@app.route("/n/forgot_password", methods=['GET']) +#@app.route("/n/forgot_password", methods=['GET']) def forgot_password(): """Entry point for forgotten password""" print("ARGS: ", request.args) @@ -860,7 +860,7 @@ def forgot_password(): print("ERRORS: ", errors) return render_template("new_security/forgot_password.html", errors=errors) -@app.route("/n/forgot_password_submit", methods=('POST',)) +#@app.route("/n/forgot_password_submit", methods=('POST',)) def forgot_password_submit(): """When a forgotten password form is submitted we get here""" params = request.form @@ -945,7 +945,7 @@ def is_redis_available(): # return LoginUser().actual_login(user, assumed_by=assumed_by) -@app.route("/n/register", methods=('GET', 'POST')) +#@app.route("/n/register", methods=('GET', 'POST')) def register(): params = None errors = None diff --git a/wqflask/wqflask/user_session.py b/wqflask/wqflask/user_session.py index 4c2305ba..50419146 100644 --- a/wqflask/wqflask/user_session.py +++ b/wqflask/wqflask/user_session.py @@ -119,10 +119,10 @@ class UserSession(object): @property def user_id(self): """Shortcut to the user_id""" - if 'user_id' in self.record: - return self.record['user_id'] - else: - return '' + if 'user_id' not in self.record: + self.record['user_id'] = str(uuid.uuid4()) + + return self.record['user_id'] @property def redis_user_id(self): @@ -161,7 +161,7 @@ class UserSession(object): """List of user's collections""" #ZS: Get user's collections if they exist - collections = get_user_collections(self.redis_user_id) + collections = get_user_collections(self.user_id) collections = [item for item in collections if item['name'] != "Your Default Collection"] + [item for item in collections if item['name'] == "Your Default Collection"] #ZS: Ensure Default Collection is last in list return collections @@ -277,7 +277,7 @@ class UserSession(object): def update_collections(self, updated_collections): collection_body = json.dumps(updated_collections) - save_collections(self.redis_user_id, collection_body) + save_collections(self.user_id, collection_body) def import_traits_to_user(self, anon_id): collections = get_user_collections(anon_id) diff --git a/wqflask/wqflask/views.py b/wqflask/wqflask/views.py index 44752246..938570f3 100644 --- a/wqflask/wqflask/views.py +++ b/wqflask/wqflask/views.py @@ -40,7 +40,7 @@ from wqflask import update_search_results from wqflask import docs from wqflask import news from wqflask.submit_bnw import get_bnw_input -from base.data_set import DataSet # Used by YAML in marker_regression +from base.data_set import create_dataset, DataSet # Used by YAML in marker_regression from wqflask.show_trait import show_trait from wqflask.show_trait import export_trait_data from wqflask.heatmap import heatmap @@ -593,12 +593,21 @@ def loading_page(): if 'num_vals' in start_vars: num_vals = int(start_vars['num_vals']) else: - if 'primary_samples' in start_vars: - samples = start_vars['primary_samples'].split(",") - for sample in samples: - value = start_vars.get('value:' + sample) - if value != "x": - num_vals += 1 + dataset = create_dataset(start_vars['dataset']) + genofile_samplelist = [] + samples = start_vars['primary_samples'].split(",") + if 'genofile' in start_vars: + if start_vars['genofile'] != "": + genofile_string = start_vars['genofile'] + dataset.group.genofile = genofile_string.split(":")[0] + genofile_samples = run_mapping.get_genofile_samplelist(dataset) + if len(genofile_samples) > 1: + samples = genofile_samples + + for sample in samples: + value = start_vars.get('value:' + sample) + if value != "x": + num_vals += 1 start_vars['num_vals'] = num_vals start_vars['wanted_inputs'] = initial_start_vars['wanted_inputs'] |