Number formatting in Reports (Ignition 8.1.2)

Here's an entirely self contained example, though I'd recommend making some changes for "production" use (detailed below):
report_localization.zip (12.9 KB)

In this case I'm just using the "static CSV" input type for simplicity. Everything that matters happens in the script data source:
First, I'm defining this function. This is slightly modified from my example posted here; all it does is update an entire column of a dataset in one operation, calling the provided function parameter on each value in the column. The modification was giving it the ability to override the column type, since you're going from numbers to strings. In production, you should move this into the project library so you can call it from anywhere in your project.

def mapColumn(function, dataset, column, columnType=None):
	if isinstance(column, basestring):
		column = dataset.getColumnIndex(column)

	columnData = map(function, dataset.getColumnAsList(column))
	columnsToKeep = range(dataset.columnCount)
	columnsToKeep.pop(column)
	dsWithoutColumn = system.dataset.filterColumns(dataset, columnsToKeep)
	
	return system.dataset.addColumn(
		dsWithoutColumn, 
		column, 
		columnData, 
		dataset.getColumnName(column), 
		columnType or dataset.getColumnType(column)
	)

Then I'm defining a function to actually do the localization of a number into currency format in the provided locale. I'm leaning on Java's built in number formatting for this. Again, this should be defined in the project library, but for simplicity I put it all in one place. The locale you pass in should be a language tag string, like "de_DE" for German (Germany) or "en_US" for English (United States), etc.

from java.text import NumberFormat
from com.inductiveautomation.ignition.common.i18n import LocaleUtils

def localizeNumber(number, locale):
	locale = LocaleUtils.parseLocale(locale).orElseThrow()
	nf = NumberFormat.getCurrencyInstance(locale)
	return nf.format(number)

Finally, the piece that actually does anything with the report.
The function definition is just used to provide a default value to the general purpose localizeNumber function. You could also use functools.partial or a lambda expression for this. The key is to take a function that accepts two arguments and return a function that accepts one argument, because that's what mapColumn is expecting.

Then, that new function is applied to the two numeric columns in the static_data dataset, turning them into strings. Then that new dataset is output as a new data key. The overall concept of what we're doing is covered here.

def localizeToGerman(number):
	return localizeNumber(number, "de_DE")

ds = data["static_data"]
ds = mapColumn(localizeToGerman, ds, "Column2", columnType = str)
ds = mapColumn(localizeToGerman, ds, "Column3", columnType = str)

data["localized"] = ds

The end result is something like this, where the top table is the original data, and the bottom table is the localized presentation:
image

2 Likes