def render_lipid_pair(**kwargs):
	"""
	Abstracted the vmdmake routine for looping.
	"""
	global special_ion_color
	#---default settings
	hbond_style = ['dashed','cylinder'][-1]
	licorice_thick = 0.4
	hbond_cylinder_radius = 0.15
	goodsell_ions = False
	goodsell_lipids = True
	#---unpack the kwargs
	sn = kwargs.pop('sn')
	frame = kwargs.pop('frame')
	tempdir = kwargs.pop('tempdir')
	hydrogen_bonds = kwargs.pop('hydrogen_bonds',{})
	pair = kwargs.pop('pair',{})
	snapshot_fn = kwargs.pop('fn')
	associates = kwargs.pop('associates',None)
	lipid_color_specific = kwargs.pop('lipid_color_specific',None)
	if not pair: raise Exception('render_lipid_pair requires a pair')
	gro,xtc,tpr = [kwargs.pop(i) for i in 'gro xtc tpr'.split()]
	lipid_atoms = kwargs.pop('lipid_atoms',None)
	lipid_style = kwargs.pop('lipid_style',{})
	show_water = kwargs.pop('show_water',False)
	lipid_colors = kwargs.pop('lipid_colors',False)
	if kwargs: raise Exception('unprocessed arguments: %s'%kwargs)
	#---run VMD to make the snapshots via vmdmake
	view = vmdmake.VMDWrap(site=tempdir,gro=gro,xtc=xtc,tpr=tpr,
		frames='',res=(4000,4000),**kwargs_vmdmake)
	view.do('load_dynamic','standard','bonder')
	view.command("animate goto %d"%(frame))
	selections = []
	#---change water oxygen color for show_water (starting with v15)
	view.command('color Name O pink')
	#---show both lipids
	sel1 = "(resname %s and resid %s) and not hydrogen"%(pair['resname_1'],pair['resid_1'])
	sel2 = "(resname %s and resid %s) and not hydrogen"%(pair['resname_2'],pair['resid_2'])
	if lipid_atoms is not None:
		sel1 = '(%s) and (%s)'%(sel1,' or '.join(['name %s'%i for i in lipid_atoms]))
		sel2 = '(%s) and (%s)'%(sel2,' or '.join(['name %s'%i for i in lipid_atoms]))
	selections.append(sel1)
	#---disallow the two lipid coloring schemes to work at the same time
	if lipid_color_specific and lipid_colors:
		raise Exception('incompatible arguments: lipid_color_specific and lipid_colors')
	if lipid_color_specific: view.set_color_cursor(lipid_color_specific)
	if lipid_colors: view.set_color_cursor(lipid_colors[pair['resname_1']])
	view.select(**dictsum({'partner_1':selections[-1],
		'style':'Licorice %.3f 12.000000 12.000000'%licorice_thick,'goodsell':goodsell_lipids},lipid_style,
		{'color_specific':True} if lipid_color_specific or lipid_colors else {}))
	selections.append(sel2)
	if lipid_colors: view.set_color_cursor(lipid_colors[pair['resname_2']])
	view.select(**dictsum({'partner_2':selections[-1],
		'style':'Licorice %.3f 12.000000 12.000000'%licorice_thick,'goodsell':goodsell_lipids},lipid_style,
		{'color_specific':True} if lipid_color_specific or lipid_colors else {}))
	#---show associates
	if associates:
		for assoc_num,assoc in enumerate(associates):
			if lipid_colors: view.set_color_cursor(lipid_colors[assoc['resname']])
			selections.append("(resname %s and resid %s) and not hydrogen"%(assoc['resname'],assoc['resid']))
			view.select(**dictsum({'assoc_%d'%assoc_num:selections[-1],'style':
				'Licorice %.3f 12.000000 12.000000'%licorice_thick,'goodsell':goodsell_lipids},
				{'color_specific':True} if lipid_color_specific or lipid_colors else {}))
	#---for each hydrogen bond, show the lipids with the hydrogen (both are plotted to include the bond)
	if lipid_color_specific:
		view.set_color_cursor(lipid_color_specific)
	this_style = dictsum({'style':'Licorice %.3f 12.000000 12.000000'%licorice_thick,
		'goodsell':goodsell_lipids},lipid_style,{'color_specific':True} if lipid_color_specific else {})
	for hnum,hbond in enumerate(hydrogen_bonds):
		#---the first residue in the pair is the donor and we draw it here
		selstring = "(resname %s and resid %s)"%(hbond['resname_1'],hbond['resid_1'])
		if lipid_atoms is not None: 
			selstring = '(%s) and (%s)'%(selstring,' or '.join(['name %s'%i for i in lipid_atoms]))
		selections.append('(%s and not hydrogen) or (%s and name %s)'%(selstring,selstring,hbond['name_h']))
		select_args = dict(**{'partner_1_hbond_%d'%hnum:selections[-1]})
		select_args.update(**this_style)
		view.select(**select_args)
		#---also set the endpoints for the bond itself
		#---! currently set for heavy-heavy dashed line below
		#view.select(**{'partner_1_hbond_%d_ref'%hnum:'(%s and name %s)'%(selstring,hbond['name_h'])})
		view.command('set partner_1_hbond_%d_ref [atomselect top "%s"]'%(
			hnum,'(%s and name %s)'%(selstring,hbond['name_1'])))
		#---draw the other lipid
		selstring = "(resname %s and resid %s)"%(hbond['resname_2'],hbond['resid_2'])
		if lipid_atoms is not None: 
			selstring = '(%s) and (%s)'%(selstring,' or '.join(['name %s'%i for i in lipid_atoms]))
		selections.append('(%s and not hydrogen)'%selstring)
		select_args = dict(**{'partner_2_hbond_%d'%hnum:selections[-1]})
		select_args.update(**this_style)
		view.select(**select_args)
		view.command('set partner_2_hbond_%d_ref [atomselect top "%s"]'%(
			hnum,'(%s and name %s)'%(selstring,hbond['name_2'])))
	#---set the selections
	#---! debugging this now
	view.command('set me [atomselect top "%s"]'%' or '.join(['(%s)'%i for i in selections[:2]]))
	#---removed the VMD HBonds call because it is too permissive (allows too many atom types)
	#---set selections for the vmd_render_good_side_bond method over a bond (or at least two points)
	#---we could use representative points like "C14" or "P" but the conformations are too dynamic
	for resid_ind in [1,2]:
		view.command("set %s [atomselect top \"(resname %s and resid %s and name %s)\"]"%(
			'partner_%d_bead'%resid_ind,pair['resname_%d'%resid_ind],
			pair['resid_%d'%resid_ind],pair['name_%d'%resid_ind]))
	#---show the good side
	view.command(vmd_render_good_side_bond)
	#---see vmdmake.py for vmd colors
	cation = work.meta[sn].get('cation_relevant',work.meta[sn]['cation'])
	#---trying to fix color
	#---previously used the special_ion_color when show_water but reverting to original colors for v15
	if lipid_colors or (show_water and False): view.set_color_cursor(special_ion_color)
	elif show_water: view.set_color_cursor({'MG':'red','Cal':'blue'}.get(cation,'purple'))
	else: view.set_color_cursor({'MG':'pink','Cal':'blue','NA':'green','K':'tan'}.get(cation,'purple'))
	#---show ions near both residues
	for resid_ind in [1,2]:
		view.select(**{'near_ions_%d'%resid_ind:
			"name %s and within 4.6 of (resname %s and resid %s)"%(
			cation,work.meta[sn]['ptdins_resname'],pair['resid_%d'%resid_ind]),
			'smooth':False,'style':'VDW 0.4 12.0','goodsell':goodsell_ions,'color_specific':True})
	#---option to show waters near the ions
	if show_water:
		if show_water.get('distance_color',False):
			for resid_ind in [1,2]:
				view.command('set pivots [atomselect top "[$near_ions_%d text]"]'%resid_ind)
				view.command(custom_water_coloring)
		#---deprecated method which passed the show water dictionary through to the view select
		elif show_water.get('deprecated_method',False):
			#---! this representation HAS MAJOR PROBLEMS. cg_bonds.tcl can be used to fix the extralong bonds
			#---! ...in PIP2 but it erases the bonds with water. we always just use the VDW representation
			#---! ...with large spheres. enormous amount of wasted time trying to fix this annoying bug.
			#---! ...need to get some kind of way of loading the TPR natively in VMD
			for resid_ind in [1,2]:
				view.select(**dictsum({'near_water_near_ions_%d'%resid_ind:
					"same residue as (water and within 3.0 of "+
						"(name %s and within 4.6 of (resname %s and resid %s)))"%(
					cation,work.meta[sn]['ptdins_resname'],pair['resid_%d'%resid_ind]),
					'smooth':False,'style':'licorice','goodsell':True},show_water))
		#---note that version 8 used normal water coloring but the other colors were not quite right
		#---...while version 14 colored waters by distance but probably went out too far
		#---deprecated method 
		elif show_water.get('hydration_shell',False):
			for resid_ind in [1,2]:
				view.select(**{'near_water_near_ions_%d'%resid_ind:
					"same residue as (water and within 3.05 of "+
						"(name %s and within 4.6 of (resname %s and resid %s)))"%(
					cation,work.meta[sn]['ptdins_resname'],pair['resid_%d'%resid_ind]),
					'smooth':False,'style':'licorice','goodsell':True})
		else: raise Exception('no valid show_water methods')
	#---emphasize the hydrogen bonds
	for hnum,hbond in enumerate(hydrogen_bonds):
		if hbond_style=='cylinder':
			if not show_water: view.command('draw color black')
			#---changed cylinder from silver to cyan for v15
			else: view.command('draw color iceblue')
			view.command(("draw cylinder [expr [$partner_1_hbond_%d_ref get {x y z}]] "+
				"[expr [$partner_2_hbond_%d_ref get {x y z}]] radius %.3f")%(
				hnum,hnum,hbond_cylinder_radius))
		elif hbond_style=='dashed':
			view.command(("draw line [expr [$partner_1_hbond_%d_ref get {x y z}]] "+
				"[expr [$partner_2_hbond_%d_ref get {x y z}]] style dashed")%(hnum,hnum))
		else: raise Exception('unclear hydrogen bond style %s'%hbond_style)
	#---render to disk
	view['snapshot_filename'] = snapshot_fn
	view.do('snapshot')
	view.show(quit=True)
	'legend_loc':'upper right','fs_legend':14,'legend_color_strength':0.5,
	'label_color_strength':1.0,'fs_legend_title':20,
	'binary_color_intensity':0.5,'time_tick_interval':20,
	'fs_xticks':11,'fs_yticks':6,'fs_xticks_bars':6}
