Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384

385

386

387

388

389

390

391

392

393

394

395

396

397

398

399

400

401

402

403

404

405

406

407

408

409

410

411

412

413

414

415

416

417

418

419

420

421

422

423

424

425

426

427

428

429

430

431

432

433

434

435

436

437

438

439

440

441

442

443

444

445

446

447

448

449

450

451

452

453

454

455

456

457

458

459

460

461

462

463

464

465

466

467

468

469

470

471

472

473

474

475

476

477

478

479

480

481

482

483

484

485

486

487

488

489

490

491

492

493

494

495

496

497

498

499

500

501

502

503

504

505

506

507

508

509

510

511

512

513

514

515

516

517

518

519

520

521

522

523

524

525

526

527

528

529

530

531

532

533

534

535

536

537

538

539

540

541

542

543

544

545

546

547

548

549

550

551

552

553

554

555

556

557

558

559

560

561

562

563

564

565

566

567

568

569

570

571

572

573

574

575

576

577

578

579

580

581

582

583

584

585

586

587

588

589

590

591

592

593

594

595

596

597

598

599

600

601

602

603

604

605

606

607

608

609

610

611

612

613

614

615

616

617

618

619

620

621

622

623

624

625

626

627

628

629

630

631

632

633

634

635

636

637

638

639

640

641

642

643

644

645

646

647

648

649

650

651

652

653

654

655

656

657

658

659

660

661

662

663

664

665

666

667

668

669

670

671

672

673

674

675

676

677

678

679

680

681

682

683

684

685

686

687

688

689

690

691

692

693

694

695

696

697

698

699

700

701

702

703

704

705

706

707

708

709

710

711

712

713

714

715

716

717

718

719

720

721

722

723

724

725

726

727

728

729

730

731

732

733

734

735

736

737

738

739

740

741

742

743

744

745

746

747

748

749

750

751

752

753

754

755

756

757

758

759

760

761

762

763

764

765

766

767

768

769

770

771

772

773

774

775

776

777

778

779

780

781

782

783

784

785

786

787

788

789

790

791

792

793

794

795

796

797

798

799

800

801

802

803

804

805

806

807

808

809

810

811

812

813

814

815

816

817

818

819

820

821

822

823

824

825

826

827

828

829

830

831

832

833

834

835

836

837

838

839

840

841

842

843

844

845

846

847

848

849

850

851

852

853

854

855

856

857

858

859

860

861

862

863

864

865

866

867

868

869

870

871

872

873

874

875

876

877

878

879

880

881

882

883

884

885

886

887

888

889

890

891

892

893

894

895

896

897

898

899

900

901

902

903

904

905

906

907

908

909

910

911

912

913

914

915

916

917

918

919

920

921

922

923

924

925

926

927

928

929

930

931

932

933

934

935

936

937

938

939

940

941

942

943

944

945

946

947

948

949

950

951

952

953

954

955

956

957

958

959

960

961

962

963

964

965

966

967

968

969

970

971

972

973

974

975

976

977

978

979

980

981

982

983

984

985

986

987

988

989

990

991

992

993

994

995

996

997

998

999

1000

1001

1002

1003

1004

1005

1006

1007

1008

1009

1010

1011

1012

1013

1014

1015

1016

1017

1018

1019

1020

1021

1022

1023

1024

1025

1026

1027

1028

1029

1030

1031

1032

1033

1034

1035

1036

1037

1038

1039

1040

1041

1042

1043

1044

1045

1046

1047

1048

1049

1050

1051

1052

1053

1054

1055

1056

1057

1058

1059

1060

1061

1062

1063

1064

1065

1066

1067

1068

1069

1070

1071

1072

1073

from __future__ import (absolute_import, division, print_function, 

unicode_literals) 

 

import six 

from six.moves import tkinter as Tk 

 

import logging 

import os.path 

import sys 

 

# Paint image to Tk photo blitter extension 

import matplotlib.backends.tkagg as tkagg 

 

from matplotlib.backends.backend_agg import FigureCanvasAgg 

import matplotlib.backends.windowing as windowing 

 

import matplotlib 

from matplotlib import backend_tools, cbook, rcParams 

from matplotlib.backend_bases import ( 

_Backend, FigureCanvasBase, FigureManagerBase, NavigationToolbar2, 

StatusbarBase, TimerBase, ToolContainerBase, cursors) 

from matplotlib.backend_managers import ToolManager 

from matplotlib._pylab_helpers import Gcf 

from matplotlib.figure import Figure 

from matplotlib.widgets import SubplotTool 

 

 

_log = logging.getLogger(__name__) 

 

backend_version = Tk.TkVersion 

 

# the true dots per inch on the screen; should be display dependent 

# see http://groups.google.com/groups?q=screen+dpi+x11&hl=en&lr=&ie=UTF-8&oe=UTF-8&safe=off&selm=7077.26e81ad5%40swift.cs.tcd.ie&rnum=5 for some info about screen dpi 

PIXELS_PER_INCH = 75 

 

cursord = { 

cursors.MOVE: "fleur", 

cursors.HAND: "hand2", 

cursors.POINTER: "arrow", 

cursors.SELECT_REGION: "tcross", 

cursors.WAIT: "watch", 

} 

 

 

