dpraz's picture
Update app.py
c10a2f0
raw
history blame
11.6 kB
import gradio as gr
import pandas as pd
import plotly.express as px
import numpy as np
from numpy.core.multiarray import zeros
import math as M
def upload_file(files):
file_paths = [file.name for file in files]
df = pd.read_excel(file_paths[0])
return file_paths,og_Data.update(value=df, visible=True)
def plot(df, one, two, element, indice, mix_norm):
if mix_norm==True:
df[indice]=0
else:
df[one]=0
df[two]=0
to_drop=[]
for ii in range(2,df.shape[1],2):
to_drop.append(df.columns[ii])
for col in to_drop:
df=df.drop(col, axis=1)
#df.set_index(df.columns[0])
df2=df.transpose()
header=df2.iloc[0]
df2=df2[1:]
for jj in range(0,len(header)):
header[jj]=str(header[jj])
df2.columns=header
df2.reset_index()
#print(df2.index.tolist(), df2.columns.tolist()) #isotopes and samplenames.. exactly right.
plot=px.line(df2, x=df2.index,y=df2.columns, markers=True, title=f"Internal Normalization to <sup>{one}</sup>{element}/<sup>{two}</sup>{element}",
labels={
"index":f'<sup>i</sup>{element}',
"value":f"ε<sup>i</sup>{element}",
f"{df.columns[0]}": " "
})
if mix_norm==True:
plot=px.line(df2, x=df2.index,y=df2.columns, markers=True, title=f"Internal Normalization to <sup>{one}</sup>{element}/<sup>{two}</sup>{element} <br><sup>Index Isotope: <sup>{indice}</sup>{element}</sup>",
labels={
"index":f'<sup>i</sup>{element}',
"value":f"ε<sup>i</sup>{element}",
f"{df.columns[0]}": " "
#f"variable": " ",
#f"{df2.columns}": f"{header}"
})
plot.update_xaxes(tickvals=df2.index)
return gr.update(value=plot, visible=True)
def norm(df, i, j, u, v, m, p, mix_norm):
df1= np.zeros_like(df)
df2=pd.DataFrame(data=df)
normalized= pd.DataFrame(df1)
normalized.columns = df2.columns
normalized[normalized.columns[0]]=df[df.columns[0]]
if mix_norm==False:
m=j
p=v
i_col= df2.columns[((df2.columns.get_loc(int(f'{i}'))+1))] #columns which correspond to errors on m,i,j,p,u and v
j_col= df2.columns[((df2.columns.get_loc(int(f'{j}'))+1))]
u_col= df2.columns[((df2.columns.get_loc(int(f'{u}'))+1))]
v_col= df2.columns[((df2.columns.get_loc(int(f'{v}'))+1))]
m_col= df2.columns[((df2.columns.get_loc(int(f'{m}'))+1))]
p_col= df2.columns[((df2.columns.get_loc(int(f'{p}'))+1))]
if mix_norm==False:
df2[i]=0
df2[j]=0
for err in df2[i_col]:
if err == "":
err=0
for err in df2[j_col]:
if err =="":
err=0
elif mix_norm==True:
df2[m]=0
for err in df2[m_col]:
if err=="":
err=0
for ii in range(1,df2.shape[1],2):
k= df2.columns[ii]
error_k=df2.columns[ii+1]
md=(k-p)/(u-v)
for jj in range(0,df2.shape[0]):
if (df2[k].iloc[jj] == "") or (df2[p].iloc[jj] == "") or (df2[v].iloc[jj] == "") or (df2[u].iloc[jj] == ""): #screens for empty cells..
normalized[k][jj] = ""
else:
df2[k][jj]=float(df2[k][jj]); df2[p][jj]=float(df2[p][jj]); df2[v][jj]=float(df2[v][jj]); df2[u][jj]=float(df2[u][jj]) #indexing...
normalized[k][jj]= df2[k][jj]-df2[p][jj]+((df2[v][jj]-df2[u][jj])*md) #epsilon transformation equation
normalized[k][jj]=round(normalized[k][jj], 3)
if (df2[error_k].iloc[jj]=="") or (df2[p_col].iloc[jj]=="") or (df2[v_col].iloc[jj]=="") or (df2[u_col].iloc[jj]==""):
normalized[error_k][jj] = ""
else:
df2[error_k][jj]=float(df2[error_k][jj]); df2[p_col][jj]=float(df2[p_col][jj]); df2[v_col][jj]=float(df2[v_col][jj]); df2[u_col][jj]=float(df2[u_col][jj]);# indexing..
normalized[error_k][jj]=M.sqrt(((1)**2)*(df2[error_k][jj])**2 + ((-1)**2)*(df2[p_col][jj])**2 + (md**2)*(df2[v_col][jj])**2 + (md**2)*(df2[u_col][jj])**2) #error propagation
normalized[error_k][jj]=round(normalized[error_k][jj], 3)
return gr.update(value=normalized, visible=True), xx.update(visible=True)
def write_xl(norm,u,v, element, mix_norm,p):
if mix_norm==False:
xl=norm.to_excel(f'{u}.{v} {element} Normalization.xlsx')
return f'{u}.{v} {element} Normalization.xlsx'
else:
xl=norm.to_excel(f'{u}.{v} {element} Mixed({p}) Normalization.xlsx')
return f'{u}.{v} {element} Mixed({p}) Normalization.xlsx'
def mix_norm_click(bool):
if bool==True:
val=True
else:
val=False
return gr.update(visible=val), gr.update(visible=val)
def hide_intro(intro):
if intro==1:
return gr.update(value=0), gr.update(value="Example Input Formatting"),gr.update(visible=False)
else:
return gr.update(value=1), gr.update(value="Hide Formatting"),gr.update(visible=True)
def search_sample_names(df):
names=df.iloc[:, 0].tolist()
name_count = {}
updated_names = []
for name in names:
if name in name_count:
name_count[name] += 1
updated_names.append(f"{name}{name_count[name]:02}")
else:
name_count[name] = 0
updated_names.append(name)
df.iloc[:, 0]=updated_names
return gr.update(value=df)
with gr.Blocks() as demo:
format= '<a href="{link}">{text}</a>'
text_with_link=format.format
gr.Markdown(f"""
# Epsilon-value Transformation
{text_with_link(link='http://mailto:dan_razionale@brown.edu?subject=Epsilon-value%20Transformation', text='Dan Razionale')} and Gerrit Budde; Department of Earth, Environmental and Planetary Sciences, Brown University, Providence, RI 02912, USA.""")
gr.Markdown(f"""Last updated May 26<sup>th</sup>, 2023 :: {text_with_link(link='https://huggingface.co/spaces/dpraz/Epsilon_Transformation', text='Link to Repository')}""")
with gr.Row():
with gr.Column(scale=1):
a1=gr.Markdown(f"""
# Introduction:
This script automates the transformation of internally-normalized isotope data, as originally described by {text_with_link(link='http://dx.doi.org/10.1086/182628', text='McCulloch & Wasserburg (1978).')} It allows the re-calculation of ε-values for any element using alternative isotope pairs for the internal normalization. In using this script, you will generate an interactive plot and table with the re-normalized data, both of which are downloadable. Additionally, errors on your original data will propagate to the new data, if included. Note: if errors are not provided for isotopes used in the original internal normalization (m, i, or j), they are assumed to be zero. If any of these isotopes are then used for the new normalization (as p, u, or v), the propagated error will underestimate the total error. Otherwise, if error is omitted for isotope k, p, u or v, no propagated error will be displayed.""")
with gr.Row():
hide=gr.Button(value="Example Input Formatting").style(size="sm", full_width=False)############
with gr.Column(scale=1):
a2=gr.Markdown("""# Calculations:""")
with gr.Row():
eq1=gr.Image("Epsi_tran_calc.png", label="Epsilon Transformation:").style(height=75, width=350)
with gr.Row():
eq2=gr.Image("Error_prop_calculation.png", label="Error Propagation:").style(height=100, width=400)
with gr.Row():
with gr.Column(scale=1):
a3=gr.Markdown("""
# Formatting Guidelines:
To begin, assemble an excel document containing the data you wish to transform and save it in an easily accessible location. The functionality of this application hinges upon proper formatting of the input data – please adhere closely to the format defined in the annotated image. As an example, we provide a molybdenum dataset that is internally normalized to <sup>98</sup>Mo/<sup>96</sup>Mo, to be transformed to a <sup>97</sup>Mo/<sup>95</sup>Mo normalization.""")
with gr.Column(scale=1):
a4=gr.Markdown("k denotes the identity of the isotope of interest; u/v and i/j represent the new and old isotope pair used for internal normalization, respectively; p and m are the new and old index isotopes, respectively, which are the denominators in the isotope ratios. Usually, p=v and m=j, although ‘mixed normalizations’ are permitted by activating the homonymous checkbox, which allows you to manually set these indices. Where these variables are not preceded by an epsilon sign, they simply refer to the mass number of the respective isotopes; where they are preceded by a delta, they refer to the associated absolute error. ")
with gr.Row():
format_img=gr.Image("Formatting.png", show_label=False, visible=False).style(height=400, width=750)
with gr.Row():
intro=gr.Number(value=0, visible=False)
hide.click(fn=hide_intro, inputs=[intro], outputs=[intro,hide,format_img])
with gr.Row():
with gr.Column(scale=1, min_width=100):
Element= gr.Textbox(label="Element", placeholder="Enter element symbol (e.g. Mo)")
with gr.Row():
mix_norm=gr.Checkbox(label="Mixed Normalization")
with gr.Row():
upload_button = gr.UploadButton("Import Data", file_types=[".xlsx"], file_count=1)
with gr.Row():
norm_button=gr.Button("Transform and Plot")
with gr.Column(scale=1, min_width=100):
i= gr.Number(label="Current Isotope Pair for Internal Normalization [i/j]", info="e.g. for 98Mo/96Mo", value=98, precision=0)
j= gr.Number(label="", value=96, precision=0)
m=gr.Number(visible=False, label= "Current Index Isotope [m]", value=96, info= "e.g. for kMo/96Mo", precision=0)
with gr.Column(scale=1, min_width=100):
u=gr.Number(label="Desired Isotope Pair for Internal Normalization [u/v]", info="e.g. for 97Mo/95Mo", value=97, precision=0)
v=gr.Number(label="", precision=0, value=95)
p=gr.Number(visible=False, label= "Desired Index Isotope [p]", value=95, info= "e.g. for kMo/95Mo", precision=0)
mix_norm.change(fn=mix_norm_click, inputs=[mix_norm], outputs=[m, p])
with gr.Row():
file_output = gr.File(visible=False)
with gr.Row():
og_Data = gr.Dataframe(type="pandas", visible=False, label="Original Data", interactive=True) ####
with gr.Row():
with gr.Column():
og_Plot= gr.Plot(label="Original Data", visible=False)
with gr.Column():
norm_Plot= gr.Plot(label="Transformed Data", visible=False)
with gr.Row():
norm_Data=gr.Dataframe(type="pandas", visible=False, label="Transformed data", interactive=False)
with gr.Row():
with gr.Column(scale=3):
gr.Button(visible=False,interactive=False)
with gr.Column(scale=3):
gr.Button(visible=False,interactive=False)
xx=gr.Files(visible=False, file_count="multiple", label="Download .xlsx Files")
with gr.Column(scale=1.1):
upload_button.upload(upload_file, upload_button, outputs=[ file_output,og_Data]).success(fn=search_sample_names, inputs=[og_Data], outputs=[og_Data])
norm_button.click(fn=search_sample_names, inputs=[og_Data],outputs=[og_Data]).success(
fn=norm,inputs=[og_Data, i, j, u, v, m, p, mix_norm],outputs=[norm_Data, xx], scroll_to_output=True).success(fn=plot, inputs=[og_Data, i, j, Element, m, mix_norm], outputs=og_Plot, scroll_to_output=True).success(
fn=plot, inputs=[norm_Data, u, v, Element, p, mix_norm], outputs=norm_Plot).success(fn=write_xl, inputs=[norm_Data, u, v, Element, mix_norm,p], outputs=[xx])
demo.queue(concurrency_count=5).launch(debug=True)