diff --git a/beat/web/reports/static/reports/app/directives/edit/plotItem.js b/beat/web/reports/static/reports/app/directives/edit/plotItem.js
index b545b9b25029bf6deecb6b06e2ef1db2814f7e25..a0cdf0b4f008044feeab2e649043d5ca4274e94b 100644
--- a/beat/web/reports/static/reports/app/directives/edit/plotItem.js
+++ b/beat/web/reports/static/reports/app/directives/edit/plotItem.js
@@ -40,11 +40,19 @@ angular.module('reportApp')
 			// container for the plots applet to insert into
 			scope.renderDivId = `${scope.domId}-render`;
 
+			// the callback for when the plot renders
+			// (called every time the plot re-renders, e.g. user changes config/merged
+			const updatePlotConfig = (selectedPlotter, selectedConfig, isMerged) => {
+				scope.content.merged = isMerged;
+				scope.content.savedPlotter = selectedPlotter;
+				scope.content.savedConfig = selectedConfig;
+			};
+
 			// wait until the container html element is rendered.
 			// angular will run these functions called with $timeout
 			// after everything has been rendered
 			$timeout(function() {
-				PlotService.addPlot(scope.group, scope.itemId, scope.renderDivId);
+				PlotService.addPlot(scope.group, scope.itemId, scope.renderDivId, updatePlotConfig);
 			});
 
 			let plotTimer;
@@ -58,7 +66,7 @@ angular.module('reportApp')
 					// redo the render
 					if(el && el.childNodes.length > 0){
 						el.innerHTML = '';
-						PlotService.addPlot(scope.group, scope.itemId, scope.renderDivId);
+						PlotService.addPlot(scope.group, scope.itemId, scope.renderDivId, updatePlotConfig);
 					}
 				};
 
diff --git a/beat/web/reports/static/reports/app/services/plotService.js b/beat/web/reports/static/reports/app/services/plotService.js
index e03227a6f1dd87738046aa371263fbf42e8ac5bb..bc7d836e7d3011bb8de3ba2b53294ce917044fcf 100644
--- a/beat/web/reports/static/reports/app/services/plotService.js
+++ b/beat/web/reports/static/reports/app/services/plotService.js
@@ -58,10 +58,10 @@ angular.module('reportApp').factory('PlotService', ['UrlService', function(UrlSe
 		}
 
 		// a plot obj can have different plotters,
-		let plotter = content.savedPlotter || plotters.find(p => p.name === defaults.plotter);
+		let plotter = plotters.find(p => p.name === content.savedPlotter) || plotters.find(p => p.name === defaults.plotter);
 
 		// which can each have different configurations (plotter parameter instances)
-		let config = content.savedConfig || plotterParameters.find(pp => pp.name === defaults.parameter);
+		let config = plotterParameters.find(pp => pp.name === content.savedConfig) || plotterParameters.find(pp => pp.name === defaults.parameter);
 
 		if(!content || !defaults || !plotter || !config){
 			console.error(`plotter info not found: content: ${content} defaults: ${defaults} plotter: ${plotter} config: ${config}`);
@@ -127,23 +127,17 @@ angular.module('reportApp').factory('PlotService', ['UrlService', function(UrlSe
 		return returnStruct;
 	};
 
-	// makes the call to the server, via some helper funcs found in the global namespace
-	const fetchRenderUsingStruct = (requestData, containerId) => {
-		// the 'url_prefix' field found throughout the BEAT code is confusing,
-		// but it seems to always be an empty string now
-		const urlPrefix = '';//UrlService.getApiSegment().split('/').filter(s => s.length > 0).join('/');
+	const fetchDownload = (requestData, contentType) => {
+		const urlPrefix = '';
 
-		// promisify this utils func so we dont have to deal with callback hell
 		return new Promise((resolve, reject) => {
-			beat.experiments.utils.displayPlot(
+			beat.experiments.utils.getPlotData(
 				// url_prefix
 				urlPrefix,
-				// element to append render to
-				document.querySelector(`#${containerId}`),
 				// spread out the request data to fill the next 3 spots
 				...requestData,
-				// dont replace inner content
-				false,
+				// content type: png, jpeg, pdf
+				contentType,
 				// callback
 				(...args) => {
 					// resolve promise
@@ -153,18 +147,43 @@ angular.module('reportApp').factory('PlotService', ['UrlService', function(UrlSe
 		});
 	};
 
+	// makes the call to the server, via some helper funcs found in the global namespace
+	const fetchRender = (requestData, containerId, onRenderCallback) => {
+		// the 'url_prefix' field found throughout the BEAT code is confusing,
+		// but it seems to always be an empty string now
+		const urlPrefix = '';//UrlService.getApiSegment().split('/').filter(s => s.length > 0).join('/');
+
+		// promisify this utils func so we dont have to deal with callback hell
+		beat.experiments.utils.displayPlot(
+			// url_prefix
+			urlPrefix,
+			// element to append render to
+			document.querySelector(`#${containerId}`),
+			// spread out the request data to fill the next 3 spots
+			...requestData,
+			// dont replace inner content
+			false,
+			// callback
+			(plotter, config, merged) => {
+				onRenderCallback(plotter, config, merged);
+			}
+		);
+	};
+
 	// helper func to process a request to plot
-	const processItem = (group, itemId, containerId) => {
+	const processItem = (group, itemId, containerId, onRenderCallback) => {
 		const reqData = constructPlotInfo(group, itemId);
-		return fetchRenderUsingStruct(reqData, containerId);
+
+		fetchRender(reqData, containerId, onRenderCallback);
 	};
 
 	// used if we arent ready to directly service requests
-	const addItemToQueue = (group, itemId, containerId) => {
+	const addItemToQueue = (group, itemId, containerId, onRenderCallback) => {
 		queue.push([
 			group,
 			itemId,
-			containerId
+			containerId,
+			onRenderCallback
 		]);
 	};