def compare_grimoires(uid_1, uid_2): ''' compare two items of the same type ''' try: data = (helpers.get_node(uid_1), helpers.get_node(uid_2)) except NameError: return redirect('/compare') nodes = [d['node'] for d in data] rels = [d['rels'] for d in data] data = { 'item_1': nodes[0], 'item_2': nodes[1] } # ----- check that item 1 and item 2 are both grimoires if nodes[0]['parent_label'] != 'parent:book' or nodes[1]['parent_label'] != 'parent:book': return redirect(nodes[0]['link']) # ----- get all shared items to list out max_list_size = 0 # keeps track of the biggest list data['shared_list'] = {} for entity in entities + ['spell']: entity_lists = [ extract_rel_list_by_type(rel_list, 'lists', 'end', label=entity) for rel_list in rels] data['shared_list'][entity] = intersection(entity_lists[0], entity_lists[1]) max_list_size = max_list_size \ if len(data['shared_list'][entity]) < max_list_size \ else len(data['shared_list'][entity]) data['default_collapse'] = max_list_size > 20 data['title'] = '"%s" vs "%s"' % (nodes[0]['props']['identifier'], nodes[1]['props']['identifier']) # ----- Properties table grim_items = [grimoire_item(nodes[i], rels[i]) for i in range(2)] details = [g['details'] for g in grim_items] for d in details: d['author'] = d.get('author', [{'text': 'Unknown'}]) keys = list(set(details[0].keys()) & set(details[1].keys())) keys = [k for k in keys if k not in ['Name', 'online_edition']] data['props'] = {k: [details[0][k], details[1][k]] for k in keys} # ----- compare remaining rels rels = [helpers.exclude_rels(rel_list, ['lists']) for rel_list in rels] # pull out rels between the two grimoires data['self_rels'] = [] for rel in rels[0]: if rel['start']['props']['uid'] in [uid_1, uid_2] and \ rel['end']['props']['uid'] in [uid_1, uid_2]: data['self_rels'].append(rel) exclude_ids = [r['id'] for r in data['self_rels']] rels[0] = [r for r in rels[0] if not r['id'] in exclude_ids] rels[1] = [r for r in rels[1] if not r['id'] in exclude_ids] # make a dictionary for each relationship type with an empty array value # ie: {'wrote': [[], []], 'influenced': [[], []]} types = {t: [[], []] for t in \ list(set([r['type'] for r in rels[0] + rels[1]]))} # populate types dictionary with every relationship of that type for (i, rel_list) in enumerate(rels): for rel in rel_list: types[rel['type']][i] += [rel] # remove types that only exist for one item or the other types = {k: v for (k, v) in types.items() if v[0] and v[1]} data['same'] = {'start': [], 'end': []} for rel_type in types: relset = types[rel_type] direction = 'end' if \ relset[0][0]['start']['props']['uid'] == uid_1 \ else 'start' subjects = [[rel[direction] for rel in r] for r in relset] same_uids = [ i['props']['uid'] for i in intersection(subjects[0], subjects[1]) ] same_rels = [rel for rel in relset[0] if \ rel[direction]['props']['uid'] in same_uids] data['same']['start' if direction == 'end' else 'end'] += same_rels data['same'] = { 'start': helpers.combine_rels(data['same']['start']), 'end': helpers.combine_rels(data['same']['end']) } data['grimoires'] = graph.get_all('grimoire')['nodes'] return render_template(request.url, 'compare.html', **data)
def compare_grimoires(uid_1, uid_2): ''' compare two items of the same type ''' try: data = (helpers.get_node(uid_1), helpers.get_node(uid_2)) except NameError: return redirect('/compare') nodes = [d['node'] for d in data] rels = [d['rels'] for d in data] data = {'item_1': nodes[0], 'item_2': nodes[1]} # ----- check that item 1 and item 2 are both grimoires if nodes[0]['parent_label'] != 'parent:book' or \ nodes[1]['parent_label'] != 'parent:book': return redirect(nodes[0]['link']) # ----- get all shared items to list out max_list_size = 0 # keeps track of the biggest list data['shared_list'] = {} for entity in entities + ['spell']: entity_lists = [ extract_rel_list_by_type(rel_list, 'lists', 'end', label=entity) for rel_list in rels ] data['shared_list'][entity] = intersection(entity_lists[0], entity_lists[1]) max_list_size = max_list_size \ if len(data['shared_list'][entity]) < max_list_size \ else len(data['shared_list'][entity]) data['default_collapse'] = max_list_size > 20 data['title'] = '"%s" vs "%s"' % (nodes[0]['props']['identifier'], nodes[1]['props']['identifier']) # ----- Properties table grim_items = [grimoire_item(nodes[i], rels[i]) for i in range(2)] details = [g['details'] for g in grim_items] for d in details: d['author'] = d.get('author', [{'text': 'Unknown'}]) keys = list(set(details[0].keys()) & set(details[1].keys())) keys = [k for k in keys if k not in ['Name', 'online_edition']] data['props'] = {k: [details[0][k], details[1][k]] for k in keys} # ----- compare remaining rels rels = [helpers.exclude_rels(rel_list, ['lists']) for rel_list in rels] # pull out rels between the two grimoires data['self_rels'] = [] for rel in rels[0]: if rel['start']['props']['uid'] in [uid_1, uid_2] and \ rel['end']['props']['uid'] in [uid_1, uid_2]: data['self_rels'].append(rel) exclude_ids = [r['id'] for r in data['self_rels']] rels[0] = [r for r in rels[0] if not r['id'] in exclude_ids] rels[1] = [r for r in rels[1] if not r['id'] in exclude_ids] # make a dictionary for each relationship type with an empty array value # ie: {'wrote': [[], []], 'influenced': [[], []]} types = {t: [[], []] for t in \ list(set([r['type'] for r in rels[0] + rels[1]]))} # populate types dictionary with every relationship of that type for (i, rel_list) in enumerate(rels): for rel in rel_list: types[rel['type']][i] += [rel] # remove types that only exist for one item or the other types = {k: v for (k, v) in types.items() if v[0] and v[1]} data['same'] = {'start': [], 'end': []} for rel_type in types: relset = types[rel_type] direction = 'end' if \ relset[0][0]['start']['props']['uid'] == uid_1 \ else 'start' subjects = [[rel[direction] for rel in r] for r in relset] same_uids = [ i['props']['uid'] for i in intersection(subjects[0], subjects[1]) ] same_rels = [rel for rel in relset[0] if \ rel[direction]['props']['uid'] in same_uids] data['same']['start' if direction == 'end' else 'end'] += same_rels data['same'] = { 'start': helpers.combine_rels(data['same']['start']), 'end': helpers.combine_rels(data['same']['end']) } data['grimoires'] = graph.get_all('grimoire')['nodes'] return render_template(request.url, 'compare.html', **data)
def item(label, uid): ''' generic page for an item :param label: the desired neo4j label :param uid: the human-readable uid of the node :return: customized data for this label rendered item page template ''' # load and validate url data label = helpers.sanitize(label) if not graph.validate_label(label): logging.error('Invalid label %s', label) return render_template(request.url, 'label-404.html', labels=graph.get_labels()) try: data = helpers.get_node(uid) except NameError: items = graph.get_all(label) return render_template(request.url, 'item-404.html', items=items['nodes'], search=graph.search(uid)['nodes'], label=label) node = data['node'] rels = data['rels'] # ----- page header/metadata title = node['props']['identifier'] # ----- formatted data switch = { 'parent:book': grimoire_item, 'parent:entity': entity_item, 'art': art_item, 'language': language_item, 'edition': edition_item, 'publisher': publisher_item, 'editor': editor_item, 'default': generic_item, 'spell': spell_item, 'talisman': spell_item, 'parent:ingredient': ingredient_item, 'outcome': outcome_item } key = node['parent_label'] if node['parent_label'] in switch else \ (label if label in switch else 'default') item_data = switch[key](node, rels) item_data['rels'] = helpers.combine_rels(item_data['rels']) # ----- sidebar sidebar = [] related = graph.related(uid, label) if related['nodes']: sidebar = [{'title': 'Similar %s' % \ helpers.capitalize_filter(helpers.pluralize(label)), 'data': related['nodes']}] sidebar += get_others(data['rels'], node) if not item_data['content'] and not item_data['excerpts']: item_data['content'] = 'The %s "%s."' % \ (helpers.format_filter(label), helpers.unthe(title)) max_main_length = max([len(i['data']) for i in item_data['main']] + [0]) default_collapse = len(item_data['main']) > 2 or max_main_length > 30 return render_template(request.url, 'item.html', data=item_data, title=title, label=label, sidebar=sidebar, default_collapse=default_collapse)
def item(label, uid): ''' generic page for an item :param label: the desired neo4j label :param uid: the human-readable uid of the node :return: customized data for this label rendered item page template ''' # load and validate url data label = helpers.sanitize(label) if not graph.validate_label(label): logging.error('Invalid label %s', label) return render_template(request.url, '404.html', labels=graph.get_labels()) try: data = helpers.get_node(uid) except NameError: items = graph.get_all(label) return render_template(request.url, '404.html', items=items['nodes'], search=graph.search(uid)['nodes'], label=label) node = data['node'] rels = data['rels'] # ----- page header/metadata title = node['props']['identifier'] # ----- formatted data switch = { 'parent:book': grimoire_item, 'parent:entity': entity_item, 'art': art_item, 'language': language_item, 'edition': edition_item, 'publisher': publisher_item, 'editor': editor_item, 'default': generic_item, 'spell': spell_item, 'talisman': spell_item, 'parent:ingredient': ingredient_item, 'outcome': outcome_item } key = node['parent_label'] if node['parent_label'] in switch else \ (label if label in switch else 'default') item_data = switch[key](node, rels) item_data['rels'] = helpers.combine_rels(item_data['rels']) # ----- sidebar sidebar = [] related = graph.related(uid, label) if related['nodes']: sidebar = [{'title': 'Similar %s' % \ helpers.capitalize_filter(helpers.pluralize(label)), 'data': related['nodes']}] sidebar += get_others(data['rels'], node) if not item_data['content'] and not item_data['excerpts']: item_data['content'] = 'The %s "%s."' % \ (helpers.format_filter(label), helpers.unthe(title)) max_main_length = max([len(i['data']) for i in item_data['main']] + [0]) default_collapse = len(item_data['main']) > 2 or max_main_length > 30 return render_template(request.url, 'item.html', data=item_data, title=title, label=label, sidebar=sidebar, default_collapse=default_collapse)