def raise_msg_to_str(msg): 

"""msg is a return arg from a raise. Join with new lines""" 

if not isinstance(msg, six.string_types): 

msg = '\n'.join(map(str, msg)) 

return msg 

 

def error_msg_tkpaint(msg, parent=None): 

from six.moves import tkinter_messagebox as tkMessageBox 

tkMessageBox.showerror("matplotlib", msg) 

 

 

class TimerTk(TimerBase): 

''' 

Subclass of :class:`backend_bases.TimerBase` that uses Tk's timer events. 

 

Attributes 

---------- 

interval : int 

The time between timer events in milliseconds. Default is 1000 ms. 

single_shot : bool 

Boolean flag indicating whether this timer should operate as single 

shot (run once and then stop). Defaults to False. 

callbacks : list 

Stores list of (func, args) tuples that will be called upon timer 

events. This list can be manipulated directly, or the functions 

`add_callback` and `remove_callback` can be used. 

 

''' 

def __init__(self, parent, *args, **kwargs): 

TimerBase.__init__(self, *args, **kwargs) 

self.parent = parent 

self._timer = None 

 

def _timer_start(self): 

self._timer_stop() 

self._timer = self.parent.after(self._interval, self._on_timer) 

 

def _timer_stop(self): 

if self._timer is not None: 

self.parent.after_cancel(self._timer) 

self._timer = None 

 

def _on_timer(self): 

TimerBase._on_timer(self) 

 

# Tk after() is only a single shot, so we need to add code here to 

# reset the timer if we're not operating in single shot mode. However, 

# if _timer is None, this means that _timer_stop has been called; so 

# don't recreate the timer in that case. 

if not self._single and self._timer: 

self._timer = self.parent.after(self._interval, self._on_timer) 

else: 

self._timer = None 

 

 

class FigureCanvasTk(FigureCanvasBase): 

keyvald = {65507 : 'control', 

65505 : 'shift', 

65513 : 'alt', 

65515 : 'super', 

65508 : 'control', 

65506 : 'shift', 

65514 : 'alt', 

65361 : 'left', 

65362 : 'up', 

65363 : 'right', 

65364 : 'down', 

65307 : 'escape', 

65470 : 'f1', 

65471 : 'f2', 

65472 : 'f3', 

65473 : 'f4', 

65474 : 'f5', 

65475 : 'f6', 

65476 : 'f7', 

65477 : 'f8', 

65478 : 'f9', 

65479 : 'f10', 

65480 : 'f11', 

65481 : 'f12', 

65300 : 'scroll_lock', 

65299 : 'break', 

65288 : 'backspace', 

65293 : 'enter', 

65379 : 'insert', 

65535 : 'delete', 

65360 : 'home', 

65367 : 'end', 

65365 : 'pageup', 

65366 : 'pagedown', 

65438 : '0', 

65436 : '1', 

65433 : '2', 

65435 : '3', 

65430 : '4', 

65437 : '5', 

65432 : '6', 

65429 : '7', 

65431 : '8', 

65434 : '9', 

65451 : '+', 

65453 : '-', 

65450 : '*', 

65455 : '/', 

65439 : 'dec', 

65421 : 'enter', 

} 

 

_keycode_lookup = { 

262145: 'control', 

524320: 'alt', 

524352: 'alt', 

1048584: 'super', 

1048592: 'super', 

131074: 'shift', 

131076: 'shift', 

} 

"""_keycode_lookup is used for badly mapped (i.e. no event.key_sym set) 

keys on apple keyboards.""" 

 

def __init__(self, figure, master=None, resize_callback=None): 

super(FigureCanvasTk, self).__init__(figure) 

self._idle = True 

self._idle_callback = None 

t1,t2,w,h = self.figure.bbox.bounds 

w, h = int(w), int(h) 

self._tkcanvas = Tk.Canvas( 

master=master, background="white", 

width=w, height=h, borderwidth=0, highlightthickness=0) 

self._tkphoto = Tk.PhotoImage( 

master=self._tkcanvas, width=w, height=h) 

