petal-qc 0.0.9__py3-none-any.whl → 0.0.10__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of petal-qc might be problematic. Click here for more details.

@@ -0,0 +1,27 @@
1
+ import json
2
+ from itkdb_gtk import ITkDBlogin
3
+ from petal_qc.metrology import readAVSdata
4
+ dlg = ITkDBlogin.ITkDBlogin()
5
+ session = dlg.get_client()
6
+
7
+ ofile = "weights_ppc16.json"
8
+ PSF = "/Users/lacasta/Nextcloud/ITk/5-Petal_cores/PPC.016/AVS.P052.PSH.035 - Petal 016.xlsx"
9
+
10
+ ofile = "weights_ppc17.json"
11
+ ofat = "metrology_test_ppc17.json"
12
+ PSF = "/Users/lacasta/Nextcloud/ITk/5-Petal_cores/PPC.017/AVS.P052.PSH.036 - Petal 017.xlsx"
13
+ FAT = "/Users/lacasta/Nextcloud/ITk/5-Petal_cores/PPC.017/AVS.P052.FRT.036 r0 - FAT_Serie_017.xlsx"
14
+ manuf_json, weights_json, DESY_comp, alias = readAVSdata.readProductionSheet(session, PSF, "SNnnnn")
15
+
16
+ vi_test, delamination_test, grounding_test, metrology_test, batch, petal_weight = readAVSdata.readFATfile(session, FAT, "SNnnn")
17
+
18
+ with open(ofile, "w", encoding="UTF-8") as fin:
19
+ json.dump(weights_json, fin, indent=3)
20
+
21
+
22
+ with open(ofat, "w", encoding="UTF-8") as fin:
23
+ json.dump(metrology_test, fin, indent=3)
24
+
25
+
26
+ print("done")
27
+ dlg.die()
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env python3
2
+ """Analize AVS metrology tests."""
3
+ import numpy as np
4
+ import matplotlib.pyplot as plt
5
+
6
+ try:
7
+ import itkdb_gtk
8
+
9
+ except ImportError:
10
+ import sys
11
+ from pathlib import Path
12
+ cwd = Path(__file__).parent.parent
13
+ sys.path.append(cwd.as_posix())
14
+
15
+ from itkdb_gtk import ITkDBlogin, ITkDButils
16
+
17
+
18
+ def do_metrology(results, M_values):
19
+ pass
20
+
21
+ def do_weighing(results, weights):
22
+ """Accumulates weighing values to produce stack plot.
23
+
24
+ Args:
25
+ results (): Results from DB
26
+ weights (): Dict with the values.
27
+ """
28
+ for value in results:
29
+ ipos = value["code"].find("_")
30
+ weights.setdefault(value["code"][ipos+1:], []).append(value["value"])
31
+
32
+
33
+ def plot_weighing(weights, tick_labels, show_total=False):
34
+ """Make the plot of weights."""
35
+ labels = ["COOLINGLOOPASSEMBLY", "LOCATOR_A", "LOCATOR_B", "LOCATOR_C",
36
+ "HONEYCOMBSET", "FACING_FRONT", "FACING_BACK",
37
+ "EPOXYADHESIVE", "EPOXYPUTTY", "EPOXYCONDUCTIVE"]
38
+
39
+ fig = plt.figure(tight_layout=True)
40
+ fig.suptitle("Petal Core weight (gr)")
41
+ ax = fig.add_subplot(1, 1, 1)
42
+ ax.set_ylabel("Weight [gr]")
43
+ ax.set_ylim(0, 300)
44
+ npoints = len(weights["CORE"])
45
+ X = np.arange(npoints)
46
+
47
+ values = [ weights[k] for k in labels]
48
+ Y = np.vstack(values)
49
+ ax.stackplot(X, Y, labels=labels)
50
+ ax.set_xticks(range(npoints), labels=tick_labels, rotation="vertical")
51
+
52
+ if not show_total:
53
+ ax.plot(X, [225.0 for x in range(npoints)], linestyle="dashed", color="black", linewidth=1)
54
+ ax.plot(X, [250.0 for x in range(npoints)], '-', color="black", linewidth=1, label="Nominal")
55
+ ax.plot(X, [275.0 for x in range(npoints)], linestyle="dashed", color="black", linewidth=1,)
56
+
57
+
58
+ ax.legend(loc="upper left", ncol=3, fontsize="x-small")
59
+
60
+
61
+ def main(session):
62
+ """Entry point"""
63
+ # find all cores
64
+ # Now all the objects
65
+ payload = {
66
+ "filterMap": {
67
+ "componentType": ["CORE_PETAL"],
68
+ "type": ["CORE_AVS"],
69
+ #"currentLocation": ["IFIC"],
70
+ },
71
+ "sorterList": [
72
+ {"key": "alternativeIdentifier", "descending": False }
73
+ ],
74
+ }
75
+
76
+ core_list = session.get("listComponents", json=payload)
77
+ core_tests = ["METROLOGY_AVS", "WEIGHING"]
78
+
79
+ weights = {}
80
+ petal_ids = []
81
+ M_values = []
82
+ for core in core_list:
83
+ SN = core["serialNumber"]
84
+ altid = core['alternativeIdentifier']
85
+ if "PPC" not in altid:
86
+ continue
87
+
88
+ if altid in ["PPC.016", "PPC.017"]:
89
+ pass
90
+
91
+ petal_ids.append(altid)
92
+
93
+ location = core["currentLocation"]['code']
94
+ coreStage = core["currentStage"]['code']
95
+
96
+ print("\nPetal {} [{}] - {}. {}".format(SN, altid, coreStage, location))
97
+ test_list = session.get("listTestRunsByComponent", json={"filterMap":{"serialNumber": SN, "state": "ready", "testType":core_tests}})
98
+
99
+ good_tests = {}
100
+ for tst in test_list:
101
+ ttype = tst["testType"]["code"]
102
+ if ttype not in core_tests:
103
+ print(ttype)
104
+ continue
105
+
106
+ T = session.get("getTestRun", json={"testRun": tst["id"]})
107
+ if T["state"] != "ready":
108
+ continue
109
+
110
+ print("-- {} [{}]".format(T["testType"]["name"], T["runNumber"]))
111
+ if ttype in good_tests:
112
+ if good_tests[ttype]["runNumber"] < T["runNumber"]:
113
+ good_tests[ttype] = T
114
+ else:
115
+ good_tests[ttype] = T
116
+
117
+ for ttype, T in good_tests.items():
118
+
119
+ if ttype == "WEIGHING":
120
+ do_weighing(T["results"], weights)
121
+
122
+ elif ttype == "METROLOGY_AVS":
123
+ do_metrology(T["results"], M_values)
124
+
125
+ else:
126
+ for value in T["results"]:
127
+ print("\t{} - {}".format(value["code"], value["value"]))
128
+
129
+
130
+ if not T["passed"]:
131
+ print("\t## test FAILED")
132
+
133
+ print("\t+ Defects:")
134
+ if len(T["defects"]):
135
+ for D in T["defects"]:
136
+ print("\t{} - {}".format(D["name"], D["description"]))
137
+ else:
138
+ print("\nNone")
139
+
140
+ plot_weighing(weights, petal_ids)
141
+ plt.show()
142
+
143
+ if __name__ == "__main__":
144
+ # ITk_PB authentication
145
+ dlg = ITkDBlogin.ITkDBlogin()
146
+ session = dlg.get_client()
147
+
148
+ try:
149
+ main(session)
150
+
151
+ except Exception as E:
152
+ print(E)
153
+
154
+ dlg.die()
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env python3
2
+ """Get a summery of Petal core TEsts."""
3
+
4
+ try:
5
+ import itkdb_gtk
6
+
7
+ except ImportError:
8
+ import sys
9
+ from pathlib import Path
10
+ cwd = Path(__file__).parent.parent
11
+ sys.path.append(cwd.as_posix())
12
+
13
+ from itkdb_gtk import ITkDBlogin, ITkDButils
14
+ from itkdb_gtk.dbGtkUtils import replace_in_container, DictDialog, ask_for_confirmation
15
+
16
+
17
+ def main(session):
18
+ """Main entry point."""
19
+
20
+ # find all cores
21
+ # Now all the objects
22
+ payload = {
23
+ "filterMap": {
24
+ #"componentType": ["BT"],
25
+ "componentType": ["CORE_PETAL"],
26
+ "type": ["CORE_AVS"],
27
+ "currentLocation": ["IFIC"],
28
+ },
29
+ "sorterList": [
30
+ {"key": "alternativeIdentifier", "descending": False }
31
+ ],
32
+ }
33
+ core_list = session.get("listComponents", json=payload)
34
+ core_tests = ["PETAL_METROLOGY_FRONT", "PETAL_METROLOGY_BACK", "XRAYIMAGING", "THERMAL_EVALUATION", "BTTESTING"]
35
+
36
+ do_check_stage = "AT_QC_SITE"
37
+ #do_check_stage = None
38
+
39
+ for core in core_list:
40
+ SN = core["serialNumber"]
41
+ altid = core['alternativeIdentifier']
42
+ if "PPC" not in altid:
43
+ continue
44
+
45
+
46
+ location = core["currentLocation"]['code']
47
+ coreStage = core["currentStage"]['code']
48
+ if do_check_stage:
49
+ if coreStage != do_check_stage:
50
+ rc = ITkDButils.set_object_stage(session, SN, do_check_stage)
51
+ if rc is None:
52
+ print("Could not change stage")
53
+ return False
54
+
55
+ print("Petal {} [{}] - {}. {}".format(SN, id, coreStage, location))
56
+
57
+ test_list = session.get("listTestRunsByComponent", json={"filterMap":{"serialNumber": SN, "state": "ready", "testType":core_tests}})
58
+
59
+ for tst in test_list:
60
+ ttype = tst["testType"]["code"]
61
+ if ttype not in core_tests:
62
+ print(ttype)
63
+ continue
64
+
65
+ T = session.get("getTestRun", json={"testRun": tst["id"]})
66
+ if T["state"] != "ready":
67
+ print(T)
68
+
69
+ print("-- {} [{}]".format(T["testType"]["name"], T["runNumber"]))
70
+ if not T["passed"]:
71
+ print("\t## test FAILED")
72
+
73
+ for D in T["defects"]:
74
+ print("\t{} - {}".format(D["name"], D["description"]))
75
+
76
+
77
+ if __name__ == "__main__":
78
+ # ITk_PB authentication
79
+ dlg = ITkDBlogin.ITkDBlogin()
80
+ session = dlg.get_client()
81
+
82
+ try:
83
+ main(session)
84
+
85
+ except Exception as E:
86
+ print(E)
87
+
88
+ dlg.die()
89
+
@@ -1,9 +1,10 @@
1
1
  #!/usr/bin/env python3
