m@77: # -*- coding: utf-8 -*- m@77: """ m@77: Created on Fri Jun 24 13:06:12 2016 m@77: m@77: @author: mariapanteli m@77: """ m@77: m@77: import numpy as np m@77: import matplotlib.pyplot as plt m@102: from bokeh.models import HoverTool, TapTool, CustomJS, Title, Label#, OpenURL, Button m@102: #from bokeh.io import show, vform m@77: from bokeh.plotting import figure, show, save, output_file, ColumnDataSource m@77: from mpl_toolkits.basemap import Basemap m@77: from shapely.geometry import Point, Polygon m@77: import random m@77: from bokeh.models.widgets import Panel, Tabs m@77: import os m@77: m@77: m@77: SHAPEFILE = os.path.join(os.path.dirname(__file__), 'util_data', 'shapefiles', 'ne_110m_admin_0_countries') m@77: m@77: m@77: def get_random_point_in_polygon(poly): m@77: (minx, miny, maxx, maxy) = poly.bounds m@77: while True: m@77: p = Point(random.uniform(minx, maxx), random.uniform(miny, maxy)) m@77: if poly.contains(p): m@77: return p m@77: m@77: m@77: def get_random_point_in_country_poly(countries_data): m@77: pp_x, pp_y, coords_poly, countries_poly = get_countries_lonlat_poly(SHAPEFILE) m@77: data_x = [] m@77: data_y = [] m@77: for country in countries_data: m@77: #print country m@77: poly_inds = np.where(countries_poly==country)[0] m@77: if len(poly_inds)<1: m@77: data_x.append(np.nan) m@77: data_y.append(np.nan) m@77: continue m@77: poly = coords_poly[poly_inds[0]] m@77: if len(poly_inds)>1: m@77: # if many polys for country choose the largest one (ie most points) m@77: len_list = [len(pp_x[poly_ind]) for poly_ind in poly_inds] m@77: poly = coords_poly[poly_inds[np.argmax(len_list)]] m@77: p = Polygon(poly) m@77: point_in_poly = get_random_point_in_polygon(p) m@77: data_x.append(point_in_poly.x) m@77: data_y.append(point_in_poly.y) m@77: return data_x, data_y m@77: m@77: m@77: def get_countries_lonlat_poly(shapefile): m@77: mm=Basemap() m@77: mm.readshapefile(shapefile, 'units', color='#444444', linewidth=.2) m@77: pp_x = [] m@77: pp_y = [] m@77: for shape in mm.units: m@77: pp_x.append([ss[0] for ss in shape]) m@77: pp_y.append([ss[1] for ss in shape]) m@77: countries_poly = [] m@77: for mm_info in mm.units_info: m@77: countries_poly.append(mm_info['admin']) m@77: countries_poly = np.array(countries_poly, dtype=str) m@77: #(-52.55642473001839, 2.504705308437053) for French Guiana m@77: countries_poly[102] = 'French Guiana' # manual correction m@77: return pp_x, pp_y, mm.units, countries_poly m@77: m@77: m@77: def add_bokeh_interactivity(p, r, hover_outlier=False): m@77: '''add interactivity m@77: ''' m@77: callback = CustomJS(args=dict(r=r), code=""" m@77: var inds = cb_obj.get('selected')['1d'].indices; m@77: var d1 = cb_obj.get('data'); m@77: url = d1['url'][inds[0]]; m@77: if (url){ m@77: window.open(url);}""") m@77: hover_tooltips = """ m@77:
m@77:
@name
m@77:
@info
m@77:
""" m@77: hover_tooltips_outlier = """ m@77:
m@77:
@name
m@77:
@info
m@101:
@outlierMD
m@101:
@collection
m@77:
""" m@77: if hover_outlier: m@77: p.add_tools(HoverTool(renderers=[r], tooltips=hover_tooltips_outlier)) m@77: else: m@77: p.add_tools(HoverTool(renderers=[r], tooltips=hover_tooltips)) m@77: p.add_tools(TapTool(renderers=[r], callback = callback)) m@77: return p m@77: m@77: m@77: def beautify_bokeh_background(p): m@77: '''remove unnecessary background m@77: ''' m@77: p.outline_line_color = None m@77: p.grid.grid_line_color=None m@77: p.axis.axis_line_color=None m@77: p.axis.major_label_text_font_size='0pt' m@77: p.axis.major_tick_line_color=None m@77: p.axis.minor_tick_line_color=None m@77: return p m@77: m@77: m@77: def plot_outliers_world_figure(MD, y_pred, df, out_file=None): m@77: '''assume features, df are in the same order m@77: ''' m@77: pp_x, pp_y, coords_poly, countries_poly = get_countries_lonlat_poly(SHAPEFILE) m@77: data_x, data_y = get_random_point_in_country_poly(df['Country'].get_values()) m@77: m@77: #threshold, y_pred, MD = get_outliers(features, chi2thr=0.995) m@80: #alpha_color = MD/np.max(MD) # if outlier vary transparency wrt MD m@80: #alpha_color[y_pred==False] = 0.2 # if not outlier just color white m@80: # min transparency at least 0.5 m@80: alpha_color = (MD-np.min(MD)+0.5)/(np.max(MD)-np.min(MD)+0.5) m@84: alpha_color[y_pred==False] = 0.3 m@77: m@77: circle_color = np.repeat('grey', repeats=len(y_pred)) m@77: circle_color[y_pred] = 'red' m@101: m@102: #bl_inds = np.where(np.isnan(df['BuyLinkTrackDownload']))[0] m@102: bl_inds = np.where(df['Collection']=='British Library')[0] m@101: collection = np.repeat('Smithsonian Folkways', len(df)) m@101: collection[bl_inds] = 'British Library' m@101: m@101: outlier_info = [] m@101: for i in range(len(MD)): m@101: if y_pred[i]: m@101: # if outlier m@101: outlier_info.append('outlier, MD=' + str(int(MD[i]))) m@101: else: m@101: outlier_info.append('non-outlier, MD=' + str(int(MD[i]))) m@101: m@77: source = ColumnDataSource(data=dict( m@77: x=data_x, m@77: y=data_y, m@77: name=df['Country'].get_values(), m@77: color=circle_color, m@77: alpha=alpha_color, m@102: #info = zip(df['Culture'].get_values(),df['Language'].get_values(),df['Genre_Album'].get_values()), m@102: info = zip(df['Culture'].get_values(),df['Language'].get_values(),df['Genre'].get_values()), m@101: #outlierMD=[str(y_pred[i])+'('+str(int(MD[i]))+')' for i in range(len(MD))], m@101: outlierMD = outlier_info, m@101: collection = collection, m@102: #url=df['songurls_Album'].get_values() m@102: url=df['Url'].get_values() m@77: )) m@77: m@77: TOOLS="wheel_zoom,box_zoom,pan,reset,save" m@77: m@102: p = figure(tools=TOOLS, plot_width=1200, title="Outlier recordings per country (click on each point to listen to the audio). More info at: github.com/mpanteli/music-outliers/tree/master/demo/README.md.") m@77: outlier_ind = np.argmax(MD) m@77: nonoutlier_ind = np.argmin(MD) m@84: rleg1 = p.circle(data_x[outlier_ind], data_y[outlier_ind], fill_color='red', alpha=alpha_color[outlier_ind], size=6, m@80: line_color=None, selection_color="firebrick", nonselection_color='white', legend="outliers") m@80: rleg2 = p.circle(data_x[nonoutlier_ind], data_y[nonoutlier_ind], fill_color='grey', alpha=alpha_color[nonoutlier_ind], m@84: size=6, line_color=None, selection_color="firebrick", nonselection_color='white', legend="non-outliers") m@77: r1 = p.patches(pp_x, pp_y, fill_color='white', line_width=0.4, line_color='grey') m@84: r2 = p.circle_cross('x','y', fill_color='color', alpha='alpha', size=6, line_color=None, m@77: selection_color="firebrick", nonselection_color='color', source=source) m@77: m@77: p = add_bokeh_interactivity(p, r2, hover_outlier=True) m@77: p = beautify_bokeh_background(p) m@77: m@102: #from bokeh.layouts import widgetbox m@102: #button = Button(label="Button", callback=OpenURL(url='http://www.cnn.com/'), button_type="success") m@102: #button = Button(label="Button", callback=CustomJS(code="""window.open('http://www.cnn.com/');"""), button_type="success") m@102: #show(vform(button)) m@102: #button.js_on_event(events.ButtonClick, OpenURL(url="http://www.colors.commutercreative.com/")) m@102: m@102: #test_url = "http://www.colors.commutercreative.com/" m@84: #explanation = Label(x=70, y=70, x_units='screen', y_units='screen', m@102: # text='For more info click here.', border_line_color='black', border_line_alpha=1.0, m@84: # background_fill_color='white', background_fill_alpha=1.0) m@84: #p.add_layout(explanation) m@102: #r3 = p.scatter(x=70, y=70, size=20) m@102: #p.add_tools(TapTool(renderers=[r3], callback=OpenURL(url=test_url))) m@102: #p.scatter(x=70, y=70, size=20, source=source_url) m@80: m@102: #callback = CustomJS(args=dict(r=r3), code=""" m@102: # var inds = cb_obj.get('selected')['1d'].indices; m@102: # var d1 = cb_obj.get('data'); m@102: # url = d1['url'][inds[0]]; m@102: # if (url){ m@102: # window.open(url);}""") m@102: #p.add_tools(TapTool(renderers=[r3], callback = callback)) m@102: #taptool = p.select(type=TapTool) m@102: #taptool.callback = OpenURL(url=url) m@102: m@77: if out_file is not None: m@77: output_file(out_file) m@77: save(p) m@77: #show(p) m@77: return p m@77: m@77: m@77: def plot_tabs(tab_all, tabs_feat, out_file="temp.html"): m@77: tab1 = Panel(child=tab_all, title="All") m@77: tab2 = Panel(child=tabs_feat[0], title="Rhythm") m@77: tab3 = Panel(child=tabs_feat[1], title="Melody") m@77: tab4 = Panel(child=tabs_feat[2], title="Timbre") m@77: tab5 = Panel(child=tabs_feat[3], title="Harmony") m@77: tabs = Tabs(tabs=[tab1,tab2,tab3,tab4,tab5]) m@77: output_file(out_file) m@77: save(tabs) m@77: show(tabs)