Vision EZChart Axis Dataset with Cell Update Binding on Row 0 is Actually Using Row 1

This looks like a bug in Vision ezChart.

For an EZChart Axis dataset when I bind using cell update on row 0 to a component like a text box the binding gets bound to row 1 when the axis dataset is loaded from a script.

Is this a bug or am I doing something wrong?

See cell update binding below:

So when I load dataset into the axis property
components that are bound to row 0 actually get bound to row 1
components that are bound to row 1 actually get bound to row 2
etc.

See below:

However, If I put data into the component so it will write a value to the ezChart, all the bindings go to the correct order, that is.
components that are bound to row 0 actually get bound to row 0
components that are bound to row 1 actually get bound to row 1
etc.

I am running Ignition 8.1.12.

Here is the code:

I have a button btn0_PresetLoad with ActionPerformed event handler with this code:

logger = system.util.getLogger("Vision.Components.Button0")
s_logPfx = event.source.name + ".actionPerformed"
logger.trace(s_logPfx + " --->")
#logger.debug(s_logPfx + " --- ")

cmpnt.btn0.onActionPerformed(event)

cntnr_Root = system.gui.getParentWindow(event).getRootContainer()
cntnr_Parent = event.source.parent

dropdL0_Chart = event.source.parent.getComponent("dropdL0_Chart")
i_chart = dropdL0_Chart.selectedValue
ds_chart = dropdL0_Chart.data
pds_chart = system.dataset.toPyDataSet(ds_chart)
s_tmplt = pds_chart[i_chart][2] 

dropdL0_Filter = event.source.parent.getComponent("dropdL0_Filter")
i_filter = dropdL0_Filter.selectedValue
ds_filter = dropdL0_Filter.data
pds_filter = system.dataset.toPyDataSet(ds_filter )

dropdL0_Grp = cntnr_Parent.getComponent("dropdL0_Grp")
i_grp = dropdL0_Grp.selectedValue
s_grp = dropdL0_Grp.selectedStringValue

s_dsktpHandle = system.gui.getCurrentDesktop()
logger.debug(s_logPfx + " --- " + " s_dsktpHandle: " + s_dsktpHandle)

if system.gui.desktop(s_dsktpHandle).confirm("Are you sure you want to load preset %s?" %(s_grp), "Confirm"):
	logger.debug(s_logPfx + " --- " + " loading preset %s begin" %(s_grp))
	
	s_wndwMain = cntnr_Root.CurrentWindow
	logger.debug(s_logPfx + " --- " + " s_wndwMain: " + s_wndwMain)

	try:
		wndw_Main = system.gui.desktop(s_dsktpHandle).getWindow(s_wndwMain)
	except ValueError:
		wndw_Main = None
	
	if wndw_Main is not None:
	
		cntnr_Main_Root = wndw_Main.getRootContainer()
		tmplt = cntnr_Main_Root.getComponent(s_tmplt)
		cntnr_Tmplt_Root = tmplt.getComponent(0)
		
		ezChrt0_ = tmplt.getComponent(0).getComponent("ezChrt0_")
		
		b_error = False
		s_txId = system.db.beginTransaction(timeout=5000)
		
		try:
	
			#Tag Pens
			if i_filter == 0 or i_filter == 1:
				s_tbl = "tbl_chart_tag_pen"
				logger.debug(s_logPfx + " --- " + " s_tbl: " + s_tbl)
				pds_1 = event.source.loadDSfrTable(s_txId, s_tbl, i_grp)
				ds_1 = system.dataset.toDataSet(pds_1)
				ezChrt0_.tagPens = ds_1
		
			
			#DB Pens
			if i_filter == 0 or i_filter == 2:
				s_tbl = "tbl_chart_db_pen"
				pds_1 = event.source.loadDSfrTable(s_txId, s_tbl, i_grp)
				i_rows = len(pds_1)
				ds_1 = system.dataset.toDataSet(pds_1)
				ezChrt0_.pens = ds_1
	
			
			#Calc Pens
			if i_filter == 0 or i_filter == 3:
				s_tbl = "tbl_chart_calc_pen"
				pds_1 = event.source.loadDSfrTable(s_txId, s_tbl, i_grp)
				ds_1 = system.dataset.toDataSet(pds_1)
				ezChrt0_.calcPens = ds_1
			
			
			#Axes
			if i_filter == 0 or i_filter == 4:
				s_tbl = "tbl_chart_axes"
				pds_1 = event.source.loadDSfrTable(s_txId, s_tbl, i_grp)
				ds_1 = system.dataset.toDataSet(pds_1)
				ezChrt0_.axes = ds_1
		
				ds_axes = ds_1
				for r in range(ds_axes.getRowCount()):
					cntrn0_VAxis = cntnr_Tmplt_Root.getComponent("cntnr0_0Main").getComponent("cntnr0_VAxis" + str(r))
					if cntrn0_VAxis is not None:
		
						b_auto_range = ds_axes.getValueAt(r, "auto_range")
						mSBtn0_Axis_Auto = cntrn0_VAxis.getComponent("mSBtn0_Axis_Auto")
						if mSBtn0_Axis_Auto is not None:
							mSBtn0_Axis_Auto.controlValue = b_auto_range
						
						f_lower_bound = ds_axes.getValueAt(r, "lower_bound")
						nTFld0_Axis_Min = cntrn0_VAxis.getComponent("nTFld0_Axis_Min")
						if nTFld0_Axis_Min is not None:
							nTFld0_Axis_Min.floatValue = f_lower_bound
		
						f_upper_bound = ds_axes.getValueAt(r, "upper_bound")
						nTFld0_Axis_Max = cntrn0_VAxis.getComponent("nTFld0_Axis_Max")
						if nTFld0_Axis_Max is not None:
							nTFld0_Axis_Max.floatValue = f_upper_bound

			
			#SubPlots
			if i_filter == 0 or i_filter == 5:
				s_tbl = "tbl_chart_subplot"
				pds_1 = event.source.loadDSfrTable(s_txId, s_tbl, i_grp)
				ds_1 = system.dataset.toDataSet(pds_1)
				ezChrt0_.subplots = ds_1
	
		except:
			raise
			b_error = True
			
		if b_error:
			#Error encountered, rollback the transaction
			system.db.rollbackTransaction(s_txId)
			logger.debug(s_logPfx + " --- " + " loading preset %s cancelled" %(s_grp))

		else:
			#No Error encountered, commit the transaction
			system.db.commitTransaction(s_txId)
			logger.debug(s_logPfx + " --- " + " loaded preset %s completed" %(s_grp))

			tmplt = wndw_Main.rootContainer.getComponent(s_tmplt)
			if wndw_Main is not None:
				tFld0_Title1 = tmplt.getComponent(0).getComponent("cntnr0_0Main").getComponent("tFld0_Title1")
				if tFld0_Title1 is not None:
					tFld0_Title1.text = "Preset " + s_grp

		# In either case, close the transaction when we're done.
		system.db.closeTransaction(s_txId)
	else:
		logger.debug(s_logPfx + " --- " + "  loading preset %s cancelled" %(s_grp))


