def _drug_combination_heatmap(request, dataset, drug_id, cell_line_id, template): if not all(isinstance(d, collections.Sequence) for d in drug_id): return HttpResponse( 'Please select either one or more individual drugs, or a ' 'single drug combination', status=400) if len(drug_id) != 1: return HttpResponse( 'Please select only one drug combination ' 'at a time', status=400) if len(cell_line_id) != 1: return HttpResponse( 'Please select a single cell line for drug ' 'combination plots', status=400) color_by = request.GET.get('colorBy', 'off') if color_by != 'off': return HttpResponse( 'Color overlay must be set to default for drug ' 'combination heat plots', status=400) response_metric = request.GET.get('drMetric', 'dip') if response_metric != 'dip': return HttpResponse( 'Viability drug combination plots are not ' 'supported', status=400) dip_absolute = request.GET.get('drcType', 'rel') == 'abs' if dip_absolute: return HttpResponse( 'Must use relative DIP rate for drug combination ' 'heat plots', status=400) try: ctrl_resp_data, expt_resp_data = df_dip_rates( dataset_id=dataset.id, drug_id=drug_id, cell_line_id=cell_line_id, use_dataset_names=True) except NoDataException: return HttpResponse( 'No data found for this request. This ' 'drug/cell line/assay combination may not exist.', status=400) return plot_drug_combination_heatmap(ctrl_resp_data, expt_resp_data, template=template)
def _generate_dip_rates(dataset, regenerate_cache=False): file_name = 'dip_rates_{}.h5'.format(dataset.id) file_type = 'dip_rates' file_type_protocol = 1 mod_date = timezone.now() file = _cached_file(dataset, file_type, file_type_protocol) if file and not regenerate_cache: full_path = file.file.name else: ctrl, expt = df_dip_rates(dataset, cell_line_id=None, drug_id=None) expt = expt.reset_index() n_drugs = expt['drug'].apply(len).max() expt = _unstack_doses(expt).reset_index() wells = Well.objects.filter( plate__dataset_id=dataset.id).select_related('plate') if ctrl is None: df_data = expt else: ctrl = ctrl.reset_index() df_data = pd.concat([ctrl, expt], ignore_index=True, sort=False) df_data.drop(columns=['plate', 'dataset'], inplace=True) well_df = pd.DataFrame( { 'well_id': well.id, 'plate': well.plate.name, 'well_num': well.well_num, 'well': well.plate.well_id_to_name(well.well_num) } for well in wells) df_data = df_data.merge(well_df, on='well_id') df_data.rename( columns={f'dose{n+1}': f'drug{n+1}.conc' for n in range(n_drugs)}, inplace=True) df_data.rename(columns={'cell_line': 'cell.line'}, inplace=True) df_data.sort_values(['plate', 'well_num'], inplace=True) columns = ['plate', 'well', 'cell.line'] + \ [f'drug{n+1}' for n in range(n_drugs)] + \ [f'drug{n+1}.conc' for n in range(n_drugs)] + \ ['dip_rate', 'dip_fit_std_err'] df_data = df_data[columns] full_path = os.path.join(settings.DOWNLOADS_ROOT, file_name) df_data.to_csv(full_path, sep='\t', index=False) df, created = HTSDatasetFile.objects.get_or_create( dataset=dataset, file_type=file_type, defaults={ 'file_type_protocol': file_type_protocol, 'file': full_path }) if not created: df.file_type_protocol = file_type_protocol df.file = full_path df.creation_date = mod_date df.save() return full_path
def _dose_response_plot(request, dataset, dataset2_id, permission_required, drug_id, cell_line_id, plot_type, template=default_plotly_template): if dataset2_id is not None: try: dataset2 = HTSDataset.objects.get(pk=dataset2_id) except HTSDataset.DoesNotExist: raise Http404() _assert_has_perm(request, dataset2, permission_required) if dataset.name == dataset2.name: return HttpResponse( 'Cannot compare two datasets with the same ' 'name. Please rename one of the datasets.', status=400) datasets = dataset if not dataset2_id else [dataset, dataset2] color_by = request.GET.get('colorBy', 'off') if color_by == 'off': color_by = None drug_tag_ids = [int(dt) for dt in request.GET.getlist('dT')] color_groups = None aggregate_drugs = request.GET.get('aggregateDrugs', False) == "true" if not drug_id and drug_tag_ids: drug_id, drug_groups = _process_aggreate( request, 'drugs', drug_tag_ids, aggregate_drugs or color_by == 'dr', datasets) if aggregate_drugs: aggregate_drugs = drug_groups if color_by == 'dr': color_groups = drug_groups cell_line_tag_ids = [int(ct) for ct in request.GET.getlist('cT')] aggregate_cell_lines = request.GET.get('aggregateCellLines', False) \ == "true" if not cell_line_id and cell_line_tag_ids: cell_line_id, cell_line_groups = _process_aggreate( request, 'cell_lines', cell_line_tag_ids, aggregate_cell_lines or color_by == 'cl', datasets) if aggregate_cell_lines: aggregate_cell_lines = cell_line_groups if color_by == 'cl': color_groups = cell_line_groups if color_groups: color_groups = _make_tags_unique(color_groups) elif color_by == 'cl': # The tags will just be the cell lines themselves color_groups = { cl.name: [cl.name] for cl in CellLine.objects.filter( id__in=cell_line_id).order_by('name') } elif color_by == 'dr': # Ditto for drugs color_groups = { dr.name: [dr.name] for dr in Drug.objects.filter(id__in=drug_id).order_by('name') } if color_groups and len(color_groups) > MAX_COLOR_GROUPS: return HttpResponse( 'Cannot plot using more than {} unique colors. Please remove ' 'some entries or turn off coloring to proceed.'.format( MAX_COLOR_GROUPS), status=400) if not cell_line_id: return HttpResponse('Please enter at least one cell line', status=400) if not drug_id: return HttpResponse('Please enter at least one drug', status=400) response_metric = request.GET.get('drMetric', 'dip') if response_metric not in ('dip', 'viability', 'compare'): return HttpResponse( 'Unknown metric. Supported values: dip, ' 'viability, compare.', status=400) def _setup_dr_par(name, needs_toggle=False): if needs_toggle and \ request.GET.get(name + 'Toggle', 'off') != 'on': return None par_name = request.GET.get(name, None) if par_name is not None and '_custom' in par_name: rep_value = request.GET.get(name + 'Custom', None) if int(rep_value) < 0: raise ValueError() par_name = par_name.replace('_custom', rep_value) return par_name try: dr_par = _setup_dr_par('drPar') except ValueError: return HttpResponse( 'Parameter custom value ' 'needs to be a positive integer', status=400) try: dr_par_two = _setup_dr_par('drParTwo', needs_toggle=True) except ValueError: return HttpResponse( 'Parameter two custom value ' 'needs to be a positive integer', status=400) try: dr_par_order = _setup_dr_par('drParOrder', needs_toggle=True) except ValueError: return HttpResponse( 'Parameter order custom value ' 'needs to be a positive integer', status=400) # 'compare' plots are only available for one dataset and metric if response_metric == 'compare': if dataset2_id is not None: return HttpResponse( '"compare" mode not compatible with two ' 'datasets', status=400) if dr_par_two is not None: return HttpResponse( 'Parameter two not available with "compare" ' 'mode', status=400) if dr_par_order is not None: return HttpResponse( 'Parameter order not available with "compare" ' 'mode', status=400) if plot_type == 'drc': return HttpResponse( 'Dose response curves not available with ' '"compare" mode', status=400) if dr_par.endswith('_rel'): return HttpResponse( 'Relative metrics are not available with ' '"compare" mode', status=400) # Work out any non-standard parameters we need to calculate # e.g. non-standard IC concentrations ic_concentrations = set() ec_concentrations = set() e_values = set() e_rel_values = set() regexes = { IC_REGEX: ic_concentrations, EC_REGEX: ec_concentrations, E_REGEX: e_values, E_REL_REGEX: e_rel_values } need_aa = False need_hill = False need_emax = False need_einf = False for param_idx, param in enumerate((dr_par, dr_par_two, dr_par_order)): if param is None: continue if param == 'label' and param_idx == 2: continue if param == 'aa_obs': continue if param == 'aa': need_aa = True continue if param == 'hill': need_hill = True continue if param.startswith('emax'): need_emax = True continue if param == 'einf': need_einf = True continue for regex, value_list in regexes.items(): match = regex.match(param) if not match: continue try: value = int(match.groups(0)[0]) if value < 0 or value > 100: raise ValueError() value_list.add(value) break except ValueError: return HttpResponse( 'Invalid custom value - must be ' 'an integer between 1 and 100', status=400) else: return HttpResponse('Unknown parameter: {}'.format(param), status=400) dataset_ids = dataset.id if dataset2_id is None else [ dataset.id, dataset2_id ] # Fit Hill curves and compute parameters if response_metric == 'compare': all_metrics = ('dip', 'viability') else: all_metrics = (response_metric, ) try: base_params = [ df_curve_fits(dataset_ids, metric, drug_id, cell_line_id) for metric in all_metrics ] except NoDataException: return HttpResponse( 'No data found for this request. This drug/cell ' 'line/assay combination may not exist.', status=400) include_response_values = False ctrl_resp_data = None expt_resp_data = None if plot_type == 'drc': single_drug = len( base_params[0].index.get_level_values('drug').unique()) == 1 single_cl = len( base_params[0].index.get_level_values('cell_line').unique()) \ == 1 if single_cl and single_drug: try: if response_metric == 'dip': ctrl_resp_data, expt_resp_data = df_dip_rates( dataset_id=dataset_ids, drug_id=drug_id, cell_line_id=cell_line_id, use_dataset_names=True) else: expt_resp_data, ctrl_resp_data = _get_viability_scores( datasets, drug_id, cell_line_id, viability_time=base_params[0]._viability_time) except NoDataException: return HttpResponse( 'No data found for this request. This drug/' 'cell line/assay combination may not exist.', status=400) include_response_values = True need_emax = True ic_concentrations = {50} ec_concentrations = {50} with warnings.catch_warnings(record=True) as w: fit_params = [ fit_params_from_base( base_param_set, ctrl_resp_data=ctrl_resp_data, expt_resp_data=expt_resp_data, include_response_values=include_response_values, custom_ic_concentrations=ic_concentrations, custom_ec_concentrations=ec_concentrations, custom_e_values=e_values, include_aa=need_aa, include_hill=need_hill, include_emax=need_emax, include_einf=need_einf) for base_param_set in base_params ] # Currently only care about warnings if plotting AA if plot_type == 'drpar' and (dr_par == 'aa' or dr_par_two == 'aa'): w = [i for i in w if issubclass(i.category, AAFitWarning)] if w: return HttpResponse(w[0].message, status=400) if response_metric == 'compare': # Create new dataframe import pandas as pd fit_params = pd.concat([ fit_params[0]['label'], fit_params[0][dr_par], fit_params[1][dr_par] ], join='inner', axis=1) fit_params.columns = [ 'label', 'dip__{}'.format(dr_par), 'viability__{}'.format(dr_par) ] fit_params._viability_time = base_params[1]._viability_time fit_params._drmetric = 'compare' dr_par, dr_par_two = fit_params.columns[1:] else: fit_params = fit_params[0] if plot_type == 'drpar': if dr_par is None: return HttpResponse('Dose response parameter is a required field', status=400) try: plot_fig = plot_drc_params( fit_params, fit_param=dr_par, fit_param_compare=dr_par_two, fit_param_sort=dr_par_order, aggregate_cell_lines=aggregate_cell_lines, aggregate_drugs=aggregate_drugs, color_by=color_by, color_groups=color_groups, multi_dataset=dataset2_id is not None, template=template) except CannotPlotError as e: return HttpResponse(e, status=400) else: dip_absolute = request.GET.get('drcType', 'rel') == 'abs' plot_fig = plot_drc(fit_params, is_absolute=dip_absolute, color_by=color_by, color_groups=color_groups, template=template) return plot_fig