plotspec_small = {'fs_legend_title':14,'fs_legend':12,'fs_xticks':12,'fs_yticks':8}
#---define salt bridges
valid_salt_bridges = [
	{'resname':'ARG','atoms':['NH1','NH2']},
	{'resname':'LYS','atoms':['NZ']},
	{'resname':'HIS','atoms':['ND1','NE2']},]
#---special subselections
special_protein_parts = {'nwaspbilayernochl':np.arange(0,22+1).astype(int)}

#---which combinations of simulations to plot, and how to name them 
specs = {
	'all':{'plotspec':dictsum(plotspec,dict(figsize=(8,16),fs_ylabel=10))},
	'mDia2':{'lipid_resnames':['DOPS','PI2P'],'tag':'.PS_PIP2',
		'sns':['mdia2bilayer_nochl2','mdia2bilayerphys'],
		'plotspec':dictsum(plotspec_small,dict(figsize=(8,8),fs_ylabel=10))},
	'gelsolin':{'lipid_resnames':['DOPS','PI2P'],'tag':'.PS_PIP2',
		'sns':['gelbilayer_nochl','gelbilayerphys'],
		'plotspec':dictsum(plotspec_small,dict(figsize=(8,8),fs_ylabel=10))},
	'nwasp':{'lipid_resnames':['DOPS','PI2P'],'tag':'.PS_PIP2',
		'sns':['nwasppeptide2','nwaspbilayermut1','nwaspbilayernochl','nwasppeptideb'],
		'plotspec':dictsum(plotspec_small,dict(figsize=(8,14),fs_ylabel=10))},}