self._tkcanvas.create_image(w//2, h//2, image=self._tkphoto) 

self._resize_callback = resize_callback 

self._tkcanvas.bind("<Configure>", self.resize) 

self._tkcanvas.bind("<Key>", self.key_press) 

self._tkcanvas.bind("<Motion>", self.motion_notify_event) 

self._tkcanvas.bind("<KeyRelease>", self.key_release) 

for name in "<Button-1>", "<Button-2>", "<Button-3>": 

self._tkcanvas.bind(name, self.button_press_event) 

for name in "<Double-Button-1>", "<Double-Button-2>", "<Double-Button-3>": 

self._tkcanvas.bind(name, self.button_dblclick_event) 

for name in "<ButtonRelease-1>", "<ButtonRelease-2>", "<ButtonRelease-3>": 

self._tkcanvas.bind(name, self.button_release_event) 

 

# Mouse wheel on Linux generates button 4/5 events 

for name in "<Button-4>", "<Button-5>": 

self._tkcanvas.bind(name, self.scroll_event) 

# Mouse wheel for windows goes to the window with the focus. 

# Since the canvas won't usually have the focus, bind the 

# event to the window containing the canvas instead. 

# See http://wiki.tcl.tk/3893 (mousewheel) for details 

root = self._tkcanvas.winfo_toplevel() 

root.bind("<MouseWheel>", self.scroll_event_windows, "+") 

 

# Can't get destroy events by binding to _tkcanvas. Therefore, bind 

# to the window and filter. 

def filter_destroy(evt): 

if evt.widget is self._tkcanvas: 

self._master.update_idletasks() 

self.close_event() 

root.bind("<Destroy>", filter_destroy, "+") 

 

self._master = master 

self._tkcanvas.focus_set() 

 

def resize(self, event): 

width, height = event.width, event.height 

if self._resize_callback is not None: 

self._resize_callback(event) 

 

# compute desired figure size in inches 

dpival = self.figure.dpi 

winch = width/dpival 

hinch = height/dpival 

self.figure.set_size_inches(winch, hinch, forward=False) 

 

 

self._tkcanvas.delete(self._tkphoto) 

self._tkphoto = Tk.PhotoImage( 

master=self._tkcanvas, width=int(width), height=int(height)) 

self._tkcanvas.create_image(int(width/2),int(height/2),image=self._tkphoto) 

self.resize_event() 

self.draw() 

 

# a resizing will in general move the pointer position 

# relative to the canvas, so process it as a motion notify 

# event. An intended side effect of this call is to allow 

# window raises (which trigger a resize) to get the cursor 

# position to the mpl event framework so key presses which are 

# over the axes will work w/o clicks or explicit motion 

self._update_pointer_position(event) 

 

def _update_pointer_position(self, guiEvent=None): 

""" 

Figure out if we are inside the canvas or not and update the 

canvas enter/leave events 

""" 

# if the pointer if over the canvas, set the lastx and lasty 

# attrs of the canvas so it can process event w/o mouse click 

# or move 

 

# the window's upper, left coords in screen coords 

xw = self._tkcanvas.winfo_rootx() 

yw = self._tkcanvas.winfo_rooty() 

# the pointer's location in screen coords 

xp, yp = self._tkcanvas.winfo_pointerxy() 

 

# not figure out the canvas coordinates of the pointer 

xc = xp - xw 

yc = yp - yw 

 

# flip top/bottom 

yc = self.figure.bbox.height - yc 

 

# JDH: this method was written originally to get the pointer 

# location to the backend lastx and lasty attrs so that events 

# like KeyEvent can be handled without mouse events. e.g., if 

# the cursor is already above the axes, then key presses like 

# 'g' should toggle the grid. In order for this to work in 

# backend_bases, the canvas needs to know _lastx and _lasty. 

# There are three ways to get this info the canvas: 

# 

# 1) set it explicitly 

# 

# 2) call enter/leave events explicitly. The downside of this 

# in the impl below is that enter could be repeatedly 

# triggered if the mouse is over the axes and one is 

# resizing with the keyboard. This is not entirely bad, 

# because the mouse position relative to the canvas is 

# changing, but it may be surprising to get repeated entries 

# without leaves 

# 

# 3) process it as a motion notify event. This also has pros 

# and cons. The mouse is moving relative to the window, but 

# this may surpise an event handler writer who is getting 

# motion_notify_events even if the mouse has not moved 

 

# here are the three scenarios 

if 1: 

# just manually set it 

self._lastx, self._lasty = xc, yc 

elif 0: 

# alternate implementation: process it as a motion 

FigureCanvasBase.motion_notify_event(self, xc, yc, guiEvent) 

elif 0: 

# alternate implementation -- process enter/leave events 

# instead of motion/notify 

if self.figure.bbox.contains(xc, yc): 

self.enter_notify_event(guiEvent, xy=(xc,yc)) 

else: 

self.leave_notify_event(guiEvent) 

 

show = cbook.deprecated("2.2", name="FigureCanvasTk.show", 

alternative="FigureCanvasTk.draw")( 

lambda self: self.draw()) 

 

def draw_idle(self): 

'update drawing area only if idle' 

if self._idle is False: 

return 

 

self._idle = False 

 

def idle_draw(*args): 

try: 

self.draw() 

finally: 

self._idle = True 

 

self._idle_callback = self._tkcanvas.after_idle(idle_draw) 

 

def get_tk_widget(self): 

"""returns the Tk widget used to implement FigureCanvasTkAgg. 

Although the initial implementation uses a Tk canvas, this routine 

is intended to hide that fact. 

""" 

return self._tkcanvas 

 

def motion_notify_event(self, event): 

x = event.x 

# flipy so y=0 is bottom of canvas 

y = self.figure.bbox.height - event.y 

FigureCanvasBase.motion_notify_event(self, x, y, guiEvent=event) 

 

 

def button_press_event(self, event, dblclick=False): 

x = event.x 

# flipy so y=0 is bottom of canvas 

y = self.figure.bbox.height - event.y 

num = getattr(event, 'num', None) 

 

if sys.platform=='darwin': 

# 2 and 3 were reversed on the OSX platform I 

# tested under tkagg 

if num==2: num=3 

elif num==3: num=2 

 

FigureCanvasBase.button_press_event(self, x, y, num, dblclick=dblclick, guiEvent=event) 

 

def button_dblclick_event(self,event): 

self.button_press_event(event,dblclick=True) 

 

def button_release_event(self, event): 

x = event.x 

# flipy so y=0 is bottom of canvas 

y = self.figure.bbox.height - event.y 

 

num = getattr(event, 'num', None) 

 

if sys.platform=='darwin': 

# 2 and 3 were reversed on the OSX platform I 

# tested under tkagg 

if num==2: num=3 

elif num==3: num=2 

 

FigureCanvasBase.button_release_event(self, x, y, num, guiEvent=event) 

 

def scroll_event(self, event): 

x = event.x 

y = self.figure.bbox.height - event.y 

num = getattr(event, 'num', None) 

if num==4: step = +1 

elif num==5: step = -1 

else: step = 0 

 

FigureCanvasBase.scroll_event(self, x, y, step, guiEvent=event) 

 

def scroll_event_windows(self, event): 

"""MouseWheel event processor""" 

# need to find the window that contains the mouse 

w = event.widget.winfo_containing(event.x_root, event.y_root) 

if w == self._tkcanvas: 

x = event.x_root - w.winfo_rootx() 

y = event.y_root - w.winfo_rooty() 

y = self.figure.bbox.height - y 

step = event.delta/120. 

FigureCanvasBase.scroll_event(self, x, y, step, guiEvent=event) 

 

def _get_key(self, event): 

val = event.keysym_num 

if val in self.keyvald: 

key = self.keyvald[val] 

elif val == 0 and sys.platform == 'darwin' and \ 

event.keycode in self._keycode_lookup: 

key = self._keycode_lookup[event.keycode] 

elif val < 256: 

key = chr(val) 

else: 

key = None 

 

# add modifier keys to the key string. Bit details originate from 

# http://effbot.org/tkinterbook/tkinter-events-and-bindings.htm 

# BIT_SHIFT = 0x001; BIT_CAPSLOCK = 0x002; BIT_CONTROL = 0x004; 

# BIT_LEFT_ALT = 0x008; BIT_NUMLOCK = 0x010; BIT_RIGHT_ALT = 0x080; 

# BIT_MB_1 = 0x100; BIT_MB_2 = 0x200; BIT_MB_3 = 0x400; 

# In general, the modifier key is excluded from the modifier flag, 

# however this is not the case on "darwin", so double check that 

# we aren't adding repeat modifier flags to a modifier key. 

if sys.platform == 'win32': 

modifiers = [(17, 'alt', 'alt'), 

(2, 'ctrl', 'control'), 

] 

elif sys.platform == 'darwin': 

modifiers = [(3, 'super', 'super'), 

(4, 'alt', 'alt'), 

(2, 'ctrl', 'control'), 

] 

else: 

modifiers = [(6, 'super', 'super'), 

(3, 'alt', 'alt'), 

(2, 'ctrl', 'control'), 

] 

 

if key is not None: 

# note, shift is not added to the keys as this is already accounted for 

for bitmask, prefix, key_name in modifiers: 

if event.state & (1 << bitmask) and key_name not in key: 

key = '{0}+{1}'.format(prefix, key) 

 

return key 

 

def key_press(self, event): 

key = self._get_key(event) 

FigureCanvasBase.key_press_event(self, key, guiEvent=event) 

 

def key_release(self, event): 

key = self._get_key(event) 

FigureCanvasBase.key_release_event(self, key, guiEvent=event) 

 

def new_timer(self, *args, **kwargs): 

""" 

Creates a new backend-specific subclass of :class:`backend_bases.Timer`. 

This is useful for getting periodic events through the backend's native 

event loop. Implemented only for backends with GUIs. 

 

Other Parameters 

---------------- 

interval : scalar 

Timer interval in milliseconds 

callbacks : list 

Sequence of (func, args, kwargs) where ``func(*args, **kwargs)`` 

will be executed by the timer every *interval*. 

 

""" 

return TimerTk(self._tkcanvas, *args, **kwargs) 

 

def flush_events(self): 

self._master.update() 

 

 

class FigureManagerTk(FigureManagerBase): 

""" 

Attributes 

---------- 

canvas : `FigureCanvas` 

The FigureCanvas instance 

num : int or str 

The Figure number 

toolbar : tk.Toolbar 

The tk.Toolbar 

window : tk.Window 

The tk.Window 

 

""" 

def __init__(self, canvas, num, window): 

FigureManagerBase.__init__(self, canvas, num) 

self.window = window 

self.window.withdraw() 

self.set_window_title("Figure %d" % num) 

self.canvas = canvas 

self.canvas._tkcanvas.pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) 

