tile_view.py 12.9 KB
Newer Older
Martin Schorb's avatar
Martin Schorb committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Mon Jan 18 14:52:17 2021

@author: schorb
"""


import dash

from dash.dependencies import Input, Output, State, MATCH, ALL
from dash.exceptions import PreventUpdate

import requests
Martin Schorb's avatar
Martin Schorb committed
16
import os
Martin Schorb's avatar
Martin Schorb committed
17
18
19
20
21
22
23
24
25
26
27
28
import json

from app import app

import params
from utils import helper_functions as hf

for idx in range(params.max_tileviews):
    idx_str = '_'+str(idx)
            
    
    # init slice selector
29
    for imtype in ['sliceim','tileim']:
30
31
32
33
34
35
36
37
38

        inputs = [Input({'component': 'stack_dd','module': MATCH},'value')]
        states = [State({'component': 'store_allstacks', 'module': MATCH}, 'data'),
                  State({'component': 'owner_dd','module': MATCH},'value'),
                  State({'component': 'project_dd','module': MATCH},'value'),
                  State({'component':imtype+'_section_in'+idx_str,'module': MATCH},'value')]

        if imtype == 'tileim':
            inputs.append(Input({'component': 'lead_tile', 'module': MATCH},'modified_timestamp'))
Martin Schorb's avatar
Martin Schorb committed
39
            inputs.append(Input({'component': 'tp_dd', 'module': MATCH}, 'value'))
40
            states.extend([
Martin Schorb's avatar
Martin Schorb committed
41
42
43
                State({'component': 'neighbours', 'module': MATCH}, 'children'),
                State({'component': 'lead_tile', 'module': MATCH},'data')
                ])
44
        else:
Martin Schorb's avatar
Martin Schorb committed
45
            inputs.extend([Input({'component': 'dummystore', 'module': MATCH}, 'modified_timestamp')]*2)
Martin Schorb's avatar
Martin Schorb committed
46
            states.extend([State({'component': 'dummystore', 'module': MATCH}, 'modified_timestamp')]*2)
47

48
49
        @app.callback([Output({'component':imtype+'_section_in'+idx_str,'module': MATCH},'value'),
                       Output({'component':imtype+'_section_in'+idx_str,'module': MATCH},'min'),
50
                       Output({'component':imtype+'_section_in'+idx_str,'module': MATCH},'max'),
Martin Schorb's avatar
Martin Schorb committed
51
                       Output({'component':imtype+'_section_div'+idx_str,'module': MATCH},'style'),
52
53
                       Output({'component':imtype+'_contrastslider'+idx_str, 'module': MATCH},'max'),
                       Output({'component':imtype+'_contrastslider'+idx_str, 'module': MATCH},'value')],
54
55
                      inputs,
                      states)
Martin Schorb's avatar
Martin Schorb committed
56
        def stacktoslice(stack_sel,lead_trigger,tilepairdir,allstacks,owner,project,orig_sec,neighbours,lead_tile):
57
            stacklist=[]            
58
            slicestyle = {}
59

Martin Schorb's avatar
Martin Schorb committed
60
            trigger = hf.trigger()
Martin Schorb's avatar
Martin Schorb committed
61
 
62
63
64
65
            ol = dash.callback_context.outputs_list

            tileim_idx = ol[0]['id']['component'].split('_')[-1]

66
67
            if (not stack_sel=='-' ) and (not allstacks is None):   
                 stacklist = [stack for stack in allstacks if stack['stackId']['stack'] == stack_sel]        
68
                 # stack = stack_sel          
Martin Schorb's avatar
Martin Schorb committed
69

70
            if not stacklist == []:
71
72
73
74
                stackparams = stacklist[0]
                                               
                if 'None' in (stackparams['stackId']['owner'],stackparams['stackId']['project']):
                    return dash.no_update
75
                                
76
77
                o_min = stackparams['stats']['stackBounds']['minZ']
                o_max = stackparams['stats']['stackBounds']['maxZ']
78

Martin Schorb's avatar
Martin Schorb committed
79
                if neighbours == 'True' and tileim_idx != '0' and tilepairdir not in ('', None) and lead_tile != {} :
80
81
82

                    tp_jsonfiles = hf.jsonfiles(tilepairdir)

83
                    tiles,slices,positions = hf.neighbours_from_json(tp_jsonfiles,lead_tile['tile'])
84
                    slices = list(map(int,slices))
Martin Schorb's avatar
Martin Schorb committed
85

86
                    o_val = min(slices)
Martin Schorb's avatar
Martin Schorb committed
87

Martin Schorb's avatar
Martin Schorb committed
88
                    slicestyle = {'display': 'none'}
Martin Schorb's avatar
Martin Schorb committed
89

Martin Schorb's avatar
Martin Schorb committed
90
                if trigger in ('stack_dd','dummystore'):
Martin Schorb's avatar
Martin Schorb committed
91
                    o_val = int((o_max - o_min) / 2) + o_min
92
                else:
Martin Schorb's avatar
Martin Schorb committed
93
                    o_val = orig_sec
94

95
                if o_min == o_max: slicestyle = {'display':'none'}
96
97
98
99
100
101
102
103
104
105
106
107
                
                url = params.render_base_url + params.render_version + 'owner/' + owner + '/project/' + project + '/stack/' + stack_sel
                url1 = url + '/tileIds'
                
                tile = requests.get(url1).json()[0]
                
                url2 = url +'/tile/' + tile                 
                url2 +=  '/render-parameters'
                
                tilespec = requests.get(url2).json()
                                
                max_int = tilespec['tileSpecs'][0]['maxIntensity']     
108
            
109
                return o_val,o_min,o_max,slicestyle,max_int,[0,max_int]
Martin Schorb's avatar
Martin Schorb committed
110
111
112
            
            else:
                return dash.no_update
Martin Schorb's avatar
Martin Schorb committed
113
            
114
115
116
                
                

Martin Schorb's avatar
Martin Schorb committed
117
118
119
120
121
122
123
    
    # init tile selector
    @app.callback([Output({'component':'tile_dd'+idx_str,'module': MATCH},'options'),
                   Output({'component':'tile_dd'+idx_str,'module': MATCH},'value')],
                  Input({'component':'tileim_section_in'+idx_str,'module': MATCH},'value'),
                  [State({'component': 'owner_dd','module': MATCH},'value'),
                   State({'component': 'project_dd','module': MATCH},'value'),
124
                   State({'component': 'stack_dd','module': MATCH},'value'),
Martin Schorb's avatar
Martin Schorb committed
125
126
                   State({'component':'tile_dd'+idx_str,'module': MATCH},'value'),
                   State({'component': 'tp_dd', 'module': MATCH},'value'),
127
128
                   State({'component': 'neighbours', 'module': MATCH},'children'),
                   State({'component': 'lead_tile', 'module': MATCH},'data')
Martin Schorb's avatar
Martin Schorb committed
129
130
                   ]
                  )
131
    def slicetotiles(slicenum,owner,project,stack,prev_tile,tilepairdir,neighbours,lead_tile):
132

Martin Schorb's avatar
Martin Schorb committed
133
        if None in (slicenum,owner,project,stack,neighbours,lead_tile):
Martin Schorb's avatar
Martin Schorb committed
134
135
            return dash.no_update
        
136
        if 'None' in (owner,project,stack):
137
138
            return dash.no_update

Martin Schorb's avatar
Martin Schorb committed
139

140
141
142
143
        trigger = hf.trigger()

        tileim_index = trigger.split('_')[-1]

Martin Schorb's avatar
Martin Schorb committed
144
145
146
        url = params.render_base_url + params.render_version + 'owner/' + owner + '/project/' + project + '/stack/' + stack
        url += '/tileIds?matchPattern='
        
147
148
        if owner in params.slicenumformat.keys():            
            url += params.slicenumformat[owner] %slicenum
Martin Schorb's avatar
Martin Schorb committed
149
150
        
        tiles = requests.get(url).json()
151
152
        
        if tiles == []:
153
            return dash.no_update        
154
        
Martin Schorb's avatar
Martin Schorb committed
155
        t_labels = tiles.copy()
156
        tile = tiles[int(len(tiles)/2)]
Martin Schorb's avatar
Martin Schorb committed
157

158
159
        if prev_tile is None:
            prev_tile = tile
Martin Schorb's avatar
Martin Schorb committed
160

161
162
163
        if lead_tile in (None,{},''):
            lead_tile=dict(tile=prev_tile)

Martin Schorb's avatar
Martin Schorb committed
164
165
166
167
168
        if not 'stack' in lead_tile.keys() or lead_tile['stack'] != stack:
            lead_tile = dict(tile=prev_tile,stack=stack)

        lead_tile['slice'] = slicenum

169
170
171
        if neighbours == 'True' and tileim_index != '0' and tilepairdir not in ('', None):

            tp_jsonfiles = hf.jsonfiles(tilepairdir)
Martin Schorb's avatar
Martin Schorb committed
172
            if 'tile' in lead_tile.keys():
173
                tiles,slices,positions = hf.neighbours_from_json(tp_jsonfiles,lead_tile['tile'])
Martin Schorb's avatar
Martin Schorb committed
174
                t_labels = tiles.copy()
175

Martin Schorb's avatar
Martin Schorb committed
176
177
                if tiles==[]:
                    return dash.no_update
Martin Schorb's avatar
Martin Schorb committed
178

Martin Schorb's avatar
Martin Schorb committed
179
180
                tile = tiles[-1]

Martin Schorb's avatar
Martin Schorb committed
181
            if owner in params.tile_display.keys() and len(slices)==len(t_labels):
Martin Schorb's avatar
Martin Schorb committed
182
                t_labels, tile0 = params.tile_display[owner](tiles, prev_tile, slicenum)
183

184
                for t_idx,label in enumerate(t_labels):
Martin Schorb's avatar
Martin Schorb committed
185
                    if len(slices)>1 :
186
187
188
189
190
                        slicestr = 'Slice '+str(slices[t_idx])+' - '
                    else:
                        slicestr = ''

                    t_labels[t_idx] = slicestr+label
Martin Schorb's avatar
Martin Schorb committed
191

192
193
194
            for t_idx,label in enumerate(t_labels):
                t_labels[t_idx] = t_labels[t_idx]+' '+positions[t_idx]

195
196
197
198
199
        elif owner in params.tile_display.keys():
            t_labels, tile = params.tile_display[owner](tiles, prev_tile, slicenum)

        if None in (t_labels, tile):
            return dash.no_update
Martin Schorb's avatar
Martin Schorb committed
200

Martin Schorb's avatar
Martin Schorb committed
201
202
        # assemble dropdown
        dd_options = list(dict())
203
        for t_idx,item in enumerate(tiles):
204
205
            dd_options.append({'label':t_labels[t_idx], 'value':item})

206

Martin Schorb's avatar
Martin Schorb committed
207
208
209
        return dd_options, tile
    
    
210
    @app.callback([Output({'component': 'tileim_imurl'+idx_str, 'module': MATCH},'children'),
211
212
                   Output({'component': 'tileim_link'+idx_str, 'module': MATCH},'children'),
                   Output({'component': 'lead_tile'+idx_str, 'module': MATCH},'data')],
Martin Schorb's avatar
Martin Schorb committed
213
                  [Input({'component':'tile_dd'+idx_str,'module': MATCH},'value'),
214
                   Input({'component': 'store_render_launch', 'module': MATCH},'data')],
Martin Schorb's avatar
Martin Schorb committed
215
216
                  [State({'component': 'owner_dd','module': MATCH},'value'),
                   State({'component': 'project_dd','module': MATCH},'value'),
Martin Schorb's avatar
Martin Schorb committed
217
                   State({'component': 'stack_dd','module': MATCH},'value'),
218
                   State({'component': 'tileim_section_in' + idx_str, 'module': MATCH}, 'value'),
219
                   State('url', 'pathname')
Martin Schorb's avatar
Martin Schorb committed
220
                   ])           
221
    def im_view_url(tile,runstore,owner,project,stack,section,thispage):
222
223
        if not dash.callback_context.triggered: 
            raise PreventUpdate
224
        # print('tile is now: '+ tile)
225
226
        # print('stack is now: '+ stack)

227
        thispage = thispage.lstrip('/')        
228
229
                
        if not hf.trigger(key='module') == thispage:
230
231
            return dash.no_update
            
Martin Schorb's avatar
Martin Schorb committed
232
        if None in (tile,runstore,owner,project,stack):
233
234
            return dash.no_update
        
235
236
237
        if 'None' in (owner,project,stack):
            return dash.no_update
        
238
        
Martin Schorb's avatar
Martin Schorb committed
239
240
241
242
        url = params.render_base_url + params.render_version + 'owner/' + owner + '/project/' + project + '/stack/' + stack
        url += '/tile/' + tile 
        
        url1 = url + '/render-parameters'
243
        
Martin Schorb's avatar
Martin Schorb committed
244
245
        tilespec = requests.get(url1).json()
        
246
        scale = float(params.im_width) / float(tilespec['width'])  
Martin Schorb's avatar
Martin Schorb committed
247
        
Martin Schorb's avatar
Martin Schorb committed
248
249
        out_scale = '%0.2f' %scale
        
250
        imurl = url +'/jpeg-image?scale=' + out_scale      
Martin Schorb's avatar
Martin Schorb committed
251
252
253
254
255
256
257
258
        
        if runstore is None or not 'mt_params' in runstore.keys():
            scale1 = params.default_tile_scale
        else:
            scale1 = runstore['mt_params']['scale']

        
        url1 += '?filter=true&scale=' + str(scale1)
259

Martin Schorb's avatar
Martin Schorb committed
260
        leadtile = dict(tile=tile,section=section,stack=stack)
261
262

        return imurl, url1, leadtile
263
264
    
    
265
    # init tile image display
266
267
268
269
270
271
272
273
274
275
276
277
278
279
    @app.callback(Output({'component': 'tileim_image'+idx_str, 'module': MATCH},'src'),
                  [Input({'component': 'tileim_contrastslider'+idx_str, 'module': MATCH},'value'),
                   Input({'component': 'tileim_imurl'+idx_str, 'module': MATCH},'children')]
                  )
    def im_view(c_limits,imurl):
        if not dash.callback_context.triggered: 
            raise PreventUpdate     
            
        if None in (c_limits,imurl):
            return dash.no_update
        
        if 'None' in (c_limits,imurl):
            return dash.no_update
        
Martin Schorb's avatar
Martin Schorb committed
280
281
        imurl += '&minIntensity=' + str(c_limits[0]) + '&maxIntensity=' + str(c_limits[1])
        
282
        return imurl
Martin Schorb's avatar
Martin Schorb committed
283
284
    

285
    # init slice image display
286
    @app.callback(Output({'component': 'sliceim_image'+idx_str, 'module': MATCH},'src'),
287
                  [Input({'component':'sliceim_section_in'+idx_str,'module': MATCH},'value'),
Martin Schorb's avatar
Martin Schorb committed
288
289
                   Input({'component': 'store_render_launch', 'module': MATCH},'data'),
                   Input({'component': 'sliceim_contrastslider'+idx_str, 'module': MATCH},'value')],
290
291
292
                  [State({'component': 'owner_dd','module': MATCH},'value'),
                   State({'component': 'project_dd','module': MATCH},'value'),
                   State({'component': 'stack_dd','module': MATCH},'value'),
293
                   State('url', 'pathname')
294
                   ])           
Martin Schorb's avatar
Martin Schorb committed
295
    def slice_view(section,runstore,c_limits,owner,project,stack,thispage):
296
297
        if not dash.callback_context.triggered: 
            raise PreventUpdate
298
        
299
300
        thispage = thispage.lstrip('/')        
        
301
        if not hf.trigger(key='module') == thispage:
302
            return dash.no_update
303

Martin Schorb's avatar
Martin Schorb committed
304
        if None in (section,runstore,owner,project,stack):
305
306
            return dash.no_update
        
307
308
309
310
        if 'None' in (owner,project,stack):
            return dash.no_update
        
        
311
312
313
314
315
        url = params.render_base_url + params.render_version + 'owner/' + owner + '/project/' + project + '/stack/' + stack
        
        url += '/z/'+ str(section)
        
        url1 = url + '/bounds'
316
                
317
318
319
320
321
322
323
324
        bounds = requests.get(url1).json()
        
        imwidth = bounds['maxX'] - bounds['minX']
        
        scale = float(params.im_width) / float(imwidth)
        
        out_scale = '%0.2f' %scale
        
325
326
        imurl = url +'/jpeg-image?scale=' + out_scale   
        
Martin Schorb's avatar
Martin Schorb committed
327
328
        imurl += '&minIntensity=' + str(c_limits[0]) + '&maxIntensity=' + str(c_limits[1])
        
329
        return imurl
Martin Schorb's avatar
Martin Schorb committed
330

331
332
333
334

@app.callback(Output({'component': 'lead_tile', 'module': MATCH},'data'),
              Input({'component': 'lead_tile_0', 'module': MATCH},'data'))
def collect_leadtiles(lead_in):
335
    # print(lead_in)
336
    return lead_in