1"""
2PySCeS - Python Simulator for Cellular Systems (http://pysces.sourceforge.net)
3
4Copyright (C) 2004-2020 B.G. Olivier, J.M. Rohwer, J.-H.S Hofmeyr all rights reserved,
5
6Brett G. Olivier (bgoli@users.sourceforge.net)
7Triple-J Group for Molecular Cell Physiology
8Stellenbosch University, South Africa.
9
10Permission to use, modify, and distribute this software is given under the
11terms of the PySceS (BSD style) license. See LICENSE.txt that came with
12this distribution for specifics.
13
14NO WARRANTY IS EXPRESSED OR IMPLIED.  USE AT YOUR OWN RISK.
15Brett G. Olivier
16"""
17from __future__ import division, print_function
18from __future__ import absolute_import
19from __future__ import unicode_literals
20
21from pysces.version import __version__
22__doc__ = '''PySCeS plotting module'''
23
24import numpy, scipy
25import os
26import itertools
27from time import strftime
28from getpass import getuser
29
30class PyscesGPlot:
31    '''Prototype plotting class which wraps gnuplot functions and adds some stuff'''
32    __version__ = __version__
33    save_html_header = 1
34    save_html_footer = 1
35    mode_gnuplot4 = 1
36
37    def __init__(self):
38        import scipy.sandbox.gplt as gnuplot
39        self.gnuplot = gnuplot
40
41    def plot2D(self,ginput,x,ylist,cmdout=0,name=None,fmt='w l',ykey=None,log=0):
42        """
43        plot2D(ginput,x,ylist,cmdout=0,name=None,fmt='w l',ykey=None,log=0)
44
45        Plot a 2D graph using gnuplot
46
47        Arguments:
48        =========
49        ginput: an array containing data to be plotted
50        x: the index of the x-axis
51        ylist: a list of y-axis indices
52        cmdout [default=0]: do not plot but instead output the equivalent gnuplot command
53        name [default=None]: the array name to be used with cmdout=1 (otherwise ginput)
54        fmt [default='w l']: gnuplot line format string 'w l'=lines, 'w p'=points
55        ykey [default=None]: list of y-axis key names (otherwise line index is used)
56        log [default=0]: set x and y axis to linear (0) or log (1) scales
57
58        """
59        assert ginput.shape[0] >= 1, 'ginputRow must be >= 1'
60        assert ginput.shape[1] > 1, 'ginputCol must be > 1'
61        assert x <= ginput.shape[1], 'X index should be < ginputCol index'
62        assert len(ylist) >= 1, 'Plotlist must contain a value'
63
64        if ykey != None and len(ylist) != len(ykey):
65            ykey = None
66
67        pltcmd = 'self.gnuplot.plot('
68        for dep in range(len(ylist)):
69            pltcmd += 'ginput[:,' + str(int(x)) + '],ginput[:,' + str(int(ylist[dep])) + '],'
70            if ykey != None:
71                tstr = str(ykey[dep])
72            else:
73                tstr = str(ylist[dep])
74            pltcmd += '\'t \"' + tstr + '\" ' + fmt + '\','
75        pltcmd += ')'
76        #print pltcmd
77        if cmdout and name != None:
78            return pltcmd.replace('ginput',str(name))
79        elif cmdout:
80            return pltcmd
81        else:
82            eval(pltcmd)
83            if log:
84                self.gnuplot.logx('on')
85                self.gnuplot.logy('on')
86            else:
87                self.gnuplot.logx('off')
88                self.gnuplot.logy('off')
89
90
91    def plot3D(self,ginput,x,y,z,cmdout=0,name=None,fmt='w l',zkey=None,arrayout=0,log=0):
92        """
93        plot3D(ginput,x,y,z,cmdout=0,name=None,fmt='w l',zkey=None,arrayout=0,log=0)
94
95        Plot a 3D surface with gnuplot
96
97        Arguments:
98        =========
99        ginput: an array containing data to be plotted
100        x: x-axis index
101        y: y-axis index
102        z: z-axis index
103        cmdout [default=0]: do not plot but instead output the equivalent gnuplot command
104        name [default=None]: the array name to be used with cmdout=1 (otherwise ginput)
105        fmt [default='w l']: gnuplot line format string 'w l'=lines, 'w p'=points
106        zkey [default=None]: list of z-axis key names (otherwise line index is used)
107        arrayout [default=0]: output the 3 column array of data used by scipy.plot3d
108        log [default=0]: set x, y, z axis to linear (0) or log (1) scales
109
110        """
111        assert ginput.shape[0] >= 1, 'ginputRow must be >= 1'
112        assert ginput.shape[1] > 1, 'ginputCol must be > 1'
113        assert x <= ginput.shape[1], 'X index should be < ginputCol index'
114        assert y <= ginput.shape[1], 'Y index should be < ginputCol index'
115        assert z <= ginput.shape[1], 'Z index should be < ginputCol index'
116
117        if zkey != None:
118            tstr = str(zkey)
119        else:
120            tstr = str(z)
121
122        pltcmd = 'self.gnuplot.plot3d('
123        pltcmd += 'ginput[:,:3],'
124        pltcmd += '\'t \"' + tstr + '\" ' + fmt + '\','
125        pltcmd += ')'
126
127        plotfile = []
128        plotfile.append(ginput[:,x])
129        plotfile.append(ginput[:,y])
130        plotfile.append(ginput[:,z])
131        ginput = scipy.transpose(scipy.array(plotfile))
132
133        if cmdout and name != None:
134            if arrayout:
135                return pltcmd.replace('ginput',str(name)),ginput
136            else:
137                return pltcmd.replace('ginput',str(name))
138        elif cmdout:
139            if arrayout:
140                return pltcmd,ginput
141            else:
142                return pltcmd
143        else:
144            eval(pltcmd)
145            if log:
146                self.gnuplot.logx('on')
147                self.gnuplot.logy('on')
148            else:
149                self.gnuplot.logx('off')
150                self.gnuplot.logy('off')
151
152
153    def plotX(self,ginput,cmdout=0,name=None,fmt='w l',log=0):
154        """
155        plotX(ginput,cmdout=0,name=None,fmt='w l',log=0)
156
157        Quick and dirty 2D plot where all other columns are plotted against the first column
158
159        Arguments:
160        =========
161        ginput: an array containing data to be plotted
162        cmdout [default=0]: do not plot but instead output the equivalent gnuplot command
163        name [default=None]: the array name to be used with cmdout=1 (otherwise ginput)
164        fmt [default='w l']: gnuplot line format string 'w l'=lines, 'w p'=points
165        log [default=0]: set x and y axis to linear (0) or log (1) scales
166
167        """
168        assert ginput.shape[0] >= 1 and ginput.shape[1] > 1, 'array must have at least dim(1,2)'
169
170        row,col = ginput.shape
171        pltcmd = 'self.gnuplot.plot('
172        for x in range(1,col):
173            pltcmd += 'ginput[:,0],ginput[:,' + str(x) + '],'
174            pltcmd += '\'t \"' + str(x) + '\" ' + fmt + '\''
175            if x < col-1:
176                pltcmd += ','
177        pltcmd += ')'
178
179        if cmdout and name != None:
180            return pltcmd.replace('ginput',str(name))
181        elif cmdout:
182            return pltcmd
183        else:
184            eval(pltcmd)
185            if log:
186                self.gnuplot.logx('on')
187                self.gnuplot.logy('on')
188            else:
189                self.gnuplot.logx('off')
190                self.gnuplot.logy('off')
191
192    def __save_command__(self,FileName):
193        """
194        __save_command__(FileName)
195
196        Selects the correct gnuplot command depending on gnuplot version set with mode_gnuplot4
197
198        Arguments:
199        =========
200        FileName: the name of the resulting output fil
201
202        """
203        if self.mode_gnuplot4:
204            self.gnuplot.output(FileName,'png',options=\
205                              'medium size 640,480 xffffff x000000 x404040\
206                              xff0000 xffa500 x66cdaa xcdb5cd\
207                              xadd8e6 x0000ff xdda0dd x9500d3')
208        else:
209            self.gnuplot.save(FileName)
210
211    def save(self,filename,path=None):
212        """
213        save(filename,path=None)
214
215        Save the current active plot to a file
216
217        Arguments:
218        =========
219        filename: the name of the output file
220        path [default=None]: the directory where the file should be saved
221
222        """
223        try:
224            if filename[-4:] != '.png':
225                filename += '.png'
226                print('File saved as: ' + filename)
227        except:
228            pass
229
230        if path != None:
231            filename = os.path.join(path,filename)
232        else:
233            filename = os.path.join(os.getcwd(),filename)
234        self.__save_command__(filename)
235
236
237    def save_html(self,imagename,File=None,path=None,name=None,close_file=1):
238        """
239        save_html(imagename,File=None,path=None,name=None,close_file=1)
240
241        Save the current plot to a file plus an HTML file that includes the resulting image
242
243        Arguments:
244        =========
245        imagename: the output image name
246        File [default=None]: the HTML filename defaults to imagename
247        path [default=None]: the output directory
248        name [default=None]: the HTML title of the image
249        close_file [default=1]: close the HTML (1) or leave it open for further editing (0)
250
251        """
252        imagename = str(imagename)
253        if name != None:
254            name = str(name)
255        else:
256            name = ''
257        try:
258            if imagename[-4:] != '.png':
259                imagename += '.png'
260                print('File saved as: ' + imagename)
261        except:
262            pass
263
264        if path != None:
265            imagenameout = os.path.join(path,imagename)
266            if File == None:
267                File = open(os.path.join(path,imagename[:-3]+'html'),'w')
268        else:
269            imagenameout = os.path.join(os.getcwd(),imagename)
270            if File == None:
271                File = open(os.path.join(os.getcwd(),imagename[:-3]+'html'),'w')
272        self.__save_command__(imagename)
273
274        fname = 'PySCeS generated image - '+imagename+'" generated from model file: ' + strftime("%H:%M:%S")
275
276        if File != None:
277            assert File != file, 'WriteArray(input,File=None,Row=None,Col=None,close_file=0)'
278            header = '\n'
279            header += '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\n'
280            header += '<html>\n'
281            header += '<head>\n'
282            header += '<title>PySCeS generated image - ' +imagename+ ' - ' + strftime("%H:%M:%S (%Z)") + '</title>\n'
283            header += '<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">\n'
284            header += '</head>\n'
285            header += '<body bgcolor="#FFFFCC">\n\n'
286            header += '<h4><a href="http://pysces.sourceforge.net">PySCeS</a> generated image - '+imagename+'</h4>\n\n'
287
288            if self.save_html_header:
289                File.write(header)
290            File.write('\n<!-- ' + imagename + '-->\n\n')
291
292            File.write('<p align="center">\n')
293
294            File.write('<img src="'+imagename+'" width="640" height="480" border="2">\n')
295
296            if name != None:
297                File.write('<br><font size="3">' + str(name) + '</font>\n')
298
299            File.write('</p>\n\n')
300            if self.save_html_footer:
301                try:
302                    File.write('<p><a href="http://pysces.sourceforge.net"><font size="3">PySCeS '+self.__version__+\
303                               '</font></a><font size="2"> HTML output (image <i>'+imagename+\
304                               '</i> produced at '+strftime("%H:%M:%S")+' by <i>'+getuser()+'</i>)</font></p>\n')
305                except:
306                    File.write('<p><a href="http://pysces.sourceforge.net"><font size="3">PySCeS '+__version__+\
307                               '</font></a><font size="2"> HTML output (model <i>'+imagename+\
308                               '</i> produced at '+strftime("%H:%M:%S - %Z")+')</font></p>\n')
309                File.write('</body>\n')
310                File.write('</html>\n')
311            else:
312                File.write('\n')
313
314            if close_file:
315                File.close()
316
317
318
319    def gridon(self):
320        """
321        gridon()
322
323        Enable grid for the current active plot
324
325        Arguments:
326        None
327
328        """
329        self.gnuplot.grid('on')
330
331    def gridoff(self):
332        """
333        gridoff()
334
335        Disable grid for the current active plot
336
337        Arguments:
338        None
339
340        """
341        self.gnuplot.grid('off')
342
343    def logx(self):
344        """
345        logx()
346
347        Set x logscale for active plot
348
349        Arguments:
350        None
351
352        """
353        self.gnuplot.logx('on')
354
355    def logy(self):
356        """
357        logy()
358
359        Set y logscale for active plot
360
361        Arguments:
362        None
363
364        """
365        self.gnuplot.logy('on')
366
367    def logxy(self):
368        """
369        logxy()
370
371        Set x and y logscale for active plot
372
373        Arguments:
374        None
375
376        """
377        self.gnuplot.logx('on')
378        self.gnuplot.logy('on')
379
380    def linx(self):
381        """
382        linx()
383
384        Set x linear scale for active plot
385
386        Arguments:
387        None
388
389        """
390        self.gnuplot.logx('off')
391
392    def liny(self):
393        """
394        liny()
395
396        Set y linear scale for active plot
397
398        Arguments:
399        None
400
401        """
402        self.gnuplot.logy('off')
403
404    def linxy(self):
405        """
406        linxy()
407
408        Set x and y linear scale for active plot
409
410        Arguments:
411        None
412
413        """
414        self.gnuplot.logx('off')
415        self.gnuplot.logy('off')
416
417    def logxliny(self):
418        """
419        logxliny()
420
421        Set logscale x and linear scale y for currently active plot
422
423        Arguments:
424        None
425
426        """
427        self.gnuplot.logx('on')
428        self.gnuplot.logy('off')
429
430    def linxlogy(self):
431        """
432        linxlogy()
433
434        Set logscale y and linear scale x for currently active plot
435
436        Arguments:
437        None
438
439        """
440        self.gnuplot.logx('off')
441        self.gnuplot.logy('on')
442
443    def xrng(self,start,end):
444        """
445        xrng(start,end)
446
447        Set the range of the x-axis for currently active plot
448
449        Arguments:
450        =========
451        start: lower value
452        end: upper value
453
454        """
455        self.gnuplot.xaxis((float(start),float(end)))
456
457    def yrng(self,start,end):
458        """
459        yrng(start,end)
460
461        Set the range of the y-axis for currently active plot
462
463        Arguments:
464        =========
465        start: lower value
466        end: upper value
467
468        """
469        self.gnuplot.yaxis((float(start),float(end)))
470
471    def zrng(self,start,end):
472        """
473        zrng(start,end)
474
475        Set the range of the z-axis for currently active plot
476
477        Arguments:
478        =========
479        start: lower value
480        end: upper value
481
482        """
483        self.gnuplot.zaxis((float(start),float(end)))
484
485    def xlabel(self,l=''):
486        """
487        xlabel(l='')
488
489        Set the x-axis label for the currently active plot
490
491        Arguments:
492        =========
493        l [default=' ']: axis label string
494
495        """
496        self.gnuplot.xtitle(str(l))
497
498    def ylabel(self,l=''):
499        """
500        ylabel(l='')
501
502        Set the y-axis label for the currently active plot
503
504        Arguments:
505        =========
506        l [default=' ']: axis label string
507
508        """
509        self.gnuplot.ytitle(str(l))
510
511    def zlabel(self,l=''):
512        """
513        zlabel(l='')
514
515        Set the z-axis label for the currently active plot
516
517        Arguments:
518        =========
519        l [default=' ']: axis label string
520
521        """
522        self.gnuplot.ztitle(str(l))
523
524    def title(self,l=''):
525        """
526        title(l='')
527
528        Set the graph title for the currently active plot
529
530        Arguments:
531        =========
532        l [default=' ']: graph label string
533
534        """
535        self.gnuplot.title(str(l))
536
537    def ticslevel(self,x=0.0):
538        """
539        ticslevel(x=0.0)
540
541        Set the gnuplot ticlevel for the currently active plot
542
543        Arguments:
544        =========
545        x [default=0.0]: gnuplot ticlevel
546
547        """
548        self.gnuplot.ticlevel(float(x))
549
550
551class LineObj(object):
552    __id__ = None
553    idx = None
554    data = None
555    prop = None
556
557    def __init__(self, data, idx, **kwargs):
558        self.idx = idx
559        self.data = data
560        self.prop ={'label' : None,
561                    'linewidth' : None,
562                    'colour' : None,
563                    'style' : None,
564                    }
565        for k in list(kwargs.keys()):
566            if k in self.prop:
567                self.prop[k] = kwargs[k]
568
569class AxisObj(object):
570    __id__ = None
571    idx = None
572    data = None
573    prop = None
574
575    def __init__(self, data, idx, **kwargs):
576        self.idx = idx
577        self.data = data
578        self.prop ={'label' : None,
579                    'log' : False,
580                    }
581        for k in list(kwargs.keys()):
582            if k in self.prop:
583                self.prop[k] = kwargs[k]
584
585class GraphicsObj(object):
586    xaxis = None
587    yaxis = None
588    data = None
589    data_shape = None
590    data_type = None
591    data_lines = None
592    var_idx = None
593    scalars = None
594
595    def setData(self, data):
596        assert type(data) == numpy.ndarray, '\nI need a numpy/scipy ndarray!'
597        assert data.shape[1] > 1, '\nI need at least a 2D array!'
598        self.data = data
599        self.data_shape = data.shape
600        self.data_type = data.dtype.char
601        self.scalars = numpy.zeros((data.shape[0],1),'d')
602        self.resetAxis()
603        self.setDataLabels(['l'+str(l) for l in range(self.data_shape[1])])
604
605    def setDataLabels(self, labels):
606        assert len(labels) == self.data_shape[1], '\nList unacceptable length.'
607        if self.data_lines != None:
608            [self.__delattr__(n) for n in self.data_lines ]
609        self.data_lines = []
610        for l in range(len(labels)):
611            self.data_lines.append(labels[l])
612            ##  lo = LineObj(self.data[:,l].reshape(self.data_shape[0], 1), l, label=labels[l])
613            lo = LineObj(numpy.take(self.data,[l],axis=1), l, label=labels[l])
614            setattr(self,labels[l], lo)
615
616    def setAxis(self, **kwargs):
617        ##  print kwargs
618        for key in list(kwargs.keys()):
619            if key in ['x','y'] and kwargs[key] in self.var_idx:
620                if getattr(self, key+'axis') != None:
621                    self.var_idx.append(getattr(self, key+'axis').idx)
622                    self.var_idx.sort()
623                    ##  print '\t', self.var_idx
624                ##  ao = AxisObj(self.data[:,kwargs[key]].reshape(self.data_shape[0], 1), kwargs[key], label=key)
625                ao = AxisObj(numpy.take(self.data,[kwargs[key]],axis=1), kwargs[key], label=key)
626                setattr(self, key+'axis', ao)
627                a = self.var_idx.pop(self.var_idx.index(kwargs[key]))
628                ##  print '\tkey idx :', key, kwargs[key]
629        ##  print 'var_idx', self.var_idx
630
631
632    def resetAxis(self):
633        self.xaxis = self.yaxis = None
634        self.var_idx = list(range(self.data_shape[1]))
635
636    def getIdx(self, label):
637        assert label in self.data_lines, '\n%s is not a valid data line.\nSelect one of %s' % (label, self.data_lines)
638        return self.data_lines.index(label)
639
640    def setData2Scalar(self, idx):
641        self.scalars = self.data.take([idx],axis=1)
642
643    def dataMinMax(self, idx):
644        return (numpy.min(self.data[:, idx]), numpy.max(self.data[:, idx]))
645
646    def dataLog10(self, idx):
647        self.data[:,idx] = numpy.log10(self.data[:,idx])
648
649    def getVarData(self):
650        return self.data.take(self.var_idx, axis=1)
651
652    def getRawData(self):
653        return {'data':self.data, 'scalars':self.scalars,\
654                'x_idx':self.xaxis.idx, 'y_idx':self.yaxis.idx, 'var_idx':self.var_idx,\
655                'data_lines':self.data_lines}
656
657class Graphics2dObj(GraphicsObj):
658    title = 'Graph'
659    xtitle = 'x'
660    ytitle = 'y'
661    xlog = False
662    ylog = False
663    selected = None
664    __dims__ = 2
665
666    def __init__(self, data, xidx=None, labels=None, selected=None):
667        self.setData(data)
668        if xidx != None: self.setAxis(x=xidx)
669        if labels != None: self.setDataLabels(labels)
670        if selected != None:
671            self.selected = selected
672        else:
673            selected = []
674
675    # working on this ... think I'm almost finished now
676    def getNewByIndex(self, x, lines):
677        data = self.data.take([x]+lines, axis=1)
678        G = Graphics2dObj(data, 0)
679        G.setDataLabels([self.data_lines[x]] + [self.data_lines[i] for i in lines])
680        return G
681
682    # working on this ... think I'm almost finished now
683    def getNewByName(self, x, lines):
684        return self.getNewByIndex(self.getIdx(x), [self.getIdx(l) for l in lines])
685
686class Graphics3dObj(Graphics2dObj):
687    ztitle = 'z'
688    zlog = False
689    __dims__ = 3
690
691    def __init__(self, data, xidx, yidx):
692        self.setData(data)
693        self.setAxis(x=xidx, y=yidx)
694
695class PyscesGPlot2MPL:
696    """
697    Old 'gnuplot' plotting functions using a matplotlib backend
698    """
699    mode_interactive = True
700    mode_create_new_figure = True
701    new_figure_generator = None
702    current_figure = None
703    mode_hold = False
704    # backwards compatibility
705    save_html_header = 1
706    save_html_footer = 1
707    max_open_windows = 50
708
709    def __init__(self):
710        import matplotlib
711        try:
712            matplotlib.use('TKagg')
713        except Exception as ex:
714            print(ex)
715            print("\nPySCeS uses matplotlib's TKagg backend for interactive plotting please enable this backend when compiling matplotlib")
716        ## import matplotlib.axes3d
717        import pylab
718        ## self._matplotlib_axes3d_ = matplotlib.axes3d
719        self.P = pylab
720        if self.mode_interactive: self.P.ion()
721        self.setNewFigureGenerator(self.max_open_windows)
722
723    def setNewFigureGenerator(self, num):
724        """
725        Create a new_figure_generator with range [1,num+1]
726        """
727        self.new_figure_generator = itertools.cycle(list(range(1,num+1)))
728        self.max_open_windows = num
729
730    def setActiveFigure(self, fignum):
731        self.current_figure = self.P.figure(fignum)
732
733    def setNewFigure(self):
734        self.setActiveFigure(next(self.new_figure_generator))
735
736    def closeAllPlotWindows(self):
737        for x in range(self.max_open_windows):
738            self.P.close()
739
740    def plot2D(self, data, x, ylist=[], labels=None, style=None):
741        assert type(ylist) == list, '\nylist must be a list'
742        if self.mode_create_new_figure:
743            self.setNewFigure()
744        if not self.mode_hold: self.P.clf()
745        D = Graphics2dObj(data, x)
746        if labels != None: D.setDataLabels(labels)
747        if len(ylist) == 0:
748            print('ylist empty plotting all data vs (%s)' % x)
749            ylist = list(range(data.shape[1]))
750            ylist.pop(ylist.index(x))
751        if len(ylist) > 0:
752            ylt = (numpy.array(ylist) < D.data_shape[1])
753            assert type(ylt) == numpy.ndarray, '\nInvalid y list this can be caused by a forgotten keyword labels='
754            assert ylt.all(), '\nInvalid y index'
755            D = D.getNewByIndex(x, ylist)
756        self.P.ioff()
757        usedline = []
758        for line in D.data_lines:
759            L = getattr(D, line)
760            ##  print line, D.xaxis.idx, L.idx
761            if L.idx != D.xaxis.idx and line not in usedline:
762                ##  print 'done'
763                usedline.append(line)
764                if style != None:
765                    self.P.plot(D.xaxis.data, L.data, style, label=L.prop['label'])
766                else:
767                    self.P.plot(D.xaxis.data, L.data, label=L.prop['label'])
768        if self.mode_interactive: self.P.ion()
769        self.P.legend()
770
771
772    def plot3D(self, *args, **kwargs):
773        print("*****\nplot3D not implemented yet.\n*****")
774
775    def plotX(self, data):
776        if self.mode_create_new_figure:
777            self.setNewFigure()
778        if not self.mode_hold: self.P.clf()
779        D = Graphics2dObj(data, None)
780        ##  print type(D)
781        ##  print D.var_idx
782        ##  print D.data[1]
783        self.P.plot(D.getVarData())
784
785    def save(self, fname, path=None):
786        fname += '.png'
787        if path != None: fname = os.path.join(path, fname)
788        self.P.savefig(fname)
789
790    def legendOff(self):
791        L = self.P.gca().get_legend()
792        L._visible = False
793        self.P.draw()
794
795    def gridon(self):
796        self.P.grid(True)
797
798    def gridoff(self):
799        self.P.grid(False)
800
801    def logx(self):
802        A = self.P.gca()
803        A.set_xscale('log')
804        self.P.draw()
805
806    def logy(self):
807        A = self.P.gca()
808        A.set_yscale('log')
809        if self.mode_interactive: self.P.draw()
810
811    def linx(self):
812        A = self.P.gca()
813        A.set_xscale('linear')
814        if self.mode_interactive: self.P.draw()
815
816    def liny(self):
817        A = self.P.gca()
818        A.set_yscale('linear')
819        if self.mode_interactive: self.P.draw()
820
821    def linxy(self):
822        A = self.P.gca()
823        A.set_xscale('linear')
824        A.set_yscale('linear')
825        if self.mode_interactive: self.P.draw()
826
827    def logxy(self):
828        A = self.P.gca()
829        A.set_xscale('log')
830        A.set_yscale('log')
831        if self.mode_interactive: self.P.draw()
832
833    def logxliny(self):
834        A = self.P.gca()
835        A.set_xscale('log')
836        A.set_yscale('linear')
837        if self.mode_interactive: self.P.draw()
838
839    def linxlogy(self):
840        A = self.P.gca()
841        A.set_xscale('linear')
842        A.set_yscale('log')
843        if self.mode_interactive: self.P.draw()
844
845    def xrng(self, start, end):
846        self.P.xlim(start, end)
847
848    def yrng(self, start, end):
849        self.P.ylim(start, end)
850
851    def zrng(self, start, end):
852        print("*****\n\tNot implemented yet.\n*****")
853
854    def xlabel(self, l=''):
855        self.P.xlabel(l)
856
857    def ylabel(self, l=''):
858        self.P.ylabel(l)
859
860    def zlabel(self, l=''):
861        print("*****\n\tNot implemented yet.\n*****")
862
863    def title(self, l=''):
864        self.P.title(l)
865
866    def ticslevel(self, x=0.0):
867        print("*****\n\tNot implemented yet.\n*****")
868
869    def setLineWidth(self, w=1):
870        'set line width for current axis'
871        A = self.P.gca()
872        [l.set_linewidth(w) for l in A.get_lines()]
873        if self.mode_interactive: self.P.draw()
874
875    def save_html(self,imagename,File=None,path=None,name=None,close_file=1):
876        imagename = str(imagename)
877        if name != None:
878            name = str(name)
879        else:
880            name = ''
881        try:
882            if imagename[-4:] != '.png':
883                imagename += '.png'
884                print('File saved as: ' + imagename)
885        except:
886            pass
887
888        if path != None:
889            imagenameout = os.path.join(path,imagename)
890            if File == None:
891                File = open(os.path.join(path,imagename[:-3]+'html'),'w')
892        else:
893            imagenameout = os.path.join(os.getcwd(),imagename)
894            if File == None:
895                File = open(os.path.join(os.getcwd(),imagename[:-3]+'html'),'w')
896        self.P.savefig(imagenameout,dpi=80)
897
898        fname = 'PySCeS generated image - '+imagename+'" generated from model file: ' + strftime("%H:%M:%S")
899
900        if File != None:
901            assert File != file, 'WriteArray(input,File=None,Row=None,Col=None,close_file=0)'
902            header = '\n'
903            header += '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">\n'
904            header += '<html>\n'
905            header += '<head>\n'
906            header += '<title>PySCeS generated image - ' +imagename+ ' - ' + strftime("%H:%M:%S (%Z)") + '</title>\n'
907            header += '<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">\n'
908            header += '</head>\n'
909            header += '<body bgcolor="#FFFFCC">\n\n'
910            header += '<h4><a href="http://pysces.sourceforge.net">PySCeS</a> generated image - '+imagename+'</h4>\n\n'
911
912            if self.save_html_header:
913                File.write(header)
914            File.write('\n<!-- ' + imagename + '-->\n\n')
915
916            File.write('<p align="center">\n')
917
918            File.write('<img src="'+imagename+'" width="640" height="480" border="2">\n')
919
920            if name != None:
921                File.write('<br><font size="3">' + str(name) + '</font>\n')
922
923            File.write('</p>\n\n')
924            if self.save_html_footer:
925                try:
926                    File.write('<p><a href="http://pysces.sourceforge.net"><font size="3">PySCeS '+self.__version__+\
927                               '</font></a><font size="2"> HTML output (image <i>'+imagename+\
928                               '</i> produced at '+strftime("%H:%M:%S")+' by <i>'+getuser()+'</i>)</font></p>\n')
929                except:
930                    File.write('<p><a href="http://pysces.sourceforge.net"><font size="3">PySCeS '+__version__+\
931                               '</font></a><font size="2"> HTML output (model <i>'+imagename+\
932                               '</i> produced at '+strftime("%H:%M:%S - %Z")+')</font></p>\n')
933                File.write('</body>\n')
934                File.write('</html>\n')
935            else:
936                File.write('\n')
937
938            if close_file:
939                File.close()
940
941class PyscesGPlot2MplExt(PyscesGPlot2MPL):
942    def __init__(self):
943        PyscesGPlot2MPL.__init__(self)
944
945    def plotLines2DX(self, data, x, labels=None):
946        if not self.mode_hold: self.P.clf()
947        ##  F = self.P.figure(1)
948        ##  S = self.P.subplot(1,1,1)
949        D = Graphics2dObj(data, x)
950        print(D.var_idx)
951        print(D.data[1])
952        self.P.plot(D.xaxis.data, D.getVarData())
953