self._num = num 

 

self.toolmanager = self._get_toolmanager() 

self.toolbar = self._get_toolbar() 

self.statusbar = None 

 

if self.toolmanager: 

backend_tools.add_tools_to_manager(self.toolmanager) 

if self.toolbar: 

backend_tools.add_tools_to_container(self.toolbar) 

self.statusbar = StatusbarTk(self.window, self.toolmanager) 

 

self._shown = False 

 

def notify_axes_change(fig): 

'this will be called whenever the current axes is changed' 

if self.toolmanager is not None: 

pass 

elif self.toolbar is not None: 

self.toolbar.update() 

self.canvas.figure.add_axobserver(notify_axes_change) 

 

def _get_toolbar(self): 

if matplotlib.rcParams['toolbar'] == 'toolbar2': 

toolbar = NavigationToolbar2Tk(self.canvas, self.window) 

elif matplotlib.rcParams['toolbar'] == 'toolmanager': 

toolbar = ToolbarTk(self.toolmanager, self.window) 

else: 

toolbar = None 

return toolbar 

 

def _get_toolmanager(self): 

if rcParams['toolbar'] == 'toolmanager': 

toolmanager = ToolManager(self.canvas.figure) 

else: 

toolmanager = None 

return toolmanager 

 

def resize(self, width, height=None): 

