Source code for hmis.visualizing

import pandas as pd
import matplotlib.pyplot as plt
import datetime as dt
import numpy as np
from hmis.general import *
from collections import OrderedDict
import plotly.graph_objs as go
from plotly.offline import iplot
import plotly.plotly as py
from plotly.graph_objs import Scatter, Figure, Layout
import folium
import math
from folium.plugins import MarkerCluster
import time as time
    

################################################################################
# Gets the plotting style based on what program the individual has been in.
################################################################################
[docs]def get_plotting_style(ptype): """ This function gets the plotting styles depending on the program type. Args: **ptype** (string): The project type. Returns: **color** (string): The color of the program in RGB. **width** (int): The width of the line of the program. **alpha** (float): The opaque value of the program. **style** (string): The marker style of the program. """ # The different programs and their plotting styles. programs_new = [{'name':'Emergency Shelter', 'color':'rgba(152, 150, 0, .8)', 'width':2,'style':'-','alpha':1.0}, {'name':'Day Shelter', 'color':'rgba(152, 0, 150, .8)', 'width':2,'style':'-','alpha':1.0}, {'name':'PH - Permanent Supportive Housing','color':'rgba(52, 0, 255, .8)','width':2,'style':'-','alpha':1.0}, {'name':'Transitional Housing', 'color':'rgba(255, 20, 10, .8)', 'width':2,'style':'-','alpha':1.0}, {'name':'Services Only', 'color':'rgba(152, 255, 0, .8)', 'width':2,'style':'-','alpha':1.0}, {'name':'PH - Rapid Re-Housing', 'color':'rgba(0, 255, 0, .8)', 'width':2,'style':'-','alpha':1.0}, {'name':'Homelessness Prevention', 'color':'rgba(152, 200, 200, .8)', 'width':2,'style':'-','alpha':1.0}, {'name':'Street Outreach', 'color':'rgba(20, 20, 20, .8)','width':10,'style':'-','alpha':0.5}, {'name':'RETIRED', 'color':'rgba(0, 20, 10, .8)', 'width':2,'style':'-','alpha':1.0}, {'name':'Other Safe Haven', 'color':'rgba(10, 200, 0, .8)', 'width':2,'style':'-','alpha':1.0}, {'name':'PH - Housing Only', 'color':'rgba(0, 90, 90, .8)', 'width':2,'style':'-','alpha':1.0}, {'name':'PH - Housing with Services', 'color':'rgba(12, 20, 200, .8)', 'width':2,'style':'-','alpha':1.0}, {'name':'Coordinated Assesment', 'color':'rgba(99, 109, 240, .8)','width':10,'style':'-','alpha':0.1} ] # Assigning the color, line width, opaqueness, and marker style. color,width,alpha,style = 0,0,0,0 for pt in programs_new: if ptype == pt['name']: color = pt['color'] width = pt['width'] alpha = pt['alpha'] style = pt['style'] return color,width,alpha,style
################################################################################ ################################################################################
[docs]def plot_time_series(inds, image_name=None, exploded_view=False, plotly=False): """ This function plots a time-series plot of the programs for the list of individuals. Args: **inds** (list): The list of dictionaries that are going to be plotted. **image_name** (string): The name of the figure to be saved. **exploded_view** (bool, optional): If True: each program for each individual will be plotted on the y-axis. If False: each individual will be plotted on a different point on the y-axis with multiple programs on one line. *Defaulted to: False.* **plotly** (bool, optional): If True: this time-series plot will plot with plotly. This has a mouse-over feature that is useful for understanding the data that is visualized. If False: this time-series plot will be plotted with matplotlib. *Defaulted to: False.* """ # If there is only one individual, make their dictionary a list with one item. if type(inds) != list: inds = [inds] totlens=[] color_index=0 if plotly==False and plt.gcf()==None: plt.figure(figsize=(12,5)) min_date = dt.datetime(2100,1,1) max_date = dt.datetime(1800,1,1) # Set the y-axis y = 0.0 program_list=[] # To avoid duplicated legend values in plotly. prog_list_legend = [] # Get the information for each individual for i in inds: personalID = i['Personal ID'] proj_type=[] start_dates=[] end_dates=[] stay_lengths=[] for entry in i['Programs']: start_dates.append(entry['Admission date']) end_dates.append(entry['Discharge date']) stay_lengths.append(entry['Length of stay']) proj_type.append(entry['Project type']) program_count = 0 for start,end,los,ptype in zip(start_dates,end_dates,stay_lengths,proj_type): # Handles nan if str(start)=='nan' or str(end)=='nan': 1 else: # Convert dates to datetime format. s = get_date_from_string(start) e = get_date_from_string(end) # Get plotting styles depending on what the program is. color,width,alpha,style = get_plotting_style(ptype) # Starting point on the x-axis. x_start = [s,e] # Determining if it is a one day entry or an extended stay. los = np.timedelta64(1,'ns') length= (los / np.timedelta64(1, 'D')).astype(int) # Dependent on the length of stay, the marker plotted will change. if length > 1: m_type='o' else: m_type='*' # Exploded view with make every program be on a separate line. Defaulted to have each program for one individual to be on one line. if exploded_view==True: y+=1 #y_point=[s,s] y_point = [y,y] # If plotly is True, then plotly is used to plot instead of matplotlib. if plotly==True: showlegend_bool = True if (program_count>0) or (ptype in prog_list_legend): showlegend_bool = False else: prog_list_legend.append(ptype) prog = go.Scatter( x = x_start, y= y_point, legendgroup = ptype, #legendgroup = personalID, #name = personalID, name = ptype, text = personalID+"<br>"+ptype, showlegend = showlegend_bool, marker = dict(size = 10,color = color,line = dict(width = 2,)) ) program_list.append(prog) else: # Need to do this to convert the rgba string. color = color[5:-1] color = color.split(',') color = '#%02x%02x%02x' % (int(color[0]),int(color[1]),int(color[2])) plt.plot(x_start,y_point,marker=m_type,linewidth=width,color=color,alpha=alpha,linestyle=style, label=ptype) plt.plot([0,1],[0,1]) # Keep track of max and min time to rescale axes later. if s<min_date: min_date = s if e>max_date: max_date = e program_count += 1 y += 1 if plotly==False: handles, labels = plt.gca().get_legend_handles_labels() by_label = OrderedDict(list(zip(labels, handles))) plt.legend(list(by_label.values()), list(by_label.keys()), loc='upper left') plt.xlim(min_date-dt.timedelta(365),max_date) plt.gcf().tight_layout() if image_name is not None: plt.gcf().savefig(image_name,dpi=300) if exploded_view==False and plotly==False: plt.ylim(-1,y+1) if plotly ==True: iplot(program_list)
################################################################################ # Displays markers associated with zip codes on folium maps. ################################################################################
[docs]def plot_program_locations(dictionaries, cluster= True, exploded=False): """ This function plots all of the program's zip codes with the folium package. Args: **dictionaries** (list): The list of dictionaries that are going to be plotted. Return: **map1** (Map): The map to be displayed in a Jupyter notebook. """ if type(dictionaries) == dict: dictionaries = [dictionaries] prog_name = [] if (exploded == True): zip_codes =[] else: zip_codes = {} tot_progs = 0 upeople=0 # Loop through the list of dictionaries inputted. for ind in dictionaries: prog_list = ind['Programs'] # Loop through the programs and append the zip codes and program name. for prog in prog_list: tot_progs +=1 if (exploded == True): zip_codes.append(prog['Project Zip Code']) prog_name.append(prog['Project type']) else: zipc = prog['Project Zip Code'] project_name = prog['Project type'] # Check to see if the zip code has been added to the dictionary yet if zipc in zip_codes: zip_codes[zipc][0] +=1 else: zip_codes[zipc] = [1, project_name] # Map the coordinates with the corresponding program name albany_coordinates = [42.6526, -73.7562] map1 = folium.Map(location=albany_coordinates , zoom_start=7) locations=[] popups=[] for num,zipc in enumerate(zip_codes): # Convert the zip codes to latitude and longitude coordinates if (type(zipc)==str): lat, lon = convert_to_coordinates(zipc) if cluster==False: rad = zip_codes[zipc][0]/tot_progs if exploded == True: html = " %s " % (prog_name[num]) else: html = " %s <br>Num stays: %i <br>" % (zip_codes[zipc][1],zip_codes[zipc][0]) iframe = folium.IFrame(html=html, width=200, height=80) popup = folium.Popup(iframe) locations.append([lat,lon]) popups.append(popup) if cluster == False: folium.CircleMarker([lat, lon], radius=(100*rad)+1, popup = popup).add_to(map1) if cluster == True: map1.add_child(MarkerCluster(locations=locations, popups=popups)) return map1