2
- """Prepara input files from DESY RAW."""
2
+ """Prepare raw data input files from DESY so that we can use them with this code."""
3
3
  import os
4
4
  import fnmatch
5
5
  import re
6
6
  from pathlib import Path
7
+ import argparse
7
8
 
8
9
  def all_files(root, patterns='*', single_level=False, yield_folders=False):
9
10
  """A generator that reruns all files in the given folder.
@@ -41,18 +42,26 @@ class PetalCore:
41
42
  self.back = {}
42
43
 
43
44
  def main(folder, out_folder):
44
- """Main entry point."""
45
+ """Main entry point.
46
+
47
+ It takes DESY raw data files and combines them into a single file for front
48
+ and back metrology.
49
+
50
+ Args:
51
+ folder: the input folder where to find the original files.
52
+ out_folder: the folder where the new fiels will be stored.
53
+ """
45
54
  outF = Path(out_folder).expanduser().resolve()
46
55
  if not outF.exists():
47
56
  os.mkdir(outF)
48
-
49
- rgx = re.compile(r"Project Name: (\w+)side_.*AlternativeID=PPC-(\d+)", re.MULTILINE|re.DOTALL)
57
+
58
+ rgx = re.compile(r"Project Name: (\w+)side_.*AlternativeID=PPC[-_](\d+)", re.MULTILINE|re.DOTALL)
50
59
  petal_cores = {}
51
60
  for fnam in all_files(folder, "*.txt"):
52
61
  P = Path(fnam).expanduser().resolve()
53
62
  with open(fnam, "r", encoding="UTF-8") as ff:
54
63
  R = rgx.search(ff.read())
55
- if R:
64
+ if R:
56
65
  petal_id = "PPC.{}".format(R.group(2))
57
66
  side = R.group(1).lower()
58
67
  if "_2D_" in P.name:
@@ -75,12 +84,20 @@ def main(folder, out_folder):
75
84
  list_file.write("{} {}-{} {}\n".format(oname, petal_id, side, petal_id))
76
85
  data = ""
77
86
  for data_type, fnam in values.items():
87
+ if fnam is None:
88
+ print("This should not happen.")
89
+
78
90
  with open(fnam, "r", encoding="UTF-8") as ifile:
79
91
  data += ifile.read()
80
-
92
+
81
93
  with open(oname, "w", encoding="UTF-8") as ofile:
82
94
  ofile.write(data)
83
-
95
+
84
96
  list_file.close()
97
+
85
98
  if __name__ == "__main__":
86
- main("/Users/lacasta/Downloads/DESY_Production", "/tmp/desy")
99
+ parser = argparse.ArgumentParser()
100
+ parser.add_argument("--input-folder", default=None, help="Input folder")
101
+ parser.add_argument("--output-folder", help="Outout fodler", default=None)
102
+
103
+ main("/Users/lacasta/Downloads/Report_QC-desy_Sep2024", "/tmp/desy")
@@ -41,7 +41,7 @@ class IRCore(object):
41
41
  self.files = []
42
42
  self.results = [] if results is None else results # list of AnalysisResults. One per side
43
43
  self.golden = [] # list of Golden results. One per side.
44
- self.inlet = -9999
44
+ self.inlet = params.tco2
45
45
 
46
46
  def set_files(self, files):
47
47
  """Set the input files."""
@@ -19,10 +19,10 @@ HAS_GRAPHANA = False
19
19
  try:
20
20
  from petal_qc.utils.readGraphana import ReadGraphana
21
21
  HAS_GRAPHANA = True
22
-
22
+
23
23
  except ImportError:
24
24
  HAS_GRAPHANA = False
25
-
25
+
26
26
 
27
27
 
28
28
  class IRDataGetter(object):
@@ -62,7 +62,7 @@ class IRDataGetter(object):
62
62
  kargs: keyword arguments to pass.
63
63
 
64
64
  """
