Coverage for src/arcade_collection/convert/convert_to_projection.py: 17%

48 statements  

« prev     ^ index     » next       coverage.py v7.1.0, created at 2024-12-09 19:07 +0000

1import tarfile 

2 

3import matplotlib as mpl 

4import matplotlib.pyplot as plt 

5from matplotlib.patches import Rectangle 

6 

7from arcade_collection.convert.convert_to_contours import convert_to_contours 

8 

9 

10def convert_to_projection( 

11 series_key: str, 

12 locations_tar: tarfile.TarFile, 

13 frame: int, 

14 regions: list[str], 

15 box: tuple[int, int, int], 

16 ds: float, 

17 dt: float, 

18 scale: int, 

19 colors: dict[str, str], 

20) -> mpl.figure.Figure: 

21 """ 

22 Convert data to projection figure. 

23 

24 Parameters 

25 ---------- 

26 series_key 

27 Simulation series key. 

28 locations_tar 

29 Archive of location data. 

30 frame 

31 Frame number. 

32 regions 

33 List of regions. 

34 box 

35 Size of bounding box. 

36 ds 

37 Spatial scaling in um/voxel. 

38 dt 

39 Temporal scaling in hours/tick. 

40 scale 

41 Size of scale bar (in um). 

42 colors 

43 Map of region to colors. 

44 

45 Returns 

46 ------- 

47 : 

48 Projection figure. 

49 """ 

50 

51 fig = plt.figure(figsize=(10, 10), constrained_layout=True) 

52 length, width, height = box 

53 

54 ax = fig.add_subplot() 

55 

56 ax.invert_yaxis() 

57 ax.get_xaxis().set_ticks([]) 

58 ax.get_yaxis().set_ticks([]) 

59 ax.set_xlim([0, length - 1]) 

60 ax.set_ylim([width - 1, 0]) 

61 ax.set_box_aspect(1) 

62 

63 ax_horz = ax.inset_axes([0, 1.005, 1, height / width], sharex=ax) 

64 ax_horz.set_ylim([0, height - 1]) 

65 ax_horz.get_yaxis().set_ticks([]) 

66 

67 ax_vert = ax.inset_axes([1.005, 0, height / length, 1], sharey=ax) 

68 ax_vert.set_xlim([0, height - 1]) 

69 ax_vert.get_xaxis().set_ticks([]) 

70 

71 ax.set_facecolor("#000") 

72 ax_horz.set_facecolor("#000") 

73 ax_vert.set_facecolor("#000") 

74 

75 indices = { 

76 "top": list(range(1, height)), 

77 "side1": list(range(1, width)), 

78 "side2": list(range(1, length)), 

79 } 

80 contours = convert_to_contours(series_key, locations_tar, frame, regions, box, indices) 

81 

82 for region in regions: 

83 color = colors[region] 

84 

85 for region_top_contours in contours[region]["top"].values(): 

86 for contour in region_top_contours: 

87 ax.plot(contour[:, 0], contour[:, 1], linewidth=0.5, color=color, alpha=0.5) 

88 

89 for region_side1_contours in contours[region]["side1"].values(): 

90 for contour in region_side1_contours: 

91 ax_horz.plot(contour[:, 0], contour[:, 1], linewidth=0.5, color=color, alpha=0.5) 

92 

93 for region_side2_contours in contours[region]["side2"].values(): 

94 for contour in region_side2_contours: 

95 ax_vert.plot(contour[:, 0], contour[:, 1], linewidth=0.5, color=color, alpha=0.5) 

96 

97 add_frame_timestamp(ax, length, width, dt, frame, "#ffffff") 

98 add_frame_scalebar(ax, length, width, ds, scale, "#ffffff") 

99 

100 return fig 

101 

102 

103def add_frame_timestamp( 

104 ax: mpl.axes.Axes, length: int, width: int, dt: float, frame: int, color: str 

105) -> None: 

106 """ 

107 Add a frame timestamp to figure axes. 

108 

109 Parameters 

110 ---------- 

111 ax 

112 Axes object. 

113 length 

114 Length of bounding box. 

115 width 

116 Width of bounding box. 

117 dt 

118 Temporal scaling in hours/tick. 

119 frame 

120 Frame number. 

121 color 

122 Timestamp color. 

123 """ 

124 

125 hours, minutes = divmod(round(frame * dt, 2), 1) 

126 timestamp = f"{int(hours):02d}H:{round(minutes*60):02d}M" 

127 

128 ax.text( 

129 0.03 * length, 

130 0.96 * width, 

131 timestamp, 

132 fontfamily="monospace", 

133 fontsize=20, 

134 color=color, 

135 fontweight="bold", 

136 ) 

137 

138 

139def add_frame_scalebar( 

140 ax: mpl.axes.Axes, length: int, width: int, ds: float, scale: int, color: str 

141) -> None: 

142 """ 

143 Add a frame scalebar to figure axes. 

144 

145 Parameters 

146 ---------- 

147 ax 

148 Axes object. 

149 length 

150 Length of bounding box. 

151 width 

152 Width of bounding box. 

153 ds 

154 Spatial scaling in um/voxel. 

155 scale 

156 Size of scale bar (in um). 

157 color 

158 Scalebar color. 

159 """ 

160 

161 scalebar = scale / ds 

162 

163 ax.add_patch( 

164 Rectangle( 

165 (0.95 * length - scalebar, 0.94 * width), 

166 scalebar, 

167 0.01 * width, 

168 snap=True, 

169 color=color, 

170 ) 

171 ) 

172 

173 ax.text( 

174 0.95 * length - scalebar / 2, 

175 0.975 * width, 

176 f"{scale} $\\mu$m", 

177 fontsize=10, 

178 color=color, 

179 horizontalalignment="center", 

180 )