Closed ali4006 closed 3 years ago
You can't with the current version. Happy to consider for a future release. However, what should the software do if the an input value is negative? I like to have software that has universally defined behavior. You can always transform your data prior to loading it into Surfice or MRIcroGL (e.g. by definition, all MRI magnitude data is positive).
You can set the scale to symmetric log scale just like the 'symlog' scale in matplotlib which handles negative values.
It seems symlog is based on this idea, with a Matlab implementation here. The challenge is choosing the scaling constant C
. Is there a clear consensus about this?
@pauldmccarthy FSLeyes appears to set all values less than or equal to zero to zero when the user Overlay display scaling
to logarithmic scaling
(natural log) and log10 plot views. Are you happy with this solution? Perhaps @hanayik has some thoughts on this.
Hi @neurolabusc, yes - I take the easy route in FSLeyes - any voxel for which log(value)
evaluates to NaN
is coloured with the lowest colour in the selected colour map (e.g. black, when greyscale is selected). The reason that this happens is that I do not actually log-transform the data - instead, I log transform the colour map itself, so that the mapping from voxel value to colour is as if the value had been log-transformed: https://github.com/pauldmccarthy/fsleyes/blob/master/fsleyes/gl/textures/colourmaptexture.py#L254-L261
I suppose that a more sensible option is to hide/clip those voxels, but I only added this feature as a convenience for a couple of people in FMRIB - it's not really intended for viewing images which contain negative values.
In the plotting views, any values that evaluate to NaN
are not plotted, so a discontinuous line will be plotted.
@pauldmccarthy your approach is sensible. While the symlog
solution is nice for a plot where the spacing near zero is known when generating a plot, it seems unwieldy for continuous data in an overlay, where choosing C
seems treacherous.
@neurolabusc One point which I forgot to mention - in FSLeyes, it is possible to combine the negative colour map and the logarithmic scaling options, so that negative values are also log-scaled.
Edit: this may not actually be working correctly at the moment :)
@neurolabusc following the previous question, I just realized that the tool plots NaN
values as zero. Is that possible to just leave NaN
values transparent there?
The overlay scale I'm using ranges from -3 to 3 including zero values. I don't want to show NaN
values on the overlay. Thanks.
Can you email me (email in my avatar) a link to your sample overlay (e.g. Google Drive or DropBox)?
Neither MRIcroGL or Surfice transform NIfTI images that have NIFTI_INTENT_LOGPVAL
or NIFTI_INTENT_LOG10PVAL
intent code. However, these values seem extremely rare in the wold. Further, it seems that in these cases many users may want to visualize the log values.
For general storage of log values in NIfTI images, it seems like log(x) (aka ln()), log(x,2), and log(x,10) might be the more likely base values.
Given this variability, my own suggestion would be for users to use simple Python scripts to transform their data into the preferred representation. For example, the snippet below takes log10 data and transforms it to z-scores (where input is expected to be in the range weminus infinity to zero, corresponding to a probability of zero to one).
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#Example usage
# ./logToZ.py f.nii.gz
import nibabel as nib
import numpy as np
import scipy.stats as st
import os
import sys
def log10t(fnm):
niiLog = nib.load(fnm)
img = niiLog.get_fdata()
str = f'Input intensity range {np.nanmin(img)}..{np.nanmax(img)}'
print(str)
str = f'Image shape {img.shape[1]}x{img.shape[1]}x{img.shape[1]}'
print(str)
#https://stackoverflow.com/questions/51669367/how-to-get-the-inverse-of-a-log10-value-in-python
#inverse log 10
img = 10 ** img
img = st.norm.ppf(img)
nii = nib.Nifti1Image(img, niiLog.affine, niiLog.header)
#set NIFTI_INTENT_ZSCORE (5)
nii.header['intent_code'] = 5
nii.header['scl_slope'] = 1.0
nii.header['scl_inter'] = 0.0
nii.header['cal_max'] = 0.0
nii.header['cal_min'] = 0.0
pth, nm = os.path.split(fnm)
if not pth:
pth = '.'
outnm = pth + os.path.sep + 'z' + nm
nib.save(nii, outnm)
if __name__ == '__main__':
"""Convert log10p to z-score
Parameters
----------
fnm : str
NIfTI image to convert
"""
if len(sys.argv) < 2:
print('No filename provided: I do not know which image to convert!')
sys.exit()
fnm = sys.argv[1]
log10t(fnm)
Thanks for your response.
This may be helpful for others. To transparent NaN
voxels, I ended up setting the min-max of the overlay to a value close to zero like 0.0001 and not exactly zero.
Hi, Thanks for the interesting tool. I'm using Surf-ice v1.0.20201102 on Linux. I would change the color map scale by using a log scale for that. I'm wondering if there is such a possibility?
Thanks.