# before 09-12-22, the resize method takes a single *event* 

# parameter. On the other hand, the resize method of other 

# FigureManager class takes *width* and *height* parameter, 

# which is used to change the size of the window. For the 

# Figure.set_size_inches with forward=True work with Tk 

# backend, I changed the function signature but tried to keep 

# it backward compatible. -JJL 

 

# when a single parameter is given, consider it as a event 

if height is None: 

cbook.warn_deprecated("2.2", "FigureManagerTkAgg.resize now takes " 

"width and height as separate arguments") 

width = width.width 

else: 

self.canvas._tkcanvas.master.geometry("%dx%d" % (width, height)) 

 

if self.toolbar is not None: 

self.toolbar.configure(width=width) 

 

def show(self): 

""" 

this function doesn't segfault but causes the 

PyEval_RestoreThread: NULL state bug on win32 

""" 

_focus = windowing.FocusManager() 

if not self._shown: 

def destroy(*args): 

self.window = None 

Gcf.destroy(self._num) 

self.canvas._tkcanvas.bind("<Destroy>", destroy) 

self.window.deiconify() 

else: 

self.canvas.draw_idle() 

# Raise the new window. 

self.canvas.manager.window.attributes('-topmost', 1) 

self.canvas.manager.window.attributes('-topmost', 0) 

self._shown = True 

 

def destroy(self, *args): 

if self.window is not None: 

#self.toolbar.destroy() 

if self.canvas._idle_callback: 

self.canvas._tkcanvas.after_cancel(self.canvas._idle_callback) 

self.window.destroy() 

if Gcf.get_num_fig_managers()==0: 

if self.window is not None: 

self.window.quit() 

self.window = None 

 

def get_window_title(self): 

return self.window.wm_title() 

 

def set_window_title(self, title): 

self.window.wm_title(title) 

 

def full_screen_toggle(self): 

is_fullscreen = bool(self.window.attributes('-fullscreen')) 

self.window.attributes('-fullscreen', not is_fullscreen) 

 

 

@cbook.deprecated("2.2") 

class AxisMenu(object): 

def __init__(self, master, naxes): 

self._master = master 

self._naxes = naxes 

self._mbar = Tk.Frame(master=master, relief=Tk.RAISED, borderwidth=2) 

self._mbar.pack(side=Tk.LEFT) 

self._mbutton = Tk.Menubutton( 

master=self._mbar, text="Axes", underline=0) 

self._mbutton.pack(side=Tk.LEFT, padx="2m") 

self._mbutton.menu = Tk.Menu(self._mbutton) 

self._mbutton.menu.add_command( 

label="Select All", command=self.select_all) 

self._mbutton.menu.add_command( 

label="Invert All", command=self.invert_all) 

self._axis_var = [] 

self._checkbutton = [] 

for i in range(naxes): 

self._axis_var.append(Tk.IntVar()) 

self._axis_var[i].set(1) 

self._checkbutton.append(self._mbutton.menu.add_checkbutton( 

label = "Axis %d" % (i+1), 

variable=self._axis_var[i], 

command=self.set_active)) 

self._mbutton.menu.invoke(self._mbutton.menu.index("Select All")) 

self._mbutton['menu'] = self._mbutton.menu 

self._mbar.tk_menuBar(self._mbutton) 

self.set_active() 

 

def adjust(self, naxes): 

if self._naxes < naxes: 

for i in range(self._naxes, naxes): 

self._axis_var.append(Tk.IntVar()) 

self._axis_var[i].set(1) 

self._checkbutton.append( self._mbutton.menu.add_checkbutton( 

label = "Axis %d" % (i+1), 

variable=self._axis_var[i], 

command=self.set_active)) 

elif self._naxes > naxes: 

for i in range(self._naxes-1, naxes-1, -1): 

del self._axis_var[i] 

self._mbutton.menu.forget(self._checkbutton[i]) 

del self._checkbutton[i] 

self._naxes = naxes 

self.set_active() 

 

def get_indices(self): 

a = [i for i in range(len(self._axis_var)) if self._axis_var[i].get()] 

return a 

 

def set_active(self): 

self._master.set_active(self.get_indices()) 

 

def invert_all(self): 

for a in self._axis_var: 

a.set(not a.get()) 

self.set_active() 

 

def select_all(self): 

for a in self._axis_var: 

a.set(1) 

self.set_active() 

 

 

class NavigationToolbar2Tk(NavigationToolbar2, Tk.Frame): 