#---which types of data to plot
bond_mappings = [
	#{'name':'explicit','post_key':'counts_resid_resname','upstream':'contacts'},
	#{'name':'reduced','post_key':'counts_resid_resname_singleton','upstream':'contacts'},
	#{'name':'hbonds','post_key':'hbonds_compacted','upstream':'hbonds'},
	{'name':'salt','post_key':'salt_compacted','upstream':'contacts'},]
 #---get the tpr from the raw data
 tpr = work.raw.get_last(sn, subtype='tpr')
 view = vmdmake.VMDWrap(site=work.paths['post_plot_spot'],
                        gro=gro,
                        xtc=xtc,
                        tpr=tpr,
                        frames='',
                        res=(4000, 4000))
 view['snapshot_filename'] = vmd_fn
 view.do('load_dynamic', 'standard', 'bonder')
 view.command("animate goto %d" % (frame))
 resname = work.meta[sn]['ptdins_resname']
 select = {'ptdins': 'resname %s and not hydrogen' % resname}
 if do_ptdins_color:
     view.set_color_cursor(lipid_colors[resname])
     view.select(**dictsum(select, lipid_style, {'color_specific': True}))
 else:
     view.select(**dictsum(select, lipid_style))
 #---show other lipids in their respective colors
 for resname in [
         i for i in lipid_colors
         if i not in work.vars['selectors']['resnames_PIP2']
 ]:
     select = {'res_%s' % resname: 'resname %s and not hydrogen' % resname}
     view.set_color_cursor(lipid_colors[resname])
     view.select(**dictsum(select, lipid_style, {'color_specific': True}))
 #---show the ions
 all_lipids = ' or '.join(['resname %s' % r for r in lipid_colors.keys()])
 view.set_color_cursor(cation_color)
 select = {
     'cation':