Skip to content

Commit

Permalink
Merge pull request #110 from gallantlab/animation_edits
Browse files Browse the repository at this point in the history
Animation edits
  • Loading branch information
jamesgao committed Oct 14, 2014
2 parents 0783975 + a39164e commit bc829d4
Show file tree
Hide file tree
Showing 13 changed files with 314 additions and 71 deletions.
27 changes: 22 additions & 5 deletions cortex/brainctm.py
Expand Up @@ -89,7 +89,18 @@ def addCurvature(self, **kwargs):
self.left.aux[:,1] = npz.left
self.right.aux[:,1] = npz.right

def save(self, path, method='mg2', disp_layers=['rois'], **kwargs):
def save(self, path, method='mg2', disp_layers=['rois'], extra_disp=None, **kwargs):
"""Save CTM file for static html display.
Parameters
----------
path : string filepath
method : idkwtf
disp_layers : tuple|list
list of strings; names of layers from rois.svg to show
extra_disp : tuple
(svgfile,[layers]) - tuple of (external display .svg filename, [list_of,layers_in_file,to_display])
"""
ctmname = path+".ctm"
svgname = path+".svg"
jsname = path+".json"
Expand All @@ -104,7 +115,7 @@ def save(self, path, method='mg2', disp_layers=['rois'], **kwargs):
offsets.append(fp.tell())
fp.write(rbin)

# Save the JSON descriptor
# Save the JSON descriptor | Need to add to this for extra_disp?
jsdict = dict(rois=os.path.split(svgname)[1],
data=os.path.split(ctmname)[1],
names=self.types,
Expand All @@ -130,8 +141,13 @@ def save(self, path, method='mg2', disp_layers=['rois'], **kwargs):
# add sulci & display layers
flatpts = np.vstack([self.left.flat, self.right.flat])
roipack = db.get_overlay(self.subject, pts=flatpts, otype=disp_layers)
# optionally add extra display layers
if not extra_disp is None:
esvgfile,elayerlist = extra_disp
eroipack = db.get_overlay(self.subject,pts=flatpts, otype='external',
svgfile=esvgfile,layer=elayerlist)
roipack = roipack + eroipack
layers = roipack.setup_labels()

if not isinstance(layers, (tuple, list)):
layers = (layers,)

Expand Down Expand Up @@ -223,7 +239,7 @@ def addSurf(self, pts, **kwargs):
super(DecimatedHemi, self).addSurf(pts[self.mask], **kwargs)

def make_pack(outfile, subj, types=("inflated",), method='raw', level=0,
decimate=False, disp_layers=['rois']):
decimate=False, disp_layers=['rois'],extra_disp=None):
"""Generates a cached CTM file"""

ctm = BrainCTM(subj, decimate=decimate)
Expand All @@ -237,7 +253,8 @@ def make_pack(outfile, subj, types=("inflated",), method='raw', level=0,
return ctm.save(os.path.splitext(outfile)[0],
method=method,
level=level,
disp_layers=disp_layers)
disp_layers=disp_layers,
extra_disp=extra_disp)

def read_pack(ctmfile):
fname = os.path.splitext(ctmfile)[0]
Expand Down
15 changes: 13 additions & 2 deletions cortex/dataset/views.py
Expand Up @@ -89,7 +89,18 @@ def _from_hdf_view(h5, data, xfmname=None, vmin=None, vmax=None, **kwargs):
raise ValueError("Invalid Dataview specification")

class Dataview(object):
def __init__(self, cmap=None, vmin=None, vmax=None, description="", state=None, **kwargs):
def __init__(self, cmap=None, vmin=None, vmax=None, description="", state=None,
cvmin=None,cvmax=None,cvthr=False,**kwargs):
"""
MOAR HELP PLEASE. or maybe not. Is this even visible in inherited classes?
cvmin : float,optional
Minimum value for curvature colormap. Defaults to config file value.
cvmax : float, optional
Maximum value for background curvature colormap. Defaults to config file value.
cvthr : bool,optional
Apply threshold to background curvature
"""
if self.__class__ == Dataview:
raise TypeError('Cannot directly instantiate Dataview objects')

Expand Down Expand Up @@ -207,7 +218,7 @@ def raw(self):
# Register colormap while we're at it
cm.register_cmap(self.cmap,cmap)
else:
cmap = self.cmap
cmap = cm.get_cmap(self.cmap)
norm = colors.Normalize(self.vmin, self.vmax) # Does this do anything?
return np.rollaxis(cmap(self.data), -1)

