TestApp / app.py
menikev's picture
Update app.py
740e228 verified
raw
history blame
15.4 kB
import streamlit as st
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.feature_extraction.text import CountVectorizer
import seaborn as sns
import plotly.express as px
import plotly.io as pio
import plotly.graph_objects as go
from run import run_pipeline
# Set page configuration
st.set_page_config(layout="wide")
# Function to load and clean data
def load_and_clean_data():
df1 = pd.read_csv("data/reviewed_social_media_english.csv")
df2 = pd.read_csv("data/reviewed_news_english.csv")
df3 = pd.read_csv("data/tamil_social_media.csv")
df4 = pd.read_csv("data/tamil_news.csv")
# Concatenate dataframes and clean data
df_combined = pd.concat([df1, df2, df3, df4])
# Replace 'nan' and 'None' with numpy NaN for removal
df_combined['Domain'] = df_combined['Domain'].replace({"MUSLIM": "Muslim", "nan": pd.NA, "None": pd.NA, "Other-Ethnic": "Other-Ethnicity"})
# Specific replacements for 'Sentiment' and 'Discrimination'
df_combined['Sentiment'] = df_combined['Sentiment'].replace({"nan": pd.NA, "None": pd.NA, "No": pd.NA})
df_combined['Discrimination'] = df_combined['Discrimination'].replace({"nan": pd.NA, "None": pd.NA, "No": pd.NA})
# Drop rows with NA values in 'Domain', 'Sentiment', and 'Discrimination'
df_combined.dropna(subset=['Domain', 'Sentiment', 'Discrimination'], inplace=True)
return df_combined
df = load_and_clean_data()
# Page navigation setup
page_names = ["Analytics Dashboard for Domain Predictions", "GESI Overview", "Sentiment Analysis", "Discrimination Analysis", "Channel Analysis"]
page = st.sidebar.selectbox("Choose a page", page_names)
# Sidebar Filters
domain_options = df['Domain'].dropna().unique()
channel_options = df['Channel'].dropna().unique()
sentiment_options = df['Sentiment'].dropna().unique()
discrimination_options = df['Discrimination'].dropna().unique()
domain_filter = st.sidebar.multiselect('Select Domain', options=domain_options, default=domain_options)
channel_filter = st.sidebar.multiselect('Select Channel', options=channel_options, default=channel_options)
sentiment_filter = st.sidebar.multiselect('Select Sentiment', options=sentiment_options, default=sentiment_options)
discrimination_filter = st.sidebar.multiselect('Select Discrimination', options=discrimination_options, default=discrimination_options)
# Apply filters
df_filtered = df[(df['Domain'].isin(domain_filter)) &
(df['Channel'].isin(channel_filter)) &
(df['Sentiment'].isin(sentiment_filter)) &
(df['Discrimination'].isin(discrimination_filter))]
# Define a color palette for consistent visualization styles
color_palette = px.colors.sequential.Viridis
# Function to render the model prediction visualization page
def render_prediction_page():
st.title("Streamlit Analytics Dashboard for Model Predictions")
st.write("""
Welcome to the interactive analytics dashboard that brings to life the nuanced assessment of textual content.
Dive into the insightful world of language processing where each sentence you enter is meticulously evaluated
for its domain relevance and sentiment connotation.
Instant Analysis: Enter any text snippet and get immediate predictions with our sophisticated model that assesses content with nuanced precision.
Domain Identification: Discover the domain categorization of your text, providing clarity on the subject matter with a quantifiable domain score.
""")
# User input text area
user_input = st.text_area("Enter Text/Content here to analyze", height=150)
if st.button("Perform Contextual Analysis"):
# Use run_pipeline to get predictions
prediction = run_pipeline(user_input)
# Extract prediction details
domain_label = prediction.get("domain_label", "Unknown")
domain_score = prediction.get("domain_score", 0)
discrimination_label = prediction.get("discrimination_label", "Unknown")
discrimination_score = prediction.get("discrimination_score", 0)
# Visualization layout
col1, col2 = st.columns(2)
with col1:
st.markdown("#### Domain Label")
st.markdown(f"## {domain_label}")
st.progress(domain_score)
with col2:
st.markdown("#### Discrimination Label")
st.markdown(f"## {discrimination_label}")
st.progress(discrimination_score)
col3, col4 = st.columns(2)
with col3:
# Domain Score Gauge
fig_domain = go.Figure(go.Indicator(
mode="gauge+number",
value=domain_score,
domain={'x': [0, 1], 'y': [0, 1]},
title={'text': "Domain Score"},
gauge={'axis': {'range': [None, 1]}}))
st.plotly_chart(fig_domain, use_container_width=True)
with col4:
# Discrimination Score Gauge
fig_discrimination = go.Figure(go.Indicator(
mode="gauge+number",
value=discrimination_score,
domain={'x': [0, 1], 'y': [0, 1]},
title={'text': "Discrimination Score"},
gauge={'axis': {'range': [None, 1]}}))
st.plotly_chart(fig_discrimination, use_container_width=True)
# Visualisation for Domain Distribution
def create_pie_chart(df, column, title):
fig = px.pie(df, names=column, title=title, hole=0.35)
fig.update_layout(margin=dict(l=20, r=20, t=50, b=20), legend=dict(x=0.1, y=1), font=dict(size=10))
fig.update_traces(marker=dict(colors=color_palette))
return fig
# Visualization for Distribution of Gender versus Ethnicity
def create_gender_ethnicity_distribution_chart(df):
df['GenderOrEthnicity'] = df['Domain'].apply(lambda x: "Gender: Women & LGBTQIA+" if x in ["Women", "LGBTQIA+"] else "Ethnicity")
fig = px.pie(df, names='GenderOrEthnicity', title='Distribution of Gender versus Ethnicity', hole=0.35)
fig.update_layout(margin=dict(l=20, r=20, t=50, b=20), legend=dict(x=0.1, y=1), font=dict(size=10))
return fig
# Visualization for Sentiment Distribution Across Domains
def create_sentiment_distribution_chart(df):
domain_counts = df.groupby(['Domain', 'Sentiment']).size().reset_index(name='counts')
domain_counts = domain_counts.sort_values('counts')
# Reverse the color scheme
color_map = {'Negative': 'red', 'Positive': 'blue', 'Neutral': 'lightblue'}
fig = px.bar(domain_counts, x='Domain', y='counts', color='Sentiment', color_discrete_map=color_map,
title="Sentiment Distribution Across Domains", barmode='stack')
fig.update_layout(margin=dict(l=20, r=20, t=50, b=20), xaxis_title="Domain", yaxis_title="Counts", font=dict(size=10))
return fig
# Visualization for Correlation between Sentiment and Discrimination
def create_sentiment_discrimination_grouped_chart(df):
# Creating a crosstab of 'Sentiment' and 'Discrimination'
crosstab_df = pd.crosstab(df['Sentiment'], df['Discrimination'])
# Check if 'Yes' and 'No' are in the columns after the crosstab operation
value_vars = crosstab_df.columns.intersection(['Discriminative', 'Non Discriminative']).tolist()
# If 'No' is not in columns, it will not be included in melting
melted_df = pd.melt(crosstab_df.reset_index(), id_vars='Sentiment', value_vars=value_vars, var_name='Discrimination', value_name='Count')
# Proceeding to plot only if we have data to plot
if not melted_df.empty:
fig = px.bar(melted_df, x='Sentiment', y='Count', color='Discrimination', barmode='group', title="Sentiment vs. Discrimination")
fig.update_layout(margin=dict(l=20, r=20, t=50, b=20), xaxis_title="Sentiment", yaxis_title="Count", font=dict(size=10))
return fig
else:
return "No data to display for the selected filters."
# Function for Top Domains with Negative Sentiment Chart
def create_top_negative_sentiment_domains_chart(df):
domain_counts = df.groupby(['Domain', 'Sentiment']).size().unstack(fill_value=0)
domain_counts.sort_values(by='Negative', ascending=False, inplace=True)
domain_counts_subset = domain_counts.iloc[:3, [0]]
domain_counts_subset = domain_counts_subset.rename(columns={domain_counts_subset.columns[0]: 'Count'})
domain_counts_subset = domain_counts_subset.reset_index()
colors = ['limegreen', 'crimson', 'darkcyan']
fig = px.bar(domain_counts_subset, x='Count', y='Domain', title='Top Domains with Negative Sentiment', color='Domain',
orientation='h', color_discrete_sequence=colors)
fig.update_layout(margin=dict(l=20, r=20, t=50, b=20), xaxis_title="Negative sentiment content Count", yaxis_title="Domain", font=dict(size=10))
return fig
# Function for Key Phrases in Negative Sentiment Content Chart
def create_key_phrases_negative_sentiment_chart(df):
cv = CountVectorizer(ngram_range=(3,3), stop_words='english')
trigrams = cv.fit_transform(df['Content'][df['Sentiment'] == 'Negative'])
count_values = trigrams.toarray().sum(axis=0)
ngram_freq = pd.DataFrame(sorted([(count_values[i], k) for k, i in cv.vocabulary_.items()], reverse=True))
ngram_freq.columns = ['frequency', 'ngram']
fig = px.bar(ngram_freq.head(10), x='frequency', y='ngram', orientation='h', title='Key phrases in Negative Sentiment Content')
fig.update_layout(margin=dict(l=20, r=20, t=50, b=20), xaxis_title="Frequency", yaxis_title="Trigram", font=dict(size=10))
return fig
# Function for Key Phrases in Positive Sentiment Content Chart
def create_key_phrases_positive_sentiment_chart(df):
# Filter the DataFrame for positive sentiments and drop any rows with NaN in 'Content'
positive_df = df[df['Sentiment'] == 'Positive'].dropna(subset=['Content'])
# Create a CountVectorizer instance
cv = CountVectorizer(ngram_range=(3, 3), stop_words='english')
# Apply CountVectorizer only on non-null content
trigrams = cv.fit_transform(positive_df['Content'])
# Sum the frequency of each n-gram and create a DataFrame
count_values = trigrams.toarray().sum(axis=0)
ngram_freq = pd.DataFrame(sorted([(count_values[i], k) for k, i in cv.vocabulary_.items()], reverse=True))
ngram_freq.columns = ['frequency', 'ngram']
# Create the bar chart
fig = px.bar(ngram_freq.head(10), x='frequency', y='ngram', orientation='h', title='Key phrases in Positive Sentiment Content')
# Update layout settings to fit and look better
fig.update_layout(margin=dict(l=20, r=20, t=50, b=20), xaxis_title="Frequency", yaxis_title="Trigram", font=dict(size=10))
return fig
# Function for Prevalence of Discriminatory Content Chart
def create_prevalence_discriminatory_content_chart(df):
domain_counts = df.groupby(['Domain', 'Discrimination']).size().unstack(fill_value=0)
fig = px.bar(domain_counts, x=domain_counts.index, y=['Discriminative', 'Non-Discriminative'], barmode='group',
title='Prevalence of Discriminatory Content')
fig.update_layout(margin=dict(l=20, r=20, t=50, b=20), xaxis_title="Domain", yaxis_title="Count", font=dict(size=10))
return fig
# Function for Top Domains with Discriminatory Content Chart
def create_top_discriminatory_domains_chart(df):
domain_counts = df.groupby(['Domain', 'Discrimination']).size().unstack(fill_value=0)
domain_counts.sort_values(by='Discriminative', ascending=False, inplace=True)
domain_counts_subset = domain_counts.iloc[:3]
domain_counts_subset = domain_counts_subset.rename(columns={'Discriminative': 'Count'})
fig = px.bar(domain_counts_subset, x='Count', y=domain_counts_subset.index, orientation='h',
title='Top Domains with Discriminatory Content')
fig.update_layout(margin=dict(l=20, r=20, t=50, b=20), xaxis_title="Discriminatory Content Count", yaxis_title="Domain", font=dict(size=10))
return fig
# Function for Channel-wise Sentiment Over Time Chart
def create_sentiment_distribution_by_channel_chart(df):
sentiment_by_channel = df.groupby(['Channel', 'Sentiment']).size().reset_index(name='counts')
color_map = {'Positive': 'blue', 'Neutral': 'lightblue', 'Negative': 'red'}
fig = px.bar(sentiment_by_channel, x='Channel', y='counts', color='Sentiment', title="Sentiment Distribution by Channel", barmode='group', color_discrete_map=color_map)
fig.update_layout(margin=dict(l=20, r=20, t=50, b=20), xaxis_title="Channel", yaxis_title="Counts", font=dict(size=10), title_x=0.5)
return fig
# Function for Channel-wise Distribution of Discriminative Content Chart
def create_channel_discrimination_chart(df):
channel_discrimination = df.groupby(['Channel', 'Discrimination']).size().unstack(fill_value=0)
fig = px.bar(channel_discrimination, x=channel_discrimination.index, y=['Discriminative', 'Non-Discriminative'], barmode='group')
fig.update_layout(title='Channel-wise Distribution of Discriminative Content', margin=dict(l=20, r=20, t=50, b=20), font=dict(size=10), title_x=0.5)
return fig
# Function for rendering dashboard
def render_dashboard(page, df_filtered):
if page == "Analytics Dashboard for Domain Predictions":
render_prediction_page()
elif page == "GESI Overview":
st.title(" GESI Overview Dashboard")
col1, col2 = st.columns(2)
with col1:
st.plotly_chart(create_pie_chart(df_filtered, 'Domain', 'Distribution of Domains'))
with col2:
st.plotly_chart(create_gender_ethnicity_distribution_chart(df_filtered))
col3, col4 = st.columns(2)
with col3:
st.plotly_chart(create_sentiment_distribution_chart(df_filtered))
with col4:
chart = create_sentiment_discrimination_grouped_chart(df_filtered)
if isinstance(chart, str):
st.write(chart)
else:
st.plotly_chart(chart)
elif page == "Sentiment Analysis":
st.title("Sentiment Analysis Dashboard")
col1, col2 = st.columns(2)
with col1:
st.plotly_chart(create_sentiment_distribution_chart(df_filtered))
with col2:
st.plotly_chart(create_top_negative_sentiment_domains_chart(df_filtered))
col3, col4 = st.columns(2)
with col3:
st.plotly_chart(create_key_phrases_negative_sentiment_chart(df_filtered))
with col4:
st.plotly_chart(create_key_phrases_positive_sentiment_chart(df_filtered))
elif page == "Discrimination Analysis":
st.title("Discrimination Analysis Dashboard")
col1, col2 = st.columns(2)
with col1:
st.plotly_chart(create_prevalence_discriminatory_content_chart(df_filtered))
with col2:
st.plotly_chart(create_top_discriminatory_domains_chart(df_filtered))
elif page == "Channel Analysis":
st.title("Channel Analysis Dashboard")
col1, col2 = st.columns(2)
with col1:
st.plotly_chart(create_sentiment_distribution_by_channel_chart(df_filtered))
with col2:
st.plotly_chart(create_channel_discrimination_chart(df_filtered))
# Render the selected dashboard page
render_dashboard(page, df_filtered)