def song(request, song_id='511'): max_links = 100 subgraph = {"keys":[], "values":[]} outDict = {} params = {} sorted_graph = {} use_random = False createSongSongLinks = True # 'jp_ego_group_and_centrality' # 'ego_group_w_attribs' defaultMethod = 'ego_group_w_attribs' songmeminfo = {} ## The basic organization for this function should be: # # 1. Parse the GET request parameters # 2. Get a graph of song nodes # 3. Calculate the starting positions of song nodes # 4. Fetch memories associated with some set of the song nodes in the graph # 5. Create the structure expected by the force-directed layout of d3 consisting of arrays of nodes and links # Get our graph_db connection graph_db = manage_sessions.check_ag_conn() # Get the GET request - this gives us access to a QueryDict # if isinstance(request,dict): # queryParams = request inputParams = {} if request.method == 'GET': inputParams = dict(request.GET) # Set defaults if the values were not passed in # Get the starting node # if queryParams.get('startNode'): # inputParams['startNode'] = queryParams.get('startNode') # else: # # In order to handle the startup condition of a user accessing meamcentral, the start node selection should be based on the birth year that the user is requested to provide when first entering MEAM Central # inputParams['startNode'] = 511 inputParams['startNode'] = song_id if 'graphConstructionMethod' not in inputParams.keys(): inputParams['graphConstructionMethod'] = defaultMethod elif isinstance(inputParams['graphConstructionMethod'],list): inputParams['graphConstructionMethod'] = inputParams['graphConstructionMethod'][0] if 'userid' not in inputParams.keys(): inputParams['userid'] = 'anonymous'; elif isinstance(inputParams['userid'],list): inputParams['userid'] = inputParams['userid'][0] if 'memNodeDistFromSongNode' not in inputParams.keys(): memNodeDistFromSongNode = 25 if 'year' in inputParams.keys() and isinstance(inputParams['year'],list): inputParams['year'] = inputParams['year'][0] # Get a graph structure for songs, based on some criteria # We are trying out various methods, each associated with a name and a particular function method = inputParams['graphConstructionMethod'] if method in ['userSongs','ego_group_w_year_seed']: # Check to see if the requested userid matches the username useridMatchesSessionID = False if inputParams['userid'] == request.user.username: useridMatchesSessionID = True # If the username is not anonymous and the userid matches the session ID, get the mcpid from the user profile if not request.user.is_anonymous() and useridMatchesSessionID: inputParams['mcpid'] = request.user.userprofile.mcpid else: inputParams['mcpid'] = manage_sessions.lookup_mcpid(inputParams['userid']) if method == 'userSongs': graphData = song_structure.songs_for_userid(graph_db,inputParams) elif method == 'ego_group_w_year_seed': graphData = song_structure.ego_group_w_year_seed(graph_db, inputParams) if not graphData: #pdb.set_trace() return HttpResponse(json.dumps({}), content_type='application/json') elif method == 'ego_group_w_attribs': graphData = song_structure.ego_group_w_attribs(graph_db,inputParams) elif method == 'jp_ego_group_and_centrality': graph_centrality = song_structure.sna_ego_group_and_centrality(graph_db) songIDs = graph_centrality.keys() elif method == 'original': params['readfromfile'] = True params['writetofile'] = True params['fname'] = './song_graph.txt' graph = song_structure.song_graph_by_common_song_set(graph_db, params) # Select a subset of those songs if use_random: subgraph["keys"] = random.sample(graph,max_links) # this returns only the song id pairs subgraph["values"] = [graph[a] for a in subgraph["keys"]] # Extract the list of unique songIDs in this set songIDs = list(set(itertools.chain.from_iterable(subgraph["keys"]))) else: # Sort the list by the number of times a pair of songs was encountered tmp = sorted(graph.iteritems(),key=itemgetter(1),reverse=True) for pair in tmp[0:max_links]: subgraph["keys"].append(pair[0]) subgraph["values"].append(pair[1]) songIDs = list(set(itertools.chain.from_iterable(subgraph["keys"]))) # Get the positioning information of the songs # We really shouldn't have to fetch the memory information associated with songs for this particular view if method in ['jp_ego_group_and_centrality','original']: songmeminfo = view_helpers.fetch_all_song_memories(graph_db, songIDs) # PJ - 15Aug2015 - I think we should be passing subgraph in rather than tmp, as this contains the information necessary to construct the feature matrix if method == 'jp_ego_group_and_centrality': songnodeLoc = getLocation.getSongNode_Location(songmeminfo, xmethod='year',ymethod='centrality',centrality_dict=graph_centrality) else: songnodeLoc = getLocation.getSongNode_Location(songmeminfo, xmethod='svd',ymethod='svd',cooccurence_dict=tmp) elif method in ['ego_group_w_attribs', 'ego_group_w_year_seed']: # only worry about unique songs for positioning useFields = ['song','year','centrality'] songinfoMtx = np.unique(graphData['songinfo']) songnodeLoc = getLocation.getSongNode_Location(songinfoMtx[useFields], xmethod='year', ymethod='centrality', viewParams = {'startNode': inputParams['startNode'], 'height':500, 'width':750}) songmeminfo = graphData['songmeminfo'] #Tracer()() elif method == 'userSongs': #pdb.set_trace() songinfoMtx = np.unique(graphData['songinfo']) songmeminfo = graphData['songmeminfo'] useFields = ['song','year'] songnodeLoc = getLocation.getSongNode_Location(songinfoMtx[useFields], xmethod='year', ymethod='random', viewParams = {'height':500, 'width':750}) # Do the heavy lifting for the d3 layout, creating the node and link objects that we need. We have two types of nodes: song nodes and memory nodes. Memory nodes only link to song nodes. Song nodes are linked both to memory nodes and other song nodes. nodes = [] links = [] outDict["nodes"] = nodes outDict["links"] = links # Loop over the meminfo entries, adding nodes both for songs and memories, and links between songs and memories if method in ['jp_ego_group_and_centrality','original']: songmemkeys = songmeminfo.keys() songID2Idx = {} for idx,currEntry in enumerate(sorted(songmemkeys)): currSongInfo = songmeminfo[currEntry]["songinfo"] # Get the location for this particular song if not usePreviewURL: currSongLocation = Stimulus.objects.filter(stimulus_id = currSongInfo["id"])[0].location # Strip off everything but the filename sep = '/' # sname = currSongLocation.rsplit(sep).pop() sname = currSongLocation currSongInfo["location"] = baseMusicLocation + sep + sname else: currSongInfo["location"] = currSongInfo["songURL"] songDict = {"songNodeID": currEntry, "class": "song", "songmeta": currSongInfo} # Get the locations for the display in d3 if not method == 'jp_ego_group_and_centrality': songDict.update({"x": songnodeLoc[idx,0], "y": songnodeLoc[idx,1]}) else: songDict.update({"x": songnodeLoc[currEntry]['x'], "y":songnodeLoc[currEntry]['y']}) nodes.append(songDict) songIdx = len(nodes)-1 songID2Idx[currEntry] = songIdx nodes[songIdx]["children"] = [] for memory in songmeminfo[currEntry]["memories"]: nodeDict = memory nodeDict["class"] = "memory" nodes.append(nodeDict) memIdx = len(nodes)-1 nodes[songIdx]["children"].append(memIdx) linkDict = {"source": songIdx, "target": memIdx} linkDict["class"] = "songmemory" links.append(linkDict) # Loop over the subgraph to create links between song nodes if createSongSongLinks: for songPair in subgraph["keys"]: linkDict = {"source": songID2Idx[songPair[0]], "target": songID2Idx[songPair[1]], "strength": subgraph["values"][subgraph["keys"].index(songPair)]} linkDict["class"] = "songsong" links.append(linkDict) elif method in ['ego_group_w_attribs','userSongs','ego_group_w_year_seed']: # Convert the array of song information into dicts that we can feed into songmeta fields songinfoVars = ['title','album','artist','year','previewURL'] names = songinfoMtx[songinfoVars].dtype.names # The map() function converts the years to strings songmetaMtx = [dict(zip(names, map(str,record))) for record in songinfoMtx[songinfoVars]] # Create the song nodes songID2Idx = {} sidx = 0 songmeminfoKeys = songmeminfo.keys() for currSongID in songinfoMtx['song']: # Create our dictionary to be associated with this song node songDict = {"songNodeID": str(currSongID), "class": "song", "songmeta": songmetaMtx[sidx]} # Update the dictionary with the position info songDict.update({"x": float(songnodeLoc[sidx]['x']), "px": float(songnodeLoc[sidx]['x']), "y":float(songnodeLoc[sidx]['y']), "py":float(songnodeLoc[sidx]['y'])}) # Get the source of the audio file if not usePreviewURL: #pdb.set_trace() currSongLocation = Stimulus.objects.filter(stimulus_id = currSongID)[0].location # Strip off everything but the filename sep = '/' # sname = currSongLocation.rsplit(sep).pop() sname = currSongLocation songDict["songmeta"]["location"] = baseMusicLocation + sep + sname else: songDict["songmeta"]["location"] = str(songinfoMtx[sidx]["previewURL"]).encode('utf-8') # Append the dictionary to the list of nodes nodes.append(songDict) songIdx = len(nodes)-1 # If we have them, handle the memories associated with this song nodes[songIdx]["children"] = [] if songmeminfo: if str(currSongID) in songmeminfoKeys: currMemList = songmeminfo[str(currSongID)] else: currMemList = [] #pdb.set_trace() # If we are dealing with the startNode, fetch the associated memory descriptions if currMemList and currSongID == inputParams['startNode']: currMemList = view_helpers.fetch_memories_for_song(graph_db, currSongID) numMem = len(currMemList) if numMem: radPerMem = 2*math.pi/numMem # number of radians per memory for positioning else: radPerMem = 0 currTheta = 0 for memory in currMemList: nodeDict = memory nodeDict["class"] = "memory" # Figure out positions for the memory nodes # Have to cast the numbers as regular floats so that the json encoder doesn't choke nodeDict["x"] = float(songnodeLoc[sidx]['x'] + memNodeDistFromSongNode * np.cos(currTheta)) nodeDict["px"] = nodeDict["x"] nodeDict["y"] = float(songnodeLoc[sidx]['y'] + memNodeDistFromSongNode * np.sin(currTheta)) nodeDict["py"] = nodeDict["y"] currTheta += radPerMem # Add the node to the list and to the list of the song node's children nodes.append(nodeDict) memIdx = len(nodes)-1 nodes[songIdx]["children"].append(memIdx) # Create the link between the song node and memory node linkDict = {"source": songIdx, "target": memIdx} linkDict["class"] = "songmemory" links.append(linkDict) sidx += 1 # Increment our song counter # Return information to server #Tracer()() #pdb.set_trace() return HttpResponse(json.dumps(outDict), content_type='application/json')
def song(request): max_links = 20 subgraph = {"keys": [], "values": []} outDict = {} nodes = [] links = [] params = {} sorted_graph = {} use_random = False # Get a graph structure for songs, based on some criteria # params["readfromfile"] = True params["writetofile"] = False params["fname"] = "./song_graph.txt" graph = song_structure.song_graph_by_common_song_set(params) # Select a subset of those songs if use_random: subgraph["keys"] = random.sample(graph, max_links) # this returns only the song id pairs subgraph["values"] = [graph[a] for a in subgraph["keys"]] else: # Sort the list by the number of times a pair of songs was encountered tmp = sorted(graph.iteritems(), key=itemgetter(1), reverse=True) for pair in tmp[0:max_links]: subgraph["keys"].append(pair[0]) subgraph["values"].append(pair[1]) # Extract the list of unique songIDs in this set songIDs = list(set(itertools.chain.from_iterable(subgraph["keys"]))) # Run a Cypher query to get nodes query = "START n=node(" + str(songIDs).strip("[]") + ") RETURN n" data, metadata = cypher.execute(graph_db, query) songNodes = [d[0] for d in data] # Get the song IDs in this graph and get the memories associated with those songs songmeminfo = view_helpers.fetch_all_song_memories(graph_db, songNodes) # Do the heavy lifting for the d3 layout, creating the node and link objects that we need. We have two types of nodes: song nodes and memory nodes. Memory nodes only link to song nodes. Song nodes are linked both to memory nodes and other song nodes. outDict["nodes"] = nodes outDict["links"] = links # Loop over the meminfo entries, adding nodes both for songs and memories, and links between songs and memories songmemkeys = songmeminfo.keys() songID2Idx = {} for currEntry in songmemkeys: currSongInfo = songmeminfo[currEntry]["songinfo"] # Get the location for this particular song # Need to look this up from the MySQL database because this info isn't imported into neo4j currSongLocation = Stimulus.objects.filter(stimulus_id=currSongInfo["id"])[0].location # Strip off everything but the filename sep = "/" # sname = currSongLocation.rsplit(sep).pop() sname = currSongLocation currSongInfo["location"] = baseMusicLocation + sep + sname songDict = {"songNodeID": currEntry, "class": "song", "songmeta": currSongInfo} nodes.append(songDict) songIdx = len(nodes) - 1 songID2Idx[currEntry] = songIdx nodes[songIdx]["children"] = [] for memory in songmeminfo[currEntry]["memories"]: nodeDict = memory nodeDict["class"] = "memory" nodes.append(nodeDict) memIdx = len(nodes) - 1 nodes[songIdx]["children"].append(memIdx) linkDict = {"source": songIdx, "target": memIdx} linkDict["class"] = "songmemory" links.append(linkDict) # Loop over the subgraph to create links between song nodes for songPair in subgraph["keys"]: linkDict = { "source": songID2Idx[songPair[0]], "target": songID2Idx[songPair[1]], "strength": subgraph["values"][subgraph["keys"].index(songPair)], } linkDict["class"] = "songsong" links.append(linkDict) # Return information to server return HttpResponse(json.dumps(outDict), content_type="application/json")