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

from __future__ import (absolute_import, division, print_function, 

unicode_literals) 

 

import six 

from six.moves import map 

 

from matplotlib.gridspec import GridSpec, SubplotSpec 

from matplotlib import docstring 

import matplotlib.artist as martist 

from matplotlib.axes._axes import Axes 

 

import matplotlib._layoutbox as layoutbox 

 

import warnings 

from matplotlib.cbook import mplDeprecation 

 

 

class SubplotBase(object): 

""" 

Base class for subplots, which are :class:`Axes` instances with 

additional methods to facilitate generating and manipulating a set 

of :class:`Axes` within a figure. 

""" 

 

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

""" 

*fig* is a :class:`matplotlib.figure.Figure` instance. 

 

*args* is the tuple (*numRows*, *numCols*, *plotNum*), where 

the array of subplots in the figure has dimensions *numRows*, 

*numCols*, and where *plotNum* is the number of the subplot 

being created. *plotNum* starts at 1 in the upper left 

corner and increases to the right. 

 

If *numRows* <= *numCols* <= *plotNum* < 10, *args* can be the 

decimal integer *numRows* * 100 + *numCols* * 10 + *plotNum*. 

""" 

 

self.figure = fig 

 

if len(args) == 1: 

if isinstance(args[0], SubplotSpec): 

self._subplotspec = args[0] 

else: 

try: 

s = str(int(args[0])) 

rows, cols, num = map(int, s) 

except ValueError: 

raise ValueError('Single argument to subplot must be ' 

'a 3-digit integer') 

self._subplotspec = GridSpec(rows, cols, 

figure=self.figure)[num - 1] 

# num - 1 for converting from MATLAB to python indexing 

elif len(args) == 3: 

rows, cols, num = args 

rows = int(rows) 

cols = int(cols) 

if isinstance(num, tuple) and len(num) == 2: 

num = [int(n) for n in num] 

self._subplotspec = GridSpec( 

rows, cols, 

figure=self.figure)[(num[0] - 1):num[1]] 

else: 

if num < 1 or num > rows*cols: 

raise ValueError( 

("num must be 1 <= num <= {maxn}, not {num}" 

).format(maxn=rows*cols, num=num)) 

self._subplotspec = GridSpec( 

rows, cols, figure=self.figure)[int(num) - 1] 

# num - 1 for converting from MATLAB to python indexing 

else: 

raise ValueError('Illegal argument(s) to subplot: %s' % (args,)) 

 

self.update_params() 

 

# _axes_class is set in the subplot_class_factory 

self._axes_class.__init__(self, fig, self.figbox, **kwargs) 

# add a layout box to this, for both the full axis, and the poss 

# of the axis. We need both because the axes may become smaller 

# due to parasitic axes and hence no longer fill the subplotspec. 

if self._subplotspec._layoutbox is None: 

self._layoutbox = None 

self._poslayoutbox = None 

else: 

name = self._subplotspec._layoutbox.name + '.ax' 

name = name + layoutbox.seq_id() 

self._layoutbox = layoutbox.LayoutBox( 

parent=self._subplotspec._layoutbox, 

name=name, 

artist=self) 

self._poslayoutbox = layoutbox.LayoutBox( 

parent=self._layoutbox, 

name=self._layoutbox.name+'.pos', 

pos=True, subplot=True, artist=self) 

 

def __reduce__(self): 

# get the first axes class which does not 

# inherit from a subplotbase 

 

def not_subplotbase(c): 

return issubclass(c, Axes) and not issubclass(c, SubplotBase) 

 

axes_class = [c for c in self.__class__.mro() 

if not_subplotbase(c)][0] 

r = [_PicklableSubplotClassConstructor(), 

(axes_class,), 

self.__getstate__()] 

return tuple(r) 

 

def get_geometry(self): 

"""get the subplot geometry, e.g., 2,2,3""" 

rows, cols, num1, num2 = self.get_subplotspec().get_geometry() 

return rows, cols, num1 + 1 # for compatibility 

 

# COVERAGE NOTE: Never used internally or from examples 

def change_geometry(self, numrows, numcols, num): 

"""change subplot geometry, e.g., from 1,1,1 to 2,2,3""" 

self._subplotspec = GridSpec(numrows, numcols, 

figure=self.figure)[num - 1] 

self.update_params() 

self.set_position(self.figbox) 

 

def get_subplotspec(self): 

"""get the SubplotSpec instance associated with the subplot""" 

return self._subplotspec 

 

def set_subplotspec(self, subplotspec): 

"""set the SubplotSpec instance associated with the subplot""" 

self._subplotspec = subplotspec 

 

def update_params(self): 

"""update the subplot position from fig.subplotpars""" 

 

