CoolFace
Apppublic

Arts-of-coding/testazurectrl

sourceHugging Faceupdated 2y agoView on Hugging Face
0likes
dash_plotly_QC_scRNA.py493 linesDownload Raw Back to root
1# Dash app to visualize scRNA-seq data quality control metrics from scanpy objects2# Shoutout to Coding-with-Adam for the initial template of the project: 3# https://github.com/Coding-with-Adam/Dash-by-Plotly/blob/master/Dash%20Components/Graph/dash-graph.py4 5import dash6from dash import dcc, html, Output, Input7import plotly.express as px8import dash_callback_chain9import yaml10import polars as pl11import os12pl.enable_string_cache(False)13 14# Set custom resolution for plots:15config_fig = {16  'toImageButtonOptions': {17    'format': 'svg',18    'filename': 'custom_image',19    'height': 600,20    'width': 700,21    'scale': 1,22  }23}24from adlfs import AzureBlobFileSystem25mountpount=os.environ['AZURE_MOUNT_POINT'],26AZURE_STORAGE_ACCESS_KEY=os.getenv('AZURE_STORAGE_ACCESS_KEY')27AZURE_STORAGE_ACCOUNT=os.getenv('AZURE_STORAGE_ACCOUNT')28 29# Load in config file30config_path = "./data/config.yaml"31 32# Add the read-in data from the yaml file33def read_config(filename):34    with open(filename, 'r') as yaml_file:35        config = yaml.safe_load(yaml_file)36    return config37 38config = read_config(config_path)39path_parquet = config.get("path_parquet")40conditions = config.get("conditions")41col_features = config.get("col_features")42col_counts = config.get("col_counts")43col_mt = config.get("col_mt")44 45filepath = f"az://{path_parquet}"46 47storage_options={'account_name': AZURE_STORAGE_ACCOUNT, 'account_key': AZURE_STORAGE_ACCESS_KEY,'anon': False}48#azfs = AzureBlobFileSystem(**storage_options )49 50df = pl.read_parquet(filepath,storage_options=storage_options)51#abfs = AzureBlobFileSystem(account_name=accountname,account_key=accountkey)52 53#df = df.rename({"__index_level_0__": "Unnamed: 0"})54 55# Setup the app56external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']57app = dash.Dash(__name__, external_stylesheets=external_stylesheets) #, requests_pathname_prefix='/dashboard1/'58 59min_value = df[col_features].min()60max_value = df[col_features].max()61 62min_value_2 = df[col_counts].min()63min_value_2 = round(min_value_2)64max_value_2 = df[col_counts].max()65max_value_2 = round(max_value_2)66 67min_value_3 = df[col_mt].min()68min_value_3 = round(min_value_3, 1)69max_value_3 = df[col_mt].max()70max_value_3 = round(max_value_3, 1)71 72# Loads in the conditions specified in the yaml file73 74# Note: Future version perhaps all values from a column in the dataframe of the parquet file75# Note 2: This could also be a tsv of the categories and own specified colors76 77# Create the first tab content78# Add Sliders for three QC params: N genes by counts, total amount of reads and pct MT reads79 80tab1_content = html.Div([81    dcc.Dropdown(id='dpdn2', value=conditions, multi=True,82                 options=conditions),83    html.Label("N Genes by Counts"),84    dcc.RangeSlider(85        id='range-slider-1',86        step=250,87        value=[min_value, max_value],88        marks={i: str(i) for i in range(min_value, max_value + 1, 250)},89    ),90    dcc.Input(id='min-slider-1', type='number', value=min_value, debounce=True),91    dcc.Input(id='max-slider-1', type='number', value=max_value, debounce=True),92    html.Label("Total Counts"),93    dcc.RangeSlider(94        id='range-slider-2',95        step=7500,96        value=[min_value_2, max_value_2],97        marks={i: str(i) for i in range(min_value_2, max_value_2 + 1, 7500)},98    ),99    dcc.Input(id='min-slider-2', type='number', value=min_value_2, debounce=True),100    dcc.Input(id='max-slider-2', type='number', value=max_value_2, debounce=True),101    html.Label("Percent Mitochondrial Genes"),102    dcc.RangeSlider(103        id='range-slider-3',104        step=5,105        min=0,106        max=100,107        value=[min_value_3, max_value_3],108    ),109    dcc.Input(id='min-slider-3', type='number', value=min_value_3, debounce=True),110    dcc.Input(id='max-slider-3', type='number', value=max_value_3, debounce=True),111    html.Div([112        dcc.Graph(id='pie-graph', figure={}, className='four columns',config=config_fig),113        dcc.Graph(id='my-graph', figure={}, clickData=None, hoverData=None,114                  className='four columns',config=config_fig115                  ),116        dcc.Graph(id='scatter-plot', figure={}, className='four columns',config=config_fig)117    ]),118    html.Div([119        dcc.Graph(id='scatter-plot-2', figure={}, className='four columns',config=config_fig)120    ]),121    html.Div([122        dcc.Graph(id='scatter-plot-3', figure={}, className='four columns',config=config_fig)123    ]),124    html.Div([125        dcc.Graph(id='scatter-plot-4', figure={}, className='four columns',config=config_fig)126    ]),127])128 129# Create the second tab content with scatter-plot-5 and scatter-plot-6130tab2_content = html.Div([131    html.Div([132            html.Label("S-cycle genes"),133            dcc.Dropdown(id='dpdn3', value="Cdc45", multi=False,134                 options=[135    "Cdc45",136    "Uhrf1",137    "Mcm2",138    "Slbp",139    "Mcm5",140    "Pola1",141    "Gmnn",142    "Cdc6",143    "Rrm2",144    "Atad2",145    "Dscc1",146    "Mcm4",147    "Chaf1b",148    "Rfc2",149    "Msh2",150    "Fen1",151    "Hells",152    "Prim1",153    "Tyms",154    "Mcm6",155    "Wdr76",156    "Rad51",157    "Pcna",158    "Ccne2",159    "Casp8ap2",160    "Usp1",161    "Nasp",162    "Rpa2",163    "Ung",164    "Rad51ap1",165    "Blm",166    "Pold3",167    "Rrm1",168    "Cenpu",169    "Gins2",170    "Tipin",171    "Brip1",172    "Dtl",173    "Exo1",174    "Ubr7",175    "Clspn",176    "E2f8",177    "Cdca7"178]),179            html.Label("G2M-cycle genes"),180            dcc.Dropdown(id='dpdn4', value="Top2a", multi=False,181                 options=[182    "Ube2c",183    "Lbr",184    "Ctcf",185    "Cdc20",186    "Cbx5",187    "Kif11",188    "Anp32e",189    "Birc5",190    "Cdk1",191    "Tmpo",192    "Hmmr",193    "Pimreg",194    "Aurkb",195    "Top2a",196    "Gtse1",197    "Rangap1",198    "Cdca3",199    "Ndc80",200    "Kif20b",201    "Cenpf",202    "Nek2",203    "Nuf2",204    "Nusap1",205    "Bub1",206    "Tpx2",207    "Aurka",208    "Ect2",209    "Cks1b",210    "Kif2c",211    "Cdca8",212    "Cenpa",213    "Mki67",214    "Ccnb2",215    "Kif23",216    "Smc4",217    "G2e3",218    "Tubb4b",219    "Anln",220    "Tacc3",221    "Dlgap5",222    "Ckap2",223    "Ncapd2",224    "Ttk",225    "Ckap5",226    "Cdc25c",227    "Hjurp",228    "Cenpe",229    "Ckap2l",230    "Cdca2",231    "Hmgb2",232    "Cks2",233    "Psrc1",234    "Gas2l3"235]),236    ]),237    html.Div([238        dcc.Graph(id='scatter-plot-5', figure={}, className='three columns',config=config_fig)239    ]),240    html.Div([241        dcc.Graph(id='scatter-plot-6', figure={}, className='three columns',config=config_fig)242    ]),243    html.Div([244        dcc.Graph(id='scatter-plot-7', figure={}, className='three columns',config=config_fig)245    ]),246    html.Div([247        dcc.Graph(id='scatter-plot-8', figure={}, className='three columns',config=config_fig)248    ]),249])250 251# Create the second tab content with scatter-plot-5 and scatter-plot-6252tab3_content = html.Div([253    html.Div([254            html.Label("UMAP condition 1"),255            dcc.Dropdown(id='dpdn5', value="batch", multi=False,256                 options=df.columns),257            html.Label("UMAP condition 2"),258            dcc.Dropdown(id='dpdn6', value="n_genes_by_counts", multi=False,259                 options=df.columns),260            html.Label("Multi gene"),261            dcc.Dropdown(id='dpdn7', value=["Cdc45","Mcm2","Mcm5"], multi=True,262                 options=[263    "Cdc45",264    "Uhrf1",265    "Mcm2",266    "Slbp",267    "Mcm5",268    "Pola1",269    "Gmnn",270    "Cdc6",271    "Rrm2",272    "Atad2"]),273    ]),274    html.Div([275        dcc.Graph(id='scatter-plot-9', figure={}, className='four columns',config=config_fig)276    ]),277    html.Div([278        dcc.Graph(id='scatter-plot-10', figure={}, className='four columns',config=config_fig)279    ]),280    html.Div([281        dcc.Graph(id='scatter-plot-11', figure={}, className='four columns',config=config_fig)282    ]),283    html.Div([284            dcc.Graph(id='my-graph2', figure={}, clickData=None, hoverData=None,285                  className='four columns',config=config_fig286                  )287    ]),288    html.Div([289        dcc.Graph(id='scatter-plot-12', figure={}, className='four columns',config=config_fig)290    ]),291])292 293# Define the tabs layout294app.layout = html.Div([295    dcc.Tabs(id='tabs', style= {'width': 400,296        'font-size': '100%',297        'height': 50}, value='tab1',children=[298        dcc.Tab(label='QC', value='tab1', children=tab1_content),299        dcc.Tab(label='Cell cycle', value='tab2', children=tab2_content),300        dcc.Tab(label='Custom', value='tab3', children=tab3_content),301    ]),302])303 304# Define the circular callback305@app.callback(306    Output("min-slider-1", "value"),307    Output("max-slider-1", "value"),308    Output("min-slider-2", "value"),309    Output("max-slider-2", "value"),310    Output("min-slider-3", "value"),311    Output("max-slider-3", "value"),312    Input("min-slider-1", "value"),313    Input("max-slider-1", "value"),314    Input("min-slider-2", "value"),315    Input("max-slider-2", "value"),316    Input("min-slider-3", "value"),317    Input("max-slider-3", "value"),318)319def circular_callback(min_1, max_1, min_2, max_2, min_3, max_3):320    return min_1, max_1, min_2, max_2, min_3, max_3321 322@app.callback(323    Output('range-slider-1', 'value'),324    Output('range-slider-2', 'value'),325    Output('range-slider-3', 'value'),326    Input('min-slider-1', 'value'),327    Input('max-slider-1', 'value'),328    Input('min-slider-2', 'value'),329    Input('max-slider-2', 'value'),330    Input('min-slider-3', 'value'),331    Input('max-slider-3', 'value'),332)333def update_slider_values(min_1, max_1, min_2, max_2, min_3, max_3):334    return [min_1, max_1], [min_2, max_2], [min_3, max_3]335 336@app.callback(337    Output(component_id='my-graph', component_property='figure'),338    Output(component_id='pie-graph', component_property='figure'),339    Output(component_id='scatter-plot', component_property='figure'),340    Output(component_id='scatter-plot-2', component_property='figure'),341    Output(component_id='scatter-plot-3', component_property='figure'),342    Output(component_id='scatter-plot-4', component_property='figure'),  # Add this new scatter plot343    Output(component_id='scatter-plot-5', component_property='figure'),344    Output(component_id='scatter-plot-6', component_property='figure'),345    Output(component_id='scatter-plot-7', component_property='figure'),346    Output(component_id='scatter-plot-8', component_property='figure'),347    Output(component_id='scatter-plot-9', component_property='figure'),348    Output(component_id='scatter-plot-10', component_property='figure'),349    Output(component_id='scatter-plot-11', component_property='figure'),350    Output(component_id='scatter-plot-12', component_property='figure'),351    Output(component_id='my-graph2', component_property='figure'),352    Input(component_id='dpdn2', component_property='value'),353    Input(component_id='dpdn3', component_property='value'),354    Input(component_id='dpdn4', component_property='value'),355    Input(component_id='dpdn5', component_property='value'),356    Input(component_id='dpdn6', component_property='value'),357    Input(component_id='dpdn7', component_property='value'),358    Input(component_id='range-slider-1', component_property='value'),359    Input(component_id='range-slider-2', component_property='value'),360    Input(component_id='range-slider-3', component_property='value')361)362 363def update_graph_and_pie_chart(batch_chosen, s_chosen, g2m_chosen, condition1_chosen, condition2_chosen, condition3_chosen, range_value_1, range_value_2, range_value_3):364    dff = df.filter(365        (pl.col('batch').cast(str).is_in(batch_chosen)) &366        (pl.col(col_features) >= range_value_1[0]) &367        (pl.col(col_features) <= range_value_1[1]) &368        (pl.col(col_counts) >= range_value_2[0]) &369        (pl.col(col_counts) <= range_value_2[1]) &370        (pl.col(col_mt) >= range_value_3[0]) &371        (pl.col(col_mt) <= range_value_3[1])372)373    374    #Drop categories that are not in the filtered data375    dff = dff.with_columns(dff['batch'].cast(pl.Categorical))376 377    # Plot figures378    fig_violin = px.violin(data_frame=dff, x='batch', y=col_features, box=True, points="all",379                            color='batch', hover_name='batch',template="seaborn")380 381    # Cache commonly used subexpressions382    total_count = pl.lit(len(dff))383    category_counts = dff.group_by("batch").agg(pl.col("batch").count().alias("count"))384    category_counts = category_counts.with_columns(((pl.col("count") / total_count * 100).round(decimals=2)).alias("normalized_count"))385 386    # Display the result387    labels = category_counts["batch"].to_list()388    values = category_counts["normalized_count"].to_list()389 390    total_cells = total_count  # Calculate total number of cells391    pie_title = f'Percentage of Total Cells: {total_cells}'  # Include total cells in the title392 393    # Calculate the mean expression394    395    # Melt wide format DataFrame into long format396    # Specify batch column as string type and gene columns as float type397    list_conds = condition3_chosen398    list_conds += ["batch"]399    dff_pre = dff.select(list_conds)400    401    # Melt wide format DataFrame into long format402    dff_long = dff_pre.melt(id_vars="batch", variable_name="Gene", value_name="Mean expression")403 404    # Calculate the mean expression levels for each gene in each region405    expression_means = dff_long.lazy().group_by(["batch", "Gene"]).agg(pl.mean("Mean expression")).collect()406    407    # Calculate the percentage total expressed408    dff_long1 = dff_pre.melt(id_vars="batch", variable_name="Gene")#.group_by(pl.all()).agg(pl.len())409    count = 1410    dff_long2 = dff_long1.with_columns(pl.lit(count).alias("len"))411    dff_long3 = dff_long2.filter(pl.col("value") > 0).group_by(["batch", "Gene"]).agg(pl.sum("len").alias("len"))412    dff_long4 = dff_long2.group_by(["batch", "Gene"]).agg(pl.sum("len").alias("total"))413    dff_5 = dff_long4.join(dff_long3, on=["batch","Gene"], how="outer")414    result = dff_5.select([415        pl.when((pl.col('len').is_not_null()) & (pl.col('total').is_not_null()))416              .then(pl.col('len') / pl.col('total')*100)417              .otherwise(None).alias("%"),418    ])419    result = result.with_columns(pl.col("%").fill_null(100))420    dff_5[["percentage"]] = result[["%"]]421    dff_5 = dff_5.select(pl.col("batch","Gene","percentage"))422 423    # Final part to join the percentage expressed and mean expression levels424    # TO DO425    expression_means = expression_means.join(dff_5, on=["batch","Gene"], how="inner")426    427    #expression_means = expression_means.select(["batch", "Gene", "Expression"] + condition3_chosen)428    429    fig_pie = px.pie(names=labels, values=values, title=pie_title,template="seaborn")430 431    # Create the scatter plots432    fig_scatter = px.scatter(data_frame=dff, x='X_umap-0', y='X_umap-1', color='batch',433                             labels={'X_umap-0': 'umap1' , 'X_umap-1': 'umap2'},434                             hover_name='batch',template="seaborn")435 436    fig_scatter_2 = px.scatter(data_frame=dff, x='X_umap-0', y='X_umap-1', color=col_mt,437                             labels={'X_umap-0': 'umap1' , 'X_umap-1': 'umap2'},438                             hover_name='batch',template="seaborn")439 440    fig_scatter_3 = px.scatter(data_frame=dff, x='X_umap-0', y='X_umap-1', color=col_features,441                             labels={'X_umap-0': 'umap1' , 'X_umap-1': 'umap2'},442                             hover_name='batch',template="seaborn")443 444 445    fig_scatter_4 = px.scatter(data_frame=dff, x='X_umap-0', y='X_umap-1', color=col_counts,446                             labels={'X_umap-0': 'umap1' , 'X_umap-1': 'umap2'},447                             hover_name='batch',template="seaborn")448    449    fig_scatter_5 = px.scatter(data_frame=dff, x='X_umap-0', y='X_umap-1', color=s_chosen,450                            labels={'X_umap-0': 'umap1' , 'X_umap-1': 'umap2'},451                            hover_name='batch', title="S-cycle gene:",template="seaborn")452 453    fig_scatter_6 = px.scatter(data_frame=dff, x='X_umap-0', y='X_umap-1', color=g2m_chosen,454                            labels={'X_umap-0': 'umap1' , 'X_umap-1': 'umap2'},455                            hover_name='batch', title="G2M-cycle gene:",template="seaborn")456    457    fig_scatter_7 = px.scatter(data_frame=dff, x='X_umap-0', y='X_umap-1', color="S_score",458                            labels={'X_umap-0': 'umap1' , 'X_umap-1': 'umap2'},459                            hover_name='batch', title="S score:",template="seaborn")460    461    fig_scatter_8 = px.scatter(data_frame=dff, x='X_umap-0', y='X_umap-1', color="G2M_score",462                            labels={'X_umap-0': 'umap1' , 'X_umap-1': 'umap2'},463                            hover_name='batch', title="G2M score:",template="seaborn")464    465    fig_scatter_9 = px.scatter(data_frame=dff, x='X_umap-0', y='X_umap-1', color=condition1_chosen,466                            labels={'X_umap-0': 'umap1' , 'X_umap-1': 'umap2'},467                            hover_name='batch',template="seaborn")468    469    fig_scatter_10 = px.scatter(data_frame=dff, x='X_umap-0', y='X_umap-1', color=condition2_chosen,470                            labels={'X_umap-0': 'umap1' , 'X_umap-1': 'umap2'},471                            hover_name='batch',template="seaborn")472    473    fig_scatter_11 = px.scatter(data_frame=dff, x=condition1_chosen, y=condition2_chosen, color='batch',474                            #labels={'X_umap-0': 'umap1' , 'X_umap-1': 'umap2'},475                            hover_name='batch',template="seaborn")476    477    fig_scatter_12 = px.scatter(data_frame=expression_means, x="Gene", y="batch", color="Mean expression",478                                size="percentage", size_max = 20,479                            #labels={'X_umap-0': 'umap1' , 'X_umap-1': 'umap2'},480                            hover_name='batch',template="seaborn")481    482    fig_violin2 = px.violin(data_frame=dff, x=condition1_chosen, y=condition2_chosen, box=True, points="all",483                            color=condition1_chosen, hover_name=condition1_chosen,template="seaborn")484 485 486    return fig_violin, fig_pie, fig_scatter, fig_scatter_2, fig_scatter_3, fig_scatter_4, fig_scatter_5, fig_scatter_6, fig_scatter_7, fig_scatter_8, fig_scatter_9, fig_scatter_10, fig_scatter_11, fig_scatter_12, fig_violin2487 488# Set http://localhost:5000/ in web browser489# Now create your regular FASTAPI application490 491if __name__ == '__main__':492    app.run_server(debug=False, use_reloader=False, host='0.0.0.0', port=5000) #493