65
- pass
65
+ return
66
66
 
67
67
  def find_reference_image(self, irbf, *args, **kargs):
68
68
  """Find first image in sequence with T < T_min.
@@ -114,7 +114,7 @@ class IRDataGetter(object):
114
114
  An array of AnalysisResult objects.
115
115
 
116
116
  """
117
- pass
117
+ return
118
118
 
119
119
  def get_analysis_frame(self, irbf):
120
120
  """Get the frame where we want to perform the analysis."""
@@ -166,12 +166,12 @@ class IRDataIFIC(IRDataGetter):
166
166
  # T_min = -22.0
167
167
  # else:
168
168
  # T_min = args[0]
169
- #
169
+ #
170
170
  # irbf.set_concatenate(True)
171
171
  # min_T, i_min, ref_img = IRPetal.find_reference_image(irbf, T_min)
172
172
  # values = self.get_IR_data(ref_img)
173
173
  # self.factor = values.shape[0]/640
174
- #
174
+ #
175
175
  # return min_T, i_min, [values, ]
176
176
 
177
177
  def get_IR_data(self, image, **kargs):
@@ -281,10 +281,10 @@ class IRDataIFIC(IRDataGetter):
281
281
  img = self.analysis_frame[0]
282
282
  X, T = self.DB.get_temperature(img.timestamp, 1)
