diff --git a/gstlal-inspiral/bin/gstlal_inspiral_plot_background b/gstlal-inspiral/bin/gstlal_inspiral_plot_background
index d0666d96c94a7a5531c62c525dbc9f8c06d13daf..c8e02429cc1c49eff9d0e7b9a25b5fe39a8315c6 100755
--- a/gstlal-inspiral/bin/gstlal_inspiral_plot_background
+++ b/gstlal-inspiral/bin/gstlal_inspiral_plot_background
@@ -48,7 +48,6 @@ from optparse import OptionParser
 import os
 import sqlite3
 import sys
-from tqdm import tqdm
 
 
 from ligo.lw import dbtables
@@ -195,31 +194,13 @@ def parse_command_line():
 #
 
 
-def load_distributions(filenames, verbose = False):
-	# RankingStat objects go into a dictionary indexed by the template
-	# bank ID set they are for, with RankinStat objects for the same
-	# templates being summed.  RankingStatPDF objects are summed (and
-	# therefore are required to be fore the same templates).  these
-	# organizational choices reflect the current use cases for this
-	# program
-	rankingstats = {}
-	rankingstatpdf = None
-	for n, filename in enumerate(filenames, 1):
-		if verbose:
-			print("%d/%d:" % (n, len(filenames)), file=sys.stderr)
-		this_rankingstat, this_rankingstatpdf = far.parse_likelihood_control_doc(far.ligolw_utils.load_filename(filename, verbose = verbose, contenthandler = far.RankingStat.LIGOLWContentHandler))
-		if this_rankingstat is not None:
-			template_ids = this_rankingstat.template_ids
-			if template_ids in rankingstats:
-				rankingstats[template_ids] += this_rankingstat
-			else:
-				rankingstats[template_ids] = this_rankingstat
-		if this_rankingstatpdf is not None:
-			if rankingstatpdf is None:
-				rankingstatpdf = this_rankingstatpdf
-			else:
-				rankingstatpdf += this_rankingstatpdf
-	for rankingstat in tqdm(rankingstats.values(), desc = "Density estimation", disable = not verbose):
+def load_distributions(filename, verbose = False):
+	# Summing up RankingStat objects and RankingStatPDF objects for
+	# the same template bank ID set is no longer done. It is assumed
+	# that the files given as input correspond to different SVD bins,
+	# otherwise their plots will have the same filenames.
+	rankingstat, rankingstatpdf = far.parse_likelihood_control_doc(far.ligolw_utils.load_filename(filename, verbose = verbose, contenthandler = far.RankingStat.LIGOLWContentHandler))
+	if rankingstat is not None:
 		if options.add_zerolag_to_background:
 			rankingstat.denominator.lnzerolagdensity = rankingstat.zerolag
 		rankingstat.finish()
@@ -228,13 +209,12 @@ def load_distributions(filenames, verbose = False):
 	seg = (0, 0)
 	if rankingstatpdf is not None:
 		seg = rankingstatpdf.segments.extent()
-	elif rankingstats:
-		rankingstat = list(rankingstats.values())[0]
+	elif rankingstat:
 		try:
 			seg = rankingstat.segmentlists.extent_all()
 		except ValueError:
 			pass
-	return rankingstats, rankingstatpdf, seg
+	return rankingstat, rankingstatpdf, seg
 
 
 def load_search_results(filenames, tmp_path = None, verbose = False):
@@ -337,14 +317,6 @@ options, filenames = parse_command_line()
 os.makedirs(options.output_dir, exist_ok=True)
 
 
-#
-# load input
-#
-
-
-rankingstats, rankingstatpdf, seg = load_distributions(filenames, verbose = options.verbose)
-
-
 if options.database:
 	timeslide_ln_lr, zerolag_ln_lr, timeslide_sngls, zerolag_sngls = load_search_results(options.database, tmp_path = options.tmp_space, verbose = options.verbose)
 	if options.scatter_log_lambdas is not None:
@@ -360,71 +332,78 @@ else:
 #
 
 
-for bin_index, rankingstat in enumerate(sorted(rankingstats.values(), key = lambda rankingstat: sorted(rankingstat.template_ids))):
-	# SNR and \chi^2
-	for instrument in rankingstat.instruments:
-		for snr_chi_type in ("background_pdf", "injection_pdf", "zero_lag_pdf", "LR"):
-			if instrument in options.event_snr_dict.keys():
-				fig = plotfar.plot_snr_chi_pdf(rankingstat, instrument, snr_chi_type, options.max_snr, sngls = sngls, event_snr = options.event_snr_dict[instrument], event_chisq = options.event_chisq_dict[instrument], event_bank_chisq = options.event_bank_chisq_dict[instrument])
-			else:
-				fig = plotfar.plot_snr_chi_pdf(rankingstat, instrument, snr_chi_type, options.max_snr, sngls = sngls)
-			if fig is None:
-				continue
-			plotname = datafind.T050017_filename(instrument, "GSTLAL_INSPIRAL_PLOT_BACKGROUND_%s_%04d_%s_SNRCHI2" % (options.user_tag, bin_index, snr_chi_type.upper()), seg, options.output_format, path = options.output_dir)
-			if options.verbose:
-				print("writing %s" % plotname, file=sys.stderr)
-			fig.savefig(plotname)
+for num, filename in enumerate(filenames):
+	if verbose:
+		print("%d/%d:" % (num, len(filenames)), file=sys.stderr)
+	rankingstat, rankingstatpdf, seg = load_distributions(filename, verbose = options.verbose)
+
+	if rankingstat is not None:
+		# FIXME bin index is inferred from filename
+		# instead, store bin_index in rankingstat object and load here
+		bin_index = int(filename.split('-')[1][:4])
 
