matplotlib 0.1.0.alpha.20170302 → 0.1.0.alpha.20170307
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/examples/classifier_comparison.ipynb +3 -15
- data/examples/forest_importances.ipynb +42 -35
- data/examples/iruby_integration.ipynb +57 -12
- data/examples/lorenz_attractor.ipynb +13 -16
- data/examples/polar_axes.ipynb +59 -58
- data/lib/matplotlib/axes.rb +2 -24
- data/lib/matplotlib/axes_3d.rb +1 -23
- data/lib/matplotlib/iruby.rb +219 -1
- data/lib/matplotlib/polar_axes.rb +6 -0
- data/lib/matplotlib/python/ruby/matplotlib/backend_inline.py +1 -0
- data/lib/matplotlib/version.rb +1 -1
- data/lib/matplotlib.rb +3 -0
- data/matplotlib.gemspec +1 -1
- metadata +6 -4
data/lib/matplotlib/axes.rb
CHANGED
@@ -1,28 +1,6 @@
|
|
1
1
|
module Matplotlib
|
2
|
-
class
|
2
|
+
class Axes
|
3
3
|
include PyCall::PyObjectWrapper
|
4
|
-
|
5
|
-
@__pyobj__ = PyCall.import_module('matplotlib.axes').Axes
|
6
|
-
|
7
|
-
PyCall.dir(@__pyobj__).each do |name|
|
8
|
-
obj = PyCall.getattr(@__pyobj__, name)
|
9
|
-
next unless obj.kind_of?(PyCall::PyObject) || obj.kind_of?(PyCall::PyObjectWrapper)
|
10
|
-
next unless PyCall.callable?(obj)
|
11
|
-
|
12
|
-
define_method(name) do |*args, **kwargs|
|
13
|
-
PyCall.getattr(__pyobj__, name).(*args, **kwargs)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
class << self
|
18
|
-
attr_reader :__pyobj__
|
19
|
-
|
20
|
-
def method_missing(name, *args, **kwargs)
|
21
|
-
return super unless PyCall.hasattr?(__pyobj__, name)
|
22
|
-
PyCall.getattr(__pyobj__, name)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
PyCall::Conversions.python_type_mapping(__pyobj__, self)
|
4
|
+
wrap_class PyCall.import_module('matplotlib.axes').Axes
|
27
5
|
end
|
28
6
|
end
|
data/lib/matplotlib/axes_3d.rb
CHANGED
@@ -1,28 +1,6 @@
|
|
1
1
|
module Matplotlib
|
2
2
|
class Axes3D
|
3
3
|
include PyCall::PyObjectWrapper
|
4
|
-
|
5
|
-
@__pyobj__ = PyCall.import_module('mpl_toolkits.mplot3d').Axes3D
|
6
|
-
|
7
|
-
PyCall.dir(@__pyobj__).each do |name|
|
8
|
-
obj = PyCall.getattr(@__pyobj__, name)
|
9
|
-
next unless obj.kind_of?(PyCall::PyObject) || obj.kind_of?(PyCall::PyObjectWrapper)
|
10
|
-
next unless PyCall.callable?(obj)
|
11
|
-
|
12
|
-
define_method(name) do |*args, **kwargs|
|
13
|
-
PyCall.getattr(__pyobj__, name).(*args, **kwargs)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
class << self
|
18
|
-
attr_reader :__pyobj__
|
19
|
-
|
20
|
-
def method_missing(name, *args, **kwargs)
|
21
|
-
return super unless PyCall.hasattr?(__pyobj__, name)
|
22
|
-
PyCall.getattr(__pyobj__, name)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
PyCall::Conversions.python_type_mapping(__pyobj__, self)
|
4
|
+
wrap_class PyCall.import_module('mpl_toolkits.mplot3d').Axes3D
|
27
5
|
end
|
28
6
|
end
|
data/lib/matplotlib/iruby.rb
CHANGED
@@ -2,6 +2,79 @@ require 'pycall'
|
|
2
2
|
|
3
3
|
module Matplotlib
|
4
4
|
module IRuby
|
5
|
+
module HookExtension
|
6
|
+
def self.extended(obj)
|
7
|
+
@event_registry ||= {}
|
8
|
+
@event_registry[obj] = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.register_event(target, event, hook)
|
12
|
+
@event_registry[target][event] ||= []
|
13
|
+
@event_registry[target][event] << hook
|
14
|
+
end
|
15
|
+
|
16
|
+
def register_event(event, hook=nil, &block)
|
17
|
+
HookExtension.register_event(self, event, [hook, block].compact)
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.unregister_event(target, event, hook)
|
21
|
+
return unless @event_registry[target]
|
22
|
+
return unless @event_registry[target][event]
|
23
|
+
@event_registry[target][event].delete(hook)
|
24
|
+
end
|
25
|
+
|
26
|
+
def unregister_event(event, hook)
|
27
|
+
HookExtension.unregister_event(self, event, hook)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.trigger_event(target, event)
|
31
|
+
return unless @event_registry[target][event]
|
32
|
+
@event_registry[target][event].each do |hooks|
|
33
|
+
hooks.to_a.each do |hook|
|
34
|
+
hook.call if hook
|
35
|
+
end
|
36
|
+
end
|
37
|
+
rescue Exception
|
38
|
+
$stderr.puts "Error occurred in triggerred event: target=#{target} event=#{event}", $!.to_s, *$!.backtrace
|
39
|
+
end
|
40
|
+
|
41
|
+
def trigger_event(event)
|
42
|
+
HookExtension.trigger_event(self, event)
|
43
|
+
end
|
44
|
+
|
45
|
+
def execute_request(msg)
|
46
|
+
code = msg[:content]['code']
|
47
|
+
@execution_count += 1 if msg[:content]['store_history']
|
48
|
+
@session.send(:publish, :execute_input, code: code, execution_count: @execution_count)
|
49
|
+
|
50
|
+
trigger_event(:pre_execute)
|
51
|
+
|
52
|
+
content = {
|
53
|
+
status: :ok,
|
54
|
+
payload: [],
|
55
|
+
user_expressions: {},
|
56
|
+
execution_count: @execution_count
|
57
|
+
}
|
58
|
+
result = nil
|
59
|
+
begin
|
60
|
+
result = @backend.eval(code, msg[:content]['store_history'])
|
61
|
+
rescue SystemExit
|
62
|
+
content[:payload] << { source: :ask_exit }
|
63
|
+
rescue Exception => e
|
64
|
+
content = error_message(e)
|
65
|
+
@session.send(:publish, :error, content)
|
66
|
+
end
|
67
|
+
|
68
|
+
trigger_event(:post_execute)
|
69
|
+
|
70
|
+
@session.send(:reply, :execute_reply, content)
|
71
|
+
@session.send(:publish, :execute_result,
|
72
|
+
data: ::IRuby::Display.display(result),
|
73
|
+
metadata: {},
|
74
|
+
execution_count: @execution_count) unless result.nil? || msg[:content]['silent']
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
5
78
|
AGG_FORMATS = {
|
6
79
|
"image/png" => "png",
|
7
80
|
"application/pdf" => "pdf",
|
@@ -9,7 +82,7 @@ module Matplotlib
|
|
9
82
|
"image/eps" => "eps",
|
10
83
|
"application/postscript" => "ps",
|
11
84
|
"image/svg+xml" => "svg"
|
12
|
-
}
|
85
|
+
}.freeze
|
13
86
|
|
14
87
|
module Helper
|
15
88
|
def register_formats
|
@@ -31,7 +104,152 @@ module Matplotlib
|
|
31
104
|
class << self
|
32
105
|
# NOTE: This method is translated from `IPython.core.activate_matplotlib` function.
|
33
106
|
def activate(gui=:inline)
|
107
|
+
enable_matplotlib(gui)
|
108
|
+
end
|
109
|
+
|
110
|
+
GUI_BACKEND_MAP = {
|
111
|
+
tk: :TkAgg,
|
112
|
+
gtk: :GTKAgg,
|
113
|
+
gtk3: :GTK3Agg,
|
114
|
+
wx: :WXAgg,
|
115
|
+
qt: :Qt4Agg,
|
116
|
+
qt4: :Qt4Agg,
|
117
|
+
qt5: :Qt5Agg,
|
118
|
+
osx: :MacOSX,
|
119
|
+
nbagg: :nbAgg,
|
120
|
+
notebook: :nbAgg,
|
121
|
+
agg: :agg,
|
122
|
+
inline: 'module://ruby.matplotlib.backend_inline',
|
123
|
+
}.freeze
|
124
|
+
|
125
|
+
BACKEND_GUI_MAP = Hash[GUI_BACKEND_MAP.select {|k, v| v }].freeze
|
126
|
+
|
127
|
+
private_constant :GUI_BACKEND_MAP, :BACKEND_GUI_MAP
|
128
|
+
|
129
|
+
def available_gui_names
|
130
|
+
GUI_BACKEND_MAP.keys
|
131
|
+
end
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
# This method is based on IPython.core.interactiveshell.InteractiveShell.enable_matplotlib function.
|
136
|
+
def enable_matplotlib(gui=nil)
|
137
|
+
gui, backend = find_gui_and_backend(gui, @gui_select)
|
138
|
+
|
139
|
+
if gui != :inline
|
140
|
+
if @gui_select.nil?
|
141
|
+
@gui_select = gui
|
142
|
+
elsif gui != @gui_select
|
143
|
+
$stderr.puts "Warning: Cannot change to a different GUI toolkit: #{gui}. Using #{@gui_select} instead."
|
144
|
+
gui, backend = find_gui_and_backend(@gui_select)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
activate_matplotlib(backend)
|
149
|
+
configure_inline_support(backend)
|
150
|
+
# self.enable_gui(gui)
|
151
|
+
# register matplotlib-aware execution runner for ExecutionMagics
|
152
|
+
|
153
|
+
[gui, backend]
|
154
|
+
end
|
155
|
+
|
156
|
+
# Given a gui string return the gui and matplotlib backend.
|
157
|
+
# This method is based on IPython.core.pylabtools.find_gui_and_backend function.
|
158
|
+
#
|
159
|
+
# @param [String, Symbol, nil] gui can be one of (:tk, :gtk, :wx, :qt, :qt4, :inline, :agg).
|
160
|
+
# @param [String, Symbol, nil] gui_select can be one of (:tk, :gtk, :wx, :qt, :qt4, :inline, :agg).
|
161
|
+
#
|
162
|
+
# @return A pair of (gui, backend) where backend is one of (:TkAgg, :GTKAgg, :WXAgg, :Qt4Agg, :agg).
|
163
|
+
def find_gui_and_backend(gui=nil, gui_select=nil)
|
164
|
+
gui = gui.to_sym if gui.kind_of? String
|
165
|
+
|
166
|
+
if gui && gui != :auto
|
167
|
+
# select backend based on requested gui
|
168
|
+
backend = GUI_BACKEND_MAP[gui]
|
169
|
+
gui = nil if gui == :agg
|
170
|
+
return [gui, backend]
|
171
|
+
end
|
172
|
+
|
173
|
+
backend = Matplotlib.rcParamsOrig['backend']&.to_sym
|
174
|
+
gui = BACKEND_GUI_MAP[backend]
|
175
|
+
|
176
|
+
# If we have already had a gui active, we need it and inline are the ones allowed.
|
177
|
+
if gui_select && gui != gui_select
|
178
|
+
gui = gui_select
|
179
|
+
backend = backend[gui]
|
180
|
+
end
|
181
|
+
|
182
|
+
[gui, backend]
|
183
|
+
end
|
184
|
+
|
185
|
+
# Activate the given backend and set interactive to true.
|
186
|
+
# This method is based on IPython.core.pylabtools.activate_matplotlib function.
|
187
|
+
#
|
188
|
+
# @param [String, Symbol] backend a name of matplotlib backend
|
189
|
+
def activate_matplotlib(backend)
|
190
|
+
require 'matplotlib'
|
191
|
+
Matplotlib.interactive(true)
|
192
|
+
|
193
|
+
backend = backend.to_s
|
194
|
+
Matplotlib.rcParams['backend'] = backend
|
195
|
+
|
34
196
|
require 'matplotlib/pyplot'
|
197
|
+
Matplotlib::Pyplot.switch_backend(backend)
|
198
|
+
|
199
|
+
# TODO: should support wrapping python function
|
200
|
+
# plt = Matplotlib::Pyplot
|
201
|
+
# plt.__pyobj__.show._needmain = false
|
202
|
+
# plt.__pyobj__.draw_if_interactive = flag_calls(plt.__pyobj__.draw_if_interactive)
|
203
|
+
end
|
204
|
+
|
205
|
+
# This method is based on IPython.core.pylabtools.configure_inline_support function.
|
206
|
+
#
|
207
|
+
# @param shell an instance of IRuby shell
|
208
|
+
# @param backend a name of matplotlib backend
|
209
|
+
def configure_inline_support(backend)
|
210
|
+
# Temporally monky-patching IRuby kernel to enable flushing and closing figures.
|
211
|
+
# TODO: Make this feature a pull-request for sciruby/iruby.
|
212
|
+
kernel = ::IRuby::Kernel.instance
|
213
|
+
kernel.extend HookExtension
|
214
|
+
if backend == GUI_BACKEND_MAP[:inline]
|
215
|
+
kernel.register_event(:post_execute, method(:flush_figures))
|
216
|
+
# TODO: save original rcParams and overwrite rcParams with IRuby-specific configuration
|
217
|
+
new_backend_name = :inline
|
218
|
+
else
|
219
|
+
kernel.unregister_event(:post_execute, method(:flush_figures))
|
220
|
+
# TODO: restore saved original rcParams
|
221
|
+
new_backend_name = :not_inline
|
222
|
+
end
|
223
|
+
if new_backend_name != @current_backend
|
224
|
+
# TODO: select figure formats
|
225
|
+
@current_backend = new_backend_name
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
# This method is based on ipykernel.pylab.backend_inline.flush_figures function.
|
230
|
+
def flush_figures
|
231
|
+
# TODO: I want to allow users to turn on/off automatic figure closing.
|
232
|
+
show_figures(true)
|
233
|
+
end
|
234
|
+
|
235
|
+
# This method is based on ipykernel.pylab.backend_inline.show function.
|
236
|
+
#
|
237
|
+
# @param [true, false] close If true, a `plt.close('all')` call is automatically issued after sending all the figures.
|
238
|
+
def show_figures(close=false)
|
239
|
+
_pylab_helpers = PyCall.import_module('matplotlib._pylab_helpers')
|
240
|
+
gcf = PyCall.getattr(_pylab_helpers, :Gcf)
|
241
|
+
kernel = ::IRuby::Kernel.instance
|
242
|
+
gcf.get_all_fig_managers.().each do |fig_manager|
|
243
|
+
data = ::IRuby::Display.display(fig_manager.canvas.figure)
|
244
|
+
kernel.session.send(:publish, :execute_result,
|
245
|
+
data: data,
|
246
|
+
metadata: {},
|
247
|
+
execution_count: kernel.instance_variable_get(:@execution_count))
|
248
|
+
end
|
249
|
+
ensure
|
250
|
+
unless gcf.get_all_fig_managers.().none?
|
251
|
+
Matplotlib::Pyplot.close('all')
|
252
|
+
end
|
35
253
|
end
|
36
254
|
end
|
37
255
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
from matplotlib.backends.backend_agg import new_figure_manager, FigureCanvasAgg
|
data/lib/matplotlib/version.rb
CHANGED
data/lib/matplotlib.rb
CHANGED
data/matplotlib.gemspec
CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
22
|
spec.require_paths = ["lib"]
|
23
23
|
|
24
|
-
spec.add_dependency "pycall", ">= 0.1.0.alpha.
|
24
|
+
spec.add_dependency "pycall", ">= 0.1.0.alpha.20170307"
|
25
25
|
|
26
26
|
spec.add_development_dependency "bundler", "~> 1.13"
|
27
27
|
spec.add_development_dependency "rake", "~> 10.0"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: matplotlib
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.0.alpha.
|
4
|
+
version: 0.1.0.alpha.20170307
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kenta Murata
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-03-
|
11
|
+
date: 2017-03-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pycall
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.1.0.alpha.
|
19
|
+
version: 0.1.0.alpha.20170307
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.1.0.alpha.
|
26
|
+
version: 0.1.0.alpha.20170307
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -107,7 +107,9 @@ files:
|
|
107
107
|
- lib/matplotlib/axes_3d.rb
|
108
108
|
- lib/matplotlib/figure.rb
|
109
109
|
- lib/matplotlib/iruby.rb
|
110
|
+
- lib/matplotlib/polar_axes.rb
|
110
111
|
- lib/matplotlib/pyplot.rb
|
112
|
+
- lib/matplotlib/python/ruby/matplotlib/backend_inline.py
|
111
113
|
- lib/matplotlib/version.rb
|
112
114
|
- matplotlib.gemspec
|
113
115
|
homepage: https://github.com/mrkn/matplotlib.rb
|