diff --git a/__pycache__/eda_view.cpython-311.pyc b/__pycache__/eda_view.cpython-311.pyc new file mode 100644 index 000000000000..5b5dbf3c9ba1 Binary files /dev/null and b/__pycache__/eda_view.cpython-311.pyc differ diff --git a/__pycache__/prediction_view.cpython-311.pyc b/__pycache__/prediction_view.cpython-311.pyc new file mode 100644 index 000000000000..828d1221ec0a Binary files /dev/null and b/__pycache__/prediction_view.cpython-311.pyc differ diff --git a/eda_view.py b/eda_view.py new file mode 100644 index 000000000000..69ce74af607d --- /dev/null +++ b/eda_view.py @@ -0,0 +1,251 @@ +import altair as alt +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +import streamlit as st +import seaborn as sns +import plotly.express as px +import plotly.graph_objects as go +from plotly.subplots import make_subplots + + + +def run(df): + # LAYOUT DEL DASHBOARD + # Primera fila con una sola columna + row1,row12 = st.columns((2,1), gap='medium') + # Segunda fila con dos columnas + col1, col2 = st.columns(2) + # Tercera fila con dos columnas + col3, col4, col5, col6 = st.columns(4) + # quarta fila con una sola columna + row21 = st.container() + # Quinta fila con una sola columna + row2 = st.container() + + # Añadimos contenido + row1.header('Gestión de incidencias - Overview') + + total_incidencias = df['task_id'].nunique() # Mostrar el número total de incidencias + row12.markdown(f'
Número total de incidencias: {total_incidencias}
', unsafe_allow_html=True) + + # Insertar graficos + variable = col1.selectbox('Seleccione la variable para agrupar:', ['priority', 'has_breached', 'assignment_group', 'company', 'contact_type','impact']) + incidencias_timeline_fig = incidencias_timeline(df, variable) # grafico de barras, analisis temporal + tiempo_trabajado_fig = tiempo_trabajado(df, variable) # priority vs time worked + col1.plotly_chart(incidencias_timeline_fig) + col2.plotly_chart(tiempo_trabajado_fig) + + # Pie charts + pie1 = pie_chart_menos_24h(df) + pie2 = pie_chart_mas_24h(df) + pie3 = pie_chart_reasigned(df) + pie4 = pie_chart_not_reasigned(df) + + col3.plotly_chart(pie1) + col4.plotly_chart(pie2) + col5.plotly_chart(pie3) + col6.plotly_chart(pie4) + + + var_select = col4.selectbox('Seleccione la variable para agrupar:', ['assignment_group', 'company', 'priority']) + contact_type_fig = contact_type(df, var_select) + row21.plotly_chart(contact_type_fig) + + variable_select = row2.selectbox('Seleccione la variable para agrupar:', ['assignment_group', 'company', 'contact_type']) + table = tabla(df, variable_select) + row2.table(table) + + +# FUNCIONES GRAFICOS --------------------------------------------------------------------------------- +def incidencias_timeline(df, variable): + df['end_time'] = pd.to_datetime(df['end_time']) + df.set_index('end_time', inplace=True) + + grouped = df.groupby(variable).resample('M')['task_id'].nunique().reset_index() + + # Crear un gráfico de barras apilado con colores basados en la variable seleccionada + incidencias_timeline_fig = px.bar(grouped, x='end_time', y='task_id', color=variable, title='Número de incidencias por mes', + labels={'task_id':'Número de incidencias'}, height=400) + incidencias_timeline_fig.update_layout(barmode='stack') + incidencias_timeline_fig.update_xaxes(title_text='Mes y año de finalización') + #st.plotly_chart(incidencias_timeline_fig) + return incidencias_timeline_fig + +def tiempo_trabajado(df, variable): + tiempo_trabajado_fig = px.bar(df, y='time_worked', x='priority', color=variable) + tiempo_trabajado_fig.update_layout( + title='Relación entre la prioridad y el tiempo trabajado', + yaxis_title='Tiempo trabajado', + xaxis_title='Prioridad' + ) + #st.plotly_chart(tiempo_trabajado_fig) + return tiempo_trabajado_fig + +def tabla(df, variable_select): + priority_counts = df.groupby([variable_select, 'priority']).size().reset_index(name='counts') + total_counts = df.groupby(variable_select).size() + priority_counts['percentage'] = priority_counts.apply(lambda row: (row['counts'] / total_counts[row[variable_select]]) * 100, axis=1) + priority_counts['percentage'] = priority_counts['percentage'].round(2) + priority_counts['percentage'] = priority_counts['percentage'].astype(str) + '%' + pivot_table = priority_counts.pivot(index=variable_select, columns='priority', values='percentage') + #pivot_columns = pivot_table.columns.tolist() + + print(pivot_table) + column_names = [variable_select, '% de incidencias', 'Media business duration', + '% incumplimiento SLA', 'Critical', 'High', 'Moderate', 'Low','Planning'] #+ pivot_columns + + # column_names = pd.MultiIndex.from_tuples([(None, variable_select), + # (None,'% de incidencias'), + # (None, 'Media business duration'), + # (None, '% infracción SLA'), + # ('Priority', 'Critical'), ('Priority', 'High'), + # ('Priority', 'Moderate'), ('Priority', 'Low'), ('Priority', 'Planning')]) + + + # tabla para representar la info + grouped_table = df.groupby(variable_select).agg({'task_id': lambda x: x.count() / df['task_id'].count() * 100, + 'business_duration': 'mean', + 'has_breached': lambda x: x.sum() / x.count() * 100}) + grouped_table = pd.merge(grouped_table, pivot_table, on=variable_select, how='left') + + # has_brached = yes -> % de incidencias que han incumplido el SLA + grouped_table['task_id'] = grouped_table['task_id'].round(2) + grouped_table['task_id'] = grouped_table['task_id'].astype(str) + '%' + grouped_table['business_duration'] = grouped_table['business_duration'].round(0).astype(int) + grouped_table['has_breached'] = grouped_table['has_breached'].round(2) + grouped_table['has_breached'] = grouped_table['has_breached'].astype(str) + '%' # ponerlo en modo de barra si se puede + + grouped_table = grouped_table.reset_index() + grouped_table.columns = column_names + + grouped_table.set_index(variable_select, inplace=True) + grouped_table['% incumplimiento SLA'] = grouped_table['% incumplimiento SLA'].apply(add_warning_icon) + grouped_table = grouped_table.fillna('0%') # if 'Critical', 'High', 'Moderate', 'Low','Planning' == nana -> 0% + + # apply styles + grouped_table = grouped_table.style.applymap(color_cell_priority).set_properties(**{'text-align': 'center'}).set_table_styles([dict(selector='th', props=[('background', '#54B4CE'), ('color', 'white')])]) + #st.table(grouped_table) + return grouped_table + +def contact_type(df, var_select): + fig3 = px.bar(df, x=var_select, y='task_id', color='contact_type', labels={'task_id':'Número de incidencias'}) + fig3.update_layout( + title= f'{var_select} vs tipo de contacto', + xaxis_title=var_select, + yaxis_title='Número de incidencias' + ) + ax = plt.gca() # get current axes + ax.set_yticklabels([]) + fig3.update_layout(barmode='stack') + #st.plotly_chart(fig3) + return fig3 + +#def pie_charts(df): + selection_variable = st.selectbox('Seleccione la variable para agrupar:', ['reassingment_count_bool','u_24_7']) + contact_types = df['contact_type'].unique() + + fig6 = make_subplots(rows=1, cols=len(contact_types), subplot_titles=contact_types, specs=[[{'type':'domain'}]*len(contact_types)]) + + for i, contact_type in enumerate(contact_types): + data = df[df['contact_type'] == contact_type][selection_variable].value_counts() + fig6.add_trace(go.Pie(labels=data.index, values=data, name=contact_type), 1, i+1) + + fig6.update_layout(height=600, width=900, title_text=f'Tipo de contacto vs {selection_variable}', + legend_title_text=f'{selection_variable}', title_x=0.5, title_y=0.95) + st.plotly_chart(fig6) + +def pie_chart_menos_24h(df): + + df['less_24h'] = df['u_24_7'].apply(lambda x: 1 if x == True else 0) # 1 si ha sido resuelta en menos de 24h + + # guardar en una variable el % de incidencias que han sido resueltas en menos de 24h + porcentaje_less = df['less_24h'].sum() / df['less_24h'].count() * 100 + + df_filtered = df[df['less_24h'] == 1] # solo aquellas incidencias que han sido resueltas en menos de 24h + + # un único pie chart coloreado por tipo de contacto, indicando el % de incidencias que han sido resueltas en menos de 24h + pie = px.pie(df_filtered, names='contact_type', title=f'Incidencias resueltas en menos de 24h - {porcentaje_less:.2f}%', + labels={'contact_type':'Tipo de contacto'}, height=400) + + #st.plotly_chart(pie) + return pie + +def pie_chart_mas_24h(df): + + df['more_24h'] = df['u_24_7'].apply(lambda x: 1 if x == False else 0) # 1 si ha sido resuelta en menos de 24h + + # guardar en una variable el % de incidencias que han sido resueltas en menos de 24h + porcentaje_more = df['more_24h'].sum() / df['less_24h'].count() * 100 + + df_filtered = df[df['more_24h'] == 1] # solo aquellas incidencias que han sido resueltas en menos de 24h + + # un único pie chart coloreado por tipo de contacto, indicando el % de incidencias que han sido resueltas en menos de 24h + pie = px.pie(df_filtered, names='contact_type', title=f'Incidencias resueltas en más de 24h - {porcentaje_more:.2f}%', + labels={'contact_type':'Tipo de contacto'}, height=400) + + return pie + +def pie_chart_reasigned(df): + + + # guardar en una variable el % de incidencias que han sido resueltas en menos de 24h + porcentaje_reasigned = df['reassingment_count_bool'].sum() / df['reassingment_count_bool'].count() * 100 + + df_filtered = df[df['reassingment_count_bool'] == 1] # solo aquellas incidencias que han sido resueltas en menos de 24h + + # un único pie chart coloreado por tipo de contacto, indicando el % de incidencias que han sido resueltas en menos de 24h + pie = px.pie(df_filtered, names='contact_type', title=f'Incidencias reasignadas - {porcentaje_reasigned:.2f}%', + labels={'contact_type':'Tipo de contacto'}, height=400) + + return pie + +def pie_chart_not_reasigned(df): + # cambiar los 1 por 0 y los 0 por 1 + df['reassingment_count_bool'] = df['reassingment_count_bool'].apply(lambda x: 0 if x == 1 else 1) + # guardar en una variable el % de incidencias que han sido resueltas en menos de 24h + porcentaje_not_reasigned = df['reassingment_count_bool'].sum() / df['reassingment_count_bool'].count() * 100 + + df_filtered = df[df['reassingment_count_bool'] == 1] # solo aquellas incidencias que han sido resueltas en menos de 24h + + # un único pie chart coloreado por tipo de contacto, indicando el % de incidencias que han sido resueltas en menos de 24h + pie = px.pie(df_filtered, names='contact_type', title=f'Incidencias no reasignadas - {porcentaje_not_reasigned:.2f}%', + labels={'contact_type':'Tipo de contacto'}, height=400) + + return pie + + + +# FUNCIONES AUXILIARES --------------------------------------------------------------------------------- + +def add_warning_icon(val): + if isinstance(val, str) and val.endswith('%'): + percentage = float(val.rstrip('%')) + if percentage > 10: + return f'{val} ⚠️' + return val + +def color_cell_priority(val): + priority = ['Critical', 'High', 'Moderate', 'Low', 'Planning'] + if isinstance(val, str): + if val in priority: + percentage = float(val.rstrip('%')) + if percentage > 50: + return 'background-color: yellow' + return '' + +def set_page_layout(page_width='70%', page_align='center'): + st.markdown( + f""" + + """, + unsafe_allow_html=True, + ) diff --git a/prediction_view.py b/prediction_view.py new file mode 100644 index 000000000000..cd97ff68d1e1 --- /dev/null +++ b/prediction_view.py @@ -0,0 +1,23 @@ +import altair as alt +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +import streamlit as st + + +def run(): + # boton en el centro para crear una nueva incidencia que abra un formulario con campos basicos + if st.button('Crear una nueva incidencia'): + with st.form(key='my_form'): + st.write('Cree una nueva incidencia:') + + # Aquí puedes agregar los campos que necesites para tu formulario + campo1 = st.text_input(label='Campo 1') + campo2 = st.text_input(label='Campo 2') + campo3 = st.text_input(label='Campo 3') + + # Botón de envío del formulario + submit_button = st.form_submit_button(label='Enviar') + + # botón para cancelr el formulario + cancel_button = st.form_submit_button(label='Cancelar') diff --git a/sentiment-analysis-view.py b/sentiment-analysis-view.py new file mode 100644 index 000000000000..1408133611f6 --- /dev/null +++ b/sentiment-analysis-view.py @@ -0,0 +1,12 @@ +import altair as alt +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +import matplotlib as mpl +mpl.use('TkAgg') +import streamlit as st +import seaborn as sns +import plotly.express as px + + + diff --git a/streamlit_app.py b/streamlit_app.py index 7a0ed1272052..928792878d7b 100644 --- a/streamlit_app.py +++ b/streamlit_app.py @@ -2,39 +2,31 @@ import numpy as np import pandas as pd import streamlit as st - -""" -# Welcome to Streamlit! - -Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:. -If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community -forums](https://discuss.streamlit.io). - -In the meantime, below is an example of what you can do with just a few lines of code: -""" - -num_points = st.slider("Number of points in spiral", 1, 10000, 1100) -num_turns = st.slider("Number of turns in spiral", 1, 300, 31) - -indices = np.linspace(0, 1, num_points) -theta = 2 * np.pi * num_turns * indices -radius = indices - -x = radius * np.cos(theta) -y = radius * np.sin(theta) - -df = pd.DataFrame({ - "x": x, - "y": y, - "idx": indices, - "rand": np.random.randn(num_points), -}) - -st.altair_chart(alt.Chart(df, height=700, width=700) - .mark_point(filled=True) - .encode( - x=alt.X("x", axis=None), - y=alt.Y("y", axis=None), - color=alt.Color("idx", legend=None, scale=alt.Scale()), - size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])), - )) +import eda_view as view1 +import prediction_view as view2 +import streamlit_option_menu +from streamlit_option_menu import option_menu + +st.set_page_config(layout="wide", + initial_sidebar_state="expanded") +alt.themes.enable("dark") + +with st.sidebar: + st.title("Gestión de incidencias") + selected = option_menu( + menu_title = "Menu", + options = ['Overview', 'Nueva incidencia'], + icons = ["house","gear"], + menu_icon = "cast", + default_index = 0, +) + +#df = pd.read_excel('/Users/carlotapersonal/Library/CloudStorage/OneDrive-UFV/CURSO_5/PFG/Code/proyecto-fin-de-grado-2024-2-carlotagomezr/data-analysis/eda/dataset_post_EDA.xlsx') +df = pd.read_excel('/Users/carlotro/Desktop/Escritorio/Personal-Carlota/UFV/PFG/APP-REPO/dataset_post_EDA.xlsx') +df['reassingment_count_bool'] = df['reassignment_count'].apply(lambda x: 1 if x > 0 else 0) # indicar si ha habido reasignacion o no + + +if selected == 'Overview': + view1.run(df) +elif selected == 'Nueva incidencia': + view2.run(df) \ No newline at end of file