11# General imports
22
33# ETS imports
4- from traits .api import Button , Instance , observe
5- from traitsui .api import HGroup , Item , Label , ModelView , Spring , View
4+ import numpy as np
5+ import pandas as pd
6+ from traits .api import Bool , Button , Enum , Instance , List , observe
7+ from traitsui .api import HGroup , Item , Label , ListStrEditor , ModelView , \
8+ Spring , VGroup , View
69from traitsui .ui_editors .data_frame_editor import DataFrameEditor
10+
711# Local imports
8- from ..model .image_folder import ImageFolder
12+ from ..model .image_folder import FILENAME_COL , ImageFolder , NUM_FACE_COL
913
1014
11- DISPLAYED_COLUMNS = [
15+ DISPLAYED_COLUMNS = [FILENAME_COL , NUM_FACE_COL ] + [
1216 'ApertureValue' , 'ExifVersion' , 'Model' , 'Make' , 'LensModel' , 'DateTime' ,
13- 'ShutterSpeedValue' , 'XResolution' , 'YResolution'
17+ 'ShutterSpeedValue' , 'ExposureTime' , 'XResolution' , 'YResolution' ,
18+ 'Orientation' , 'GPSInfo' , 'DigitalZoomRatio' , 'FocalLengthIn35mmFilm' ,
19+ 'ISOSpeedRatings' , 'SceneType'
1420]
1521
1622
@@ -21,28 +27,96 @@ class ImageFolderView(ModelView):
2127
2228 scan = Button ("Scan for faces..." )
2329
24- view = View (
25- Item ("model.path" , style = "readonly" , show_label = False ),
26- Item ("model.data" , editor = DataFrameEditor (columns = DISPLAYED_COLUMNS ,
27- update = "data_updated" ),
28- show_label = False , visible_when = "len(model.data) > 0" ),
29- HGroup (
30- Spring (),
31- Label ("No images found. No data to show" ),
32- Spring (),
33- visible_when = "len(model.data) == 0" ,
34- ),
35- HGroup (
36- Spring (),
37- Item ("scan" , show_label = False , enabled_when = "len(model.data) > 0" ),
38- Spring (),
30+ # Filters widgets
31+ view_filter_controls = Bool
32+
33+ filtered_data = Instance (pd .DataFrame )
34+
35+ year_mask = Instance (pd .Series )
36+
37+ selected_years = List
38+
39+ all_years = List
40+
41+ selected_make = Enum (["All" , "Canon" , "Nikon" , "Sony" , "Apple" , "samsung" ])
42+
43+ make_mask = Instance (pd .Series )
44+
45+ def traits_view (self ):
46+ view = View (
47+ Item ("model.path" , style = "readonly" , show_label = False ),
48+ HGroup (
49+ Spring (),
50+ Item ("view_filter_controls" ),
51+ ),
52+ HGroup (
53+ Item ("all_years" , label = "Years" ,
54+ editor = ListStrEditor (selected = "selected_years" ,
55+ multi_select = True )
56+ ),
57+ Item ("selected_make" , label = "Camera make" ),
58+ visible_when = "view_filter_controls" ,
59+ ),
60+ Item ("filtered_data" ,
61+ editor = DataFrameEditor (columns = DISPLAYED_COLUMNS ,
62+ update = "data_updated" ),
63+ show_label = False , visible_when = "len(model.data) > 0" ),
64+ HGroup (
65+ Spring (),
66+ Label ("No images found. No data to show" ),
67+ Spring (),
68+ visible_when = "len(model.data) == 0" ,
69+ ),
70+ HGroup (
71+ Spring (),
72+ Item ("scan" , show_label = False ,
73+ enabled_when = "len(model.data) > 0" ),
74+ Spring (),
75+ ),
76+ resizable = True , height = 800
3977 )
40- )
78+ return view
79+
80+ # Listener methods --------------------------------------------------------
4181
4282 @observe ("scan" )
4383 def scan_for_faces (self , event ):
4484 self .model .compute_num_faces ()
4585
86+ @observe ("selected_years" )
87+ def update_years (self , event ):
88+ self .year_mask = self .model .data ['Year' ].isin (self .selected_years )
89+
90+ @observe ("selected_make" )
91+ def update_make (self , event ):
92+ if self .selected_make == "All" :
93+ self .make_mask = pd .Series (np .ones (len (self .model .data ),
94+ dtype = bool ))
95+ else :
96+ self .make_mask = self .model .data ['Make' ] == self .selected_make
97+
98+ @observe ("year_mask, make_mask" )
99+ def update_filtered_data (self , event ):
100+ self .filtered_data = self .model .data [self .year_mask & self .make_mask ]
101+
102+ # Initialization methods --------------------------------------------------
103+
104+ def _make_mask_default (self ):
105+ return pd .Series (np .ones (len (self .model .data ), dtype = bool ))
106+
107+ def _year_mask_default (self ):
108+ return pd .Series (np .ones (len (self .model .data ), dtype = bool ))
109+
110+ def _filtered_data_default (self ):
111+ return self .model .data
112+
113+ def _all_years_default (self ):
114+ def parse_year (x ):
115+ return x .split (":" )[0 ] if isinstance (x , str ) else "unknown"
116+
117+ self .model .data ['Year' ] = self .model .data ['DateTime' ].apply (parse_year )
118+ return sorted (self .model .data ['Year' ].unique ().tolist ())
119+
46120
47121if __name__ == '__main__' :
48122 from os .path import dirname , join
0 commit comments