-	# candidate rates
-	fig = plotfar.plot_rates(rankingstat)
-	plotname = datafind.T050017_filename("H1L1V1", "GSTLAL_INSPIRAL_PLOT_BACKGROUND_%s_%04d_RATES" % (options.user_tag, bin_index), seg, options.output_format, path = options.output_dir)
-	if options.verbose:
-		print("writing %s" % plotname, file=sys.stderr)
-	fig.savefig(plotname)
-
-
-# SNR PDFs
-if options.plot_snr_snr_pdfs:
-	# assume PDFs are identical for all template bank bins, and pick
-	# one set to plot
-	rankingstat = list(rankingstats.values())[0]
-	for (instruments, horizon_distances) in sorted(rankingstat.numerator.SNRPDF.snr_joint_pdf_cache.keys(), key = lambda x: sorted(x[1])):
-		# they're stored as a frozen set of quantized key/value
-		# pairs, need to unquantize them and get a dictionary back
-		horizon_distances = rankingstat.numerator.SNRPDF.quantized_horizon_distances(horizon_distances)
-		fig = plotfar.plot_snr_joint_pdf(rankingstat.numerator.SNRPDF, instruments, horizon_distances, rankingstat.min_instruments, options.max_snr, sngls = sngls)
-		if fig is not None:
-			plotname = datafind.T050017_filename(instruments, "GSTLAL_INSPIRAL_PLOT_BACKGROUND_%s_SNR_PDF_%s" % (options.user_tag, "_".join(["%s_%s" % (k, horizon_distances[k]) for k in sorted(horizon_distances)]) ), seg, options.output_format, path = options.output_dir)
+		# SNR and \chi^2
+		for instrument in rankingstat.instruments:
+			for snr_chi_type in ("background_pdf", "injection_pdf", "zero_lag_pdf", "LR"):
+				if instrument in options.event_snr_dict.keys():
+					fig = plotfar.plot_snr_chi_pdf(rankingstat, instrument, snr_chi_type, options.max_snr, sngls = sngls, event_snr = options.event_snr_dict[instrument], event_chisq = options.event_chisq_dict[instrument], event_bank_chisq = options.event_bank_chisq_dict[instrument])
+				else:
+					fig = plotfar.plot_snr_chi_pdf(rankingstat, instrument, snr_chi_type, options.max_snr, sngls = sngls)
+				if fig is None:
+					continue
+				plotname = datafind.T050017_filename(instrument, "GSTLAL_INSPIRAL_PLOT_BACKGROUND_%s_%04d_%s_SNRCHI2" % (options.user_tag, bin_index, snr_chi_type.upper()), seg, options.output_format, path = options.output_dir)
+				if options.verbose:
+					print("writing %s" % plotname, file=sys.stderr)
+				fig.savefig(plotname)
+
+		# candidate rates
+		fig = plotfar.plot_rates(rankingstat)
+		plotname = datafind.T050017_filename("H1L1V1", "GSTLAL_INSPIRAL_PLOT_BACKGROUND_%s_%04d_RATES" % (options.user_tag, bin_index), seg, options.output_format, path = options.output_dir)
+		if options.verbose:
+			print("writing %s" % plotname, file=sys.stderr)
+		fig.savefig(plotname)
+
+		# SNR PDFs
+		if options.plot_snr_snr_pdfs:
+			# assume PDFs are identical for all template bank bins, and plot
+			# only the first one
+			if num == 0:
+				for (instruments, horizon_distances) in sorted(rankingstat.numerator.SNRPDF.snr_joint_pdf_cache.keys(), key = lambda x: sorted(x[1])):
+					# they're stored as a frozen set of quantized key/value
+					# pairs, need to unquantize them and get a dictionary back
+					horizon_distances = rankingstat.numerator.SNRPDF.quantized_horizon_distances(horizon_distances)
+					fig = plotfar.plot_snr_joint_pdf(rankingstat.numerator.SNRPDF, instruments, horizon_distances, rankingstat.min_instruments, options.max_snr, sngls = sngls)
+					if fig is not None:
+						plotname = datafind.T050017_filename(instruments, "GSTLAL_INSPIRAL_PLOT_BACKGROUND_%s_SNR_PDF_%s" % (options.user_tag, "_".join(["%s_%s" % (k, horizon_distances[k]) for k in sorted(horizon_distances)]) ), seg, options.output_format, path = options.output_dir)
+						if options.verbose:
+							print("writing %s" % plotname, file=sys.stderr)
+						fig.savefig(plotname)
+
+	# ranking statistic PDFs and CCDFs
+	if rankingstatpdf is not None:
+		for Title, which, NAME in (("Noise", "noise", "NOISE"), ("Signal", "signal", "SIGNAL")):
+			fig = plotfar.plot_likelihood_ratio_pdf(rankingstatpdf, (options.min_log_lambda, options.max_log_lambda), Title, which = which)
+			plotname = datafind.T050017_filename("COMBINED", "GSTLAL_INSPIRAL_PLOT_BACKGROUND_%s_%s_LIKELIHOOD_RATIO_PDF" % (options.user_tag, NAME), seg, options.output_format, path = options.output_dir)
 			if options.verbose:
 				print("writing %s" % plotname, file=sys.stderr)
 			fig.savefig(plotname)
 
