liveplots.xmlrpcserver
Covered: 171 lines
Missed: 72 lines
Skipped 46 lines
Percent: 70 %
  1
__author__="fccoelho@gmail.com"
  2
__date__ ="$26/02/2009 10:44:29$"
  3
__docformat__ = "restructuredtext en"
  5
import Gnuplot
  6
import numpy
  7
from SimpleXMLRPCServer import SimpleXMLRPCServer
 10
from multiprocessing import Process
 11
from threading import Thread, Lock
 12
from Queue import Queue
 13
import time
 15
Gnuplot.GnuplotOpts.prefer_inline_data = 1
 16
Gnuplot.GnuplotOpts.prefer_fifo_data = 0
 18
__ports_used = []
 20
Q = Queue()
 21
def worker():
 22
    while True:
 23
        item = Q.get()
 24
        item[0](*item[1])
 25
        Q.task_done()
 28
def enqueue(f):
 29
    """Decorator that places the call on a queue"""
 30
    def queued(self,*args,**kw):
 31
        Q.put((f,(self,)+args))
 32
    queued.__doc__ = f.__doc__
 33
    queued.__name__ = f.__name__
 34
    return queued
 36
class RTplot():
 37
    '''
 38
    Real time plotting class based on Gnuplot
 39
    '''
 40
    def __init__(self, persist=0,debug=0,**kwargs):
 41
        self.gp = Gnuplot.Gnuplot(persist = persist, debug=debug)
 42
        self.plots = []
 43
        self.Queue = Q
 44
        self.persist = persist
 45
        self.hold = 0 if 'hold' not in kwargs else kwargs['hold']
 46
        t= Thread(target=worker,args=())
 47
        t.setDaemon(True)
 48
        t.start()
 50
    def set_hold(self,on):
 51
        '''
 52
        Sets hold state of the plot.
 53
        takes 0 or 1 as argument
 54
        '''
 55
        self.hold = on
 57
    def clearFig(self):
 58
        '''
 59
        Clears the figure.
 60
        '''
 61
        self.plots = []
 62
        return 0 
 64
    def close_plot(self):
 65
        self.flush_queue()
 66
        if self.persist:
 67
            self.gp.close()
 68
        return 0 
 70
    def flush_queue(self):
 71
        self.Queue.join()
 72
        return 0
 74
    @enqueue
 75
    def scatter(self,x,y,labels=[],title='',style='points', jitter=True, multiplot=0):
 76
        """
 77
        Makes scatter plots from numpy arrays.
 78
        if x and are multidimensional(lists of lists), multiple scatter plots will be generated, pairing rows.
 80
        :Parameters:
 81
            -`x`: list of numbers or list of lists
 82
            -`y`: list of numbers or list of lists
 83
            -`labels`: list of strings (variable names)
 84
            -`title`: Title of the plot
 85
        """
 86
        assert len(x)==len(y)
 87
        if multiplot:
 88
            sq = numpy.sqrt(len(x))
 89
            ad = 1 if sq%1 >0.5 else 0
 90
            r= numpy.floor(sq);c=numpy.ceil(sq)+ad
 91
            if len(x) == 3:
 92
                r=3;c=1
 93
            self.gp('set multiplot layout %s,%s title "%s"'%(r, c, title))
 94
        else:
 95
            self.gp('set title "%s"'%title)
 96
        if jitter:
 97
            jt = numpy.random.normal(1, 1e-4,1)[0]
 98
        else:
 99
            jt = 1
100
        x = numpy.array(x)
101
        y = numpy.array(y)
103
        if x.shape != y.shape:
104
            raise ValueError("x, %s and y, %s arrays must have the same shape."%(x.shape,y.shape))
105
        if labels:
106
            if len(x.shape)==1:
107
                if len(labels) !=2:
108
                    raise ValueError("Labels list should contain exactly 2 elements, but has %s"%len(labels))
109
            else:
110
                if len(labels) != x.shape[0]:
111
                    raise ValueError("labels list must have exactly %s items, but has %s."%(x.shape[0],len(labels)))
114
        self.gp('set title "%s"'%title)
115
        if not labels:
116
            labels = ['s%s'%i for i in range(x.shape[0])]
117
        if len(x.shape) > 1 and len(x.shape) <= 2:
118
            i = 0
119
            for n in range(x.shape[0]):
120
                self.plots.append(Gnuplot.PlotItems.Data(x[n]*jt,y[n]*jt,title=labels[i],with_=style))
121
                i += 1
122
            if multiplot:
123
                [self.gp.plot(pl) for pl in self.plots]
124
                self.gp('unset multiplot')
125
            else:
126
                self.gp.plot(*tuple(self.plots))
127
        elif len(x.shape) >2:
128
                pass
129
        else:
131
            self.plots.append(Gnuplot.PlotItems.Data(x*jt,y*jt,title=labels[0],with_=style))
132
            if multiplot:
133
                [self.gp.plot(pl) for pl in self.plots]
134
                self.gp('unset multiplot')
135
            else:
136
                self.gp.plot(*tuple(self.plots))
137
        if not self.hold:
138
            self.plots = []
139
        return 0
141
    @enqueue
142
    def lines(self, data, x=[], labels=[],title='',style='lines', multiplot=0):
143
        '''
144
        Create a single/multiple line plot from a numpy array or record array.
146
        :Parameters:
147
            - `data`: must be a list of lists.
148
            - `x`: x values for the series: list
149
            - `labels`: is a list of strings to serve as legend labels
150
            - `style`: plot styles from gnuplot: lines, boxes, points, linespoints, etc.
151
            - `multiplot`: Whether to make multiple subplots
152
        '''
154
        if multiplot:
155
            sq = numpy.sqrt(len(data))
156
            ad = 1 if sq%1 >0.5 else 0
157
            r= numpy.floor(sq);c=numpy.ceil(sq)+ad
158
            if len(data) == 3:
159
                r=3;c=1
160
            self.gp('set multiplot layout %s,%s title "%s"'%(r, c, title))
161
        else:
162
            self.gp('set title "%s"'%title)
164
        assert isinstance (data, list)
165
        data = numpy.array(data)
167
        if len(data.shape) > 1 and len(data.shape) <= 2:
168
            i = 0
169
            for row in data:
170
                if  x== []:
171
                    x = numpy.arange(len(row))
172
                if labels:
173
                    self.plots.append(Gnuplot.PlotItems.Data(x, row,title=labels[i], with_=style))
174
                else:
175
                    self.plots.append(Gnuplot.PlotItems.Data(x, row, with_=style))
176
                i += 1
177
            if multiplot:
178
                [self.gp.plot(pl) for pl in self.plots]
179
                self.gp('unset multiplot')
180
            else:
181
                self.gp.plot(*tuple(self.plots))
182
        elif len(data.shape) >2:
183
                pass
184
        else:
186
            if x == [] :
187
                x = numpy.arange(len(data))
188
            self.plots.append(Gnuplot.PlotItems.Data(x,data,title=labels[0],with_=style))
189
            self.gp.plot(*tuple(self.plots))
190
            if not multiplot:
191
                self.gp('unset multiplot')
192
        if not self.hold:
193
            self.plots = []
194
        return 0
199
    @enqueue  
200
    def histogram(self,data,labels=[],title='',multiplot=0,**kwargs):
201
        '''
202
        Create a single/multiple Histogram plot from a numpy array or record array.
204
        :Parameters:
205
            - `data`: must be a list of lists.
206
            - `labels`: is a list of strings to serve as legend labels
207
            - `multiplot`: Whether to make multiple subplots
208
        '''
209
        if multiplot:
210
            sq = numpy.sqrt(len(data))
211
            ad = 1 if sq%1 >0.5 else 0
212
            r= numpy.floor(sq);c=numpy.ceil(sq)+ad
213
            if len(data) == 3:
214
                r=3;c=1
215
            self.gp('set multiplot layout %s,%s title "%s"'%(r, c, title))
216
        else:
217
            self.gp('set title "%s"'%title)
218
        self.gp('set style data boxes')
220
        assert isinstance (data, list)
221
        data = numpy.array(data)
222
        if not labels:
223
            labels = ['Var_%s'%i for i in range(data.shape[0])]
224
        if len(data.shape) == 2:
225
            for n,row in enumerate(data):
226
                m,bins = numpy.histogram(row,normed=True,bins=50)
227
                d = zip(bins[:-1],m)
228
                self.plots.append(Gnuplot.PlotItems.Data(d,title=labels[n]))
230
            if multiplot:
231
                [self.gp.plot(pl) for pl in self.plots]
232
                self.gp('unset multiplot')
233
            else:
234
                self.gp.plot(*tuple(self.plots))
237
        elif len(data.shape) >2:
238
            pass
239
        elif len(data.shape) == 1:
240
            m,bins = numpy.histogram(data,normed=True,bins=50)
241
            d = zip(bins[:-1],m)
242
            self.plots.append(Gnuplot.PlotItems.Data(d,title=labels[0]))
243
            self.gp.plot(*tuple(self.plots))
244
            if multiplot:
245
                self.gp('unset multiplot')
247
        if not self.hold:
248
            self.plots = []
249
        return 0
253
def _start_server(server, persist,hold):
254
    server.register_instance(RTplot(persist=persist, hold=hold))
255
    server.register_introspection_functions()
256
    server.serve_forever()
260
def rpc_plot(port=0, persist=0, hold=0):
261
    """
262
    XML RPC plot server factory function
263
    returns port if server successfully started or 0
264
    """
265
    if port == 0:
266
        port = 10001
267
    while 1:
268
        if port in __ports_used:
269
            port += 1
270
            continue
271
        try:
272
            server = SimpleXMLRPCServer(("localhost", port),logRequests=False, allow_none=True)
273
            server.register_introspection_functions()
274
            p = Process(target=_start_server, args=(server, persist, hold))
277
            p.daemon = True
278
            p.start()
279
            break
280
        except:         
281
            port += 1
282
    port = port
283
    __ports_used.append(port)
284
    return port
287
if __name__ == "__main__":
288
    pass