""" 

Attributes 

---------- 

canvas : `FigureCanvas` 

the figure canvas on which to operate 

win : tk.Window 

the tk.Window which owns this toolbar 

 

""" 

def __init__(self, canvas, window): 

self.canvas = canvas 

self.window = window 

NavigationToolbar2.__init__(self, canvas) 

 

def destroy(self, *args): 

del self.message 

Tk.Frame.destroy(self, *args) 

 

def set_message(self, s): 

self.message.set(s) 

 

def draw_rubberband(self, event, x0, y0, x1, y1): 

height = self.canvas.figure.bbox.height 

y0 = height - y0 

y1 = height - y1 

if hasattr(self, "lastrect"): 

self.canvas._tkcanvas.delete(self.lastrect) 

self.lastrect = self.canvas._tkcanvas.create_rectangle(x0, y0, x1, y1) 

 

#self.canvas.draw() 

 

def release(self, event): 

try: self.lastrect 

except AttributeError: pass 

else: 

self.canvas._tkcanvas.delete(self.lastrect) 

del self.lastrect 

 

def set_cursor(self, cursor): 

self.window.configure(cursor=cursord[cursor]) 

self.window.update_idletasks() 

 

def _Button(self, text, file, command, extension='.gif'): 

img_file = os.path.join( 

rcParams['datapath'], 'images', file + extension) 

im = Tk.PhotoImage(master=self, file=img_file) 

b = Tk.Button( 

master=self, text=text, padx=2, pady=2, image=im, command=command) 

b._ntimage = im 

b.pack(side=Tk.LEFT) 

return b 

 

def _Spacer(self): 

# Buttons are 30px high, so make this 26px tall with padding to center it 

s = Tk.Frame( 

master=self, height=26, relief=Tk.RIDGE, pady=2, bg="DarkGray") 

s.pack(side=Tk.LEFT, padx=5) 

return s 

 

def _init_toolbar(self): 

xmin, xmax = self.canvas.figure.bbox.intervalx 

height, width = 50, xmax-xmin 

Tk.Frame.__init__(self, master=self.window, 

width=int(width), height=int(height), 

borderwidth=2) 

 

self.update() # Make axes menu 

 

for text, tooltip_text, image_file, callback in self.toolitems: 

if text is None: 

# Add a spacer; return value is unused. 

self._Spacer() 

else: 

button = self._Button(text=text, file=image_file, 

command=getattr(self, callback)) 

if tooltip_text is not None: 

ToolTip.createToolTip(button, tooltip_text) 

 

self.message = Tk.StringVar(master=self) 

self._message_label = Tk.Label(master=self, textvariable=self.message) 

self._message_label.pack(side=Tk.RIGHT) 

self.pack(side=Tk.BOTTOM, fill=Tk.X) 

 

def configure_subplots(self): 

toolfig = Figure(figsize=(6,3)) 

window = Tk.Toplevel() 

canvas = type(self.canvas)(toolfig, master=window) 

toolfig.subplots_adjust(top=0.9) 

canvas.tool = SubplotTool(self.canvas.figure, toolfig) 

canvas.draw() 

canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) 

window.grab_set() 

 

def save_figure(self, *args): 

from six.moves import tkinter_tkfiledialog, tkinter_messagebox 

filetypes = self.canvas.get_supported_filetypes().copy() 

default_filetype = self.canvas.get_default_filetype() 

 

# Tk doesn't provide a way to choose a default filetype, 

# so we just have to put it first 

default_filetype_name = filetypes.pop(default_filetype) 

sorted_filetypes = ([(default_filetype, default_filetype_name)] 

+ sorted(six.iteritems(filetypes))) 

tk_filetypes = [(name, '*.%s' % ext) for ext, name in sorted_filetypes] 

 

# adding a default extension seems to break the 

# asksaveasfilename dialog when you choose various save types 

# from the dropdown. Passing in the empty string seems to 

# work - JDH! 

#defaultextension = self.canvas.get_default_filetype() 

defaultextension = '' 

initialdir = os.path.expanduser(rcParams['savefig.directory']) 

initialfile = self.canvas.get_default_filename() 

fname = tkinter_tkfiledialog.asksaveasfilename( 

master=self.window, 

title='Save the figure', 

filetypes=tk_filetypes, 

defaultextension=defaultextension, 

initialdir=initialdir, 

initialfile=initialfile, 

) 

 

if fname in ["", ()]: 

return 

# Save dir for next time, unless empty str (i.e., use cwd). 

if initialdir != "": 

rcParams['savefig.directory'] = ( 

os.path.dirname(six.text_type(fname))) 

try: 

# This method will handle the delegation to the correct type 

self.canvas.figure.savefig(fname) 

except Exception as e: 

tkinter_messagebox.showerror("Error saving file", str(e)) 

 

def set_active(self, ind): 

self._ind = ind 

self._active = [self._axes[i] for i in self._ind] 

 

def update(self): 

_focus = windowing.FocusManager() 

self._axes = self.canvas.figure.axes 

NavigationToolbar2.update(self) 

 

 

class ToolTip(object): 

