Slackbot Functions

This notebook defines a set of functions that will be exposed by the slack_bot notebook when run. Cells executed in this notebook will be immediately available to Slack users.

To start, we need to make the kernel associated with this ntoebook known to the slack bot notebook. The simplest way to do this is via the local filesystem.


In [1]:
ip = get_ipython()

In [2]:
!rm -f /tmp/defrag_demo
!ln -s {ip.kernel.config['IPKernelApp']['connection_file']} /tmp/defrag_demo

We'll use the IPython auto call feature to avoid the need for parentheses on all invocations. We'll also avoid printing what the call would have been.


In [3]:
%autocall 2


Automatic calling is: Full

In [4]:
ip.show_rewritten_input = False

Import common libs for convenience.


In [5]:
%matplotlib inline

In [6]:
import matplotlib.pyplot as plt
import pandas as pd
import seaborn as sns
import numpy as np
import requests
import json
import datetime

Define a function that prints other functions so users in Slack know what they can say.


In [7]:
def hi():
    '''Prints available functions.'''
    avail = []
    print('Hi there. Try running one of these:\n')
    exclude = ('exit', 'quit', 'get_ipython', 'hi')
    for key, value in ip.user_ns.items():
        if callable(value) and not key.startswith('_') and not key in exclude:
            avail.append(key)
    print(', '.join(avail))

Now define some demo functions


In [8]:
def plot_random(n=5):
    '''Draws N series with N points in each. Just as a demo.'''
    data = np.random.rand(n,n)
    df = pd.DataFrame(data)
    df.plot()

In [9]:
def plot_tips(hue='smoker'):
    '''
    Plots features of the tip data set as a pair plot colored by one column.
    
    Available columns:
    'total_bill', 'tip', 'sex', 'smoker', 'day', 'time', 'size'
    '''
    tips = sns.load_dataset('tips')
    sns.pairplot(tips, hue=hue)

Define functions that use some remote APIs.


In [29]:
_API_KEY = 'XXXXXXXXXXXXXXXXXXXXX'

In [11]:
def _meetups(topic):
    r = requests.get("https://api.meetup.com/2/open_events", params={'topic': topic, 'key': _API_KEY})    
    r.raise_for_status()
    results = r.json()['results']
    df = pd.DataFrame(results)
    df['localtime'] = pd.to_datetime(df.time+df.utc_offset, unit='ms')
    return df, results

In [26]:
def bluemix_meetups(limit=10):
    '''
    Show upcoming Bluemix meetups in a list.
    '''
    df, results = _meetups('bluemix')
    msgs = []
    for i, result in enumerate(results[:limit]):
        tmpl = '{}. <{result[event_url]}|{result[name]}>'
        if 'venue' in result:
            tmpl += ' at <https://www.google.com/maps/@{result[venue][lat]},{result[venue][lon]},17z|{result[venue][city]}, {result[venue][country]}>'
        tmpl += ' ({result[yes_rsvp_count]} :bust_in_silhouette:)'

        msgs.append(tmpl.format(i+1, result=result))
        
    print('Here are the next {} upcoming Bluemix meetups around the world:'.format(limit))
    print('\n'.join(msgs))

In [13]:
def bluemix_rsvps(pattern=None):
    '''
    Show affirmative RSVP growth for the Bluemix meetup over time.
    '''
    df, _ = _meetups('bluemix')
    if pattern is not None:
        # sublime/atom-like matching
        regex = ''.join(ch+'.*' for ch in pattern)
        df = df[df.name.str.contains(regex, case=False)]
    if not len(df):
        print("Sorry. There are no Bluemix meetup names matching `{}`.".format(pattern))

    # take the first if multiple matches
    event_id = df.iloc[0]['id']
    target_time = pd.to_datetime(df.iloc[0]['time'], unit='ms')
    
    # get rvps without paging (capped at API limit per request)
    r = requests.get("https://api.meetup.com/2/rsvps", {'event_id': event_id, 'key': _API_KEY, 'rsvp': 'yes'})
    results = r.json()['results']
    
    # convert to datetime
    dts = pd.to_datetime([r['created'] for r in results], unit='ms')
    events_df = pd.DataFrame(index=dts, columns=['RSVPs'])
    # treat every yes as a +1, don't look for users that later changed their mind for now
    events_df['RSVPs'] = 1
    events_df = events_df.sort().cumsum()
    
    # plot and put a vline at the scheduled datetime of the meetup
    ax = events_df.plot(figsize=(10,5))
    ax.axvline(x=target_time.to_datetime(), linewidth=2, color='k')
    ax.set_ylabel('Yes RSVPs')
    ax.set_xlabel('Date/time (UTC)')
    ax.set_ylim(top=events_df.tail(1)['RSVPs'].get(0)+5)
    ax.set_xlim(right=target_time.to_datetime()+datetime.timedelta(days=2))
    _ = ax.set_title(results[0]['event']['name'], y=1.08, loc='center')