283
283
  return np.min(T)
284
-
284
+
285
285
  else:
286
286
  return -9999
287
-
287
+
288
288
 
289
289
 
290
290
  class IRDataDESY(IRDataGetter):
@@ -35,7 +35,7 @@ debug_plot = DebugPlot.DebugPlot()
35
35
  the_segments = None # global variable to store the last segments found.
36
36
  the_contours = None # Global variable to store the last contours found
37
37
  the_images = None
38
-
38
+ the_3d_points = None
39
39
 
40
40
  class DebugTempProfile(object):
41
41
  """Stores Debug data."""
@@ -68,6 +68,10 @@ class DebugTempProfile(object):
68
68
  T_profile = None # Global to store the temp. profile.
69
69
 
70
70
 
71
+ def get_all_3d_points():
72
+ """Return all pipe path 3D points."""
73
+ return the_3d_points
74
+
71
75
  def get_last_segments():
72
76
  """Return the last segments found."""
73
77
  global the_segments
@@ -145,6 +149,39 @@ class Segment(object):
145
149
 
146
150
  return points
147
151
 
152
+ @staticmethod
153
+ def get_3d_points_in_list(segments):
154
+ """Return a list with all the 3D points (x,y,T) in the list of segments.
155
+
156
+ Args:
157
+ ----
158
+ segments (list[Segment]): The list of segments
159
+
160
+ Returns
161
+ -------
162
+ np.array: array of points.
163
+
164
+ """
165
+ # Count the number of points
166
+ npts = 0
167
+ for S in segments:
168
+ if S.Pmin is not None:
169
+ npts += len(S.Pmin)
170
+
171
+ points = np.zeros([npts, 3])
172
+ ipoint = 0
173
+ for S in segments:
174
+ if S.Pmin is None:
175
+ continue
176
+
177
+ for i, Pmin in enumerate(S.Pmin):
178
+ points[ipoint, 0] = Pmin.x
179
+ points[ipoint, 1] = Pmin.y
180
+ points[ipoint, 2] = S.Tmin[i]
181
+ ipoint += 1
182
+
183
+ return points
184
+
148
185
  @staticmethod