""" 

Tooltip recipe from 

http://www.voidspace.org.uk/python/weblog/arch_d7_2006_07_01.shtml#e387 

""" 

@staticmethod 

def createToolTip(widget, text): 

toolTip = ToolTip(widget) 

def enter(event): 

toolTip.showtip(text) 

def leave(event): 

toolTip.hidetip() 

widget.bind('<Enter>', enter) 

widget.bind('<Leave>', leave) 

 

def __init__(self, widget): 

self.widget = widget 

self.tipwindow = None 

self.id = None 

self.x = self.y = 0 

 

def showtip(self, text): 

"Display text in tooltip window" 

self.text = text 

if self.tipwindow or not self.text: 

return 

x, y, _, _ = self.widget.bbox("insert") 

x = x + self.widget.winfo_rootx() + 27 

y = y + self.widget.winfo_rooty() 

self.tipwindow = tw = Tk.Toplevel(self.widget) 

tw.wm_overrideredirect(1) 

tw.wm_geometry("+%d+%d" % (x, y)) 

try: 

# For Mac OS 

tw.tk.call("::tk::unsupported::MacWindowStyle", 

"style", tw._w, 

"help", "noActivates") 

except Tk.TclError: 

pass 

label = Tk.Label(tw, text=self.text, justify=Tk.LEFT, 

background="#ffffe0", relief=Tk.SOLID, borderwidth=1) 

label.pack(ipadx=1) 

 

def hidetip(self): 

tw = self.tipwindow 

self.tipwindow = None 

if tw: 

tw.destroy() 

 

 

class RubberbandTk(backend_tools.RubberbandBase): 

def __init__(self, *args, **kwargs): 

backend_tools.RubberbandBase.__init__(self, *args, **kwargs) 

 

def draw_rubberband(self, x0, y0, x1, y1): 

height = self.figure.canvas.figure.bbox.height 

y0 = height - y0 

y1 = height - y1 

if hasattr(self, "lastrect"): 

self.figure.canvas._tkcanvas.delete(self.lastrect) 

self.lastrect = self.figure.canvas._tkcanvas.create_rectangle( 

x0, y0, x1, y1) 

 

def remove_rubberband(self): 

if hasattr(self, "lastrect"): 

self.figure.canvas._tkcanvas.delete(self.lastrect) 

del self.lastrect 

 

 

class SetCursorTk(backend_tools.SetCursorBase): 

def set_cursor(self, cursor): 

self.figure.canvas.manager.window.configure(cursor=cursord[cursor]) 

 

 

class ToolbarTk(ToolContainerBase, Tk.Frame): 

_icon_extension = '.gif' 

def __init__(self, toolmanager, window): 

ToolContainerBase.__init__(self, toolmanager) 

xmin, xmax = self.toolmanager.canvas.figure.bbox.intervalx 

height, width = 50, xmax - xmin 

Tk.Frame.__init__(self, master=window, 

width=int(width), height=int(height), 

borderwidth=2) 

self._toolitems = {} 

self.pack(side=Tk.TOP, fill=Tk.X) 

self._groups = {} 

 

def add_toolitem( 

self, name, group, position, image_file, description, toggle): 

frame = self._get_groupframe(group) 

button = self._Button(name, image_file, toggle, frame) 

if description is not None: 

ToolTip.createToolTip(button, description) 

self._toolitems.setdefault(name, []) 

self._toolitems[name].append(button) 

 

def _get_groupframe(self, group): 

if group not in self._groups: 

if self._groups: 

self._add_separator() 

frame = Tk.Frame(master=self, borderwidth=0) 

frame.pack(side=Tk.LEFT, fill=Tk.Y) 

self._groups[group] = frame 

return self._groups[group] 

 

def _add_separator(self): 

separator = Tk.Frame(master=self, bd=5, width=1, bg='black') 

separator.pack(side=Tk.LEFT, fill=Tk.Y, padx=2) 

 

def _Button(self, text, image_file, toggle, frame): 

if image_file is not None: 

im = Tk.PhotoImage(master=self, file=image_file) 

else: 

im = None 

 

if not toggle: 

b = Tk.Button(master=frame, text=text, padx=2, pady=2, image=im, 

command=lambda: self._button_click(text)) 

else: 

# There is a bug in tkinter included in some python 3.6 versions 

# that without this variable, produces a "visual" toggling of 

# other near checkbuttons 

# https://bugs.python.org/issue29402 

# https://bugs.python.org/issue25684 

var = Tk.IntVar() 

b = Tk.Checkbutton(master=frame, text=text, padx=2, pady=2, 

image=im, indicatoron=False, 

command=lambda: self._button_click(text), 

variable=var) 

b._ntimage = im 

b.pack(side=Tk.LEFT) 

return b 

 

def _button_click(self, name): 

self.trigger_tool(name) 

 

def toggle_toolitem(self, name, toggled): 

if name not in self._toolitems: 

return 

for toolitem in self._toolitems[name]: 

if toggled: 

toolitem.select() 

else: 

toolitem.deselect() 

 

def remove_toolitem(self, name): 

for toolitem in self._toolitems[name]: 

toolitem.pack_forget() 

del self._toolitems[name] 

 

 

class StatusbarTk(StatusbarBase, Tk.Frame): 