self.figbox, self.rowNum, self.colNum, self.numRows, self.numCols = \ 

self.get_subplotspec().get_position(self.figure, 

return_all=True) 

 

def is_first_col(self): 

return self.colNum == 0 

 

def is_first_row(self): 

return self.rowNum == 0 

 

def is_last_row(self): 

return self.rowNum == self.numRows - 1 

 

def is_last_col(self): 

return self.colNum == self.numCols - 1 

 

# COVERAGE NOTE: Never used internally. 

def label_outer(self): 

"""Only show "outer" labels and tick labels. 

 

x-labels are only kept for subplots on the last row; y-labels only for 

subplots on the first column. 

""" 

lastrow = self.is_last_row() 

firstcol = self.is_first_col() 

if not lastrow: 

for label in self.get_xticklabels(which="both"): 

label.set_visible(False) 

self.get_xaxis().get_offset_text().set_visible(False) 

self.set_xlabel("") 

if not firstcol: 

for label in self.get_yticklabels(which="both"): 

label.set_visible(False) 

self.get_yaxis().get_offset_text().set_visible(False) 

self.set_ylabel("") 

 

def _make_twin_axes(self, *kl, **kwargs): 

""" 

Make a twinx axes of self. This is used for twinx and twiny. 

""" 

from matplotlib.projections import process_projection_requirements 

if 'sharex' in kwargs and 'sharey' in kwargs: 

# The following line is added in v2.2 to avoid breaking Seaborn, 

# which currently uses this internal API. 

if kwargs["sharex"] is not self and kwargs["sharey"] is not self: 

raise ValueError("Twinned Axes may share only one axis.") 

kl = (self.get_subplotspec(),) + kl 

projection_class, kwargs, key = process_projection_requirements( 

self.figure, *kl, **kwargs) 

 

ax2 = subplot_class_factory(projection_class)(self.figure, 

*kl, **kwargs) 

self.figure.add_subplot(ax2) 

self.set_adjustable('datalim') 

ax2.set_adjustable('datalim') 

 

if self._layoutbox is not None and ax2._layoutbox is not None: 

# make the layout boxes be explicitly the same 

ax2._layoutbox.constrain_same(self._layoutbox) 

ax2._poslayoutbox.constrain_same(self._poslayoutbox) 

 

self._twinned_axes.join(self, ax2) 

return ax2 

 

_subplot_classes = {} 

 

 

def subplot_class_factory(axes_class=None): 

# This makes a new class that inherits from SubplotBase and the 

# given axes_class (which is assumed to be a subclass of Axes). 

# This is perhaps a little bit roundabout to make a new class on 

# the fly like this, but it means that a new Subplot class does 

# not have to be created for every type of Axes. 

if axes_class is None: 

axes_class = Axes 

 

new_class = _subplot_classes.get(axes_class) 

if new_class is None: 

new_class = type(str("%sSubplot") % (axes_class.__name__), 

(SubplotBase, axes_class), 

{'_axes_class': axes_class}) 

_subplot_classes[axes_class] = new_class 

 

return new_class 

 

# This is provided for backward compatibility 

Subplot = subplot_class_factory() 

 

 

class _PicklableSubplotClassConstructor(object): 

""" 

This stub class exists to return the appropriate subplot 

class when __call__-ed with an axes class. This is purely to 

allow Pickling of Axes and Subplots. 

""" 

def __call__(self, axes_class): 

# create a dummy object instance 

subplot_instance = _PicklableSubplotClassConstructor() 

subplot_class = subplot_class_factory(axes_class) 

# update the class to the desired subplot class 

subplot_instance.__class__ = subplot_class 

return subplot_instance 

 

 

docstring.interpd.update(Axes=martist.kwdoc(Axes)) 

docstring.interpd.update(Subplot=martist.kwdoc(Axes)) 

 

""" 

# this is some discarded code I was using to find the minimum positive 

# data point for some log scaling fixes. I realized there was a 

# cleaner way to do it, but am keeping this around as an example for 

# how to get the data out of the axes. Might want to make something 

# like this a method one day, or better yet make get_verts an Artist 

# method 

 

minx, maxx = self.get_xlim() 

if minx<=0 or maxx<=0: 

# find the min pos value in the data 

xs = [] 

for line in self.lines: 

xs.extend(line.get_xdata(orig=False)) 

for patch in self.patches: 

xs.extend([x for x,y in patch.get_verts()]) 

for collection in self.collections: 

xs.extend([x for x,y in collection.get_verts()]) 

posx = [x for x in xs if x>0] 

if len(posx): 

 

minx = min(posx) 

maxx = max(posx) 

# warning, probably breaks inverted axis 

self.set_xlim((0.1*minx, maxx)) 

 

"""