149
186
  def get_spread_in_list(segments):
150
187
  """Return an array with spread values."""
@@ -323,7 +360,7 @@ def extract_mirrored_pipe_path(values, params):
323
360
  (left_pipe, right_pipe): The 2 paths.
324
361
 
325
362
  """
326
- global the_images
363
+ global the_images, the_3d_points
327
364
  if params.rotate:
328
365
  rotated = rotate_full_image(values)
329
366
  else:
@@ -331,11 +368,14 @@ def extract_mirrored_pipe_path(values, params):
331
368
 
332
369
  imgs = split_IR_image(rotated)
333
370
  pipes = []
371
+ points_3d = []
334
372
  for img in imgs:
335
373
  pipe = extract_pipe_path(img, params)
336
374
  pipes.append(pipe)
375
+ points_3d.append(get_all_3d_points())
337
376
 
338
377
  the_images = imgs
378
+ the_3d_points = points_3d
339
379
  return list(pipes)
340
380
 
341
381
 
@@ -684,7 +724,7 @@ def get_derivatives(T_min, x_min, x_max, coeff):
684
724
  return valid_roots, valid_values, valid_curv
685
725
 
686
726
 
687
- def show_profile(debug_plot):
727
+ def show_profile(debug_plot, title=None):
688
728
  """Plot a profile."""
689
729
  debug_plot.setup_debug("Slices", is_3d=True)
690
730
  if T_profile:
@@ -693,6 +733,12 @@ def show_profile(debug_plot):
693
733
  if T_profile._pF is not None:
694
734
  debug_plot.plotx("Slices", T_profile._pF[:, 0], T_profile._pF[:, 1], T_profile._Fn, 'b-')
695
735
 
736
+ if title:
737
+ debug_plot.set_title("Slices", title)
738
+
739
+
740
+ __call_id__ = 0
741
+ __img_num__ = 0
696
742
 
697
743
  def slice_contours(data, inner, outer, distance=50, npoints=15, do_fit=False, show=False) -> list[Segment]:
698
744
  """Make slices between contours.
