Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion bin/nib-nifti-dx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# copyright and license terms.
#
### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
''' Print nifti diagnostics for header files '''
""" Print nifti diagnostics for header files """

from nibabel.cmdline.nifti_dx import main

Expand Down
6 changes: 3 additions & 3 deletions doc/source/dicom/derivations/dicom_mosaic.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
''' Just showing the mosaic simplification '''
""" Just showing the mosaic simplification """

from sympy import Matrix, Symbol, symbols, simplify

Expand All @@ -19,12 +19,12 @@ def numbered_vector(nrows, symbol_prefix):
'md_{cols} md_{rows} rd_{cols} rd_{rows}')

md_adj = Matrix((mdc - 1, mdr - 1, 0)) / -2
rd_adj = Matrix((rdc - 1 , rdr - 1, 0)) / -2
rd_adj = Matrix((rdc - 1, rdr - 1, 0)) / -2

adj = -(RS * md_adj) + RS * rd_adj
adj.simplify()

Q = RS[:,:2] * Matrix((
Q = RS[:, :2] * Matrix((
(mdc - rdc) / 2,
(mdr - rdr) / 2))

Expand Down
82 changes: 43 additions & 39 deletions doc/source/dicom/derivations/spm_dicom_orient.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
''' Symbolic versions of the DICOM orientation mathemeatics.
""" Symbolic versions of the DICOM orientation mathemeatics.

Notes on the SPM orientation machinery.

There are symbolic versions of the code in ``spm_dicom_convert``,
``write_volume`` subfunction, around line 509 in the version I have (SPM8, late
2009 vintage).
'''
"""

import numpy as np

Expand All @@ -16,21 +16,21 @@
# The code below is general (independent of SPMs code)
def numbered_matrix(nrows, ncols, symbol_prefix):
return Matrix(nrows, ncols, lambda i, j: Symbol(
symbol_prefix + '_{%d%d}' % (i+1, j+1)))
symbol_prefix + '_{%d%d}' % (i + 1, j + 1)))


def numbered_vector(nrows, symbol_prefix):
return Matrix(nrows, 1, lambda i, j: Symbol(
symbol_prefix + '_{%d}' % (i+1)))
symbol_prefix + '_{%d}' % (i + 1)))


# premultiplication matrix to go from 0 based to 1 based indexing
one_based = eye(4)
one_based[:3,3] = (1,1,1)
one_based[:3, 3] = (1, 1, 1)
# premult for swapping row and column indices
row_col_swap = eye(4)
row_col_swap[:,0] = eye(4)[:,1]
row_col_swap[:,1] = eye(4)[:,0]
row_col_swap[:, 0] = eye(4)[:, 1]
row_col_swap[:, 1] = eye(4)[:, 0]

# various worming matrices
orient_pat = numbered_matrix(3, 2, 'F')
Expand All @@ -40,47 +40,49 @@ def numbered_vector(nrows, symbol_prefix):
pos_pat_N = numbered_vector(3, 'T^N')
pixel_spacing = symbols((r'\Delta{r}', r'\Delta{c}'))
NZ = Symbol('N')
slice_spacing = Symbol('\Delta{s}')
slice_spacing = Symbol(r'\Delta{s}')

R3 = orient_pat * np.diag(pixel_spacing)
R = zeros(4, 2)
R[:3,:] = R3
R[:3, :] = R3

# The following is specific to the SPM algorithm.
x1 = ones(4, 1)
y1 = ones(4, 1)
y1[:3,:] = pos_pat_0
y1[:3, :] = pos_pat_0

to_inv = zeros(4, 4)
to_inv[:,0] = x1
to_inv[:,1] = symbols('a b c d')
to_inv[0,2] = 1
to_inv[1,3] = 1
to_inv[:, 0] = x1
to_inv[:, 1] = symbols('a b c d')
to_inv[0, 2] = 1
to_inv[1, 3] = 1
inv_lhs = zeros(4, 4)
inv_lhs[:,0] = y1
inv_lhs[:,1] = symbols('e f g h')
inv_lhs[:,2:] = R
inv_lhs[:, 0] = y1
inv_lhs[:, 1] = symbols('e f g h')
inv_lhs[:, 2:] = R


def spm_full_matrix(x2, y2):
rhs = to_inv[:,:]
rhs[:,1] = x2
lhs = inv_lhs[:,:]
lhs[:,1] = y2
rhs = to_inv[:, :]
rhs[:, 1] = x2
lhs = inv_lhs[:, :]
lhs[:, 1] = y2
return lhs * rhs.inv()


# single slice case
orient = zeros(3, 3)
orient[:3,:2] = orient_pat
orient[:,2] = orient_cross
x2_ss = Matrix((0,0,1,0))
orient[:3, :2] = orient_pat
orient[:, 2] = orient_cross
x2_ss = Matrix((0, 0, 1, 0))
y2_ss = zeros(4, 1)
y2_ss[:3,:] = orient * Matrix((0,0,slice_spacing))
y2_ss[:3, :] = orient * Matrix((0, 0, slice_spacing))
A_ss = spm_full_matrix(x2_ss, y2_ss)

# many slice case
x2_ms = Matrix((1,1,NZ,1))
x2_ms = Matrix((1, 1, NZ, 1))
y2_ms = ones(4, 1)
y2_ms[:3,:] = pos_pat_N
y2_ms[:3, :] = pos_pat_N
A_ms = spm_full_matrix(x2_ms, y2_ms)

# End of SPM algorithm
Expand All @@ -92,22 +94,22 @@ def spm_full_matrix(x2, y2):
single_aff = eye(4)
rot = orient
rot_scale = rot * np.diag(pixel_spacing[:] + (slice_spacing,))
single_aff[:3,:3] = rot_scale
single_aff[:3,3] = pos_pat_0
single_aff[:3, :3] = rot_scale
single_aff[:3, 3] = pos_pat_0

# For multi-slice case, we have the start and the end slice position
# patient. This gives us the third column of the affine, because,
# ``pat_pos_N = aff * [[0,0,ZN-1,1]].T
multi_aff = eye(4)
multi_aff[:3,:2] = R3
trans_z_N = Matrix((0,0, NZ-1, 1))
multi_aff[:3, :2] = R3
trans_z_N = Matrix((0, 0, NZ - 1, 1))
multi_aff[:3, 2] = missing_r_col
multi_aff[:3, 3] = pos_pat_0
est_pos_pat_N = multi_aff * trans_z_N
eqns = tuple(est_pos_pat_N[:3,0] - pos_pat_N)
solved = sympy.solve(eqns, tuple(missing_r_col))
multi_aff_solved = multi_aff[:,:]
multi_aff_solved[:3,2] = multi_aff_solved[:3,2].subs(solved)
eqns = tuple(est_pos_pat_N[:3, 0] - pos_pat_N)
solved = sympy.solve(eqns, tuple(missing_r_col))
multi_aff_solved = multi_aff[:, :]
multi_aff_solved[:3, 2] = multi_aff_solved[:3, 2].subs(solved)

# Check that SPM gave us the same result
A_ms_0based = A_ms * one_based
Expand All @@ -121,10 +123,10 @@ def spm_full_matrix(x2, y2):
A_i = single_aff
nz_trans = eye(4)
NZT = Symbol('d')
nz_trans[2,3] = NZT
nz_trans[2, 3] = NZT
A_j = A_i * nz_trans
IPP_i = A_i[:3,3]
IPP_j = A_j[:3,3]
IPP_i = A_i[:3, 3]
IPP_j = A_j[:3, 3]

# SPM does it with the inner product of the vectors
spm_z = IPP_j.T * orient_cross
Expand All @@ -135,11 +137,13 @@ def spm_full_matrix(x2, y2):
ipp_sum_div = sum(IPP_j) / sum(orient_cross)
ipp_sum_div = sympy.simplify(ipp_sum_div)


# Dump out the formulae here to latex for the RST docs
def my_latex(expr):
S = sympy.latex(expr)
return S[1:-1]


print('Latex stuff')
print(' R = ' + my_latex(to_inv))
print(' ')
Expand All @@ -159,4 +163,4 @@ def my_latex(expr):
print()
print(' T^j = ' + my_latex(IPP_j))
print()
print(' T^j \cdot \mathbf{c} = ' + my_latex(spm_z))
print(r' T^j \cdot \mathbf{c} = ' + my_latex(spm_z))
40 changes: 20 additions & 20 deletions doc/tools/apigen.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@


class ApiDocWriter(object):
''' Class for automatic detection and parsing of API docs
to Sphinx-parsable reST format'''
""" Class for automatic detection and parsing of API docs
to Sphinx-parsable reST format"""

# only separating first two levels
rst_section_levels = ['*', '=', '-', '~', '^']
Expand All @@ -42,7 +42,7 @@ def __init__(self,
module_skip_patterns=None,
other_defines=True
):
''' Initialize package for parsing
""" Initialize package for parsing

Parameters
----------
Expand Down Expand Up @@ -70,7 +70,7 @@ def __init__(self,
other_defines : {True, False}, optional
Whether to include classes and functions that are imported in a
particular module but not defined there.
'''
"""
if package_skip_patterns is None:
package_skip_patterns = ['\\.tests$']
if module_skip_patterns is None:
Expand All @@ -85,7 +85,7 @@ def get_package_name(self):
return self._package_name

def set_package_name(self, package_name):
''' Set package_name
""" Set package_name

>>> docwriter = ApiDocWriter('sphinx')
>>> import sphinx
Expand All @@ -95,7 +95,7 @@ def set_package_name(self, package_name):
>>> import docutils
>>> docwriter.root_path == docutils.__path__[0]
True
'''
"""
# It's also possible to imagine caching the module parsing here
self._package_name = package_name
root_module = self._import(package_name)
Expand All @@ -106,30 +106,30 @@ def set_package_name(self, package_name):
'get/set package_name')

def _import(self, name):
''' Import namespace package '''
""" Import namespace package """
mod = __import__(name)
components = name.split('.')
for comp in components[1:]:
mod = getattr(mod, comp)
return mod

def _get_object_name(self, line):
''' Get second token in line
""" Get second token in line
>>> docwriter = ApiDocWriter('sphinx')
>>> docwriter._get_object_name(" def func(): ")
'func'
>>> docwriter._get_object_name(" class Klass(object): ")
'Klass'
>>> docwriter._get_object_name(" class Klass: ")
'Klass'
'''
"""
name = line.split()[1].split('(')[0].strip()
# in case we have classes which are not derived from object
# ie. old style classes
return name.rstrip(':')

def _uri2path(self, uri):
''' Convert uri to absolute filepath
""" Convert uri to absolute filepath

Parameters
----------
Expand All @@ -155,7 +155,7 @@ def _uri2path(self, uri):
True
>>> docwriter._uri2path('sphinx.does_not_exist')

'''
"""
if uri == self.package_name:
return os.path.join(self.root_path, '__init__.py')
path = uri.replace(self.package_name + '.', '')
Expand All @@ -171,15 +171,15 @@ def _uri2path(self, uri):
return path

def _path2uri(self, dirpath):
''' Convert directory path to uri '''
""" Convert directory path to uri """
package_dir = self.package_name.replace('.', os.path.sep)
relpath = dirpath.replace(self.root_path, package_dir)
if relpath.startswith(os.path.sep):
relpath = relpath[1:]
return relpath.replace(os.path.sep, '.')

def _parse_module(self, uri):
''' Parse module defined in *uri* '''
""" Parse module defined in *uri* """
filename = self._uri2path(uri)
if filename is None:
print(filename, 'erk')
Expand Down Expand Up @@ -233,7 +233,7 @@ def _parse_module_with_import(self, uri):
return functions, classes

def _parse_lines(self, linesource):
''' Parse lines of text for functions and classes '''
""" Parse lines of text for functions and classes """
functions = []
classes = []
for line in linesource:
Expand All @@ -254,7 +254,7 @@ def _parse_lines(self, linesource):
return functions, classes

def generate_api_doc(self, uri):
'''Make autodoc documentation template string for a module
"""Make autodoc documentation template string for a module

Parameters
----------
Expand All @@ -267,7 +267,7 @@ def generate_api_doc(self, uri):
Module name, table of contents.
body : string
Function and class docstrings.
'''
"""
# get the names of all classes and functions
functions, classes = self._parse_module_with_import(uri)
if not len(functions) and not len(classes) and DEBUG:
Expand Down Expand Up @@ -317,7 +317,7 @@ def generate_api_doc(self, uri):
return head, body

def _survives_exclude(self, matchstr, match_type):
''' Returns True if *matchstr* does not match patterns
""" Returns True if *matchstr* does not match patterns

``self.package_name`` removed from front of string if present

Expand All @@ -336,7 +336,7 @@ def _survives_exclude(self, matchstr, match_type):
>>> dw.module_skip_patterns.append('^\\.badmod$')
>>> dw._survives_exclude('sphinx.badmod', 'module')
False
'''
"""
if match_type == 'module':
patterns = self.module_skip_patterns
elif match_type == 'package':
Expand All @@ -359,7 +359,7 @@ def _survives_exclude(self, matchstr, match_type):
return True

def discover_modules(self):
''' Return module sequence discovered from ``self.package_name``
""" Return module sequence discovered from ``self.package_name``


Parameters
Expand All @@ -381,7 +381,7 @@ def discover_modules(self):
>>> 'sphinx.util' in dw.discover_modules()
False
>>>
'''
"""
modules = [self.package_name]
# raw directory parsing
for dirpath, dirnames, filenames in os.walk(self.root_path):
Expand Down
Loading