Coverage for /usr/local/lib/python3.11/dist-packages/grond/problems/double_dc/plot.py: 27%

62 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2025-04-03 09:31 +0000

1# https://pyrocko.org/grond - GPLv3 

2# 

3# The Grond Developers, 21st Century 

4import math 

5import logging 

6 

7from matplotlib import pyplot as plt 

8 

9from pyrocko.guts import Float, Tuple 

10from pyrocko import gf 

11from pyrocko.plot import mpl_init, beachball, mpl_color 

12 

13from grond import stats 

14from grond.plot.collection import PlotItem 

15from grond.plot.config import PlotConfig 

16 

17logger = logging.getLogger('grond.problem.double_dc.plot') 

18 

19guts_prefix = 'grond' 

20 

21km = 1e3 

22 

23 

24class DoubleDCDecompositionPlot(PlotConfig): 

25 ''' 

26 Double DC decomposition plot. 

27 ''' 

28 name = 'dc_decomposition' 

29 size_cm = Tuple.T(2, Float.T(), default=(15., 5.)) 

30 

31 def make(self, environ): 

32 cm = environ.get_plot_collection_manager() 

33 history = environ.get_history(subset='harvest') 

34 mpl_init(fontsize=self.font_size) 

35 cm.create_group_mpl( 

36 self, 

37 self.draw_figures(history), 

38 title=u'Double DC Decomposition', 

39 section='solution', 

40 feather_icon='sun', 

41 description=u''' 

42Double DC decomposition of the best and mean solution into its two contributing 

43focal mechanisms. 

44Shown are the ensemble best and the ensemble mean. The symbol size indicates 

45the relative strength of the mechanisms. The inversion result is consistent 

46and stable if ensemble mean and ensemble best have similar symbol size and 

47patterns. 

48''') 

49 

50 def draw_figures(self, history): 

51 fontsize = self.font_size 

52 

53 fig = plt.figure(figsize=self.size_inch) 

54 axes = fig.add_subplot(1, 1, 1, aspect=1.0) 

55 

56 fig.subplots_adjust(left=0., right=1., bottom=0., top=1.) 

57 

58 problem = history.problem 

59 models = history.models 

60 if models.size == 0: 

61 logger.warn('Empty models vector.') 

62 return [] 

63 

64 mean_source = stats.get_mean_source( 

65 problem, history.models) 

66 best_source = history.get_best_source() 

67 nlines_max = int(round(self.size_cm[1] / 5. * 4. - 1.0)) 

68 

69 def get_deco(source): 

70 if isinstance(source, gf.DoubleDCSource): 

71 return [source] + source.split() 

72 

73 lines = [] 

74 lines.append( 

75 ('Ensemble best', get_deco(best_source), mpl_color('aluminium5'))) 

76 lines.append( 

77 ('Ensemble mean', get_deco(mean_source), mpl_color('aluminium5'))) 

78 

79 mag_max = max(dc.magnitude for (_, line, _) in lines for dc in line) 

80 

81 for xpos, label in [ 

82 (0., 'Double DC'), 

83 (2., 'DC 1'), 

84 (4., 'DC 2')]: 

85 

86 axes.annotate( 

87 label, 

88 xy=(1 + xpos, nlines_max), 

89 xycoords='data', 

90 xytext=(0., 0.), 

91 textcoords='offset points', 

92 ha='center', 

93 va='center', 

94 color='black', 

95 fontsize=fontsize) 

96 

97 for i, (label, deco, color_t) in enumerate(lines): 

98 ypos = nlines_max - i - 1.0 

99 [ddc, dc1, dc2] = deco 

100 size0 = ddc.magnitude / mag_max 

101 

102 axes.annotate( 

103 label, 

104 xy=(-2., ypos), 

105 xycoords='data', 

106 xytext=(0., 0.), 

107 textcoords='offset points', 

108 ha='left', 

109 va='center', 

110 color='black', 

111 fontsize=fontsize) 

112 

113 for xpos, dc_part, ratio, ops in [ 

114 (0., ddc, 1., '='), 

115 (2., dc1, dc1.magnitude / mag_max, '+'), 

116 (4., dc2, dc2.magnitude / mag_max, None)]: 

117 

118 if ratio > 1e-4: 

119 try: 

120 beachball.plot_beachball_mpl( 

121 dc_part.pyrocko_moment_tensor(), axes, 

122 position=(1. + xpos, ypos), 

123 size=0.9 * size0 * math.sqrt(ratio), 

124 size_units='data', 

125 color_t=color_t, 

126 linewidth=1.0) 

127 except beachball.BeachballError as e: 

128 logger.warn(str(e)) 

129 axes.annotate( 

130 'ERROR', 

131 xy=(1. + xpos, ypos), 

132 ha='center', 

133 va='center', 

134 color='red', 

135 fontsize=fontsize) 

136 else: 

137 axes.annotate( 

138 'N/A', 

139 xy=(1. + xpos, ypos), 

140 ha='center', 

141 va='center', 

142 color='black', 

143 fontsize=fontsize) 

144 if ops is not None: 

145 axes.annotate( 

146 ops, 

147 xy=(2. + xpos, ypos), 

148 ha='center', 

149 va='center', 

150 color='black', 

151 fontsize=fontsize) 

152 axes.axison = False 

153 axes.set_xlim(-2.25, 9.75) 

154 axes.set_ylim(-0.5, nlines_max+0.5) 

155 item = PlotItem(name='main') 

156 return [[item, fig]]