4545# PLOTTING FUNCTIONS
4646
4747
48- def _fig_to_img (function = None , fig = None , ** kwargs ):
48+ def _fig_to_img (function = None , fig = None , image_format = 'png' ,
49+ scale = None , ** kwargs ):
4950 """Wrapper function to plot figure and create a binary image"""
5051 import matplotlib .pyplot as plt
5152 if function is not None :
5253 plt .close ('all' )
5354 fig = function (** kwargs )
5455 output = BytesIO ()
55- fig .savefig (output , format = 'png' , bbox_inches = 'tight' , dpi = fig .get_dpi ())
56+ if scale is not None :
57+ _scale_mpl_figure (fig , scale )
58+ fig .savefig (output , format = image_format , bbox_inches = 'tight' ,
59+ dpi = fig .get_dpi ())
5660 plt .close (fig )
57- return base64 .b64encode (output .getvalue ()).decode ('ascii' )
61+ output = output .getvalue ()
62+ return (output if image_format == 'svg' else
63+ base64 .b64encode (output ).decode ('ascii' ))
64+
65+
66+ def _scale_mpl_figure (fig , scale ):
67+ """Magic scaling helper
68+
69+ Keeps font-size and artist sizes constant
70+ 0.5 : current font - 4pt
71+ 2.0 : current font + 4pt
72+
73+ XXX it's unclear why this works, but good to go for most cases
74+ """
75+ fig .set_size_inches (fig .get_size_inches () * scale )
76+ fig .set_dpi (fig .get_dpi () * scale )
77+ import matplotlib as mpl
78+ if scale >= 1 :
79+ sfactor = scale ** 2
80+ elif scale < 1 :
81+ sfactor = - ((1. / scale ) ** 2 )
82+ for text in fig .findobj (mpl .text .Text ):
83+ fs = text .get_fontsize ()
84+ text .set_fontsize (fs + sfactor )
85+
86+ fig .canvas .draw ()
5887
5988
6089def _figs_to_mrislices (sl , n_jobs , ** kwargs ):
@@ -75,7 +104,6 @@ def _iterate_trans_views(function, **kwargs):
75104 from scipy .misc import imread
76105 import matplotlib .pyplot as plt
77106 import mayavi
78-
79107 fig = function (** kwargs )
80108
81109 assert isinstance (fig , mayavi .core .scene .Scene )
@@ -283,7 +311,8 @@ def _iterate_coronal_slices(array, limits=None):
283311 yield ind , np .flipud (np .rot90 (array [:, :, ind ]))
284312
285313
286- def _iterate_mri_slices (name , ind , global_id , slides_klass , data , cmap ):
314+ def _iterate_mri_slices (name , ind , global_id , slides_klass , data , cmap ,
315+ image_format = 'png' ):
287316 """Auxiliary function for parallel processing of mri slices.
288317 """
289318 img_klass = 'slideimg-%s' % name
@@ -294,8 +323,7 @@ def _iterate_mri_slices(name, ind, global_id, slides_klass, data, cmap):
294323 img = _build_image (data , cmap = cmap )
295324 first = True if ind == 0 else False
296325 html = _build_html_image (img , slice_id , div_klass ,
297- img_klass , caption ,
298- first )
326+ img_klass , caption , first )
299327 return ind , html
300328
301329
@@ -497,6 +525,8 @@ def _build_html_slider(slices_range, slides_klass, slider_id):
497525{{default interactive = False}}
498526{{default width = 50}}
499527{{default id = False}}
528+ {{default image_format = 'png'}}
529+ {{default scale = None}}
500530
501531<li class="{{div_klass}}" {{if id}}id="{{id}}"{{endif}}
502532{{if not show}}style="display: none"{{endif}}>
@@ -506,8 +536,19 @@ def _build_html_slider(slices_range, slides_klass, slider_id):
506536{{endif}}
507537<div class="thumbnail">
508538{{if not interactive}}
509- <img alt="" style="width:{{width}}%;"
510- src="data:image/png;base64,{{img}}">
539+ {{if image_format == 'png'}}
540+ {{if scale is not None}}
541+ <img alt="" style="width:{{width}}%;"
542+ src="data:image/png;base64,{{img}}">
543+ {{else}}
544+ <img alt=""
545+ src="data:image/png;base64,{{img}}">
546+ {{endif}}
547+ {{elif image_format == 'svg'}}
548+ <div style="text-align:center;">
549+ {{img}}
550+ </div>
551+ {{endif}}
511552{{else}}
512553 <center>{{interactive}}</center>
513554{{endif}}
@@ -657,7 +698,7 @@ def _validate_input(self, items, captions, section):
657698 return items , captions
658699
659700 def _add_figs_to_section (self , figs , captions , section = 'custom' ,
660- scale = None ):
701+ image_format = 'png' , scale = None ):
661702 """Auxiliary method for `add_section` and `add_figs_to_section`.
662703 """
663704 try :
@@ -668,7 +709,6 @@ def _add_figs_to_section(self, figs, captions, section='custom',
668709 warnings .warn ('Could not import mayavi. Trying to render '
669710 '`mayavi.core.scene.Scene` figure instances'
670711 ' will throw an error.' )
671- import matplotlib as mpl
672712 figs , captions = self ._validate_input (figs , captions , section )
673713 for fig , caption in zip (figs , captions ):
674714 caption = 'custom plot' if caption == '' else caption
@@ -682,27 +722,16 @@ def _add_figs_to_section(self, figs, captions, section='custom',
682722 temp_fname = op .join (tempdir , 'test' )
683723 fig .scene .save_png (temp_fname )
684724 mayavi .mlab .close (fig )
685- with open (temp_fname , 'rb' ) as fid :
686- img = base64 .b64encode (fid .read ()).decode ('ascii' )
687- else :
688- img = _fig_to_img (fig = fig )
689- if scale is None :
690- if isinstance (fig , mpl .figure .Figure ):
691- my_scale = fig .get_figwidth () # "magic' scaling factor
692- else :
693- my_scale = fig .scene .get_size ()
694- my_scale *= 5
695- elif callable (scale ):
696- my_scale = scale (fig )
697725 else :
698- my_scale = scale
699-
726+ img = _fig_to_img ( fig = fig , scale = scale ,
727+ image_format = image_format )
700728 html = image_template .substitute (img = img , id = global_id ,
701729 div_klass = div_klass ,
702730 img_klass = img_klass ,
703731 caption = caption ,
704732 show = True ,
705- width = my_scale )
733+ image_format = image_format ,
734+ width = scale )
706735 self .fnames .append ('%s-#-%s-#-custom' % (caption , sectionvar ))
707736 self ._sectionlabels .append (sectionvar )
708737 self .html .append (html )
@@ -728,7 +757,7 @@ def add_section(self, figs, captions, section='custom'):
728757 section = section )
729758
730759 def add_figs_to_section (self , figs , captions , section = 'custom' ,
731- scale = None ):
760+ scale = None , image_format = 'png' ):
732761 """Append custom user-defined figures.
733762
734763 Parameters
@@ -739,18 +768,23 @@ def add_figs_to_section(self, figs, captions, section='custom',
739768 or np.ndarray (images read in using scipy.imread).
740769 captions : list of str
741770 A list of captions to the figures.
742- scale : float | None | callable
743- Scale the images maintaining the aspect ratio.
744- If None, equals fig.get_figwidth() * 5. If callable, function
745- should take a figure object as input parameter.
746771 section : str
747772 Name of the section. If section already exists, the figures
748773 will be appended to the end of the section
774+ scale : float | None | callable
775+ Scale the images maintaining the aspect ratio.
776+ If None, no scaling is applied.
777+ If float, scale will determine the relative width in percent.
778+ If function, should take a figure object as input parameter.
779+ Defaults to None.
780+ image_format : {'png', 'svg'}
781+ The image format to be used for the report. Defaults to 'png'.
749782 """
750783 return self ._add_figs_to_section (figs = figs , captions = captions ,
751- section = section , scale = scale )
784+ section = section , scale = scale ,
785+ image_format = image_format )
752786
753- def add_images_to_section (self , fnames , captions , scale = 1.0 ,
787+ def add_images_to_section (self , fnames , captions , scale = None ,
754788 section = 'custom' ):
755789 """Append custom user-defined images.
756790
@@ -760,9 +794,9 @@ def add_images_to_section(self, fnames, captions, scale=1.0,
760794 A list of filenames from which images are read.
761795 captions : list of str
762796 A list of captions to the images.
763- scale : float
797+ scale : float | None
764798 Scale the images maintaining the aspect ratio.
765- Defaults to 1 .
799+ Defaults to None. If None, no scaling will be applied .
766800 section : str
767801 Name of the section. If section already exists, the images
768802 will be appended to the end of the section.
@@ -771,8 +805,6 @@ def add_images_to_section(self, fnames, captions, scale=1.0,
771805 # imports PIL anyway. It's not possible to redirect image output
772806 # to binary string using scipy.misc.
773807 from PIL import Image
774-
775- scale *= 100
776808 fnames , captions = self ._validate_input (fnames , captions , section )
777809
778810 for fname , caption in zip (fnames , captions ):
@@ -1245,7 +1277,7 @@ def _render_evoked(self, evoked_fname, figsize=None):
12451277 if len (pick_types (ev .info , meg = 'mag' , eeg = False )) > 0 :
12461278 has_types .append ('mag' )
12471279 for ch_type in has_types :
1248- kwargs = dict (ch_type = ch_type , show = False )
1280+ kwargs . update (ch_type = ch_type )
12491281 img = _fig_to_img (ev .plot_topomap , ** kwargs )
12501282 caption = u'Topomap (ch_type = %s)' % ch_type
12511283 html .append (image_template .substitute (img = img ,
@@ -1315,7 +1347,7 @@ def _render_cov(self, cov_fname, info_fname):
13151347 return html
13161348
13171349 def _render_trans (self , trans_fname , path , info , subject ,
1318- subjects_dir ):
1350+ subjects_dir , image_format = 'png' ):
13191351 """Render trans.
13201352 """
13211353 kwargs = dict (info = info , trans_fname = trans_fname , subject = subject ,
0 commit comments