# supress warnings about future deprecations import warnings warnings.simplefilter(action='ignore', category=FutureWarning) import pandas as pd import altair as alt import numpy as np import pprint import datetime as dt from vega_datasets import data import matplotlib.pyplot as plt # Import panel and vega datasets import panel as pn import vega_datasets df2=pd.read_csv("https://raw.githubusercontent.com/dallascard/SI649_public/main/altair_hw3/approval_topline.csv") # fix the time stamps and reorganize the data to combine approve and disapprove into one column df2['timestamp']=pd.to_datetime(df2['timestamp']) df2=pd.melt(df2, id_vars=['president', 'subgroup', 'timestamp'], value_vars=['approve','disapprove']).rename(columns={'variable':'choice', 'value':'rate'}) # Enable Panel extensions pn.extension('vega') # we want to use bootstrap/template, tell Panel to load up what we need # pn.extension(design='bootstrap') # Define a function to create and return a plot def create_plot(subgroup='All polls', date_range=[df2['timestamp'].min(), df2['timestamp'].max()], moving_av_window=1): # Downselection! approval_df2 = df2.copy() approval_df2 = approval_df2[approval_df2['subgroup'] == subgroup] approval_df2 = approval_df2[approval_df2['choice'] == 'approve'] # remove columns approval_df2 = approval_df2.drop(columns=['choice', 'subgroup', 'president']) # convert date_range to datetime date_range = [pd.to_datetime(date_range[0]), pd.to_datetime(date_range[1])] # narrow down dates approval_df2 = approval_df2[ (approval_df2['timestamp'] >= date_range[0]) & (approval_df2['timestamp'] <= date_range[1]) ] # Apply any required transformations to the data in pandas smooth_data = approval_df2.sort_values('timestamp').rolling(window=moving_av_window, on='timestamp', center=True).mean().shift(-moving_av_window+1) chart_data = approval_df2.sort_values('timestamp').copy() # Line chart line = alt.Chart(smooth_data).mark_line(color='red', size=2).encode( x=alt.X('timestamp:T', scale=alt.Scale(domain=date_range)), y=alt.Y('rate:Q', scale=alt.Scale(domain=[30, 60]), title='approve, mov_avg'), ) # Scatter plot with individual polls scatter = alt.Chart(chart_data).mark_point(size=2, opacity=0.7, color='grey').encode( x=alt.X('timestamp:T', scale=alt.Scale(domain=date_range)), y=alt.Y('rate:Q', scale=alt.Scale(domain=[30, 60])) ) # Put them together plot = alt.layer(scatter, line).resolve_scale(y='shared') # Return the combined chart return plot # Create the selection widget subgroup_select = pn.widgets.Select(name='Select subgroup', options=['Adults', 'All polls', 'Voters']) # Create the slider for the date range date_range_slider = pn.widgets.DateRangeSlider(name='Date range slider', end=df2['timestamp'].max(), start=df2['timestamp'].min(), value=(df2['timestamp'].min(), df2['timestamp'].max())) # Create the slider for the moving average window moving_av_slider = pn.widgets.IntSlider(name='Moving average window', start=1, end=100, value=1) # Bind the widgets to the create_plot function @pn.depends(subgroup_select.param.value, date_range_slider.param.value, moving_av_slider.param.value) def reactive_plot(subgroup, date_range, moving_av_window): return create_plot(subgroup, date_range, moving_av_window) # Combine everything in a Panel Column to create an app app = pn.Column(reactive_plot, subgroup_select, date_range_slider, moving_av_slider) # Set the app to be servable app.servable()