##// END OF EJS Templates
More work on the kernel.
Brian Granger -
Show More
@@ -0,0 +1,90 b''
1 from numpy import *
2
3 def mandel(n, m, itermax, xmin, xmax, ymin, ymax):
4 '''
5 Fast mandelbrot computation using numpy.
6
7 (n, m) are the output image dimensions
8 itermax is the maximum number of iterations to do
9 xmin, xmax, ymin, ymax specify the region of the
10 set to compute.
11 '''
12 # The point of ix and iy is that they are 2D arrays
13 # giving the x-coord and y-coord at each point in
14 # the array. The reason for doing this will become
15 # clear below...
16 ix, iy = mgrid[0:n, 0:m]
17 # Now x and y are the x-values and y-values at each
18 # point in the array, linspace(start, end, n)
19 # is an array of n linearly spaced points between
20 # start and end, and we then index this array using
21 # numpy fancy indexing. If A is an array and I is
22 # an array of indices, then A[I] has the same shape
23 # as I and at each place i in I has the value A[i].
24 x = linspace(xmin, xmax, n)[ix]
25 y = linspace(ymin, ymax, m)[iy]
26 # c is the complex number with the given x, y coords
27 c = x+complex(0,1)*y
28 del x, y # save a bit of memory, we only need z
29 # the output image coloured according to the number
30 # of iterations it takes to get to the boundary
31 # abs(z)>2
32 img = zeros(c.shape, dtype=int)
33 # Here is where the improvement over the standard
34 # algorithm for drawing fractals in numpy comes in.
35 # We flatten all the arrays ix, iy and c. This
36 # flattening doesn't use any more memory because
37 # we are just changing the shape of the array, the
38 # data in memory stays the same. It also affects
39 # each array in the same way, so that index i in
40 # array c has x, y coords ix[i], iy[i]. The way the
41 # algorithm works is that whenever abs(z)>2 we
42 # remove the corresponding index from each of the
43 # arrays ix, iy and c. Since we do the same thing
44 # to each array, the correspondence between c and
45 # the x, y coords stored in ix and iy is kept.
46 ix.shape = n*m
47 iy.shape = n*m
48 c.shape = n*m
49 # we iterate z->z^2+c with z starting at 0, but the
50 # first iteration makes z=c so we just start there.
51 # We need to copy c because otherwise the operation
52 # z->z^2 will send c->c^2.
53 z = copy(c)
54 for i in xrange(itermax):
55 if not len(z): break # all points have escaped
56 # equivalent to z = z*z+c but quicker and uses
57 # less memory
58 multiply(z, z, z)
59 add(z, c, z)
60 # these are the points that have escaped
61 rem = abs(z)>2.0
62 # colour them with the iteration number, we
63 # add one so that points which haven't
64 # escaped have 0 as their iteration number,
65 # this is why we keep the arrays ix and iy
66 # because we need to know which point in img
67 # to colour
68 img[ix[rem], iy[rem]] = i+1
69 # -rem is the array of points which haven't
70 # escaped, in numpy -A for a boolean array A
71 # is the NOT operation.
72 rem = -rem
73 # So we select out the points in
74 # z, ix, iy and c which are still to be
75 # iterated on in the next step
76 z = z[rem]
77 ix, iy = ix[rem], iy[rem]
78 c = c[rem]
79 return img
80
81 if __name__=='__main__':
82 from pylab import *
83 import time
84 start = time.time()
85 I = mandel(400, 400, 100, -2, .5, -1.25, 1.25)
86 print 'Time taken:', time.time()-start
87 I[I==0] = 101
88 img = imshow(I.T, origin='lower left')
89 img.write_png('mandel.png', noscale=True)
90 show()
@@ -1,458 +1,458 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 The IPython cluster directory
5 5 """
6 6
7 7 #-----------------------------------------------------------------------------
8 8 # Copyright (C) 2008-2009 The IPython Development Team
9 9 #
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING, distributed as part of this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 18 from __future__ import with_statement
19 19
20 20 import os
21 21 import shutil
22 22 import sys
23 23
24 24 from twisted.python import log
25 25
26 26 from IPython.core import release
27 27 from IPython.config.loader import PyFileConfigLoader
28 28 from IPython.core.application import Application
29 29 from IPython.core.component import Component
30 30 from IPython.config.loader import ArgParseConfigLoader, NoConfigDefault
31 31 from IPython.utils.traitlets import Unicode, Bool
32 32
33 33 #-----------------------------------------------------------------------------
34 34 # Imports
35 35 #-----------------------------------------------------------------------------
36 36
37 37
38 38 class ClusterDirError(Exception):
39 39 pass
40 40
41 41
42 42 class PIDFileError(Exception):
43 43 pass
44 44
45 45
46 46 class ClusterDir(Component):
47 47 """An object to manage the cluster directory and its resources.
48 48
49 49 The cluster directory is used by :command:`ipcontroller`,
50 50 :command:`ipcontroller` and :command:`ipcontroller` to manage the
51 51 configuration, logging and security of these applications.
52 52
53 53 This object knows how to find, create and manage these directories. This
54 54 should be used by any code that want's to handle cluster directories.
55 55 """
56 56
57 57 security_dir_name = Unicode('security')
58 58 log_dir_name = Unicode('log')
59 59 pid_dir_name = Unicode('pid')
60 60 security_dir = Unicode(u'')
61 61 log_dir = Unicode(u'')
62 62 pid_dir = Unicode(u'')
63 63 location = Unicode(u'')
64 64
65 65 def __init__(self, location):
66 66 super(ClusterDir, self).__init__(None)
67 67 self.location = location
68 68
69 69 def _location_changed(self, name, old, new):
70 70 if not os.path.isdir(new):
71 71 os.makedirs(new, mode=0777)
72 72 else:
73 73 os.chmod(new, 0777)
74 74 self.security_dir = os.path.join(new, self.security_dir_name)
75 75 self.log_dir = os.path.join(new, self.log_dir_name)
76 76 self.pid_dir = os.path.join(new, self.pid_dir_name)
77 77 self.check_dirs()
78 78
79 79 def _log_dir_changed(self, name, old, new):
80 80 self.check_log_dir()
81 81
82 82 def check_log_dir(self):
83 83 if not os.path.isdir(self.log_dir):
84 84 os.mkdir(self.log_dir, 0777)
85 85 else:
86 86 os.chmod(self.log_dir, 0777)
87 87
88 88 def _security_dir_changed(self, name, old, new):
89 89 self.check_security_dir()
90 90
91 91 def check_security_dir(self):
92 92 if not os.path.isdir(self.security_dir):
93 93 os.mkdir(self.security_dir, 0700)
94 94 else:
95 95 os.chmod(self.security_dir, 0700)
96 96
97 97 def _pid_dir_changed(self, name, old, new):
98 98 self.check_pid_dir()
99 99
100 100 def check_pid_dir(self):
101 101 if not os.path.isdir(self.pid_dir):
102 102 os.mkdir(self.pid_dir, 0700)
103 103 else:
104 104 os.chmod(self.pid_dir, 0700)
105 105
106 106 def check_dirs(self):
107 107 self.check_security_dir()
108 108 self.check_log_dir()
109 109 self.check_pid_dir()
110 110
111 111 def load_config_file(self, filename):
112 112 """Load a config file from the top level of the cluster dir.
113 113
114 114 Parameters
115 115 ----------
116 116 filename : unicode or str
117 117 The filename only of the config file that must be located in
118 118 the top-level of the cluster directory.
119 119 """
120 120 loader = PyFileConfigLoader(filename, self.location)
121 121 return loader.load_config()
122 122
123 123 def copy_config_file(self, config_file, path=None, overwrite=False):
124 124 """Copy a default config file into the active cluster directory.
125 125
126 126 Default configuration files are kept in :mod:`IPython.config.default`.
127 127 This function moves these from that location to the working cluster
128 128 directory.
129 129 """
130 130 if path is None:
131 131 import IPython.config.default
132 132 path = IPython.config.default.__file__.split(os.path.sep)[:-1]
133 133 path = os.path.sep.join(path)
134 134 src = os.path.join(path, config_file)
135 135 dst = os.path.join(self.location, config_file)
136 136 if not os.path.isfile(dst) or overwrite:
137 137 shutil.copy(src, dst)
138 138
139 139 def copy_all_config_files(self, path=None, overwrite=False):
140 140 """Copy all config files into the active cluster directory."""
141 141 for f in ['ipcontroller_config.py', 'ipengine_config.py',
142 142 'ipcluster_config.py']:
143 143 self.copy_config_file(f, path=path, overwrite=overwrite)
144 144
145 145 @classmethod
146 146 def create_cluster_dir(csl, cluster_dir):
147 147 """Create a new cluster directory given a full path.
148 148
149 149 Parameters
150 150 ----------
151 151 cluster_dir : str
152 152 The full path to the cluster directory. If it does exist, it will
153 153 be used. If not, it will be created.
154 154 """
155 155 return ClusterDir(cluster_dir)
156 156
157 157 @classmethod
158 158 def create_cluster_dir_by_profile(cls, path, profile='default'):
159 159 """Create a cluster dir by profile name and path.
160 160
161 161 Parameters
162 162 ----------
163 163 path : str
164 164 The path (directory) to put the cluster directory in.
165 165 profile : str
166 166 The name of the profile. The name of the cluster directory will
167 167 be "cluster_<profile>".
168 168 """
169 169 if not os.path.isdir(path):
170 170 raise ClusterDirError('Directory not found: %s' % path)
171 171 cluster_dir = os.path.join(path, 'cluster_' + profile)
172 172 return ClusterDir(cluster_dir)
173 173
174 174 @classmethod
175 175 def find_cluster_dir_by_profile(cls, ipythondir, profile='default'):
176 176 """Find an existing cluster dir by profile name, return its ClusterDir.
177 177
178 178 This searches through a sequence of paths for a cluster dir. If it
179 179 is not found, a :class:`ClusterDirError` exception will be raised.
180 180
181 181 The search path algorithm is:
182 182 1. ``os.getcwd()``
183 183 2. ``ipythondir``
184 184 3. The directories found in the ":" separated
185 185 :env:`IPCLUSTERDIR_PATH` environment variable.
186 186
187 187 Parameters
188 188 ----------
189 189 ipythondir : unicode or str
190 190 The IPython directory to use.
191 191 profile : unicode or str
192 192 The name of the profile. The name of the cluster directory
193 193 will be "cluster_<profile>".
194 194 """
195 195 dirname = 'cluster_' + profile
196 196 cluster_dir_paths = os.environ.get('IPCLUSTERDIR_PATH','')
197 197 if cluster_dir_paths:
198 198 cluster_dir_paths = cluster_dir_paths.split(':')
199 199 else:
200 200 cluster_dir_paths = []
201 201 paths = [os.getcwd(), ipythondir] + cluster_dir_paths
202 202 for p in paths:
203 203 cluster_dir = os.path.join(p, dirname)
204 204 if os.path.isdir(cluster_dir):
205 205 return ClusterDir(cluster_dir)
206 206 else:
207 207 raise ClusterDirError('Cluster directory not found in paths: %s' % dirname)
208 208
209 209 @classmethod
210 210 def find_cluster_dir(cls, cluster_dir):
211 211 """Find/create a cluster dir and return its ClusterDir.
212 212
213 213 This will create the cluster directory if it doesn't exist.
214 214
215 215 Parameters
216 216 ----------
217 217 cluster_dir : unicode or str
218 218 The path of the cluster directory. This is expanded using
219 219 :func:`os.path.expandvars` and :func:`os.path.expanduser`.
220 220 """
221 221 cluster_dir = os.path.expandvars(os.path.expanduser(cluster_dir))
222 222 if not os.path.isdir(cluster_dir):
223 223 raise ClusterDirError('Cluster directory not found: %s' % cluster_dir)
224 224 return ClusterDir(cluster_dir)
225 225
226 226
227 227 class AppWithClusterDirArgParseConfigLoader(ArgParseConfigLoader):
228 228 """Default command line options for IPython cluster applications."""
229 229
230 230 def _add_other_arguments(self):
231 self.parser.add_argument('-ipythondir', '--ipython-dir',
231 self.parser.add_argument('--ipython-dir',
232 232 dest='Global.ipythondir',type=str,
233 233 help='Set to override default location of Global.ipythondir.',
234 234 default=NoConfigDefault,
235 235 metavar='Global.ipythondir'
236 236 )
237 self.parser.add_argument('-p','-profile', '--profile',
237 self.parser.add_argument('-p', '--profile',
238 238 dest='Global.profile',type=str,
239 239 help='The string name of the profile to be used. This determines '
240 240 'the name of the cluster dir as: cluster_<profile>. The default profile '
241 241 'is named "default". The cluster directory is resolve this way '
242 242 'if the --cluster-dir option is not used.',
243 243 default=NoConfigDefault,
244 244 metavar='Global.profile'
245 245 )
246 self.parser.add_argument('-log_level', '--log-level',
246 self.parser.add_argument('--log-level',
247 247 dest="Global.log_level",type=int,
248 248 help='Set the log level (0,10,20,30,40,50). Default is 30.',
249 249 default=NoConfigDefault,
250 250 metavar="Global.log_level"
251 251 )
252 self.parser.add_argument('-cluster_dir', '--cluster-dir',
252 self.parser.add_argument('--cluster-dir',
253 253 dest='Global.cluster_dir',type=str,
254 254 help='Set the cluster dir. This overrides the logic used by the '
255 255 '--profile option.',
256 256 default=NoConfigDefault,
257 257 metavar='Global.cluster_dir'
258 258 )
259 self.parser.add_argument('-clean_logs', '--clean-logs',
259 self.parser.add_argument('--clean-logs',
260 260 dest='Global.clean_logs', action='store_true',
261 261 help='Delete old log flies before starting.',
262 262 default=NoConfigDefault
263 263 )
264 self.parser.add_argument('-noclean_logs', '--no-clean-logs',
264 self.parser.add_argument('--no-clean-logs',
265 265 dest='Global.clean_logs', action='store_false',
266 266 help="Don't Delete old log flies before starting.",
267 267 default=NoConfigDefault
268 268 )
269 269
270 270 class ApplicationWithClusterDir(Application):
271 271 """An application that puts everything into a cluster directory.
272 272
273 273 Instead of looking for things in the ipythondir, this type of application
274 274 will use its own private directory called the "cluster directory"
275 275 for things like config files, log files, etc.
276 276
277 277 The cluster directory is resolved as follows:
278 278
279 279 * If the ``--cluster-dir`` option is given, it is used.
280 280 * If ``--cluster-dir`` is not given, the application directory is
281 281 resolve using the profile name as ``cluster_<profile>``. The search
282 282 path for this directory is then i) cwd if it is found there
283 283 and ii) in ipythondir otherwise.
284 284
285 285 The config file for the application is to be put in the cluster
286 286 dir and named the value of the ``config_file_name`` class attribute.
287 287 """
288 288
289 289 auto_create_cluster_dir = True
290 290
291 291 def create_default_config(self):
292 292 super(ApplicationWithClusterDir, self).create_default_config()
293 293 self.default_config.Global.profile = 'default'
294 294 self.default_config.Global.cluster_dir = ''
295 295 self.default_config.Global.log_to_file = False
296 296 self.default_config.Global.clean_logs = False
297 297
298 298 def create_command_line_config(self):
299 299 """Create and return a command line config loader."""
300 300 return AppWithClusterDirArgParseConfigLoader(
301 301 description=self.description,
302 302 version=release.version
303 303 )
304 304
305 305 def find_resources(self):
306 306 """This resolves the cluster directory.
307 307
308 308 This tries to find the cluster directory and if successful, it will
309 309 have done:
310 310 * Sets ``self.cluster_dir_obj`` to the :class:`ClusterDir` object for
311 311 the application.
312 312 * Sets ``self.cluster_dir`` attribute of the application and config
313 313 objects.
314 314
315 315 The algorithm used for this is as follows:
316 316 1. Try ``Global.cluster_dir``.
317 317 2. Try using ``Global.profile``.
318 318 3. If both of these fail and ``self.auto_create_cluster_dir`` is
319 319 ``True``, then create the new cluster dir in the IPython directory.
320 320 4. If all fails, then raise :class:`ClusterDirError`.
321 321 """
322 322
323 323 try:
324 324 cluster_dir = self.command_line_config.Global.cluster_dir
325 325 except AttributeError:
326 326 cluster_dir = self.default_config.Global.cluster_dir
327 327 cluster_dir = os.path.expandvars(os.path.expanduser(cluster_dir))
328 328 try:
329 329 self.cluster_dir_obj = ClusterDir.find_cluster_dir(cluster_dir)
330 330 except ClusterDirError:
331 331 pass
332 332 else:
333 333 self.log.info('Using existing cluster dir: %s' % \
334 334 self.cluster_dir_obj.location
335 335 )
336 336 self.finish_cluster_dir()
337 337 return
338 338
339 339 try:
340 340 self.profile = self.command_line_config.Global.profile
341 341 except AttributeError:
342 342 self.profile = self.default_config.Global.profile
343 343 try:
344 344 self.cluster_dir_obj = ClusterDir.find_cluster_dir_by_profile(
345 345 self.ipythondir, self.profile)
346 346 except ClusterDirError:
347 347 pass
348 348 else:
349 349 self.log.info('Using existing cluster dir: %s' % \
350 350 self.cluster_dir_obj.location
351 351 )
352 352 self.finish_cluster_dir()
353 353 return
354 354
355 355 if self.auto_create_cluster_dir:
356 356 self.cluster_dir_obj = ClusterDir.create_cluster_dir_by_profile(
357 357 self.ipythondir, self.profile
358 358 )
359 359 self.log.info('Creating new cluster dir: %s' % \
360 360 self.cluster_dir_obj.location
361 361 )
362 362 self.finish_cluster_dir()
363 363 else:
364 364 raise ClusterDirError('Could not find a valid cluster directory.')
365 365
366 366 def finish_cluster_dir(self):
367 367 # Set the cluster directory
368 368 self.cluster_dir = self.cluster_dir_obj.location
369 369
370 370 # These have to be set because they could be different from the one
371 371 # that we just computed. Because command line has the highest
372 372 # priority, this will always end up in the master_config.
373 373 self.default_config.Global.cluster_dir = self.cluster_dir
374 374 self.command_line_config.Global.cluster_dir = self.cluster_dir
375 375
376 376 # Set the search path to the cluster directory
377 377 self.config_file_paths = (self.cluster_dir,)
378 378
379 379 def find_config_file_name(self):
380 380 """Find the config file name for this application."""
381 381 # For this type of Application it should be set as a class attribute.
382 382 if not hasattr(self, 'config_file_name'):
383 383 self.log.critical("No config filename found")
384 384
385 385 def find_config_file_paths(self):
386 386 # Set the search path to the cluster directory
387 387 self.config_file_paths = (self.cluster_dir,)
388 388
389 389 def pre_construct(self):
390 390 # The log and security dirs were set earlier, but here we put them
391 391 # into the config and log them.
392 392 config = self.master_config
393 393 sdir = self.cluster_dir_obj.security_dir
394 394 self.security_dir = config.Global.security_dir = sdir
395 395 ldir = self.cluster_dir_obj.log_dir
396 396 self.log_dir = config.Global.log_dir = ldir
397 397 pdir = self.cluster_dir_obj.pid_dir
398 398 self.pid_dir = config.Global.pid_dir = pdir
399 399 self.log.info("Cluster directory set to: %s" % self.cluster_dir)
400 400
401 401 def start_logging(self):
402 402 # Remove old log files
403 403 if self.master_config.Global.clean_logs:
404 404 log_dir = self.master_config.Global.log_dir
405 405 for f in os.listdir(log_dir):
406 406 if f.startswith(self.name + '-') and f.endswith('.log'):
407 407 os.remove(os.path.join(log_dir, f))
408 408 # Start logging to the new log file
409 409 if self.master_config.Global.log_to_file:
410 410 log_filename = self.name + '-' + str(os.getpid()) + '.log'
411 411 logfile = os.path.join(self.log_dir, log_filename)
412 412 open_log_file = open(logfile, 'w')
413 413 else:
414 414 open_log_file = sys.stdout
415 415 log.startLogging(open_log_file)
416 416
417 417 def write_pid_file(self):
418 418 """Create a .pid file in the pid_dir with my pid.
419 419
420 420 This must be called after pre_construct, which sets `self.pid_dir`.
421 421 This raises :exc:`PIDFileError` if the pid file exists already.
422 422 """
423 423 pid_file = os.path.join(self.pid_dir, self.name + '.pid')
424 424 if os.path.isfile(pid_file):
425 425 pid = self.get_pid_from_file()
426 426 raise PIDFileError(
427 427 'The pid file [%s] already exists. \nThis could mean that this '
428 428 'server is already running with [pid=%s].' % (pid_file, pid))
429 429 with open(pid_file, 'w') as f:
430 430 self.log.info("Creating pid file: %s" % pid_file)
431 431 f.write(repr(os.getpid())+'\n')
432 432
433 433 def remove_pid_file(self):
434 434 """Remove the pid file.
435 435
436 436 This should be called at shutdown by registering a callback with
437 437 :func:`reactor.addSystemEventTrigger`.
438 438 """
439 439 pid_file = os.path.join(self.pid_dir, self.name + '.pid')
440 440 if os.path.isfile(pid_file):
441 441 try:
442 442 self.log.info("Removing pid file: %s" % pid_file)
443 443 os.remove(pid_file)
444 444 except:
445 445 pass
446 446
447 447 def get_pid_from_file(self):
448 448 """Get the pid from the pid file.
449 449
450 450 If the pid file doesn't exist a :exc:`PIDFileError` is raised.
451 451 """
452 452 pid_file = os.path.join(self.pid_dir, self.name + '.pid')
453 453 if os.path.isfile(pid_file):
454 454 with open(pid_file, 'r') as f:
455 455 pid = int(f.read().strip())
456 456 return pid
457 457 else:
458 458 raise PIDFileError('pid file not found: %s' % pid_file) No newline at end of file
@@ -1,378 +1,383 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 The ipcluster application.
5 5 """
6 6
7 7 #-----------------------------------------------------------------------------
8 8 # Copyright (C) 2008-2009 The IPython Development Team
9 9 #
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING, distributed as part of this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 18 import logging
19 19 import os
20 20 import signal
21 21 import sys
22 22
23 23 from twisted.scripts._twistd_unix import daemonize
24 24
25 25 from IPython.core import release
26 26 from IPython.external import argparse
27 27 from IPython.config.loader import ArgParseConfigLoader, NoConfigDefault
28 28 from IPython.utils.importstring import import_item
29 29
30 30 from IPython.kernel.clusterdir import (
31 31 ApplicationWithClusterDir, ClusterDirError, PIDFileError
32 32 )
33 33
34 34 from twisted.internet import reactor, defer
35 35 from twisted.python import log
36 36
37 37 #-----------------------------------------------------------------------------
38 38 # Code for launchers
39 39 #-----------------------------------------------------------------------------
40 40
41 41
42 42
43 43 #-----------------------------------------------------------------------------
44 44 # The ipcluster application
45 45 #-----------------------------------------------------------------------------
46 46
47 47
48 48 class IPClusterCLLoader(ArgParseConfigLoader):
49 49
50 50 def _add_arguments(self):
51 51 # This has all the common options that all subcommands use
52 52 parent_parser1 = argparse.ArgumentParser(add_help=False)
53 parent_parser1.add_argument('-ipythondir', '--ipython-dir',
53 parent_parser1.add_argument('--ipython-dir',
54 54 dest='Global.ipythondir',type=str,
55 55 help='Set to override default location of Global.ipythondir.',
56 56 default=NoConfigDefault,
57 57 metavar='Global.ipythondir')
58 parent_parser1.add_argument('-log_level', '--log-level',
58 parent_parser1.add_argument('--log-level',
59 59 dest="Global.log_level",type=int,
60 60 help='Set the log level (0,10,20,30,40,50). Default is 30.',
61 61 default=NoConfigDefault,
62 62 metavar='Global.log_level')
63 63
64 64 # This has all the common options that other subcommands use
65 65 parent_parser2 = argparse.ArgumentParser(add_help=False)
66 parent_parser2.add_argument('-p','-profile', '--profile',
66 parent_parser2.add_argument('-p','--profile',
67 67 dest='Global.profile',type=str,
68 68 default=NoConfigDefault,
69 69 help='The string name of the profile to be used. This determines '
70 70 'the name of the cluster dir as: cluster_<profile>. The default profile '
71 71 'is named "default". The cluster directory is resolve this way '
72 72 'if the --cluster-dir option is not used.',
73 73 default=NoConfigDefault,
74 74 metavar='Global.profile')
75 parent_parser2.add_argument('-cluster_dir', '--cluster-dir',
75 parent_parser2.add_argument('--cluster-dir',
76 76 dest='Global.cluster_dir',type=str,
77 77 default=NoConfigDefault,
78 78 help='Set the cluster dir. This overrides the logic used by the '
79 79 '--profile option.',
80 80 default=NoConfigDefault,
81 81 metavar='Global.cluster_dir')
82 82 parent_parser2.add_argument('--log-to-file',
83 83 action='store_true', dest='Global.log_to_file',
84 84 default=NoConfigDefault,
85 85 help='Log to a file in the log directory (default is stdout)'
86 86 )
87 87
88 88 subparsers = self.parser.add_subparsers(
89 89 dest='Global.subcommand',
90 90 title='ipcluster subcommands',
91 91 description='ipcluster has a variety of subcommands. '
92 92 'The general way of running ipcluster is "ipcluster <cmd> '
93 93 ' [options]""',
94 94 help='For more help, type "ipcluster <cmd> -h"')
95 95
96 96 parser_list = subparsers.add_parser(
97 97 'list',
98 98 help='List all clusters in cwd and ipythondir.',
99 99 parents=[parent_parser1]
100 100 )
101 101
102 102 parser_create = subparsers.add_parser(
103 103 'create',
104 104 help='Create a new cluster directory.',
105 105 parents=[parent_parser1, parent_parser2]
106 106 )
107 107 parser_create.add_argument(
108 108 '--reset-config',
109 109 dest='Global.reset_config', action='store_true',
110 110 default=NoConfigDefault,
111 111 help='Recopy the default config files to the cluster directory. '
112 112 'You will loose any modifications you have made to these files.'
113 113 )
114 114
115 115 parser_start = subparsers.add_parser(
116 116 'start',
117 117 help='Start a cluster.',
118 118 parents=[parent_parser1, parent_parser2]
119 119 )
120 120 parser_start.add_argument(
121 121 '-n', '--number',
122 122 type=int, dest='Global.n',
123 123 default=NoConfigDefault,
124 124 help='The number of engines to start.',
125 125 metavar='Global.n'
126 126 )
127 parser_start.add_argument('-clean_logs', '--clean-logs',
127 parser_start.add_argument('--clean-logs',
128 128 dest='Global.clean_logs', action='store_true',
129 129 help='Delete old log flies before starting.',
130 130 default=NoConfigDefault
131 131 )
132 parser_start.add_argument('-noclean_logs', '--no-clean-logs',
132 parser_start.add_argument('--no-clean-logs',
133 133 dest='Global.clean_logs', action='store_false',
134 134 help="Don't delete old log flies before starting.",
135 135 default=NoConfigDefault
136 136 )
137 parser_start.add_argument('--daemon', '-daemon',
137 parser_start.add_argument('--daemon',
138 138 dest='Global.daemonize', action='store_true',
139 139 help='Daemonize the ipcluster program. This implies --log-to-file',
140 140 default=NoConfigDefault
141 141 )
142 parser_start.add_argument('--nodaemon', '-nodaemon',
142 parser_start.add_argument('--nodaemon',
143 143 dest='Global.daemonize', action='store_false',
144 144 help="Dont't daemonize the ipcluster program.",
145 145 default=NoConfigDefault
146 146 )
147 147
148 148 parser_start = subparsers.add_parser(
149 149 'stop',
150 150 help='Stop a cluster.',
151 151 parents=[parent_parser1, parent_parser2]
152 152 )
153 parser_start.add_argument('-sig', '--sig',
153 parser_start.add_argument('--signal-number',
154 154 dest='Global.stop_signal', type=int,
155 155 help="The signal number to use in stopping the cluster (default=2).",
156 metavar="Global.stop_signal",
156 157 default=NoConfigDefault
157 158 )
158 159
159 160 default_config_file_name = 'ipcluster_config.py'
160 161
161 162
162 163 class IPClusterApp(ApplicationWithClusterDir):
163 164
164 165 name = 'ipcluster'
165 166 description = 'Start an IPython cluster (controller and engines).'
166 167 config_file_name = default_config_file_name
167 168 default_log_level = logging.INFO
168 169 auto_create_cluster_dir = False
169 170
170 171 def create_default_config(self):
171 172 super(IPClusterApp, self).create_default_config()
172 173 self.default_config.Global.controller_launcher = \
173 174 'IPython.kernel.launcher.LocalControllerLauncher'
174 175 self.default_config.Global.engine_launcher = \
175 176 'IPython.kernel.launcher.LocalEngineSetLauncher'
176 177 self.default_config.Global.n = 2
177 178 self.default_config.Global.reset_config = False
178 179 self.default_config.Global.clean_logs = True
179 180 self.default_config.Global.stop_signal = 2
180 181 self.default_config.Global.daemonize = False
181 182
182 183 def create_command_line_config(self):
183 184 """Create and return a command line config loader."""
184 185 return IPClusterCLLoader(
185 186 description=self.description,
186 187 version=release.version
187 188 )
188 189
189 190 def find_resources(self):
190 191 subcommand = self.command_line_config.Global.subcommand
191 192 if subcommand=='list':
192 193 self.list_cluster_dirs()
193 194 # Exit immediately because there is nothing left to do.
194 195 self.exit()
195 196 elif subcommand=='create':
196 197 self.auto_create_cluster_dir = True
197 198 super(IPClusterApp, self).find_resources()
198 199 elif subcommand=='start' or subcommand=='stop':
199 200 self.auto_create_cluster_dir = False
200 201 try:
201 202 super(IPClusterApp, self).find_resources()
202 203 except ClusterDirError:
203 204 raise ClusterDirError(
204 205 "Could not find a cluster directory. A cluster dir must "
205 206 "be created before running 'ipcluster start'. Do "
206 207 "'ipcluster create -h' or 'ipcluster list -h' for more "
207 208 "information about creating and listing cluster dirs."
208 209 )
209 210
210 211 def pre_construct(self):
211 212 super(IPClusterApp, self).pre_construct()
212 213 config = self.master_config
213 214 try:
214 215 daemon = config.Global.daemonize
215 216 if daemon:
216 217 config.Global.log_to_file = True
217 218 except AttributeError:
218 219 pass
219 220
220 221 def construct(self):
221 222 config = self.master_config
222 223 if config.Global.subcommand=='list':
223 224 pass
224 225 elif config.Global.subcommand=='create':
225 226 self.log.info('Copying default config files to cluster directory '
226 227 '[overwrite=%r]' % (config.Global.reset_config,))
227 228 self.cluster_dir_obj.copy_all_config_files(overwrite=config.Global.reset_config)
228 229 elif config.Global.subcommand=='start':
229 230 self.start_logging()
230 231 reactor.callWhenRunning(self.start_launchers)
231 232
232 233 def list_cluster_dirs(self):
233 234 # Find the search paths
234 235 cluster_dir_paths = os.environ.get('IPCLUSTERDIR_PATH','')
235 236 if cluster_dir_paths:
236 237 cluster_dir_paths = cluster_dir_paths.split(':')
237 238 else:
238 239 cluster_dir_paths = []
239 240 try:
240 241 ipythondir = self.command_line_config.Global.ipythondir
241 242 except AttributeError:
242 243 ipythondir = self.default_config.Global.ipythondir
243 244 paths = [os.getcwd(), ipythondir] + \
244 245 cluster_dir_paths
245 246 paths = list(set(paths))
246 247
247 248 self.log.info('Searching for cluster dirs in paths: %r' % paths)
248 249 for path in paths:
249 250 files = os.listdir(path)
250 251 for f in files:
251 252 full_path = os.path.join(path, f)
252 253 if os.path.isdir(full_path) and f.startswith('cluster_'):
253 254 profile = full_path.split('_')[-1]
254 255 start_cmd = '"ipcluster start -n 4 -p %s"' % profile
255 256 print start_cmd + " ==> " + full_path
256 257
257 258 def start_launchers(self):
258 259 config = self.master_config
259 260
260 261 # Create the launchers
261 262 el_class = import_item(config.Global.engine_launcher)
262 263 self.engine_launcher = el_class(
263 264 self.cluster_dir, config=config
264 265 )
265 266 cl_class = import_item(config.Global.controller_launcher)
266 267 self.controller_launcher = cl_class(
267 268 self.cluster_dir, config=config
268 269 )
269 270
270 271 # Setup signals
271 272 signal.signal(signal.SIGINT, self.stop_launchers)
272 273 # signal.signal(signal.SIGKILL, self.stop_launchers)
273 274
274 275 # Setup the observing of stopping
275 276 d1 = self.controller_launcher.observe_stop()
276 277 d1.addCallback(self.stop_engines)
277 278 d1.addErrback(self.err_and_stop)
278 279 # If this triggers, just let them die
279 280 # d2 = self.engine_launcher.observe_stop()
280 281
281 282 # Start the controller and engines
282 283 d = self.controller_launcher.start(
283 284 profile=None, cluster_dir=config.Global.cluster_dir
284 285 )
285 286 d.addCallback(lambda _: self.start_engines())
286 287 d.addErrback(self.err_and_stop)
287 288
288 289 def err_and_stop(self, f):
289 290 log.msg('Unexpected error in ipcluster:')
290 291 log.err(f)
291 292 reactor.stop()
292 293
293 294 def stop_engines(self, r):
294 295 return self.engine_launcher.stop()
295 296
296 297 def start_engines(self):
297 298 config = self.master_config
298 299 d = self.engine_launcher.start(
299 300 config.Global.n,
300 301 profile=None, cluster_dir=config.Global.cluster_dir
301 302 )
302 303 return d
303 304
304 305 def stop_launchers(self, signum, frame):
305 306 log.msg("Stopping cluster")
306 307 d1 = self.engine_launcher.stop()
307 308 d2 = self.controller_launcher.stop()
308 309 # d1.addCallback(lambda _: self.controller_launcher.stop)
309 310 d1.addErrback(self.err_and_stop)
310 311 d2.addErrback(self.err_and_stop)
311 312 reactor.callLater(2.0, reactor.stop)
312 313
313 314 def start_logging(self):
314 315 # Remove old log files
315 316 if self.master_config.Global.clean_logs:
316 317 log_dir = self.master_config.Global.log_dir
317 318 for f in os.listdir(log_dir):
318 319 if f.startswith('ipengine' + '-') and f.endswith('.log'):
319 320 os.remove(os.path.join(log_dir, f))
320 321 for f in os.listdir(log_dir):
321 322 if f.startswith('ipcontroller' + '-') and f.endswith('.log'):
322 323 os.remove(os.path.join(log_dir, f))
323 324 super(IPClusterApp, self).start_logging()
324 325
325 326 def start_app(self):
326 327 """Start the application, depending on what subcommand is used."""
327 328 config = self.master_config
328 329 subcmd = config.Global.subcommand
329 330 if subcmd=='create' or subcmd=='list':
330 331 return
331 332 elif subcmd=='start':
332 333 # First see if the cluster is already running
333 334 try:
334 335 pid = self.get_pid_from_file()
335 336 except:
336 337 pass
337 338 else:
338 339 self.log.critical(
339 340 'Cluster is already running with [pid=%s]. '
340 341 'use "ipcluster stop" to stop the cluster.' % pid
341 342 )
342 sys.exit(9)
343 # Here I exit with a unusual exit status that other processes
344 # can watch for to learn how I existed.
345 sys.exit(10)
343 346 # Now log and daemonize
344 347 self.log.info('Starting ipcluster with [daemon=%r]' % config.Global.daemonize)
345 348 if config.Global.daemonize:
346 349 if os.name=='posix':
347 350 os.chdir(config.Global.cluster_dir)
348 351 self.log_level = 40
349 352 daemonize()
350 353
351 354 # Now write the new pid file after our new forked pid is active.
352 355 self.write_pid_file()
353 356 reactor.addSystemEventTrigger('during','shutdown', self.remove_pid_file)
354 357 reactor.run()
355 358 elif subcmd=='stop':
356 359 try:
357 360 pid = self.get_pid_from_file()
358 361 except PIDFileError:
359 362 self.log.critical(
360 363 'Problem reading pid file, cluster is probably not running.'
361 364 )
362 sys.exit(9)
365 # Here I exit with a unusual exit status that other processes
366 # can watch for to learn how I existed.
367 sys.exit(11)
363 368 sig = config.Global.stop_signal
364 369 self.log.info(
365 370 "Stopping cluster [pid=%r] with [signal=%r]" % (pid, sig)
366 371 )
367 372 os.kill(pid, sig)
368 373
369 374
370 375 def launch_new_instance():
371 376 """Create and run the IPython cluster."""
372 377 app = IPClusterApp()
373 378 app.start()
374 379
375 380
376 381 if __name__ == '__main__':
377 382 launch_new_instance()
378 383
@@ -1,258 +1,262 b''
1 1 #!/usr/bin/env python
2 2 # encoding: utf-8
3 3 """
4 4 The IPython controller application.
5 5 """
6 6
7 7 #-----------------------------------------------------------------------------
8 8 # Copyright (C) 2008-2009 The IPython Development Team
9 9 #
10 10 # Distributed under the terms of the BSD License. The full license is in
11 11 # the file COPYING, distributed as part of this software.
12 12 #-----------------------------------------------------------------------------
13 13
14 14 #-----------------------------------------------------------------------------
15 15 # Imports
16 16 #-----------------------------------------------------------------------------
17 17
18 18 from __future__ import with_statement
19 19
20 20 import copy
21 21 import os
22 22 import sys
23 23
24 24 from twisted.application import service
25 25 from twisted.internet import reactor
26 26 from twisted.python import log
27 27
28 28 from IPython.config.loader import Config, NoConfigDefault
29 29
30 30 from IPython.kernel.clusterdir import (
31 31 ApplicationWithClusterDir,
32 32 AppWithClusterDirArgParseConfigLoader
33 33 )
34 34
35 35 from IPython.core import release
36 36
37 37 from IPython.utils.traitlets import Str, Instance
38 38
39 39 from IPython.kernel import controllerservice
40 40
41 41 from IPython.kernel.fcutil import FCServiceFactory
42 42
43 43 #-----------------------------------------------------------------------------
44 44 # Default interfaces
45 45 #-----------------------------------------------------------------------------
46 46
47 47
48 48 # The default client interfaces for FCClientServiceFactory.interfaces
49 49 default_client_interfaces = Config()
50 50 default_client_interfaces.Task.interface_chain = [
51 51 'IPython.kernel.task.ITaskController',
52 52 'IPython.kernel.taskfc.IFCTaskController'
53 53 ]
54 54
55 55 default_client_interfaces.Task.furl_file = 'ipcontroller-tc.furl'
56 56
57 57 default_client_interfaces.MultiEngine.interface_chain = [
58 58 'IPython.kernel.multiengine.IMultiEngine',
59 59 'IPython.kernel.multienginefc.IFCSynchronousMultiEngine'
60 60 ]
61 61
62 62 default_client_interfaces.MultiEngine.furl_file = 'ipcontroller-mec.furl'
63 63
64 64 # Make this a dict we can pass to Config.__init__ for the default
65 65 default_client_interfaces = dict(copy.deepcopy(default_client_interfaces.items()))
66 66
67 67
68 68
69 69 # The default engine interfaces for FCEngineServiceFactory.interfaces
70 70 default_engine_interfaces = Config()
71 71 default_engine_interfaces.Default.interface_chain = [
72 72 'IPython.kernel.enginefc.IFCControllerBase'
73 73 ]
74 74
75 75 default_engine_interfaces.Default.furl_file = 'ipcontroller-engine.furl'
76 76
77 77 # Make this a dict we can pass to Config.__init__ for the default
78 78 default_engine_interfaces = dict(copy.deepcopy(default_engine_interfaces.items()))
79 79
80 80
81 81 #-----------------------------------------------------------------------------
82 82 # Service factories
83 83 #-----------------------------------------------------------------------------
84 84
85 85
86 86 class FCClientServiceFactory(FCServiceFactory):
87 87 """A Foolscap implementation of the client services."""
88 88
89 89 cert_file = Str('ipcontroller-client.pem', config=True)
90 90 interfaces = Instance(klass=Config, kw=default_client_interfaces,
91 91 allow_none=False, config=True)
92 92
93 93
94 94 class FCEngineServiceFactory(FCServiceFactory):
95 95 """A Foolscap implementation of the engine services."""
96 96
97 97 cert_file = Str('ipcontroller-engine.pem', config=True)
98 98 interfaces = Instance(klass=dict, kw=default_engine_interfaces,
99 99 allow_none=False, config=True)
100 100
101 101
102 102 #-----------------------------------------------------------------------------
103 103 # The main application
104 104 #-----------------------------------------------------------------------------
105 105
106 106
107 107 cl_args = (
108 108 # Client config
109 109 (('--client-ip',), dict(
110 110 type=str, dest='FCClientServiceFactory.ip', default=NoConfigDefault,
111 111 help='The IP address or hostname the controller will listen on for '
112 112 'client connections.',
113 113 metavar='FCClientServiceFactory.ip')
114 114 ),
115 115 (('--client-port',), dict(
116 116 type=int, dest='FCClientServiceFactory.port', default=NoConfigDefault,
117 117 help='The port the controller will listen on for client connections. '
118 118 'The default is to use 0, which will autoselect an open port.',
119 119 metavar='FCClientServiceFactory.port')
120 120 ),
121 121 (('--client-location',), dict(
122 122 type=str, dest='FCClientServiceFactory.location', default=NoConfigDefault,
123 123 help='The hostname or IP that clients should connect to. This does '
124 124 'not control which interface the controller listens on. Instead, this '
125 125 'determines the hostname/IP that is listed in the FURL, which is how '
126 126 'clients know where to connect. Useful if the controller is listening '
127 127 'on multiple interfaces.',
128 128 metavar='FCClientServiceFactory.location')
129 129 ),
130 130 # Engine config
131 131 (('--engine-ip',), dict(
132 132 type=str, dest='FCEngineServiceFactory.ip', default=NoConfigDefault,
133 133 help='The IP address or hostname the controller will listen on for '
134 134 'engine connections.',
135 135 metavar='FCEngineServiceFactory.ip')
136 136 ),
137 137 (('--engine-port',), dict(
138 138 type=int, dest='FCEngineServiceFactory.port', default=NoConfigDefault,
139 139 help='The port the controller will listen on for engine connections. '
140 140 'The default is to use 0, which will autoselect an open port.',
141 141 metavar='FCEngineServiceFactory.port')
142 142 ),
143 143 (('--engine-location',), dict(
144 144 type=str, dest='FCEngineServiceFactory.location', default=NoConfigDefault,
145 145 help='The hostname or IP that engines should connect to. This does '
146 146 'not control which interface the controller listens on. Instead, this '
147 147 'determines the hostname/IP that is listed in the FURL, which is how '
148 148 'engines know where to connect. Useful if the controller is listening '
149 149 'on multiple interfaces.',
150 150 metavar='FCEngineServiceFactory.location')
151 151 ),
152 152 # Global config
153 153 (('--log-to-file',), dict(
154 154 action='store_true', dest='Global.log_to_file', default=NoConfigDefault,
155 155 help='Log to a file in the log directory (default is stdout)')
156 156 ),
157 157 (('-r','--reuse-furls'), dict(
158 158 action='store_true', dest='Global.reuse_furls', default=NoConfigDefault,
159 159 help='Try to reuse all FURL files. If this is not set all FURL files '
160 160 'are deleted before the controller starts. This must be set if '
161 161 'specific ports are specified by --engine-port or --client-port.')
162 162 ),
163 (('-ns','--no-security'), dict(
163 (('--no-secure',), dict(
164 164 action='store_false', dest='Global.secure', default=NoConfigDefault,
165 165 help='Turn off SSL encryption for all connections.')
166 ),
167 (('--secure',), dict(
168 action='store_true', dest='Global.secure', default=NoConfigDefault,
169 help='Turn off SSL encryption for all connections.')
166 170 )
167 171 )
168 172
169 173
170 174 class IPControllerAppCLConfigLoader(AppWithClusterDirArgParseConfigLoader):
171 175
172 176 arguments = cl_args
173 177
174 178
175 179 default_config_file_name = 'ipcontroller_config.py'
176 180
177 181
178 182 class IPControllerApp(ApplicationWithClusterDir):
179 183
180 184 name = 'ipcontroller'
181 185 description = 'Start the IPython controller for parallel computing.'
182 186 config_file_name = default_config_file_name
183 187 auto_create_cluster_dir = True
184 188
185 189 def create_default_config(self):
186 190 super(IPControllerApp, self).create_default_config()
187 191 self.default_config.Global.reuse_furls = False
188 192 self.default_config.Global.secure = True
189 193 self.default_config.Global.import_statements = []
190 194 self.default_config.Global.clean_logs = True
191 195
192 196 def create_command_line_config(self):
193 197 """Create and return a command line config loader."""
194 198 return IPControllerAppCLConfigLoader(
195 199 description=self.description,
196 200 version=release.version
197 201 )
198 202
199 203 def post_load_command_line_config(self):
200 204 # Now setup reuse_furls
201 205 c = self.command_line_config
202 206 if hasattr(c.Global, 'reuse_furls'):
203 207 c.FCClientServiceFactory.reuse_furls = c.Global.reuse_furls
204 208 c.FCEngineServiceFactory.reuse_furls = c.Global.reuse_furls
205 209 del c.Global.reuse_furls
206 210 if hasattr(c.Global, 'secure'):
207 211 c.FCClientServiceFactory.secure = c.Global.secure
208 212 c.FCEngineServiceFactory.secure = c.Global.secure
209 213 del c.Global.secure
210 214
211 215 def construct(self):
212 216 # I am a little hesitant to put these into InteractiveShell itself.
213 217 # But that might be the place for them
214 218 sys.path.insert(0, '')
215 219
216 220 self.start_logging()
217 221 self.import_statements()
218 222
219 223 # Create the service hierarchy
220 224 self.main_service = service.MultiService()
221 225 # The controller service
222 226 controller_service = controllerservice.ControllerService()
223 227 controller_service.setServiceParent(self.main_service)
224 228 # The client tub and all its refereceables
225 229 csfactory = FCClientServiceFactory(self.master_config, controller_service)
226 230 client_service = csfactory.create()
227 231 client_service.setServiceParent(self.main_service)
228 232 # The engine tub
229 233 esfactory = FCEngineServiceFactory(self.master_config, controller_service)
230 234 engine_service = esfactory.create()
231 235 engine_service.setServiceParent(self.main_service)
232 236
233 237 def import_statements(self):
234 238 statements = self.master_config.Global.import_statements
235 239 for s in statements:
236 240 try:
237 241 log.msg("Executing statement: '%s'" % s)
238 242 exec s in globals(), locals()
239 243 except:
240 244 log.msg("Error running statement: %s" % s)
241 245
242 246 def start_app(self):
243 247 # Start the controller service and set things running
244 248 self.main_service.startService()
245 249 self.write_pid_file()
246 250 reactor.addSystemEventTrigger('during','shutdown', self.remove_pid_file)
247 251 reactor.run()
248 252
249 253
250 254 def launch_new_instance():
251 255 """Create and run the IPython controller"""
252 256 app = IPControllerApp()
253 257 app.start()
254 258
255 259
256 260 if __name__ == '__main__':
257 261 launch_new_instance()
258 262
@@ -1,23 +1,66 b''
1 1 """Count the frequencies of words in a string"""
2 2
3 from __future__ import division
4
5 import cmath as math
6
7
3 8 def wordfreq(text):
4 9 """Return a dictionary of words and word counts in a string."""
5 10
6 11 freqs = {}
7 12 for word in text.split():
8 freqs[word] = freqs.get(word, 0) + 1
13 lword = word.lower()
14 freqs[lword] = freqs.get(lword, 0) + 1
9 15 return freqs
10 16
17
11 18 def print_wordfreq(freqs, n=10):
12 19 """Print the n most common words and counts in the freqs dict."""
13 20
14 21 words, counts = freqs.keys(), freqs.values()
15 22 items = zip(counts, words)
16 23 items.sort(reverse=True)
17 24 for (count, word) in items[:n]:
18 25 print word, count
19 26
20 if __name__ == '__main__':
21 import gzip
22 text = gzip.open('HISTORY.gz').read()
23 freqs = wordfreq(text) No newline at end of file
27
28 def wordfreq_to_weightsize(worddict, minsize=10, maxsize=50, minalpha=0.4, maxalpha=1.0):
29 mincount = min(worddict.itervalues())
30 maxcount = max(worddict.itervalues())
31 weights = {}
32 for k, v in worddict.iteritems():
33 w = (v-mincount)/(maxcount-mincount)
34 alpha = minalpha + (maxalpha-minalpha)*w
35 size = minsize + (maxsize-minsize)*w
36 weights[k] = (alpha, size)
37 return weights
38
39
40 def tagcloud(worddict, n=10, minsize=10, maxsize=50, minalpha=0.4, maxalpha=1.0):
41 from matplotlib import pyplot as plt
42 import random
43
44 worddict = wordfreq_to_weightsize(worddict, minsize, maxsize, minalpha, maxalpha)
45
46 fig = plt.figure()
47 ax = fig.add_subplot(111)
48 ax.set_position([0.0,0.0,1.0,1.0])
49 plt.xticks([])
50 plt.yticks([])
51
52 words = worddict.keys()
53 alphas = [v[0] for v in worddict.values()]
54 sizes = [v[1] for v in worddict.values()]
55 items = zip(alphas, sizes, words)
56 items.sort(reverse=True)
57 for alpha, size, word in items[:n]:
58 xpos = random.normalvariate(0.5, 0.3)
59 ypos = random.normalvariate(0.5, 0.3)
60 # xpos = random.uniform(0.0,1.0)
61 # ypos = random.uniform(0.0,1.0)
62 ax.text(xpos, ypos, word.lower(), alpha=alpha, fontsize=size)
63 ax.autoscale_view()
64 return ax
65
66 No newline at end of file
General Comments 0
You need to be logged in to leave comments. Login now