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

from pyrocko.guts import Object, Float, Int, List, Tuple, String, load, clone 

 

from grond.meta import GrondError 

 

guts_prefix = 'grond' 

 

 

inch = 2.54 

 

 

class PlotFormat(Object): 

 

@property 

def extension(self): 

return self.name 

 

def get_dpi(self, size_cm): 

return None 

 

def render_mpl(self, fig, path, **kwargs): 

raise NotImplementedError 

 

def render_automap(self, automap, path, **kwargs): 

raise NotImplementedError 

 

 

class PNG(PlotFormat): 

name = 'png' 

 

dpi = Int.T( 

optional=True, 

help='DPI of the figure') 

size_pixels = Int.T( 

optional=True, 

help='Size in pixels') 

width_pixels = Int.T( 

optional=True, 

help='Width in pixels') 

height_pixels = Int.T( 

optional=True, 

help='Height in pixels') 

 

@property 

def extension(self): 

if self.dpi is not None: 

return 'd%i.png' % self.dpi 

elif self.size_pixels is not None: 

return 's%i.png' % self.size_pixels 

elif self.width_pixels is not None: 

return 'w%i.png' % self.width_pixels 

elif self.height_pixels is not None: 

return 'h%i.png' % self.height_pixels 

else: 

return 'd100.png' 

 

def get_dpi(self, size_cm): 

w_cm, h_cm = size_cm 

w_inch, h_inch = w_cm/inch, h_cm/inch 

if self.dpi: 

return self.dpi 

elif self.size_pixels is not None: 

return min(self.size_pixels/w_inch, self.size_pixels/h_inch) 

elif self.width_pixels is not None: 

return self.width_pixels/w_inch 

elif self.height_pixels is not None: 

return self.height_pixels/h_inch 

else: 

return 100.0 

 

def render_mpl(self, fig, path, **kwargs): 

return fig.savefig(path, format=self.name, **kwargs) 

 

def render_automap(self, automap, path, **kwargs): 

return automap.save(path, **kwargs) 

 

 

class PDF(PlotFormat): 

name = 'pdf' 

 

dpi = Int.T( 

default=150, 

help='DPI of the figure') 

 

def get_dpi(self, size_cm): 

return self.dpi 

 

def render_mpl(self, fig, path, **kwargs): 

return fig.savefig(path, format=self.name, **kwargs) 

 

def render_automap(self, automap, path, **kwargs): 

return automap.save(path, **kwargs) 

 

 

class SVG(PlotFormat): 

name = 'svg' 

 

dpi = Int.T( 

default=150, 

help='DPI of the figure') 

 

def get_dpi(self, size_cm): 

return self.dpi 

 

def render_mpl(self, fig, path, **kwargs): 

return fig.savefig(path, format=self.name, **kwargs) 

 

def render_automap(self, automap, path, **kwargs): 

return automap.save(path, **kwargs) 

 

 

class HTML(PlotFormat): 

name = 'html' 

 

@property 

def extension(self): 

return 'html' 

 

def render_mpl(self, fig, path, **kwargs): 

import mpld3 

kwargs.pop('dpi') 

 

mpld3.save_html( 

fig, 

fileobj=path, 

**kwargs) 

 

 

class PlotConfig(Object): 

name = 'undefined' 

variant = String.T( 

default='default', 

help='Variant of the plot (if applicable)') 

formats = List.T( 

PlotFormat.T(), 

default=[PNG()], 

help='Format of the plot') 

size_cm = Tuple.T( 

2, Float.T(), 

help='size of the plot') 

font_size = Float.T( 

default=10., 

help='font size') 

 

@property 

def size_inch(self): 

return self.size_cm[0]/inch, self.size_cm[1]/inch 

 

def make(self, environ): 

pass 

 

 

class PlotConfigCollection(Object): 

plot_configs = List.T(PlotConfig.T()) 

 

@classmethod 

def load(cls, path): 

from grond.plot import get_all_plot_classes 

get_all_plot_classes() # make sure all plot classes are loaded 

collection = load(filename=path) 

if not isinstance(collection, PlotConfigCollection): 

raise GrondError( 

'invalid plot collection configuration in file "%s"' % path) 

 

return collection 

 

def get_weeded(self, env): 

'''Get subset of plot configs supported by the current environment.''' 

 

plot_classes = env.get_plot_classes() 

plot_configs_avail = [ 

clone(pc) 

for pc in self.plot_configs 

if pc.__class__ in plot_classes] 

 

return PlotConfigCollection(plot_configs=plot_configs_avail) 

 

 

__all__ = [ 

'PlotFormat', 

'PNG', 

'PDF', 

'PlotConfig', 

'PlotConfigCollection', 

]