From 616e2566709005d8a50184f4ade6ec70c0580929 Mon Sep 17 00:00:00 2001 From: andrewolaughlin Date: Mon, 20 Oct 2014 17:22:06 -0400 Subject: [PATCH 1/4] Added a better align method, works great for fMRI --- cortex/align.py | 73 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/cortex/align.py b/cortex/align.py index f95bac233..b8911cff4 100644 --- a/cortex/align.py +++ b/cortex/align.py @@ -199,3 +199,76 @@ def autotweak(subject, xfmname): print('Saved transform as (%s, %s)'%(subject, xfmname+'_auto')) finally: shutil.rmtree(cache) + + +def automatic_bbregister(subject, xfmname, reference, noclean=False): + """Create an automatic alignment using the FLIRT boundary-based alignment (BBR) from FSL. + + If `noclean`, intermediate files will not be removed from /tmp. The `reference` image and resulting + transform called `xfmname` will be automatically stored in the database. + + It's good practice to open up this transform afterward in the manual aligner and check how it worked. + Do that using the following (with the same `subject` and `xfmname` used here, no need for `reference`): + > align.manual(subject, xfmname) + + Parameters + ---------- + subject : str + Subject identifier. + xfmname : str + String identifying the transform to be created. + reference : str + Path to a nibabel-readable image that will be used as the reference for this transform. + Usually, this is a single (3D) functional data volume. + noclean : bool, optional + If True intermediate files will not be removed from /tmp (this is useful for debugging things), + and the returned value will be the name of the temp directory. Default False. + + Returns + ------- + Nothing unless `noclean` is True. + """ + import shlex + import shutil + import tempfile + import subprocess as sp + + from .database import db + from .xfm import Transform + from .options import config + + fsl_prefix = config.get("basic", "fsl_prefix") + schfile = os.path.join(os.path.split(os.path.abspath(__file__))[0], "bbr.sch") + + retval = None + try: + cache = tempfile.mkdtemp() + absreference = os.path.abspath(reference) + raw = db.get_anat(subject, type='raw').get_filename() + bet = db.get_anat(subject, type='brainmask').get_filename() + wmseg = db.get_anat(subject, type='whitematter').get_filename() + # Compute anatomical-to-epi transform + + print('Running bbregister') + cmd = 'bbregister --s {subject} --mov {absref} --bold --init-fsl --reg {cache}/register.dat --fslmat {cache}/out.mat' + cmd = cmd.format(cache=cache, absref=absreference, subject=subject) + + if sp.call(cmd, shell=True) != 0: + raise IOError('Error calling bbregister') + + x = np.loadtxt(os.path.join(cache, "out.mat")) + # Pass transform as FROM epi TO anat; transform will be inverted + # back to anat-to-epi, standard direction for pycortex internal + # storage by from_fsl + xfm = Transform.from_fsl(x,absreference,raw) + # Save as pycortex 'coord' transform + xfm.save(subject,xfmname,'coord') + print('Success') + + finally: + if not noclean: + shutil.rmtree(cache) + else: + retval = cache + + return retval \ No newline at end of file From 7e1ee8ebc4dcf073ad7863eb1d254350b6aa82a7 Mon Sep 17 00:00:00 2001 From: andrewolaughlin Date: Fri, 24 Oct 2014 14:14:50 -0400 Subject: [PATCH 2/4] Delete align.py --- cortex/align.py | 274 ------------------------------------------------ 1 file changed, 274 deletions(-) delete mode 100644 cortex/align.py diff --git a/cortex/align.py b/cortex/align.py deleted file mode 100644 index b8911cff4..000000000 --- a/cortex/align.py +++ /dev/null @@ -1,274 +0,0 @@ -import os -import numpy as np - -def manual(subject, xfmname, reference=None, **kwargs): - """Open GUI for manually aligning a functional volume to the cortical surface for `subject`. This - creates a new transform called `xfm`. The name of a nibabel-readable file (e.g. nii) should be - supplied as `reference`. This image will be copied into the database. - - To modify an existing functional-anatomical transform, `reference` can be left blank, and the - previously used reference will be loaded. - - <> - - When the GUI is closed, the transform will be saved into the pycortex database. The GUI requires - Mayavi support. - - Parameters - ---------- - subject : str - Subject identifier. - xfmname : str - String identifying the transform to be created or loaded. - reference : str, optional - Path to a nibabel-readable image that will be used as the reference for this transform. - If given the default value of None, this function will attempt to load an existing reference - image from the database. - kwargs : dict - Passed to mayavi_aligner.get_aligner. - - Returns - ------- - m : 2D ndarray, shape (4, 4) - Transformation matrix. - """ - from .database import db - from .mayavi_aligner import get_aligner - def save_callback(aligner): - db.save_xfm(subject, xfmname, aligner.get_xfm("magnet"), xfmtype='magnet', reference=reference) - print("saved xfm") - - # Check whether transform w/ this xfmname already exists - try: - db.get_xfm(subject, xfmname) - # Transform exists, make sure that reference is None - if reference is not None: - raise ValueError('Refusing to overwrite reference for existing transform %s, use reference=None to load stored reference' % xfmname) - except IOError: - # Transform does not exist, make sure that reference exists - if reference is None or not os.path.exists(reference): - raise ValueError('Reference image file (%s) does not exist' % reference) - - m = get_aligner(subject, xfmname, epifile=reference, **kwargs) - m.save_callback = save_callback - m.configure_traits() - - magnet = m.get_xfm("magnet") - epi = os.path.abspath(m.epi_file.get_filename()) - - checked = False - while not checked: - resp = raw_input("Save? (Y/N) ").lower().strip() - if resp in ["y", "yes", "n", "no"]: - checked = True - if resp in ["y", "yes"]: - print("Saving...") - try: - db.save_xfm(subject, xfmname, magnet, xfmtype='magnet', reference=reference) - except Exception as e: - print("AN ERROR OCCURRED, THE TRANSFORM WAS NOT SAVED: %s"%e) - print("Complete!") - else: - print("Cancelled... %s"%resp) - else: - print("Didn't get that, please try again..") - - return m - -def automatic(subject, xfmname, reference, noclean=False): - """Create an automatic alignment using the FLIRT boundary-based alignment (BBR) from FSL. - - If `noclean`, intermediate files will not be removed from /tmp. The `reference` image and resulting - transform called `xfmname` will be automatically stored in the database. - - It's good practice to open up this transform afterward in the manual aligner and check how it worked. - Do that using the following (with the same `subject` and `xfmname` used here, no need for `reference`): - > align.manual(subject, xfmname) - - Parameters - ---------- - subject : str - Subject identifier. - xfmname : str - String identifying the transform to be created. - reference : str - Path to a nibabel-readable image that will be used as the reference for this transform. - Usually, this is a single (3D) functional data volume. - noclean : bool, optional - If True intermediate files will not be removed from /tmp (this is useful for debugging things), - and the returned value will be the name of the temp directory. Default False. - - Returns - ------- - Nothing unless `noclean` is True. - """ - import shlex - import shutil - import tempfile - import subprocess as sp - - from .database import db - from .xfm import Transform - from .options import config - - fsl_prefix = config.get("basic", "fsl_prefix") - schfile = os.path.join(os.path.split(os.path.abspath(__file__))[0], "bbr.sch") - - retval = None - try: - cache = tempfile.mkdtemp() - absreference = os.path.abspath(reference) - raw = db.get_anat(subject, type='raw').get_filename() - bet = db.get_anat(subject, type='brainmask').get_filename() - wmseg = db.get_anat(subject, type='whitematter').get_filename() - # Compute anatomical-to-epi transform - print('FLIRT pre-alignment') - cmd = '{fslpre}flirt -in {epi} -ref {bet} -dof 6 -omat {cache}/init.mat'.format( - fslpre=fsl_prefix, cache=cache, epi=absreference, bet=bet) - if sp.call(cmd, shell=True) != 0: - raise IOError('Error calling initial FLIRT') - print('Running BBR') - # Run epi-to-anat transform (this is more stable than anat-to-epi in FSL!) - cmd = '{fslpre}flirt -in {epi} -ref {raw} -dof 6 -cost bbr -wmseg {wmseg} -init {cache}/init.mat -omat {cache}/out.mat -schedule {schfile}' - cmd = cmd.format(fslpre=fsl_prefix, cache=cache, raw=raw, wmseg=wmseg, epi=absreference, schfile=schfile) - if sp.call(cmd, shell=True) != 0: - raise IOError('Error calling BBR flirt') - - x = np.loadtxt(os.path.join(cache, "out.mat")) - # Pass transform as FROM epi TO anat; transform will be inverted - # back to anat-to-epi, standard direction for pycortex internal - # storage by from_fsl - xfm = Transform.from_fsl(x,absreference,raw) - # Save as pycortex 'coord' transform - xfm.save(subject,xfmname,'coord') - print('Success') - - finally: - if not noclean: - shutil.rmtree(cache) - else: - retval = cache - - return retval - -def autotweak(subject, xfmname): - """Tweak an alignment using the FLIRT boundary-based alignment (BBR) from FSL. - Ideally this function should actually use a limited search range, but it doesn't. - It's probably not very useful. - - Parameters - ---------- - subject : str - Subject identifier. - xfmname : str - String identifying the transform to be tweaked. - """ - import shlex - import shutil - import tempfile - import subprocess as sp - - from .database import db - from .xfm import Transform - from .options import config - - fsl_prefix = config.get("basic", "fsl_prefix") - schfile = os.path.join(os.path.split(os.path.abspath(__file__))[0], "bbr.sch") - - magnet = db.get_xfm(subject, xfmname, xfmtype='magnet') - try: - cache = tempfile.mkdtemp() - epifile = magnet.reference.get_filename() - raw = db.get_anat(subject, type='raw').get_filename() - bet = db.get_anat(subject, type='brainmask').get_filename() - wmseg = db.get_anat(subject, type='whitematter').get_filename() - initmat = magnet.to_fsl(db.get_anat(subject, 'raw').get_filename()) - with open(os.path.join(cache, 'init.mat'), 'w') as fp: - np.savetxt(fp, initmat, fmt='%f') - print('Running BBR') - cmd = '{fslpre}flirt -in {epi} -ref {raw} -dof 6 -cost bbr -wmseg {wmseg} -init {cache}/init.mat -omat {cache}/out.mat -schedule {schfile}' - cmd = cmd.format(cache=cache, raw=raw, wmseg=wmseg, epi=epifile) - if sp.call(cmd, shell=True) != 0: - raise IOError('Error calling BBR flirt') - - x = np.loadtxt(os.path.join(cache, "out.mat")) - # Pass transform as FROM epi TO anat; transform will be inverted - # back to anat-to-epi, standard direction for pycortex internal - # storage by from_fsl - Transform.from_fsl(x, epifile, raw).save(subject, xfmname+"_auto", 'coord') - print('Saved transform as (%s, %s)'%(subject, xfmname+'_auto')) - finally: - shutil.rmtree(cache) - - -def automatic_bbregister(subject, xfmname, reference, noclean=False): - """Create an automatic alignment using the FLIRT boundary-based alignment (BBR) from FSL. - - If `noclean`, intermediate files will not be removed from /tmp. The `reference` image and resulting - transform called `xfmname` will be automatically stored in the database. - - It's good practice to open up this transform afterward in the manual aligner and check how it worked. - Do that using the following (with the same `subject` and `xfmname` used here, no need for `reference`): - > align.manual(subject, xfmname) - - Parameters - ---------- - subject : str - Subject identifier. - xfmname : str - String identifying the transform to be created. - reference : str - Path to a nibabel-readable image that will be used as the reference for this transform. - Usually, this is a single (3D) functional data volume. - noclean : bool, optional - If True intermediate files will not be removed from /tmp (this is useful for debugging things), - and the returned value will be the name of the temp directory. Default False. - - Returns - ------- - Nothing unless `noclean` is True. - """ - import shlex - import shutil - import tempfile - import subprocess as sp - - from .database import db - from .xfm import Transform - from .options import config - - fsl_prefix = config.get("basic", "fsl_prefix") - schfile = os.path.join(os.path.split(os.path.abspath(__file__))[0], "bbr.sch") - - retval = None - try: - cache = tempfile.mkdtemp() - absreference = os.path.abspath(reference) - raw = db.get_anat(subject, type='raw').get_filename() - bet = db.get_anat(subject, type='brainmask').get_filename() - wmseg = db.get_anat(subject, type='whitematter').get_filename() - # Compute anatomical-to-epi transform - - print('Running bbregister') - cmd = 'bbregister --s {subject} --mov {absref} --bold --init-fsl --reg {cache}/register.dat --fslmat {cache}/out.mat' - cmd = cmd.format(cache=cache, absref=absreference, subject=subject) - - if sp.call(cmd, shell=True) != 0: - raise IOError('Error calling bbregister') - - x = np.loadtxt(os.path.join(cache, "out.mat")) - # Pass transform as FROM epi TO anat; transform will be inverted - # back to anat-to-epi, standard direction for pycortex internal - # storage by from_fsl - xfm = Transform.from_fsl(x,absreference,raw) - # Save as pycortex 'coord' transform - xfm.save(subject,xfmname,'coord') - print('Success') - - finally: - if not noclean: - shutil.rmtree(cache) - else: - retval = cache - - return retval \ No newline at end of file From fb4ab9b55889730f7e797292a866df85dddab2c9 Mon Sep 17 00:00:00 2001 From: andrewolaughlin Date: Fri, 24 Oct 2014 14:36:42 -0400 Subject: [PATCH 3/4] put back original align.py --- cortex/align.py | 201 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 cortex/align.py diff --git a/cortex/align.py b/cortex/align.py new file mode 100644 index 000000000..f95bac233 --- /dev/null +++ b/cortex/align.py @@ -0,0 +1,201 @@ +import os +import numpy as np + +def manual(subject, xfmname, reference=None, **kwargs): + """Open GUI for manually aligning a functional volume to the cortical surface for `subject`. This + creates a new transform called `xfm`. The name of a nibabel-readable file (e.g. nii) should be + supplied as `reference`. This image will be copied into the database. + + To modify an existing functional-anatomical transform, `reference` can be left blank, and the + previously used reference will be loaded. + + <> + + When the GUI is closed, the transform will be saved into the pycortex database. The GUI requires + Mayavi support. + + Parameters + ---------- + subject : str + Subject identifier. + xfmname : str + String identifying the transform to be created or loaded. + reference : str, optional + Path to a nibabel-readable image that will be used as the reference for this transform. + If given the default value of None, this function will attempt to load an existing reference + image from the database. + kwargs : dict + Passed to mayavi_aligner.get_aligner. + + Returns + ------- + m : 2D ndarray, shape (4, 4) + Transformation matrix. + """ + from .database import db + from .mayavi_aligner import get_aligner + def save_callback(aligner): + db.save_xfm(subject, xfmname, aligner.get_xfm("magnet"), xfmtype='magnet', reference=reference) + print("saved xfm") + + # Check whether transform w/ this xfmname already exists + try: + db.get_xfm(subject, xfmname) + # Transform exists, make sure that reference is None + if reference is not None: + raise ValueError('Refusing to overwrite reference for existing transform %s, use reference=None to load stored reference' % xfmname) + except IOError: + # Transform does not exist, make sure that reference exists + if reference is None or not os.path.exists(reference): + raise ValueError('Reference image file (%s) does not exist' % reference) + + m = get_aligner(subject, xfmname, epifile=reference, **kwargs) + m.save_callback = save_callback + m.configure_traits() + + magnet = m.get_xfm("magnet") + epi = os.path.abspath(m.epi_file.get_filename()) + + checked = False + while not checked: + resp = raw_input("Save? (Y/N) ").lower().strip() + if resp in ["y", "yes", "n", "no"]: + checked = True + if resp in ["y", "yes"]: + print("Saving...") + try: + db.save_xfm(subject, xfmname, magnet, xfmtype='magnet', reference=reference) + except Exception as e: + print("AN ERROR OCCURRED, THE TRANSFORM WAS NOT SAVED: %s"%e) + print("Complete!") + else: + print("Cancelled... %s"%resp) + else: + print("Didn't get that, please try again..") + + return m + +def automatic(subject, xfmname, reference, noclean=False): + """Create an automatic alignment using the FLIRT boundary-based alignment (BBR) from FSL. + + If `noclean`, intermediate files will not be removed from /tmp. The `reference` image and resulting + transform called `xfmname` will be automatically stored in the database. + + It's good practice to open up this transform afterward in the manual aligner and check how it worked. + Do that using the following (with the same `subject` and `xfmname` used here, no need for `reference`): + > align.manual(subject, xfmname) + + Parameters + ---------- + subject : str + Subject identifier. + xfmname : str + String identifying the transform to be created. + reference : str + Path to a nibabel-readable image that will be used as the reference for this transform. + Usually, this is a single (3D) functional data volume. + noclean : bool, optional + If True intermediate files will not be removed from /tmp (this is useful for debugging things), + and the returned value will be the name of the temp directory. Default False. + + Returns + ------- + Nothing unless `noclean` is True. + """ + import shlex + import shutil + import tempfile + import subprocess as sp + + from .database import db + from .xfm import Transform + from .options import config + + fsl_prefix = config.get("basic", "fsl_prefix") + schfile = os.path.join(os.path.split(os.path.abspath(__file__))[0], "bbr.sch") + + retval = None + try: + cache = tempfile.mkdtemp() + absreference = os.path.abspath(reference) + raw = db.get_anat(subject, type='raw').get_filename() + bet = db.get_anat(subject, type='brainmask').get_filename() + wmseg = db.get_anat(subject, type='whitematter').get_filename() + # Compute anatomical-to-epi transform + print('FLIRT pre-alignment') + cmd = '{fslpre}flirt -in {epi} -ref {bet} -dof 6 -omat {cache}/init.mat'.format( + fslpre=fsl_prefix, cache=cache, epi=absreference, bet=bet) + if sp.call(cmd, shell=True) != 0: + raise IOError('Error calling initial FLIRT') + print('Running BBR') + # Run epi-to-anat transform (this is more stable than anat-to-epi in FSL!) + cmd = '{fslpre}flirt -in {epi} -ref {raw} -dof 6 -cost bbr -wmseg {wmseg} -init {cache}/init.mat -omat {cache}/out.mat -schedule {schfile}' + cmd = cmd.format(fslpre=fsl_prefix, cache=cache, raw=raw, wmseg=wmseg, epi=absreference, schfile=schfile) + if sp.call(cmd, shell=True) != 0: + raise IOError('Error calling BBR flirt') + + x = np.loadtxt(os.path.join(cache, "out.mat")) + # Pass transform as FROM epi TO anat; transform will be inverted + # back to anat-to-epi, standard direction for pycortex internal + # storage by from_fsl + xfm = Transform.from_fsl(x,absreference,raw) + # Save as pycortex 'coord' transform + xfm.save(subject,xfmname,'coord') + print('Success') + + finally: + if not noclean: + shutil.rmtree(cache) + else: + retval = cache + + return retval + +def autotweak(subject, xfmname): + """Tweak an alignment using the FLIRT boundary-based alignment (BBR) from FSL. + Ideally this function should actually use a limited search range, but it doesn't. + It's probably not very useful. + + Parameters + ---------- + subject : str + Subject identifier. + xfmname : str + String identifying the transform to be tweaked. + """ + import shlex + import shutil + import tempfile + import subprocess as sp + + from .database import db + from .xfm import Transform + from .options import config + + fsl_prefix = config.get("basic", "fsl_prefix") + schfile = os.path.join(os.path.split(os.path.abspath(__file__))[0], "bbr.sch") + + magnet = db.get_xfm(subject, xfmname, xfmtype='magnet') + try: + cache = tempfile.mkdtemp() + epifile = magnet.reference.get_filename() + raw = db.get_anat(subject, type='raw').get_filename() + bet = db.get_anat(subject, type='brainmask').get_filename() + wmseg = db.get_anat(subject, type='whitematter').get_filename() + initmat = magnet.to_fsl(db.get_anat(subject, 'raw').get_filename()) + with open(os.path.join(cache, 'init.mat'), 'w') as fp: + np.savetxt(fp, initmat, fmt='%f') + print('Running BBR') + cmd = '{fslpre}flirt -in {epi} -ref {raw} -dof 6 -cost bbr -wmseg {wmseg} -init {cache}/init.mat -omat {cache}/out.mat -schedule {schfile}' + cmd = cmd.format(cache=cache, raw=raw, wmseg=wmseg, epi=epifile) + if sp.call(cmd, shell=True) != 0: + raise IOError('Error calling BBR flirt') + + x = np.loadtxt(os.path.join(cache, "out.mat")) + # Pass transform as FROM epi TO anat; transform will be inverted + # back to anat-to-epi, standard direction for pycortex internal + # storage by from_fsl + Transform.from_fsl(x, epifile, raw).save(subject, xfmname+"_auto", 'coord') + print('Saved transform as (%s, %s)'%(subject, xfmname+'_auto')) + finally: + shutil.rmtree(cache) From 3b4a7fc3d0334579aac2a00c5eb27363a136d23e Mon Sep 17 00:00:00 2001 From: andrewolaughlin Date: Fri, 24 Oct 2014 15:20:49 -0400 Subject: [PATCH 4/4] fixed to_svg() --- cortex/polyutils.py | 49 +++++++++++++++++++++++++++++++++++++++++++++ cortex/rois.py | 18 ++++++++++------- 2 files changed, 60 insertions(+), 7 deletions(-) diff --git a/cortex/polyutils.py b/cortex/polyutils.py index 82acc5efc..da5d5a0ec 100644 --- a/cortex/polyutils.py +++ b/cortex/polyutils.py @@ -43,6 +43,55 @@ def __init__(self, pts, polys): self._rlfac_solvers = dict() self._nLC_solvers = dict() + @property + def poly_graph(self): + """NetworkX undirected graph representing polygons of this Surface. + """ + import networkx as nx + from collections import defaultdict + edges = defaultdict(list) + for ii,(a,b,c) in enumerate(self.polys): + edges[frozenset([a,b])].append(ii) + edges[frozenset([a,c])].append(ii) + edges[frozenset([b,c])].append(ii) + + #nedges = len(edges) + #ii,jj = np.vstack(edges.values()).T + #polymat = sparse.coo_matrix((np.ones((nedges,)), (ii, jj)), shape=[len(self.polys)]*2) + polygraph = nx.Graph() + polygraph.add_edges_from(((p[0], p[1], dict(verts=k)) for k,p in edges.iteritems())) + return polygraph + + def get_boundary(self, vertices, remove_danglers=False): + """Return interior and exterior boundary sets for `vertices`. + If `remove_danglers` is True vertices in the internal boundary with + only one neighbor in the internal boundary will be moved to the external + boundary. + """ + if not len(vertices): + return [], [] + + import networkx as nx + + # Use networkx to get external boundary + external_boundary = set(nx.node_boundary(self.graph, vertices)) + + # Find adjacent vertices to get inner boundary + internal_boundary = set.union(*[set(self.graph[v].keys()) + for v in external_boundary]).intersection(set(vertices)) + + if remove_danglers: + ingraph = self.graph.subgraph(internal_boundary) + danglers = [n for n,d in ingraph.degree().items() if d==1] + while danglers: + internal_boundary -= set(danglers) + external_boundary |= set(danglers) + + ingraph = self.graph.subgraph(internal_boundary) + danglers = [n for n,d in ingraph.degree().items() if d<2] + + return list(internal_boundary), list(external_boundary) + @property @_memo def ppts(self): diff --git a/cortex/rois.py b/cortex/rois.py index 6a762fb25..2bc55f29b 100644 --- a/cortex/rois.py +++ b/cortex/rois.py @@ -7,11 +7,12 @@ import networkx as nx from db import surfs + +from dataset import db from svgroi import get_roipack, _make_layer, _find_layer, parser from lxml import etree -from dataset import VertexData -from polyutils import Surface, boundary_edges -from utils import get_curvature, add_roi +from polyutils import Surface + import quickflat class ROIpack(object): @@ -29,9 +30,12 @@ def load_roifile(self): print("ROI file %s doesn't exist.." % self.roifile) return - # Create basic VertexData to avoid expensive initialization.. - empty = VertexData(None, self.subject) - + #Used to create basic VertexData to avoid expensive initialization.. + #empty = VertexData(None, self.subject) + + #hack just gets curvature VertexData to prevent error from old way + empty = db.get_surfinfo(self.subject) + # Load ROIs from file if self.roifile.endswith("npz"): roidata = np.load(self.roifile) @@ -79,7 +83,7 @@ def to_svg(self, open_inkscape=False, filename=None): # Add default layers # Add curvature from matplotlib import cm - curv = VertexData(np.hstack(get_curvature(self.subject)), self.subject) + curv = db.get_surfinfo(self.subject) fp = cStringIO.StringIO() curvim = quickflat.make_png(fp, curv, height=1024, with_rois=False, with_labels=False, with_colorbar=False, cmap=cm.gray,recache=True)