import streamlit as st
import pandas as  pd
import numpy as np
from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, roc_curve, precision_recall_curve
import pylab as pl
#from sklearn.metrics import plot_confusion_matrix, plot_roc_Curve, precision_recall_curve
from sklearn.metrics import precision_score, recall_score

def main():
    st.title("Binary Classification Web App")
    st.sidebar.title("Binary Classification Web App")
    st.markdown(" Are your mushrooms edible or poisonous web 🍄 ??")
    st.sidebar.markdown("Are your mushrooms edible or poisonous web 🍄 ??")


    ########
    import numpy as np


    def plot_confusion_matrix(cm,
                            target_names,
                            title='Confusion matrix',
                            cmap=None,
                            normalize=True):

        import matplotlib.pyplot as plt
        import numpy as np
        import itertools

        accuracy = np.trace(cm) / float(np.sum(cm))
        misclass = 1 - accuracy

        if cmap is None:
            cmap = plt.get_cmap('Blues')

        plt.figure(figsize=(8, 6))
        plt.imshow(cm, interpolation='nearest', cmap=cmap)
        plt.title(title)
        plt.colorbar()

        if target_names is not None:
            tick_marks = np.arange(len(target_names))
            plt.xticks(tick_marks, target_names, rotation=45)
            plt.yticks(tick_marks, target_names)

        if normalize:
            cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]


        thresh = cm.max() / 1.5 if normalize else cm.max() / 2
        for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
            if normalize:
                plt.text(j, i, "{:0.4f}".format(cm[i, j]),
                        horizontalalignment="center",
                        color="white" if cm[i, j] > thresh else "black")
            else:
                plt.text(j, i, "{:,}".format(cm[i, j]),
                        horizontalalignment="center",
                        color="white" if cm[i, j] > thresh else "black")


        plt.tight_layout()
        plt.ylabel('True label')
        plt.xlabel('Predicted label\naccuracy={:0.4f}; misclass={:0.4f}'.format(accuracy, misclass))
        plt.show()
    ###

    @st.cache(persist = True) # data is loaded only once in the starting
    def load_data():
        data = pd.read_csv('C:/Users/shrey/Downloads/datasets_478_974_mushrooms.csv')
        label = LabelEncoder()
        for col in data:
            data[col] = label.fit_transform(data[col])
        return data
    
    @st.cache(persist = True)
    def split(df):        
        y = df['class']
        x = df.drop(columns = ['class'])
        x_train, x_test, y_train, y_test = train_test_split(x,y, test_size = 0.3, random_state = 0)
        return x_train, x_test, y_train, y_test

    def plot_metrics(metrics_list):
        if 'Confusion Matrix' in metrics_list:
            st.subheader("Confusion Matrix")
            cm = confusion_matrix(y_test,y_pred)
            # pl.matshow(cm)
            # pl.title('Confusion matrix of the classifier')    
            # pl.colorbar()
            # pl.show()
            plot_confusion_matrix(cm = cm,
                            cmap=None,
                          normalize    = False,
                          target_names = class_names,
                          title='Confusion matrix')
            #plot_confusion_matrix(model, x_test, y_test, display_labels = class_names)
            st.pyplot()

        if 'ROC Curve' in metrics_list:
            st.subheader("ROC Curve")            
            plot_roc_Curve(model, x_test, y_test)
            st.pyplot()

        if 'Precision-Recall Curve' in metrics_list:
            st.subheader("Precision-Recall Curve")
            plot_precision_recall_curve(model, x_test, y_test)
            st.pyplot()
    
    df = load_data()
    x_train, x_test, y_train, y_test = split(df)
    class_names = ['edible', 'poisonous']
    st.sidebar.subheader("Choose Classification" )
    classifier = st.sidebar.selectbox("Classifier", ("Support Vectore Machine(SVM)","Logistic Regression","Random Forest"))

    if classifier == "Support Vectore Machine(SVM)":
        st.sidebar.subheader("Model Hyperparameters")
        C = st.sidebar.number_input("C (Regularization parameter)", 0.01, 10.0, step = 0.01, key = "C")
        kernel = st.sidebar.radio("Kernel",("rbf", "linear"), key = "kernel")
        gamma = st.sidebar.radio("Gamma (Kernel coefficient)", ("scale","auto"), key = "gamma")

        metrics = st.sidebar.multiselect("What metrics to plot??", ('Confusion Matrix',"ROC Curve", "Precision-Recall Curve"))

        if st.sidebar.button("Classify", key= 'classify'):
            st.subheader("Support Vectore Machine(SVM) Results")
            model = SVC(C = C, kernel = kernel, gamma = gamma)
            model.fit(x_train, y_train)
            accuracy = model.score(x_test, y_test)
            y_pred = model.predict(x_test)
            st.write("Accuracy:", accuracy.round(2))
            st.write("Precision:", precision_score(y_test, y_pred, labels = class_names).round(2))
            st.write("Recall:", recall_score(y_test, y_pred, labels = class_names).round(2))
            plot_metrics(metrics)

    if classifier == "Logistic Regression":
        st.sidebar.subheader("Model Hyperparameters")
        C = st.sidebar.number_input("C (Regularization parameter)", 0.01, 10.0, step = 0.01, key = "C_LR")
        max_iter = st.sidebar.slider("Maximum number of iteration?",100,500, key = "max_iter")
        
        metrics = st.sidebar.multiselect("What metrics to plot??", ('Confusion Matrix',"ROC Curve", "Precision-Recall Curve"))

        if st.sidebar.button("Classify", key= 'classify'):
            st.subheader("Logistic Regression Results")
            model = LogisticRegression(C = C,max_iter= max_iter)
            model.fit(x_train, y_train)
            accuracy = model.score(x_test, y_test)
            y_pred = model.predict(x_test)
            st.write("Accuracy:", accuracy.round(2))
            st.write("Precision:", precision_score(y_test, y_pred, labels = class_names).round(2))
            st.write("Recall:", recall_score(y_test, y_pred, labels = class_names).round(2))
            plot_metrics(metrics)

    if classifier == "Random forest":
        st.sidebar.subheader("Model Hyperparameters")
        n_estimator = st.sidebar.number_input("The number of trees in forest?", 100, 5000, step = 10, key = "n_estimator")
        max_depth = st.sidebar.number_input("The maximum depth of trees?", 1 , 20, step = 1, key = 'max_depth')
        bootstrap = st.sidebar.radio("Bootstrap samples when building trees", ('True', 'False'), key = 'bootstrap')

        metrics = st.sidebar.multiselect("What metrics to plot??", ('Confusion Matrix',"ROC Curve", "Precision-Recall Curve"))

        if st.sidebar.button("Classify", key= 'classify'):
            st.subheader("Random Forest Results")
            model = RandomForestClassifier(n_estimator = n_estimator, max_depth = max_depth, bootstrap = bootstrap, n_jobs = -1)
            model.fit(x_train, y_train)
            accuracy = model.score(x_test, y_test)
            y_pred = model.predict(x_test)
            st.write("Accuracy:", accuracy.round(2))
            st.write("Precision:", precision_score(y_test, y_pred, labels = class_names).round(2))
            st.write("Recall:", recall_score(y_test, y_pred, labels = class_names).round(2))
            plot_metrics(metrics)


if __name__ == "__main__":
    main()            
