##// END OF EJS Templates
Refactor gui/pylab integration to eliminate code duplication....
Fernando Perez -
Show More
@@ -62,6 +62,7 b' from IPython.core.payload import PayloadManager'
62 from IPython.core.plugin import PluginManager
62 from IPython.core.plugin import PluginManager
63 from IPython.core.prefilter import PrefilterManager, ESC_MAGIC
63 from IPython.core.prefilter import PrefilterManager, ESC_MAGIC
64 from IPython.core.profiledir import ProfileDir
64 from IPython.core.profiledir import ProfileDir
65 from IPython.core.pylabtools import pylab_activate
65 from IPython.external.Itpl import ItplNS
66 from IPython.external.Itpl import ItplNS
66 from IPython.utils import PyColorize
67 from IPython.utils import PyColorize
67 from IPython.utils import io
68 from IPython.utils import io
@@ -2531,8 +2532,46 b' class InteractiveShell(SingletonConfigurable, Magic):'
2531 # Things related to GUI support and pylab
2532 # Things related to GUI support and pylab
2532 #-------------------------------------------------------------------------
2533 #-------------------------------------------------------------------------
2533
2534
2535 def enable_gui(self, gui=None):
2536 raise NotImplementedError('Implement enable_gui in a subclass')
2537
2534 def enable_pylab(self, gui=None, import_all=True):
2538 def enable_pylab(self, gui=None, import_all=True):
2535 raise NotImplementedError('Implement enable_pylab in a subclass')
2539 """Activate pylab support at runtime.
2540
2541 This turns on support for matplotlib, preloads into the interactive
2542 namespace all of numpy and pylab, and configures IPython to correctly
2543 interact with the GUI event loop. The GUI backend to be used can be
2544 optionally selected with the optional :param:`gui` argument.
2545
2546 Parameters
2547 ----------
2548 gui : optional, string
2549
2550 If given, dictates the choice of matplotlib GUI backend to use
2551 (should be one of IPython's supported backends, 'qt', 'osx', 'tk',
2552 'gtk', 'wx' or 'inline'), otherwise we use the default chosen by
2553 matplotlib (as dictated by the matplotlib build-time options plus the
2554 user's matplotlibrc configuration file). Note that not all backends
2555 make sense in all contexts, for example a terminal ipython can't
2556 display figures inline.
2557 """
2558
2559 # We want to prevent the loading of pylab to pollute the user's
2560 # namespace as shown by the %who* magics, so we execute the activation
2561 # code in an empty namespace, and we update *both* user_ns and
2562 # user_ns_hidden with this information.
2563 ns = {}
2564 try:
2565 gui = pylab_activate(ns, gui, import_all, self)
2566 except KeyError:
2567 error("Backend %r not supported" % gui)
2568 return
2569 self.user_ns.update(ns)
2570 self.user_ns_hidden.update(ns)
2571 # Now we must activate the gui pylab wants to use, and fix %run to take
2572 # plot updates into account
2573 self.enable_gui(gui)
2574 self.magic_run = self._pylab_magic_run
2536
2575
2537 #-------------------------------------------------------------------------
2576 #-------------------------------------------------------------------------
2538 # Utilities
2577 # Utilities
@@ -50,7 +50,7 b' from IPython.core.profiledir import ProfileDir'
50 from IPython.core.macro import Macro
50 from IPython.core.macro import Macro
51 from IPython.core import magic_arguments, page
51 from IPython.core import magic_arguments, page
52 from IPython.core.prefilter import ESC_MAGIC
52 from IPython.core.prefilter import ESC_MAGIC
53 from IPython.lib.pylabtools import mpl_runner
53 from IPython.core.pylabtools import mpl_runner
54 from IPython.testing.skipdoctest import skip_doctest
54 from IPython.testing.skipdoctest import skip_doctest
55 from IPython.utils import py3compat
55 from IPython.utils import py3compat
56 from IPython.utils.io import file_read, nlprint
56 from IPython.utils.io import file_read, nlprint
@@ -3305,24 +3305,30 b' Defaulting color scheme to \'NoColor\'"""'
3305
3305
3306 This magic replaces IPython's threaded shells that were activated
3306 This magic replaces IPython's threaded shells that were activated
3307 using the (pylab/wthread/etc.) command line flags. GUI toolkits
3307 using the (pylab/wthread/etc.) command line flags. GUI toolkits
3308 can now be enabled, disabled and changed at runtime and keyboard
3308 can now be enabled at runtime and keyboard
3309 interrupts should work without any problems. The following toolkits
3309 interrupts should work without any problems. The following toolkits
3310 are supported: wxPython, PyQt4, PyGTK, and Tk::
3310 are supported: wxPython, PyQt4, PyGTK, Tk and Cocoa (OSX)::
3311
3311
3312 %gui wx # enable wxPython event loop integration
3312 %gui wx # enable wxPython event loop integration
3313 %gui qt4|qt # enable PyQt4 event loop integration
3313 %gui qt4|qt # enable PyQt4 event loop integration
3314 %gui gtk # enable PyGTK event loop integration
3314 %gui gtk # enable PyGTK event loop integration
3315 %gui tk # enable Tk event loop integration
3315 %gui tk # enable Tk event loop integration
3316 %gui OSX # enable Cocoa event loop integration
3317 # (requires %matplotlib 1.1)
3316 %gui # disable all event loop integration
3318 %gui # disable all event loop integration
3317
3319
3318 WARNING: after any of these has been called you can simply create
3320 WARNING: after any of these has been called you can simply create
3319 an application object, but DO NOT start the event loop yourself, as
3321 an application object, but DO NOT start the event loop yourself, as
3320 we have already handled that.
3322 we have already handled that.
3321 """
3323 """
3322 from IPython.lib.inputhook import enable_gui
3323 opts, arg = self.parse_options(parameter_s, '')
3324 opts, arg = self.parse_options(parameter_s, '')
3324 if arg=='': arg = None
3325 if arg=='': arg = None
3325 return enable_gui(arg)
3326 try:
3327 return self.enable_gui(arg)
3328 except Exception as e:
3329 # print simple error message, rather than traceback if we can't
3330 # hook up the GUI
3331 error(str(e))
3326
3332
3327 def magic_load_ext(self, module_str):
3333 def magic_load_ext(self, module_str):
3328 """Load an IPython extension by its module name."""
3334 """Load an IPython extension by its module name."""
@@ -3416,9 +3422,9 b' Defaulting color scheme to \'NoColor\'"""'
3416 Parameters
3422 Parameters
3417 ----------
3423 ----------
3418 guiname : optional
3424 guiname : optional
3419 One of the valid arguments to the %gui magic ('qt', 'wx', 'gtk', 'osx' or
3425 One of the valid arguments to the %gui magic ('qt', 'wx', 'gtk',
3420 'tk'). If given, the corresponding Matplotlib backend is used,
3426 'osx' or 'tk'). If given, the corresponding Matplotlib backend is
3421 otherwise matplotlib's default (which you can override in your
3427 used, otherwise matplotlib's default (which you can override in your
3422 matplotlib config file) is used.
3428 matplotlib config file) is used.
3423
3429
3424 Examples
3430 Examples
@@ -3449,7 +3455,7 b' Defaulting color scheme to \'NoColor\'"""'
3449 else:
3455 else:
3450 import_all_status = True
3456 import_all_status = True
3451
3457
3452 self.shell.enable_pylab(s,import_all=import_all_status)
3458 self.shell.enable_pylab(s, import_all=import_all_status)
3453
3459
3454 def magic_tb(self, s):
3460 def magic_tb(self, s):
3455 """Print the last traceback with the currently active exception mode.
3461 """Print the last traceback with the currently active exception mode.
@@ -232,7 +232,8 b' def activate_matplotlib(backend):'
232 # For this, we wrap it into a decorator which adds a 'called' flag.
232 # For this, we wrap it into a decorator which adds a 'called' flag.
233 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
233 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
234
234
235 def import_pylab(user_ns, backend, import_all=True, shell=None):
235
236 def import_pylab(user_ns, import_all=True):
236 """Import the standard pylab symbols into user_ns."""
237 """Import the standard pylab symbols into user_ns."""
237
238
238 # Import numpy as np/pyplot as plt are conventions we're trying to
239 # Import numpy as np/pyplot as plt are conventions we're trying to
@@ -246,53 +247,57 b' def import_pylab(user_ns, backend, import_all=True, shell=None):'
246 )
247 )
247 exec s in user_ns
248 exec s in user_ns
248
249
249 if shell is not None:
250 # All local executions are done in a fresh namespace and we then update
251 # the set of 'hidden' keys so these variables don't show up in %who
252 # (which is meant to show only what the user has manually defined).
253 ns = {}
254 exec s in ns
255 # If using our svg payload backend, register the post-execution
256 # function that will pick up the results for display. This can only be
257 # done with access to the real shell object.
258 #
259 from IPython.zmq.pylab.backend_inline import InlineBackend
260
261 cfg = InlineBackend.instance(config=shell.config)
262 cfg.shell = shell
263 if cfg not in shell.configurables:
264 shell.configurables.append(cfg)
265
266 if backend == backends['inline']:
267 from IPython.zmq.pylab.backend_inline import flush_figures
268 from matplotlib import pyplot
269 shell.register_post_execute(flush_figures)
270 # load inline_rc
271 pyplot.rcParams.update(cfg.rc)
272
273 # Add 'figsize' to pyplot and to the user's namespace
274 user_ns['figsize'] = pyplot.figsize = figsize
275 ns['figsize'] = figsize
276
277 # Setup the default figure format
278 fmt = cfg.figure_format
279 select_figure_format(shell, fmt)
280
281 # The old pastefig function has been replaced by display
282 from IPython.core.display import display
283 # Add display and display_png to the user's namespace
284 ns['display'] = user_ns['display'] = display
285 ns['getfigs'] = user_ns['getfigs'] = getfigs
286
287 if import_all:
250 if import_all:
288 s = ("from matplotlib.pylab import *\n"
251 s = ("from matplotlib.pylab import *\n"
289 "from numpy import *\n")
252 "from numpy import *\n")
290 exec s in user_ns
253 exec s in user_ns
291 if shell is not None:
292 exec s in ns
293
254
294 # Update the set of hidden variables with anything we've done here.
255
295 shell.user_ns_hidden.update(ns)
256 def configure_shell(shell, backend, user_ns=None):
257 """Configure an IPython shell object for matplotlib use.
258
259 Parameters
260 ----------
261 shell : InteractiveShell instance
262 If None, this function returns immediately.
263
264 user_ns : dict
265 A namespace where all configured variables will be placed. If not given,
266 the `user_ns` attribute of the shell object is used.
267 """
268 if shell is None:
269 return
270
271 user_ns = shell.user_ns if user_ns is None else user_ns
272
273 # If using our svg payload backend, register the post-execution
274 # function that will pick up the results for display. This can only be
275 # done with access to the real shell object.
276 from IPython.zmq.pylab.backend_inline import InlineBackend
277
278 cfg = InlineBackend.instance(config=shell.config)
279 cfg.shell = shell
280 if cfg not in shell.configurables:
281 shell.configurables.append(cfg)
282
283 if backend == backends['inline']:
284 from IPython.zmq.pylab.backend_inline import flush_figures
285 from matplotlib import pyplot
286 shell.register_post_execute(flush_figures)
287 # load inline_rc
288 pyplot.rcParams.update(cfg.rc)
289 # Add 'figsize' to pyplot and to the user's namespace
290 user_ns['figsize'] = pyplot.figsize = figsize
291
292 # Setup the default figure format
293 fmt = cfg.figure_format
294 select_figure_format(shell, fmt)
295
296 # The old pastefig function has been replaced by display
297 from IPython.core.display import display
298 # Add display and getfigs to the user's namespace
299 user_ns['display'] = display
300 user_ns['getfigs'] = getfigs
296
301
297
302
298 def pylab_activate(user_ns, gui=None, import_all=True, shell=None):
303 def pylab_activate(user_ns, gui=None, import_all=True, shell=None):
@@ -318,8 +323,8 b' def pylab_activate(user_ns, gui=None, import_all=True, shell=None):'
318 """
323 """
319 gui, backend = find_gui_and_backend(gui)
324 gui, backend = find_gui_and_backend(gui)
320 activate_matplotlib(backend)
325 activate_matplotlib(backend)
321 import_pylab(user_ns, backend, import_all, shell)
326 import_pylab(user_ns, import_all)
322
327 configure_shell(shell, backend, user_ns)
323 print """
328 print """
324 Welcome to pylab, a matplotlib-based Python environment [backend: %s].
329 Welcome to pylab, a matplotlib-based Python environment [backend: %s].
325 For more information, type 'help(pylab)'.""" % backend
330 For more information, type 'help(pylab)'.""" % backend
@@ -57,6 +57,7 b' def test_figure_to_svg():'
57
57
58 def test_import_pylab():
58 def test_import_pylab():
59 ip = get_ipython()
59 ip = get_ipython()
60 pt.import_pylab(ip.user_ns, 'inline', import_all=False, shell=ip)
60 ns = {}
61 nt.assert_true('plt' in ip.user_ns)
61 pt.import_pylab(ns, import_all=False)
62 nt.assert_equal(ip.user_ns['np'], np)
62 nt.assert_true('plt' in ns)
63 nt.assert_equal(ns['np'], np)
@@ -29,8 +29,7 b' except:'
29 from IPython.core.error import TryNext
29 from IPython.core.error import TryNext
30 from IPython.core.usage import interactive_usage, default_banner
30 from IPython.core.usage import interactive_usage, default_banner
31 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
31 from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC
32 from IPython.lib.inputhook import enable_gui
32 from IPython.core.pylabtools import pylab_activate
33 from IPython.lib.pylabtools import pylab_activate
34 from IPython.testing.skipdoctest import skip_doctest
33 from IPython.testing.skipdoctest import skip_doctest
35 from IPython.utils import py3compat
34 from IPython.utils import py3compat
36 from IPython.utils.terminal import toggle_set_term_title, set_term_title
35 from IPython.utils.terminal import toggle_set_term_title, set_term_title
@@ -520,40 +519,9 b' class TerminalInteractiveShell(InteractiveShell):'
520 # Things related to GUI support and pylab
519 # Things related to GUI support and pylab
521 #-------------------------------------------------------------------------
520 #-------------------------------------------------------------------------
522
521
523 def enable_pylab(self, gui=None, import_all=True):
522 def enable_gui(self, gui=None):
524 """Activate pylab support at runtime.
523 from IPython.lib.inputhook import enable_gui
525
526 This turns on support for matplotlib, preloads into the interactive
527 namespace all of numpy and pylab, and configures IPython to correcdtly
528 interact with the GUI event loop. The GUI backend to be used can be
529 optionally selected with the optional :param:`gui` argument.
530
531 Parameters
532 ----------
533 gui : optional, string
534
535 If given, dictates the choice of matplotlib GUI backend to use
536 (should be one of IPython's supported backends, 'tk', 'qt', 'wx' or
537 'gtk'), otherwise we use the default chosen by matplotlib (as
538 dictated by the matplotlib build-time options plus the user's
539 matplotlibrc configuration file).
540 """
541 # We want to prevent the loading of pylab to pollute the user's
542 # namespace as shown by the %who* magics, so we execute the activation
543 # code in an empty namespace, and we update *both* user_ns and
544 # user_ns_hidden with this information.
545 ns = {}
546 try:
547 gui = pylab_activate(ns, gui, import_all)
548 except KeyError:
549 error("Backend %r not supported" % gui)
550 return
551 self.user_ns.update(ns)
552 self.user_ns_hidden.update(ns)
553 # Now we must activate the gui pylab wants to use, and fix %run to take
554 # plot updates into account
555 enable_gui(gui)
524 enable_gui(gui)
556 self.magic_run = self._pylab_magic_run
557
525
558 #-------------------------------------------------------------------------
526 #-------------------------------------------------------------------------
559 # Things related to exiting
527 # Things related to exiting
@@ -679,10 +679,11 b' loop_map = {'
679 'wx' : loop_wx,
679 'wx' : loop_wx,
680 'tk' : loop_tk,
680 'tk' : loop_tk,
681 'gtk': loop_gtk,
681 'gtk': loop_gtk,
682 None : None,
682 }
683 }
683
684
684 def enable_gui(gui, kernel=None):
685 def enable_gui(gui, kernel=None):
685 """Enable integration with a give GUI"""
686 """Enable integration with a given GUI"""
686 if kernel is None:
687 if kernel is None:
687 kernel = IPKernelApp.instance().kernel
688 kernel = IPKernelApp.instance().kernel
688 if gui not in loop_map:
689 if gui not in loop_map:
@@ -16,7 +16,7 b' from matplotlib._pylab_helpers import Gcf'
16 # Local imports.
16 # Local imports.
17 from IPython.config.configurable import SingletonConfigurable
17 from IPython.config.configurable import SingletonConfigurable
18 from IPython.core.displaypub import publish_display_data
18 from IPython.core.displaypub import publish_display_data
19 from IPython.lib.pylabtools import print_figure, select_figure_format
19 from IPython.core.pylabtools import print_figure, select_figure_format
20 from IPython.utils.traitlets import Dict, Instance, CaselessStrEnum, CBool
20 from IPython.utils.traitlets import Dict, Instance, CaselessStrEnum, CBool
21 from IPython.utils.warn import warn
21 from IPython.utils.warn import warn
22
22
@@ -390,78 +390,9 b' class ZMQInteractiveShell(InteractiveShell):'
390 }
390 }
391 self.payload_manager.write_payload(payload)
391 self.payload_manager.write_payload(payload)
392
392
393 def magic_gui(self, parameter_s=''):
393 def enable_gui(self, gui=None):
394 """Enable or disable IPython GUI event loop integration.
395
396 %gui [GUINAME]
397
398 This magic replaces IPython's threaded shells that were activated
399 using the (pylab/wthread/etc.) command line flags. GUI toolkits
400 can now be enabled at runtime and keyboard
401 interrupts should work without any problems. The following toolkits
402 are supported: wxPython, PyQt4, PyGTK, Cocoa, and Tk::
403
404 %gui wx # enable wxPython event loop integration
405 %gui qt4|qt # enable PyQt4 event loop integration
406 %gui gtk # enable PyGTK event loop integration
407 %gui OSX # enable Cocoa event loop integration (requires matplotlib 1.1)
408 %gui tk # enable Tk event loop integration
409
410 WARNING: after any of these has been called you can simply create
411 an application object, but DO NOT start the event loop yourself, as
412 we have already handled that.
413 """
414 from IPython.zmq.ipkernel import enable_gui
415 opts, arg = self.parse_options(parameter_s, '')
416 if arg=='': arg = None
417 try:
418 enable_gui(arg)
419 except Exception as e:
420 # print simple error message, rather than traceback if we can't
421 # hook up the GUI
422 error(str(e))
423
424 def enable_pylab(self, gui=None, import_all=True):
425 """Activate pylab support at runtime.
426
427 This turns on support for matplotlib, preloads into the interactive
428 namespace all of numpy and pylab, and configures IPython to correcdtly
429 interact with the GUI event loop. The GUI backend to be used can be
430 optionally selected with the optional :param:`gui` argument.
431
432 Parameters
433 ----------
434 gui : optional, string [default: inline]
435
436 If given, dictates the choice of matplotlib GUI backend to use
437 (should be one of IPython's supported backends, 'inline', 'qt', 'osx',
438 'tk', or 'gtk'), otherwise we use the default chosen by matplotlib
439 (as dictated by the matplotlib build-time options plus the user's
440 matplotlibrc configuration file).
441 """
442 from IPython.zmq.ipkernel import enable_gui
394 from IPython.zmq.ipkernel import enable_gui
443 # We want to prevent the loading of pylab to pollute the user's
395 enable_gui(gui)
444 # namespace as shown by the %who* magics, so we execute the activation
445 # code in an empty namespace, and we update *both* user_ns and
446 # user_ns_hidden with this information.
447 ns = {}
448 try:
449 gui = pylabtools.pylab_activate(ns, gui, import_all, self)
450 except KeyError:
451 error("Backend %r not supported" % gui)
452 return
453 self.user_ns.update(ns)
454 self.user_ns_hidden.update(ns)
455 # Now we must activate the gui pylab wants to use, and fix %run to take
456 # plot updates into account
457 try:
458 enable_gui(gui)
459 except Exception as e:
460 # print simple error message, rather than traceback if we can't
461 # hook up the GUI
462 error(str(e))
463 self.magic_run = self._pylab_magic_run
464
465
396
466 # A few magics that are adapted to the specifics of using pexpect and a
397 # A few magics that are adapted to the specifics of using pexpect and a
467 # remote terminal
398 # remote terminal
@@ -567,7 +498,6 b' class ZMQInteractiveShell(InteractiveShell):'
567 except Exception as e:
498 except Exception as e:
568 error("Could not start qtconsole: %r" % e)
499 error("Could not start qtconsole: %r" % e)
569 return
500 return
570
571
501
572 def set_next_input(self, text):
502 def set_next_input(self, text):
573 """Send the specified text to the frontend to be presented at the next
503 """Send the specified text to the frontend to be presented at the next
@@ -578,4 +508,5 b' class ZMQInteractiveShell(InteractiveShell):'
578 )
508 )
579 self.payload_manager.write_payload(payload)
509 self.payload_manager.write_payload(payload)
580
510
511
581 InteractiveShellABC.register(ZMQInteractiveShell)
512 InteractiveShellABC.register(ZMQInteractiveShell)
General Comments 0
You need to be logged in to leave comments. Login now