-
-# ranking statistic PDFs and CCDFs
-if rankingstatpdf is not None:
-	for Title, which, NAME in (("Noise", "noise", "NOISE"), ("Signal", "signal", "SIGNAL")):
-		fig = plotfar.plot_likelihood_ratio_pdf(rankingstatpdf, (options.min_log_lambda, options.max_log_lambda), Title, which = which)
-		plotname = datafind.T050017_filename("COMBINED", "GSTLAL_INSPIRAL_PLOT_BACKGROUND_%s_%s_LIKELIHOOD_RATIO_PDF" % (options.user_tag, NAME), seg, options.output_format, path = options.output_dir)
+	if rankingstatpdf is not None and rankingstatpdf.zero_lag_lr_lnpdf.array.any():
+		fapfar = far.FAPFAR(rankingstatpdf.new_with_extinction())
+		if zerolag_ln_lr is not None:
+			xhi = max(zerolag_ln_lr + timeslide_ln_lr)[0]
+			xhi = 5. * math.ceil(xhi / 5.)
+			xhi = max(xhi, options.max_log_lambda)
+		else:
+			xhi = options.max_log_lambda
+		fig = plotfar.plot_likelihood_ratio_ccdf(fapfar, (options.min_log_lambda, xhi), observed_ln_likelihood_ratios = zerolag_ln_lr, is_open_box = True)
+		plotname = datafind.T050017_filename("COMBINED", "GSTLAL_INSPIRAL_PLOT_BACKGROUND_%s_NOISE_LIKELIHOOD_RATIO_CCDF_OPEN_BOX" % options.user_tag, seg, options.output_format, path = options.output_dir)
 		if options.verbose:
 			print("writing %s" % plotname, file=sys.stderr)
 		fig.savefig(plotname)
 
-if rankingstatpdf is not None and rankingstatpdf.zero_lag_lr_lnpdf.array.any():
-	fapfar = far.FAPFAR(rankingstatpdf.new_with_extinction())
-	if zerolag_ln_lr is not None:
-		xhi = max(zerolag_ln_lr + timeslide_ln_lr)[0]
-		xhi = 5. * math.ceil(xhi / 5.)
-		xhi = max(xhi, options.max_log_lambda)
-	else:
-		xhi = options.max_log_lambda
-	fig = plotfar.plot_likelihood_ratio_ccdf(fapfar, (options.min_log_lambda, xhi), observed_ln_likelihood_ratios = zerolag_ln_lr, is_open_box = True)
-	plotname = datafind.T050017_filename("COMBINED", "GSTLAL_INSPIRAL_PLOT_BACKGROUND_%s_NOISE_LIKELIHOOD_RATIO_CCDF_OPEN_BOX" % options.user_tag, seg, options.output_format, path = options.output_dir)
-	if options.verbose:
-		print("writing %s" % plotname, file=sys.stderr)
-	fig.savefig(plotname)
-
-	fig = plotfar.plot_likelihood_ratio_ccdf(fapfar, (options.min_log_lambda, xhi), observed_ln_likelihood_ratios = timeslide_ln_lr, is_open_box = False)
-	plotname = datafind.T050017_filename("COMBINED", "GSTLAL_INSPIRAL_PLOT_BACKGROUND_%s_NOISE_LIKELIHOOD_RATIO_CCDF_CLOSED_BOX" % options.user_tag, seg, options.output_format, path = options.output_dir)
-	if options.verbose:
-		print("writing %s" % plotname, file=sys.stderr)
-	fig.savefig(plotname)
+		fig = plotfar.plot_likelihood_ratio_ccdf(fapfar, (options.min_log_lambda, xhi), observed_ln_likelihood_ratios = timeslide_ln_lr, is_open_box = False)
+		plotname = datafind.T050017_filename("COMBINED", "GSTLAL_INSPIRAL_PLOT_BACKGROUND_%s_NOISE_LIKELIHOOD_RATIO_CCDF_CLOSED_BOX" % options.user_tag, seg, options.output_format, path = options.output_dir)
+		if options.verbose:
+			print("writing %s" % plotname, file=sys.stderr)
+		fig.savefig(plotname)