qiprofile
Version:
Quantitative Imaging Profile ( QiPr) web application
185 lines (172 loc) • 7.18 kB
text/coffeescript
define ['angular', 'lodash', 'modeling', 'chart'], (ng, _) ->
modelingChart = ng.module(
'qiprofile.modelingchart',
['qiprofile.modeling', 'qiprofile.chart']
)
modelingChart.factory(
'ModelingChart',
['Modeling', 'Chart', (Modeling, Chart) ->
# The common modeling X axis specification.
COMMON_CONFIG =
options:
chart:
# @returns the session date
x: (paramResult) ->
paramResult.modelingResult.modeling.session.date
xAxis:
axisLabel: 'Visit Date'
tickFormat: Chart.formatDate
tooltip:
headerEnabled: false
# @returns the modeling parameter result average value
y: (paramResult) ->
paramResult.average
yAxis:
# Don't show a max and min value on the axis.
showMaxMin: true
tooltip:
headerEnabled: false
# @param modelingResults the modeling result REST objects
# to chart
# @returns the Ktrans-specific chart configuration
kTransConfiguration = (modelingResults) ->
options:
chart:
# Show both data series.
type: 'multiBarChart'
# Don't show the group/stack control.
showControls: false
yAxis:
axisLabel: 'Ktrans'
data: [
{
key: Modeling.properties.fxlKTrans.text
color: Modeling.properties.fxlKTrans.color
values: _.map(modelingResults, 'fxlKTrans')
}
{
key: Modeling.properties.fxrKTrans.text
color: Modeling.properties.fxrKTrans.color
values: _.map(modelingResults, 'fxrKTrans')
}
]
# @param modelingResults the modeling result REST objects
# to chart
# @param paramKey the Modeling.properties property to chart,
# e.g. 'vE'
# @returns the modeling parameter chart configuration
singleParameterConfiguration = (modelingResults, paramKey) ->
# The label text and bar color.
dspConf = Modeling.properties[paramKey]
if not dspConf?
throw new ReferenceError("The modeling result parameter is not" +
" supported: #{ paramKey }")
# Return the {options, data} chart configuration.
options:
chart:
# A simple single data series bar chart.
type: 'discreteBarChart'
yAxis:
axisLabel: dspConf.text
data: [
key: dspConf.text
# Pluck the modeling parameter object from each modeling
# result.
color: dspConf.color
values: _.map(modelingResults, paramKey)
]
# @param paramKey the modeling parameter key, either 'kTrans'
# or a Modeling.properties property
# @returns the parameter-specific chart configuration
parameterConfiguration = (modelingResults, paramKey) ->
if paramKey is 'kTrans'
kTransConfiguration(modelingResults)
else
singleParameterConfiguration(modelingResults, paramKey)
# @param paramKey the modeling parameter key
# @param precision the minimum number of decimals to display
# @returns the tooltip HTML content generator function
tooltipGenerator = (paramKey, precision) ->
# The tooltip displays three decimals more than the
# minimum.
valueFormatter = d3.format(".#{ precision + 3 }f")
# The ktrans tooltip shows the FXL, FXR and delta.
kTransTooltipGenerator = ->
propertyFormatter = (modelingResult, property) ->
dspConf = Modeling.properties[property]
# The value to display.
value = modelingResult[property].average
# Return the tooltip HTML.
"<tr>" +
"<td>#{ dspConf.html }:</td>" +
"<td>#{ valueFormatter(value) }</td>" +
"</tr>"
# Return the formatter function.
(obj) ->
# The charting object is the data series object,
# for either the FXL or FXR ktrans. In either case,
# the modeling parameter result is in obj.data,
# which references the parent modeling result.
# The tooltip is the same for both data series,
# and shows the FXL, FXR and delta ktrans in a
# borderless mini-table.
modelingResult = obj.data.modelingResult
props = ['fxlKTrans', 'fxrKTrans', 'deltaKTrans']
rows = (
propertyFormatter(modelingResult, prop) for prop in props
)
"<table>" +
rows.join("\n") +
"</table>"
singleParameterTooltipGenerator = (paramKey) ->
dspConf = Modeling.properties[paramKey]
# Return the formatter function.
(obj) ->
# The value to display.
value = obj.series[0].value
"#{ dspConf.html }: #{ valueFormatter(value) }"
# Return the generator function.
if paramKey is 'kTrans'
kTransTooltipGenerator()
else
singleParameterTooltipGenerator(paramKey)
# Configures the D3 chart with the given format. The format is an
# object in the form {label: string, data: array}
# where the data array has one object per data series in the form
# {label: string, color: color, accessor: (modelingResult) -> body}
#
# @param modelingResults the session modeling results array
# @param property the modeling parameter property, e.g. 'kTrans'
# @returns the nvd3 chart {data, options} configuration
configure: (modelingResults, paramKey) ->
# Start with a copy of the shared configuration.
conf = _.cloneDeep(COMMON_CONFIG)
# The parameter-specific configuration.
paramConf = parameterConfiguration(modelingResults, paramKey)
# Add the parameter-specific settings.
_.merge(conf, paramConf)
# The data set values arrays.
dsValueArrays = (ds.values for ds in conf.data)
# The modeling parameter result objects.
paramResults = _.concat(dsValueArrays...)
# The modeling parameter averages.
values = (paramResult.average for paramResult in paramResults)
# The smallest value precision that captures at least
# one non-zero digit for all non-zero values.
precision = Chart.minPrecision(values)
# The tooltip content generator.
generateTooltip = tooltipGenerator(paramKey, precision)
# The tooltip and Y tick formatter depend on the precision.
mixin =
options:
chart:
yAxis:
tickFormat: d3.format(".#{ precision }f")
tooltip:
contentGenerator: generateTooltip
# Add the additional settings.
_.merge(conf, mixin)
# Return the configuration.
conf
]
)