def __init__(self, window, *args, **kwargs): 

StatusbarBase.__init__(self, *args, **kwargs) 

xmin, xmax = self.toolmanager.canvas.figure.bbox.intervalx 

height, width = 50, xmax - xmin 

Tk.Frame.__init__(self, master=window, 

width=int(width), height=int(height), 

borderwidth=2) 

self._message = Tk.StringVar(master=self) 

self._message_label = Tk.Label(master=self, textvariable=self._message) 

self._message_label.pack(side=Tk.RIGHT) 

self.pack(side=Tk.TOP, fill=Tk.X) 

 

def set_message(self, s): 

self._message.set(s) 

 

 

class SaveFigureTk(backend_tools.SaveFigureBase): 

def trigger(self, *args): 

from six.moves import tkinter_tkfiledialog, tkinter_messagebox 

filetypes = self.figure.canvas.get_supported_filetypes().copy() 

default_filetype = self.figure.canvas.get_default_filetype() 

 

# Tk doesn't provide a way to choose a default filetype, 

# so we just have to put it first 

default_filetype_name = filetypes.pop(default_filetype) 

sorted_filetypes = ([(default_filetype, default_filetype_name)] 

+ sorted(six.iteritems(filetypes))) 

tk_filetypes = [(name, '*.%s' % ext) for ext, name in sorted_filetypes] 

 

# adding a default extension seems to break the 

# asksaveasfilename dialog when you choose various save types 

# from the dropdown. Passing in the empty string seems to 

# work - JDH! 

# defaultextension = self.figure.canvas.get_default_filetype() 

defaultextension = '' 

initialdir = os.path.expanduser(rcParams['savefig.directory']) 

initialfile = self.figure.canvas.get_default_filename() 

fname = tkinter_tkfiledialog.asksaveasfilename( 

master=self.figure.canvas.manager.window, 

title='Save the figure', 

filetypes=tk_filetypes, 

defaultextension=defaultextension, 

initialdir=initialdir, 

initialfile=initialfile, 

) 

 

if fname == "" or fname == (): 

return 

else: 

if initialdir == '': 

# explicitly missing key or empty str signals to use cwd 

rcParams['savefig.directory'] = initialdir 

else: 

# save dir for next time 

rcParams['savefig.directory'] = os.path.dirname( 

six.text_type(fname)) 

try: 

# This method will handle the delegation to the correct type 

self.figure.savefig(fname) 

except Exception as e: 

tkinter_messagebox.showerror("Error saving file", str(e)) 

 

 

class ConfigureSubplotsTk(backend_tools.ConfigureSubplotsBase): 

def __init__(self, *args, **kwargs): 

backend_tools.ConfigureSubplotsBase.__init__(self, *args, **kwargs) 

self.window = None 

 

def trigger(self, *args): 

self.init_window() 

self.window.lift() 

 

def init_window(self): 

if self.window: 

return 

 

toolfig = Figure(figsize=(6, 3)) 

self.window = Tk.Tk() 

 

canvas = type(self.canvas)(toolfig, master=self.window) 

toolfig.subplots_adjust(top=0.9) 

_tool = SubplotTool(self.figure, toolfig) 

canvas.draw() 

canvas.get_tk_widget().pack(side=Tk.TOP, fill=Tk.BOTH, expand=1) 

self.window.protocol("WM_DELETE_WINDOW", self.destroy) 

 

def destroy(self, *args, **kwargs): 

self.window.destroy() 

self.window = None 

 

 

backend_tools.ToolSaveFigure = SaveFigureTk 

backend_tools.ToolConfigureSubplots = ConfigureSubplotsTk 

backend_tools.ToolSetCursor = SetCursorTk 

backend_tools.ToolRubberband = RubberbandTk 

Toolbar = ToolbarTk 

 

 

@_Backend.export 

class _BackendTk(_Backend): 

FigureManager = FigureManagerTk 

 

@classmethod 

def new_figure_manager_given_figure(cls, num, figure): 

""" 

Create a new figure manager instance for the given figure. 

""" 

_focus = windowing.FocusManager() 

window = Tk.Tk(className="matplotlib") 

window.withdraw() 

 

# Put a mpl icon on the window rather than the default tk icon. 

# Tkinter doesn't allow colour icons on linux systems, but tk>=8.5 has 

# a iconphoto command which we call directly. Source: 

# http://mail.python.org/pipermail/tkinter-discuss/2006-November/000954.html 

icon_fname = os.path.join( 

rcParams['datapath'], 'images', 'matplotlib.ppm') 

icon_img = Tk.PhotoImage(file=icon_fname) 

try: 

window.tk.call('wm', 'iconphoto', window._w, icon_img) 

except Exception as exc: 

# log the failure (due e.g. to Tk version), but carry on 

_log.info('Could not load matplotlib icon: %s', exc) 

 

canvas = cls.FigureCanvas(figure, master=window) 

manager = cls.FigureManager(canvas, num, window) 

if matplotlib.is_interactive(): 

manager.show() 

canvas.draw_idle() 

return manager 

 

@staticmethod 

def trigger_manager_draw(manager): 

manager.show() 

 

@staticmethod 

def mainloop(): 

Tk.mainloop()