Expand Down
10 changes: 7 additions & 3 deletions cortex/quickflat.py
Expand Up @@ -244,14 +244,18 @@ def make_figure(braindata, recache=False, pixelwise=True, thick=32, sampler='nea
overlays.append(sulc)
if not extra_disp is None:
svgfile,layer = extra_disp
disp = db.get_overlay(dataview.subject,
if not isinstance(layer,(list,tuple)):
layer = [layer]
for extralayer in layer:
# Allow multiple extra layer overlays
disp = db.get_overlay(dataview.subject,
otype='external',
shadow=shadow,
labelsize=labelsize,
labelcolor=labelcolor,
layer=layer,
layer=extralayer,
svgfile=svgfile)
overlays.append(disp)
overlays.append(disp)
for oo in overlays:
roitex = oo.get_texture(height, labels=with_labels)
roitex.seek(0)
Expand Down
52 changes: 46 additions & 6 deletions cortex/svgroi.py
Expand Up @@ -36,7 +36,7 @@ def __init__(self, tcoords, svgfile, callback=None, linewidth=None,
can contain multiple paths.
If those paths are closed (i.e., if these are all ROIs), then
you can use the method ROIpack.get_roi() to get an index of the
vertices associated with
vertices associated with each roi.
Parameters
----------
Expand Down Expand Up @@ -95,7 +95,7 @@ def __init__(self, tcoords, svgfile, callback=None, linewidth=None,
else:
# Unknown display layer; default to values for ROIs
import warnings
warnings.warn('No defaults set for display layer %s; Using defaults for ROIs in options.cfg file')
warnings.warn('No defaults set for display layer %s; Using defaults for ROIs in options.cfg file'%layer)
dlayer = 'rois'
self.linewidth = float(config.get(dlayer, "line_width")) if linewidth is None else linewidth
self.linecolor = tuple(map(float, config.get(dlayer, "line_color").split(','))) if linecolor is None else linecolor
Expand All @@ -106,7 +106,6 @@ def __init__(self, tcoords, svgfile, callback=None, linewidth=None,
self.dashtype = dashtype
self.dashoffset = dashoffset


self.reload(size=labelsize, color=labelcolor)

def reload(self, **kwargs):
Expand Down Expand Up @@ -610,6 +609,39 @@ def names(self):
def __getitem__(self, name):
return self.rois[name]

def __add__(self,other_roipack):
"""Combine layers from two roipacks. Layers / svg file from first is maintained."""
comb = copy.deepcopy(self)
if hasattr(comb,'layers'):
lay1 = self.layer_names
else:
# Convert single-layer to multi-layer ROI
comb.layers = {self.layer:self}
comb.layer = 'multi_layer'
lay1 = [self.layer]
svg_fin = copy.copy(comb.svg)
if hasattr(other_roipack,'layers'):
lay2 = other_roipack.layer_names
for k,L in other_roipack.layers.items():
comb.layers[k] = L
comb.rois.update(L.rois)
to_add = _find_layer(L.svg, k)
svg_fin.getroot().insert(0, to_add)
else:
comb.layers[other_roipack.layer] = other_roipack
to_add = _find_layer(other_roipack.svg, other_roipack.layer)
svg_fin.getroot().insert(0, to_add)
lay2 = [other_roipack.layer]
# Maintain order of layers according to order of addition
comb.layer_names = lay1+lay2
comb.svg = svg_fin
comb.kdt = cKDTree(self.kdt.data) # necessary?
for L in comb.layer_names:
comb.layers[L].kdt = comb.kdt # Why the hell do I have to do this?
#for r in comb.rois:
# r.parent = comb # necessary?
return comb

def setup_labels(self, size=None, color=None, shadow=None):
"""Sets up coordinates for labels wrt SVG file (2D flatmap)"""
# Recursive call for multiple layers
Expand All @@ -619,10 +651,17 @@ def setup_labels(self, size=None, color=None, shadow=None):
label_layers.append(self.layers[L].setup_labels())
self.svg.getroot().insert(0, label_layers[-1])
return label_layers
if self.layer in config.sections():
dlayer = self.layer
else:
# Unknown display layer; default to values for ROIs
import warnings
warnings.warn('No defaults set for display layer %s; Using defaults for ROIs in options.cfg file'%self.layer)
dlayer = 'rois'
if size is None:
size = config.get(self.layer, "labelsize")
size = config.get(dlayer, "labelsize")
if color is None:
color = tuple(map(float, config.get(self.layer, "labelcolor").split(",")))
color = tuple(map(float, config.get(dlayer, "labelcolor").split(",")))
if shadow is None:
shadow = self.shadow

Expand Down Expand Up @@ -785,8 +824,9 @@ def get_labelpos(self, pts=None, norms=None, fancy=False):
if not hasattr(self, "coords"):
allpaths = itertools.chain(*[_split_multipath(path.get("d")) for path in self.paths])
cpts = [self._parse_svg_pts(p) for p in allpaths]
# Bug here. I have no idea why the combined roipack fails here but the non-combined one doesn't
self.coords = [ self.parent.kdt.query(p)[1] for p in cpts ]

if pts is None:
pts = self.parent.tcoords

Expand Down
15 changes: 9 additions & 6 deletions cortex/utils.py
Expand Up @@ -30,7 +30,7 @@ def get_roipack(*args, **kwargs):
get_mapper = DocLoader("get_mapper", ".mapper", "cortex")

def get_ctmpack(subject, types=("inflated",), method="raw", level=0, recache=False,
decimate=False, disp_layers=['rois']):
decimate=False, disp_layers=['rois'],extra_disp=None):
"""Creates ctm file for the specified input arguments.
This is a cached file that specifies (1) the surfaces between which
Expand All @@ -39,14 +39,17 @@ def get_ctmpack(subject, types=("inflated",), method="raw", level=0, recache=Fal
"""
lvlstr = ("%dd" if decimate else "%d")%level
# Generates different cache files for each combination of disp_layers
ctmcache = "%s_[{types}]_{method}_{level}_{layers}.json"%subject
ctmcache = "%s_[{types}]_{method}_{level}_{layers}{extra}.json"%subject
# Mark any ctm file containing extra_disp as unique (will be over-written every time)
ctmcache = ctmcache.format(types=','.join(types),
method=method,
level=lvlstr,
layers=repr(sorted(disp_layers)))
layers=repr(sorted(disp_layers)),
extra='' if extra_disp is None else '_xx')
ctmfile = os.path.join(db.get_cache(subject), ctmcache)

if os.path.exists(ctmfile) and not recache:
if os.path.exists(ctmfile) and not recache: # and extra_disp is None:
# (never load cache with extra_disp, which is based on files outside pycortex)
return ctmfile

print("Generating new ctm file...")
Expand All @@ -57,7 +60,8 @@ def get_ctmpack(subject, types=("inflated",), method="raw", level=0, recache=Fal
method=method,
level=level,
decimate=decimate,
disp_layers=disp_layers)
disp_layers=disp_layers,
extra_disp=extra_disp)
return ctmfile

def get_ctmmap(subject, **kwargs):
Expand Down Expand Up @@ -181,7 +185,6 @@ def add_roi(data, name="new_roi", open_inkscape=True, add_path=True, **kwargs):
if isinstance(dv, dataset.Dataset):
raise TypeError("Please specify a data view")

#rois = db.get_overlay(dv.data.subject)
rois = db.get_overlay(dv.subject)
try:
import cStringIO
Expand Down
4 changes: 2 additions & 2 deletions cortex/webgl/FallbackLoader.py
Expand Up @@ -2,8 +2,8 @@
from tornado import template

class FallbackLoader(template.BaseLoader):
"""Loads templates from a multiple directories, falling back to next
if the template is not found in the first directory.
"""Loads templates from one of multiple potential directories, falling back
to next if the template is not found in the first directory.
"""
def __init__(self, root_directories, **kwargs):
super(FallbackLoader, self).__init__(**kwargs)
Expand Down
17 changes: 11 additions & 6 deletions cortex/webgl/resources/js/LandscapeControls.js
Expand Up @@ -252,6 +252,7 @@ THREE.LandscapeControls.prototype = {
resize: function(w, h) {
this.domElement.style.width = w+"px";
this.domElement.style.height = h+"px";
this._zoom(1.0) // To set orthographic zoom correctly
},

getMouse: function ( event ) {
Expand All @@ -275,7 +276,7 @@ THREE.LandscapeControls.prototype = {
}

this._limitview();

this._zoom(1.0) // Establish zoom (?)
var altrad = this.altitude*Math.PI / 180;
var azirad = (this.azimuth+90)*Math.PI / 180;

Expand Down Expand Up @@ -344,8 +345,9 @@ THREE.LandscapeControls.prototype = {
},

_zoom: function( factor ) {
this.radius *= factor;
if (this.camera.inPerspectiveMode) {
this.radius *= factor;
// Perspective mode, zoom by changing radius from camera to object
if (this.radius > this.maxRadius) {
this.radius = this.maxRadius;
}
Expand All @@ -354,10 +356,13 @@ THREE.LandscapeControls.prototype = {
}
} else {
// Orthographic mode, zoom by changing frustrum limits
this.camera.cameraO.top *= factor;
this.camera.cameraO.bottom *= factor;
this.camera.cameraO.right *= factor;
this.camera.cameraO.left *= factor;
var aspect = this.camera.cameraP.aspect
var height = 2.0*this.radius*Math.tan(this.camera.cameraP.fov/2.0)
var width = aspect*height
this.camera.cameraO.top = height/2.0
this.camera.cameraO.bottom = -height/2.0
this.camera.cameraO.right = width/2.0
this.camera.cameraO.left = -width/2.0
this.camera.cameraO.updateProjectionMatrix();
}
},
Expand Down
18 changes: 15 additions & 3 deletions cortex/webgl/resources/js/mriview.js
Expand Up @@ -95,7 +95,7 @@ var mriview = (function(module) {
vmax: { type:'fv1',value:[1,1]},

curvAlpha: { type:'f', value:1.},
curvScale: { type:'f', value:.5},
curvScale: { type:'f', value:2.0},//0.5 TEMP FIX!!
curvLim: { type:'f', value:.2},
dataAlpha: { type:'f', value:1.0},
hatchAlpha: { type:'f', value:1.},
Expand Down Expand Up @@ -339,7 +339,7 @@ var mriview = (function(module) {
return $(this.object).find("#mix").slider("value");
case 'pivot':
//return $("#pivot").slider("value");
return this._pivot;
return this._pivot;
case 'frame':
return this.frame;
case 'azimuth':
Expand Down Expand Up @@ -370,6 +370,8 @@ var mriview = (function(module) {
return 'orthographic'}
else if (this.camera.inPerspectiveMode) {
return 'perspective'}
case 'slices':
return [this.planes[0].slice, this.planes[1].slice, this.planes[2].slice]
};
};
module.Viewer.prototype.setState = function(state, value) {
Expand Down Expand Up @@ -398,6 +400,10 @@ var mriview = (function(module) {
case 'visR':
if (this.roipack) this.roipack._updatemove = true;
return this.meshes.right.visible = value;
//case 'volume_vis':
// this.planes[0].mesh.visible = value[0]
// this.planes[1].mesh.visible = value[1]
// this.planes[2].mesh.visible = value[2]
case 'rotationL':
if (this.roipack) this.roipack._updatemove = true;
return this.meshes.left.rotation.set(value[0], value[1], value[2]);
Expand All @@ -406,15 +412,21 @@ var mriview = (function(module) {
return this.meshes.right.rotation.set(value[0], value[1], value[2]);
case 'alpha':
return this.renderer.setClearColor(0,value);
case 'specularity':
return this.specularity = value
case 'data':
return this.setData(value)
case 'labels':
return this.labelshow = value;
case 'pivot':
return 'SORRY NOT YET'
case 'projection':
if (value=='perspective'){
return this.controls.camera.toPerspective()}
else if (value=='orthographic'){
return this.controls.camera.toOrthographic()}
case 'slices':
return [this.planes[0].update(value[0]), this.planes[1].update(value[1]), this.planes[2].update(value[2])];
};
};
module.Viewer.prototype.animate = function(animation) {
Expand Down Expand Up @@ -922,7 +934,6 @@ var mriview = (function(module) {
}
this.figure.notify("playtoggle", this);
};

module.Viewer.prototype.getImage = function(width, height, post) {
if (width === undefined)
width = this.canvas.width();
Expand All @@ -943,6 +954,7 @@ var mriview = (function(module) {
var oldw = this.canvas.width(), oldh = this.canvas.height();
this.camera.setSize(width, height);
this.camera.updateProjectionMatrix();
this.controls._zoom(1.0) // To assure orthographic zoom is set correctly
//this.renderer.setSize(width, height);
this.renderer.setClearColorHex(0x0, 0);
this.renderer.render(this.scene, this.camera, renderbuf);
Expand Down

0 comments on commit bc829d4

Please sign in to comment.