main.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 '''
3 The wirecell-img main
4 '''
5 import json
6 import click
7 import matplotlib.pyplot as plt
8 
9 from wirecell import units
10 
11 @click.group("img")
12 @click.pass_context
13 def cli(ctx):
14  '''
15  Wire Cell Toolkit Imaging Commands
16  '''
17 
18 @cli.command("paraview-blobs")
19 @click.argument("cluster-tap-file")
20 @click.argument("paraview-file")
21 @click.pass_context
22 def paraview_blobs(ctx, cluster_tap_file, paraview_file):
23  '''
24  Convert a JsonClusterTap JSON file to a ParaView .vtu file of blobs
25  '''
26  from . import converter, tap
27  from tvtk.api import write_data
28 
29  gr = tap.load(cluster_tap_file)
30  if 0 == gr.number_of_nodes():
31  click.echo("no verticies in %s" % cluster_tap_file)
32  return
33  dat = converter.clusters2blobs(gr)
34  write_data(dat, paraview_file)
35  click.echo(paraview_file)
36  return
37 
38 @cli.command("paraview-activity")
39 @click.argument("cluster-tap-file")
40 @click.argument("paraview-file")
41 @click.pass_context
42 def paraview_activity(ctx, cluster_tap_file, paraview_file):
43  '''
44  Convert a JsonClusterTap JSON file to a ParaView .vti file of activity
45  '''
46  from . import converter, tap
47  from tvtk.api import write_data
48 
49  gr = tap.load(cluster_tap_file)
50  if 0 == gr.number_of_nodes():
51  click.echo("no verticies in %s" % cluster_tap_file)
52  return
53  alldat = converter.clusters2views(gr)
54  for wpid,dat in alldat.items():
55  fname = paraview_file%wpid
56  write_data(dat, fname)
57  click.echo(fname)
58  return
59 
60 
61 @cli.command("paraview-depos")
62 @click.argument("depo-npz-file")
63 @click.argument("paraview-file")
64 @click.pass_context
65 def paraview_blobs(ctx, depo_npz_file, paraview_file):
66  '''
67  Convert an NPZ file to a ParaView .vtu file of depos
68  '''
69  from . import converter
70  from tvtk.api import write_data
71  import numpy
72 
73  fp = numpy.load(open(depo_npz_file))
74  dat = fp['depo_data_0']
75  ugrid = converter.depos2pts(dat);
76  write_data(ugrid, paraview_file)
77  click.echo(paraview_file)
78  return
79 
80 # Bee support:
81 # http://bnlif.github.io/wire-cell-docs/viz/uploads/
82 
83 
84 @cli.command("bee-blobs")
85 @click.option('-o', '--output', help="The output Bee JSON file name")
86 @click.option('-g', '--geom', default="protodune",
87  help="The name of the detector geometry")
88 @click.option('--rse', nargs=3, type=int, default=[0, 0, 0],
89  help="The '<run> <subrun> <event>' numbers as a triple of integers")
90 @click.option('-s', '--sampling', type=click.Choice(["center","uniform"]), default="uniform",
91  help="The sampling technique to turn blob volumes into points")
92 @click.option('-d', '--density', type=float, default=9.0,
93  help="For samplings which care, specify target points per cc")
94 @click.argument("cluster-tap-files", nargs=-1)
95 def bee_blobs(output, geom, rse, sampling, density, cluster_tap_files):
96  '''
97  Make one Bee JSON file from the blobs in a set of 'cluster tap'
98  JSON files which are presumed to originate from one trigger.
99  '''
100  from . import tap, converter
101 
102  dat = dict(runNo=rse[0], subRunNo=rse[1], eventNo=rse[2], geom=geom, type="wire-cell",
103  x=list(), y=list(), z=list(), q=list()) # , cluster_id=list()
104 
105 
106  def fclean(arr):
107  return [round(a, 3) for a in arr]
108 
109  # given by user in units of 1/cc. Convert to system of units 1/L^3.
110  density *= 1.0/(units.cm**3)
111  sampling_func = dict(
112  center = converter.blob_center,
113  uniform = lambda b : converter.blob_uniform_sample(b, density),
114  )[sampling];
115 
116  for ctf in cluster_tap_files:
117  gr = tap.load(ctf)
118  print ("got %d" % gr.number_of_nodes())
119  if 0 == gr.number_of_nodes():
120  print("skipping empty graph %s" % ctf)
121  continue
122  arr = converter.blobpoints(gr, sampling_func)
123  print ("%s: %d points" % (ctf, arr.shape[0]))
124  dat['x'] += fclean(arr[:,0]/units.cm)
125  dat['y'] += fclean(arr[:,1]/units.cm)
126  dat['z'] += fclean(arr[:,2]/units.cm)
127  dat['q'] += fclean(arr[:,3])
128 
129  import json
130  # monkey patch
131  from json import encoder
132  encoder.FLOAT_REPR = lambda o: format(o, '.3f')
133  json.dump(dat, open(output,'w', encoding="utf8"))
134 
135 
136 
137 @cli.command("activity")
138 @click.option('-o', '--output', help="The output plot file name")
139 @click.option('-s', '--slices', nargs=2, type=int,
140  help="Range of slice IDs")
141 @click.option('-S', '--slice-line', type=int, default=-1,
142  help="Draw a line down a slice")
143 @click.argument("cluster-tap-file")
144 def activity(output, slices, slice_line, cluster_tap_file):
145  '''
146  Plot activity
147  '''
148  from matplotlib.colors import LogNorm
149  from . import tap, clusters, plots
150  gr = tap.load(cluster_tap_file)
151  cm = clusters.ClusterMap(gr)
152  ahist = plots.activity(cm)
153  arr = ahist.arr
154  extent = list()
155  if slices:
156  arr = arr[:,slices[0]:slices[1]]
157  extent = [slices[0], slices[1]]
158  else:
159  extent = [0, arr.shape[1]]
160  extent += [ahist.rangey[1], ahist.rangey[0]]
161 
162  fig,ax = plt.subplots(nrows=1, ncols=1)
163  fig.set_size_inches(8.5,11.0)
164 
165  cmap = plt.get_cmap('gist_rainbow')
166  im = ax.imshow(arr, cmap=cmap, interpolation='none', norm=LogNorm(), extent=extent)
167  if slice_line > 0:
168  ax.plot([slice_line, slice_line], [ahist.rangey[0], ahist.rangey[1]],
169  linewidth=0.1, color='black')
170 
171  ## protodune only....
172  boundary = 0
173  for chunk in [400, 400, 400, 400, 480, 480]:
174  boundary += chunk
175  y = boundary + ahist.rangey[0]
176  ax.plot(extent[:2], [y,y], color='gray', linewidth=0.1);
177 
178  from matplotlib.ticker import AutoMinorLocator
179  minorLocator = AutoMinorLocator()
180  ax.yaxis.set_minor_locator(minorLocator)
181  ax.tick_params(which="both", width=1)
182  ax.tick_params(which="major", length=7)
183  ax.tick_params(which="minor", length=3)
184 
185  plt.colorbar(im, ax=ax)
186  ax.set_title(cluster_tap_file)
187  ax.set_xlabel("slice ID")
188  ax.set_ylabel("channel IDs")
189  fig.savefig(output)
190 
191 
192 @cli.command("blob-activity-mask")
193 @click.option('-o', '--output', help="The output plot file name")
194 @click.option('-s', '--slices', nargs=2, type=int,
195  help="The output plot file name")
196 @click.option('-S', '--slice-line', type=int, default=-1,
197  help="Draw a line down a slice")
198 @click.option('--found/--missed', default=True,
199  help="Mask what blobs found or missed")
200 @click.argument("cluster-tap-file")
201 def blob_activity_mask(output, slices, slice_line, found, cluster_tap_file):
202  '''
203  Plot blobs as maskes on channel activity.
204  '''
205  from . import tap, clusters, plots
206  gr = tap.load(cluster_tap_file)
207  cm = clusters.ClusterMap(gr)
208  ahist = plots.activity(cm)
209  bhist = ahist.like()
210  plots.blobs(cm, bhist)
211  if found:
212  sel = lambda a: a>= 1
213  title="found mask"
214  else:
215  sel = lambda a: a < 1
216  title="missed mask"
217  extent = list()
218  if slices:
219  a = ahist.arr[:,slices[0]:slices[1]]
220  b = bhist.arr[:,slices[0]:slices[1]]
221  extent = [slices[0], slices[1]]
222  else:
223  a = ahist.arr
224  b = bhist.arr
225  extent = [0, a.shape[1]]
226  extent += [ahist.rangey[1], ahist.rangey[0]]
227 
228  fig,ax = plots.mask_blobs(a, b, sel, extent)
229  if slice_line > 0:
230  ax.plot([slice_line, slice_line], [ahist.rangey[0], ahist.rangey[1]],
231  linewidth=0.1, color='black')
232  ax.set_title("%s %s" % (title, cluster_tap_file))
233  ax.set_xlabel("slice ID")
234  ax.set_ylabel("channel IDs")
235  fig.savefig(output)
236 
237 
238 @cli.command("wire-slice-activity")
239 @click.option('-o', '--output', help="The output plot file name")
240 @click.option('-s', '--sliceid', type=int, help="The slice ID to plot")
241 @click.argument("cluster-tap-file")
242 def wire_slice_activity(output, sliceid, cluster_tap_file):
243  '''
244  Plot the activity in one slice as wires and blobs
245  '''
246  from . import tap, clusters, plots
247  gr = tap.load(cluster_tap_file)
248  cm = clusters.ClusterMap(gr)
249  fig, axes = plots.wire_blob_slice(cm, sliceid)
250  fig.savefig(output)
251 
252 
253 def main():
254  cli(obj=dict())
255 
256 if '__main__' == __name__:
257  main()
258 
259 
def paraview_blobs(ctx, cluster_tap_file, paraview_file)
Definition: main.py:22
def blob_activity_mask(output, slices, slice_line, found, cluster_tap_file)
Definition: main.py:201
int open(const char *, int)
Opens a file descriptor.
static bool format(QChar::Decomposition tag, QString &str, int index, int len)
Definition: qstring.cpp:11496
def cli(ctx)
Definition: main.py:13
def wire_slice_activity(output, sliceid, cluster_tap_file)
Definition: main.py:242
def activity(output, slices, slice_line, cluster_tap_file)
Definition: main.py:144
def paraview_activity(ctx, cluster_tap_file, paraview_file)
Definition: main.py:42
def main()
Definition: main.py:253
def bee_blobs(output, geom, rse, sampling, density, cluster_tap_files)
Definition: main.py:95