Skip to content

Commit fcffdf0

Browse files
authored
Merge pull request #193 from joshmoore/ometa-squashed
ometa (squashed history)
2 parents 29bbce7 + 43e1f30 commit fcffdf0

File tree

4 files changed

+659
-0
lines changed

4 files changed

+659
-0
lines changed
Lines changed: 244 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,244 @@
1+
# coding=utf-8
2+
"""
3+
MIF/Add_Key_Val_from_csv.py
4+
5+
Adds key-value (kv) metadata to images in a dataset from a csv file
6+
The first column contains the filenames
7+
The first row of the file contains the keys
8+
The rest is the values for each file/key
9+
10+
-----------------------------------------------------------------------------
11+
Copyright (C) 2018
12+
This program is free software; you can redistribute it and/or modify
13+
it under the terms of the GNU General Public License as published by
14+
the Free Software Foundation; either version 2 of the License, or
15+
(at your option) any later version.
16+
This program is distributed in the hope that it will be useful,
17+
but WITHOUT ANY WARRANTY; without even the implied warranty of
18+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19+
GNU General Public License for more details.
20+
You should have received a copy of the GNU General Public License along
21+
with this program; if not, write to the Free Software Foundation, Inc.,
22+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23+
------------------------------------------------------------------------------
24+
Created by Christian Evenhuis
25+
26+
"""
27+
28+
import omero
29+
from omero.gateway import BlitzGateway
30+
from omero.rtypes import rstring, rlong
31+
import omero.scripts as scripts
32+
from omero.model import PlateI, ScreenI, DatasetI
33+
from omero.rtypes import *
34+
from omero.cmd import Delete2
35+
36+
import sys
37+
import csv
38+
import copy
39+
40+
# this is for downloading a temp file
41+
from omero.util.temp_files import create_path
42+
43+
from omero.util.populate_roi import DownloadingOriginalFileProvider
44+
from omero.util.populate_metadata import ParsingContext
45+
46+
from collections import OrderedDict
47+
48+
49+
50+
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
51+
def get_existing_map_annotations( obj ):
52+
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
53+
print("getting the existing kv's")
54+
ord_dict = OrderedDict()
55+
for ann in obj.listAnnotations():
56+
if( isinstance(ann, omero.gateway.MapAnnotationWrapper) ):
57+
kvs = ann.getValue()
58+
for k,v in kvs:
59+
if k not in ord_dict:
60+
ord_dict[k]=set()
61+
ord_dict[k].add(v)
62+
return ord_dict
63+
64+
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
65+
def remove_map_annotations(conn, dtype, Id ):
66+
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
67+
image = conn.getObject(dtype,int(Id))
68+
namespace = omero.constants.metadata.NSCLIENTMAPANNOTATION
69+
70+
filename = image.getName()
71+
72+
anns = list( image.listAnnotations())
73+
mapann_ids = [ann.id for ann in anns
74+
if isinstance(ann, omero.gateway.MapAnnotationWrapper) ]
75+
76+
try:
77+
delete = Delete2(targetObjects={'MapAnnotation': mapann_ids})
78+
handle = conn.c.sf.submit(delete)
79+
conn.c.waitOnCmd(handle, loops=10, ms=500, failonerror=True,
80+
failontimeout=False, closehandle=False)
81+
82+
except Exception as ex:
83+
print("Failed to delete links: {}".format(ex.message))
84+
return
85+
86+
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
87+
def get_original_file(conn, object_type, object_id, file_ann_id=None):
88+
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
89+
omero_object = conn.getObject("Dataset", int(object_id))
90+
if omero_object is None:
91+
sys.stderr.write("Error: Dataset does not exist.\n")
92+
sys.exit(1)
93+
file_ann = None
94+
95+
for ann in omero_object.listAnnotations():
96+
if isinstance(ann, omero.gateway.FileAnnotationWrapper):
97+
file_name = ann.getFile().getName()
98+
# Pick file by Ann ID (or name if ID is None)
99+
if (file_ann_id is None and file_name.endswith(".csv")) or (
100+
ann.getId() == file_ann_id):
101+
file_ann = ann
102+
if file_ann is None:
103+
sys.stderr.write("Error: File does not exist.\n")
104+
sys.exit(1)
105+
106+
return file_ann.getFile()._obj
107+
108+
109+
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
110+
def populate_metadata(client, conn, script_params):
111+
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
112+
dataType = script_params["Data_Type"]
113+
ids = script_params["IDs"]
114+
115+
datasets = list(conn.getObjects(dataType, ids))
116+
for ds in datasets:
117+
ID = ds.getId()
118+
119+
# not sure what this is doing
120+
file_ann_id = None
121+
if "File_Annotation" in script_params:
122+
file_ann_id = long(script_params["File_Annotation"])
123+
print("set ann id")
124+
125+
original_file = get_original_file(
126+
conn, dataType, ID, file_ann_id)
127+
provider = DownloadingOriginalFileProvider(conn)
128+
129+
# read the csv
130+
file_handle = provider.get_original_file_data(original_file)
131+
data =list(csv.reader(file_handle,delimiter=','))
132+
file_handle.close()
133+
134+
# create a dictionary for image_name:id
135+
dict_name_id={}
136+
for img in ds.listChildren():
137+
img_name = img.getName()
138+
if( img_name in dict_name_id ):
139+
sys.stderr.write("File names not unique: {}".format(img_name))
140+
sys.exit(1)
141+
dict_name_id[img_name] = int(img.getId())
142+
143+
# keys are in the header row
144+
header =data[0]
145+
kv_data = header[1:] # first header is the fimename columns
146+
rows = data[1:]
147+
148+
nimg_updated = 0
149+
for row in rows: # loop over images
150+
img_name = row[0]
151+
if( img_name not in dict_name_id ):
152+
print("Can't find filename : {}".format(img_name) )
153+
else:
154+
img_ID = dict_name_id[img_name] # look up the ID
155+
img = conn.getObject('Image',img_ID) # get the img
156+
157+
existing_kv = get_existing_map_annotations( img )
158+
updated_kv = copy.deepcopy(existing_kv)
159+
print("Existing kv ")
160+
for k,vset in existing_kv.items():
161+
print(type(vset),len(vset))
162+
for v in vset:
163+
print(k,v)
164+
165+
for i in range(1,len(row)): # first entry is the filename
166+
key = header[i].strip()
167+
vals = row[i].strip().split(';')
168+
if( len(vals) > 0 ):
169+
for val in vals:
170+
if len(val)>0 :
171+
if key not in updated_kv: updated_kv[key] = set()
172+
print("adding",key,val)
173+
updated_kv[key].add(val)
174+
175+
if( existing_kv != updated_kv ):
176+
nimg_updated = nimg_updated + 1
177+
print("The key-values pairs are different")
178+
remove_map_annotations( conn, 'Image', img.getId() )
179+
map_ann = omero.gateway.MapAnnotationWrapper(conn)
180+
namespace = omero.constants.metadata.NSCLIENTMAPANNOTATION
181+
map_ann.setNs(namespace)
182+
# convert the ordered dict to a list of lists
183+
kv_list=[]
184+
for k,vset in updated_kv.items():
185+
for v in vset:
186+
kv_list.append( [k,v] )
187+
map_ann.setValue(kv_list)
188+
map_ann.save()
189+
img.linkAnnotation(map_ann)
190+
else:
191+
print("No change change in kv's")
192+
193+
return "Added {} kv pairs to {}/{} files ".format(len(header)-1,nimg_updated,len(dict_name_id))
194+
195+
196+
def run_script():
197+
198+
data_types = [rstring('Dataset')]
199+
client = scripts.client(
200+
'Add_Key_Val_from_csv',
201+
"""
202+
This script processes a csv file, attached to a Dataset
203+
""",
204+
scripts.String(
205+
"Data_Type", optional=False, grouping="1",
206+
description="Choose source of images",
207+
values=data_types, default="Dataset"),
208+
209+
scripts.List(
210+
"IDs", optional=False, grouping="2",
211+
description="Plate or Screen ID.").ofType(rlong(0)),
212+
213+
scripts.String(
214+
"File_Annotation", grouping="3",
215+
description="File ID containing metadata to populate."),
216+
217+
authors=["Christian Evenhuis"],
218+
institutions=["MIF UTS"],
219+
contact="https://forum.image.sc/tag/omero"
220+
)
221+
222+
try:
223+
# process the list of args above.
224+
script_params = {}
225+
for key in client.getInputKeys():
226+
if client.getInput(key):
227+
script_params[key] = client.getInput(key, unwrap=True)
228+
229+
# wrap client to use the Blitz Gateway
230+
conn = BlitzGateway(client_obj=client)
231+
print("script params")
232+
for k,v in script_params.items():
233+
print(k,v)
234+
message = populate_metadata(client, conn, script_params)
235+
client.setOutput("Message", rstring(message))
236+
except:
237+
pass
238+
239+
finally:
240+
client.closeSession()
241+
242+
243+
if __name__ == "__main__":
244+
run_script()

0 commit comments

Comments
 (0)