@@ -712,8 +758,11 @@ def slice_contours(data, inner, outer, distance=50, npoints=15, do_fit=False, sh
712
758
  A list of Segments.
713
759
 
714
760
  """
715
- global debug_plot
761
+ global debug_plot, __call_id__, __img_num__
716
762
 
763
+ __call_id__ += 1
764
+ __img_num__ = 0
765
+ #show=True
717
766
  segments = []
718
767
  dist = 0
719
768
  npts = len(outer)
@@ -726,7 +775,15 @@ def slice_contours(data, inner, outer, distance=50, npoints=15, do_fit=False, sh
726
775
  U = contours.find_closest(x0, y0, inner)
727
776
  Tmin, Pmin, spread = get_T_profile(data, Point(x0, y0), Point(U[0], U[1]), npts=npoints, do_fit=do_fit, debug=False)
728
777
  if show:
729
- show_profile(debug_plot)
778
+ show_profile(debug_plot, "Dist {:.3f}, Tmin {:.2f} ({:.1f}, {:.1f})".format(dist, Tmin[0], Pmin[0].x, Pmin[0].y))
779
+ debug_plot.savefig("Slices", "/tmp/img_{}_{}.png".format(__call_id__, __img_num__))
780
+ __img_num__ += 1
781
+ try:
782
+ ax = debug_plot.get_ax("Contours")
783
+ ax.plot([x0, U[0]], [y0, U[1]], '-')
784
+ ax.plot(Pmin[0].x, Pmin[0].y, 'o')
785
+ except KeyError:
786
+ pass
730
787
 
731
788
  # store results: distance along segment and temperature
732
789
  T = []
@@ -764,7 +821,16 @@ def slice_contours(data, inner, outer, distance=50, npoints=15, do_fit=False, sh
764
821
 
765
822
  segments.append(Segment((x0, y0), V, Pmin, path_length, Tmin, spread))
766
823
  if show:
767
- show_profile(debug_plot)
824
+ show_profile(debug_plot, "Dist {:.3f} Tmin {:.2f} ({:.1f}, {:.1f})".format(path_length, Tmin[0], Pmin[0].x, Pmin[0].y))
825
+ debug_plot.savefig("Slices", "/tmp/img_{}_{}.png".format(__call_id__, __img_num__))
826
+ __img_num__ += 1
827
+
828
+ try:
829
+ ax = debug_plot.get_ax("Contours")
830
+ ax.plot([x0, V[0]], [y0, V[1]], '-')
831
+ ax.plot(Pmin[0].x, Pmin[0].y, 'o')
832
+ except KeyError:
833
+ pass
768
834
 
769
835
  dist = 0
770
836
 
@@ -772,6 +838,7 @@ def slice_contours(data, inner, outer, distance=50, npoints=15, do_fit=False, sh
772
838
  if show:
773
839
  debug_plot.setup_debug("SlicePipe")
774
840
  debug_plot.plot("SlicePipe", D, T, '-o')
841
+ debug_plot.savefig("SlicePipe", "/tmp/slice_pipe_{}.png".format(__call_id__))
775
842
 
776
843
  return segments
777
844
 
@@ -829,10 +896,12 @@ def find_image_contours(data, params):
829
896
  print("contour area: {:.3f}".format(area))
830
897
 
831
898
  if params.debug:
899
+ debug_plot.setup_debug("Contours", 1, 1)
832
900
  colors = ["#ff9b54", "#ff7f51"] # ["#540b0e", "#9e2a2b"]
833
901
  print("Number of countours:", len(out))
834
902
 
835
- fig, ax = plt.subplots(1, 1, tight_layout=True)
903
+ ax = debug_plot.get_ax("Contours")
904
+ ax.clear()
836
905
  ax.imshow(data, origin='lower', cmap='jet')
837
906
  for i, cnt in enumerate(out):
838
907
  ax.plot(cnt[:, 0], cnt[:, 1], linewidth=3, color=colors[i % 2])
@@ -870,6 +939,7 @@ def get_segments(data, params) -> list[Segment]:
870
939
  list of segments. See `slice_contours`
871
940
 
872
941
  """
942
+ global the_3d_points
873
943
  cntrs = find_image_contours(data, params)
874
944
  if cntrs is None:
875
945
  return None
@@ -881,6 +951,7 @@ def get_segments(data, params) -> list[Segment]:
881
951
  do_fit=params.do_fit,
882
952
  show=params.debug)
883
953
 
954
+ the_3d_points = Segment.get_3d_points_in_list(the_segments)
884
955
  return the_segments
885
956
 
886
957
 
@@ -30,7 +30,7 @@ class AnalysisResult(object):
30
30
  continue
31
31
 
32
32
 
33
- def show_2D_image(img, title=None):
33
+ def show_2D_image(img, title=None, show_fig=True):
34
34
  """Show a 2D image."""
35
35
  if isinstance(img, list):
36
36
  fig, ax = plt.subplots(1, len(img))
@@ -51,8 +51,9 @@ def show_2D_image(img, title=None):
51
51
  pcm = ax.imshow(img, origin='lower', cmap=HighContrast.reversed()) # cmap="jet")
52
52
  fig.colorbar(pcm, ax=ax)
53
53
 
54
- plt.draw()
55
- plt.pause(0.001)
54
+ if show_fig:
55
+ plt.draw()
56
+ plt.pause(0.001)
56
57
 
57
58
  return fig, ax
58
59
 
@@ -498,7 +498,7 @@ class PipeFit(object):
498
498
 
499
499
  return X, Y
500
500
 
501
- def plot(self):
501
+ def plot(self, show_fig=True):
502
502
  """Plot result of fit and data."""
503
503
  fig, ax = plt.subplots(1, 1, tight_layout=True)
504
504
  ax.plot(self.pipe[:, 0], self.pipe[:, 1], label="Pipe")
@@ -509,8 +509,9 @@ class PipeFit(object):
509
509
 
510
510
  ax.plot(out[:, 0], out[:, 1], 'o', label="Data")
511
511
  ax.legend()
512
- plt.draw()
513
- plt.pause(0.0001)
512
+ if show_fig:
513
+ plt.draw()
514
+ plt.pause(0.0001)
514
515
  return fig, ax
515
516
 
516
517