logger.trace(s_logPfx + "<--- ")

The important part of actionPerformed event handler is:

 ...
		#Axes
		if i_filter == 0 or i_filter == 4:
			s_tbl = "tbl_chart_axes"
			pds_1 = event.source.loadDSfrTable(s_txId, s_tbl, i_grp)
			ds_1 = system.dataset.toDataSet(pds_1)
			ezChrt0_.axes = ds_1
..
		

The button has this custom method

def loadDSfrTable(self, x_txId, s_tbl, i_grp)
	"""
	Arguments:
	    self: A reference to the component instance this method is involed on. This arguement
	      is automatic and should not be specified when invoking this method.
	"""
	logger = system.util.getLogger("Vision.Components.Button0")
	s_logPfx = self.name + ".loadDSfrTable"
	logger.trace(s_logPfx + " --->")
	#logger.debug(s_logPfx + " --- ")

	ary_col_MD_map = database.get_DS_DB_map(s_tbl)


	s_sql_header = dataset.pyDataSetToStrForSelQryHeader(ary_col_MD_map)

	s_sql = "SELECT %s FROM %s WHERE grp_id = %d ORDER BY ds_ord" %(s_sql_header, s_tbl, i_grp)
	logger.debug(s_logPfx + " ---" + " s_sql: " + s_sql)
	

	pds_1 = system.db.runQuery(s_sql)
	i_rows = len(pds_1)
	logger.debug(s_logPfx + " ---" + " i_rows: " + str(i_rows))

	
	logger.trace(s_logPfx + "<--- ")
	return pds_1
	

Any help appreciated.

-Mark

It is not a bug. It is an error in my code.
The index in my for loop was off by 1.

I replaced the following lines

			#Axes
			if i_filter == 0 or i_filter == 4:
				s_tbl = "tbl_chart_axes"
				pds_1 = event.source.loadDSfrTable(s_txId, s_tbl, i_grp)
				ds_1 = system.dataset.toDataSet(pds_1)
				ezChrt0_.axes = ds_1
		
				ds_axes = ds_1
				for r in range(ds_axes.getRowCount()):
					cntrn0_VAxis = cntnr_Tmplt_Root.getComponent("cntnr0_0Main").getComponent("cntnr0_VAxis" + str(r))
					if cntrn0_VAxis is not None:

with these lines.
Note the ds_axes.getRowCount()-1 and str(r+1) in the for loop.

			#Axes
			if i_filter == 0 or i_filter == 4:
				s_tbl = "tbl_chart_axes"
				pds_1 = event.source.loadDSfrTable(s_txId, s_tbl, i_grp)
				ds_1 = system.dataset.toDataSet(pds_1)
				ezChrt0_.axes = ds_1
		
				ds_axes = ds_1
				for r in range(ds_axes.getRowCount()-1):
					cntrn0_VAxis = cntnr_Tmplt_Root.getComponent("cntnr0_0Main").getComponent("cntnr0_VAxis" + str(r+1))
					if cntrn0_VAxis is not None:

-Mark

I’m surprised it worked at all. I’ve never seen anything to suggest cell update bindings should work when you script a dataset change underneath them.

Yeah, I wasn’t sure if it would work, but its working for now. Hopefully that continues.