class DatePicker(Widget): value = param.CalendarDate(default=None) start = param.CalendarDate(default=None) end = param.CalendarDate(default=None) disabled_dates = param.List(default=None, class_=(date, str)) enabled_dates = param.List(default=None, class_=(date, str)) _source_transforms = {} _rename = {'start': 'min_date', 'end': 'max_date', 'name': 'title'} _widget_type = _BkDatePicker def _process_property_change(self, msg): msg = super(DatePicker, self)._process_property_change(msg) if 'value' in msg: if isinstance(msg['value'], string_types): msg['value'] = datetime.date( datetime.strptime(msg['value'], '%Y-%m-%d')) return msg
class _DatetimePickerBase(Widget): start = param.CalendarDate(default=None) end = param.CalendarDate(default=None) disabled_dates = param.List(default=None, class_=(date, str)) enabled_dates = param.List(default=None, class_=(date, str)) enable_time = param.Boolean(default=True) enable_seconds = param.Boolean(default=True) military_time = param.Boolean(default=True) _source_transforms = { 'value': None, 'start': None, 'end': None, 'mode': None } _rename = {'start': 'min_date', 'end': 'max_date', 'name': 'title'} _widget_type = _bkDatetimePicker __abstract = True def __init__(self, **params): super().__init__(**params) self._update_value_bounds() @staticmethod def _date_to_datetime(x): if isinstance(x, date): return datetime(x.year, x.month, x.day) @param.depends('start', 'end', watch=True) def _update_value_bounds(self): self.param.value.bounds = ( self._date_to_datetime(self.start), self._date_to_datetime(self.end), ) self.param.value._validate(self.value) def _process_property_change(self, msg): msg = super()._process_property_change(msg) if 'value' in msg: msg['value'] = self._serialize_value(msg['value']) return msg def _process_param_change(self, msg): msg = super()._process_param_change(msg) if 'value' in msg: msg['value'] = self._deserialize_value(msg['value']) return msg
class TestSet(param.Parameterized): numpy_params = ['r'] pandas_params = ['s','t','u'] conditionally_unsafe = ['f', 'o'] a = param.Integer(default=5, doc='Example doc', bounds=(2,30), inclusive_bounds=(True, False)) b = param.Number(default=4.3, allow_None=True) c = param.String(default='foo') d = param.Boolean(default=False) e = param.List([1,2,3], class_=int) f = param.List([1,2,3]) g = param.Date(default=datetime.datetime.now()) h = param.Tuple(default=(1,2,3), length=3) i = param.NumericTuple(default=(1,2,3,4)) j = param.XYCoordinates(default=(32.1, 51.5)) k = param.Integer(default=1) l = param.Range(default=(1.1,2.3), bounds=(1,3)) m = param.String(default='baz', allow_None=True) n = param.ObjectSelector(default=3, objects=[3,'foo'], allow_None=False) o = param.ObjectSelector(default=simple_list, objects=[simple_list], allow_None=False) p = param.ListSelector(default=[1,4,5], objects=[1,2,3,4,5,6]) q = param.CalendarDate(default=datetime.date.today()) r = None if np is None else param.Array(default=ndarray) s = None if pd is None else param.DataFrame(default=df1, columns=2) t = None if pd is None else param.DataFrame(default=pd.DataFrame( {'A':[1,2,3], 'B':[1.1,2.2,3.3]}), columns=(1,4), rows=(2,5)) u = None if pd is None else param.DataFrame(default=df2, columns=['A', 'B']) v = param.Dict({'1':2})
def test_get_soft_bounds(self): q = param.CalendarDate(dt.date(2017,2,25), bounds=(dt.date(2017,2,1), dt.date(2017,2,26)), softbounds=(dt.date(2017,2,1), dt.date(2017,2,25))) self.assertEqual(q.get_soft_bounds(), (dt.date(2017,2,1), dt.date(2017,2,25)))
class DatePicker(Widget): """ The `DatePicker` allows selecting selecting a `date` value using a text box and a date-picking utility. Reference: https://panel.holoviz.org/reference/widgets/DatePicker.html :Example: >>> DatePicker( ... value=date(2025,1,1), ... start=date(2025,1,1), end=date(2025,12,31), ... name='Date' ... ) """ value = param.CalendarDate(default=None, doc=""" The current value""") start = param.CalendarDate(default=None, doc=""" Inclusive lower bound of the allowed date selection""") end = param.CalendarDate(default=None, doc=""" Inclusive upper bound of the allowed date selection""") disabled_dates = param.List(default=None, class_=(date, str)) enabled_dates = param.List(default=None, class_=(date, str)) _source_transforms = {} _rename = {'start': 'min_date', 'end': 'max_date', 'name': 'title'} _widget_type = _BkDatePicker def _process_property_change(self, msg): msg = super()._process_property_change(msg) if 'value' in msg: if isinstance(msg['value'], str): msg['value'] = datetime.date( datetime.strptime(msg['value'], '%Y-%m-%d')) return msg
class CustomExample(param.Parameterized): """An example Parameterized class""" select_string = param.Selector(objects=[ "red", "yellow", "green", ]) date = param.CalendarDate( default=default, bounds=( start, end, ), ) number = param.Number( default=0, bounds=( -5.0, 5.0, ), )
class MyParameterized(param.Parameterized): enable = param.Boolean(True, doc="A sample Boolean parameter", allow_None=True) what_proportion = param.Magnitude(default=0.9) age = param.Number(49, bounds=(0, 100), doc="Any Number between 0 to 100") how_many = param.Integer() favorite_quote = param.String(default="Hello, world!") choose_file_or_folder = param.Path(search_paths='./') choose_folder = param.Foldername(search_paths="./") choose_file = param.Filename(search_paths="./") select_a_file = param.FileSelector(path='./*') select_multiple_files = param.MultiFileSelector(path='./*') favorite_color = param.ObjectSelector( default="green", objects=["red", "yellow", "green"]) favorite_fruit = param.Selector(default="Apple", objects=["Orange", "Apple", "Mango"]) select_multiple = param.ListSelector(default=[3, 5], objects=[1, 2, 3, 4, 5]) birthday = param.CalendarDate(dt.date(2017, 1, 1), bounds=(dt.date(2017, 1, 1), dt.date(2017, 2, 1))) appointment = param.Date(dt.datetime(2017, 1, 1), bounds=(dt.datetime(2017, 1, 1), dt.datetime(2017, 2, 1))) least_favorite_color = param.Color(default='#FF0000') dataset = param.DataFrame(pd.util.testing.makeDataFrame().iloc[:3]) this_strange_thing = param.Tuple(default=(False, ), allow_None=True) some_numbers = param.NumericTuple(default=(1, 2, 3.0, 4.0)) home_city = param.XYCoordinates(default=(-111.65, 40.23)) bounds = param.Range(default=(-10, 10))
class cmrUrls(param.Parameterized): '''Class to allow user to select product params and then search for matching data''' # product Information # Select Product product = param.ObjectSelector(defaultProduct, objects=products) productFilter = param.ObjectSelector( productOptions[defaultProduct][0], objects=productOptions[defaultProduct]) # Date range for search firstDate = param.CalendarDate(default=datetime(2000, 1, 1).date()) lastDate = param.CalendarDate(default=datetime.today().date()) LatMin = pn.widgets.FloatSlider(name='Lat min', disabled=True, value=defaultBounds['LatMin'], start=defaultBounds['LatMin'], end=defaultBounds['LatMax']) LatMax = pn.widgets.FloatSlider(name='Lat max', disabled=True, value=defaultBounds['LatMax'], start=defaultBounds['LatMin'] + 1, end=defaultBounds['LatMax']) LonMin = pn.widgets.FloatSlider(name='Lon min', disabled=True, value=defaultBounds['LonMin'], start=defaultBounds['LonMin'], end=defaultBounds['LonMax']) LonMax = pn.widgets.FloatSlider(name='Lon max', disabled=True, value=defaultBounds['LonMax'], start=defaultBounds['LonMin'] + 1, end=defaultBounds['LonMax']) # Search = param.Boolean(False) Clear = param.Boolean(False) results = pd.DataFrame() def __init__(self, mode='none', debug=False, date1=None, date2=None, verbose=False): super().__init__() # self.mode = mode.lower() # self.param.set_param('product', modes[self.mode]['defaultProduct']) self.setProductOptions() # self.validProducts = \ [products[x] for x in modes[self.mode]['productIndexes']] self.param.set_param('product', products[modes[self.mode]['productIndexes'][0]]) self.verbose = verbose # # Pick only 1 481 product by box name if modes[self.mode]['boxNames']: if modes[self.mode]['boxNames']: productOptions['NSIDC-0481'] = self.TSXBoxNames() productOptions['NSIDC-0646'] = self.TSXBoxNames(product= 'NSIDC-0646') for x in productOptions['NSIDC-0481']: productGroups[x] = ['vv'] fileTypes[x] = ['.tif'] for x in productOptions['NSIDC-0646']: productGroups[x] = ['vx'] fileTypes[x] = ['.tif'] # Subsetter modes only one option if not modes[self.mode]['cumulative']: self.param.Clear.precedence = -1 for prod in velocityMosaics: productOptions[prod] = ['-'] # Get mode appropriate objects self.param.product.objects = \ [self.param.product.objects[x] for x in modes[self.mode]['productIndexes']] # Init variables self.first = True self.cogs = [] self.urls = [] self.nUrls = 0 self.productList = [] self.nProducts = 0 self.newProductCount = 0 self.dates = [] self.debug = debug self.msg = 'Init' # initialize with empty list def getCogs(self, replace=None, removeTiff=False): cogs = [x for x in self.urls if x.endswith('.tif')] if removeTiff: cogs = [x.replace('.tif', '') for x in cogs] if replace is not None: cogs = [x.replace(replace, '*') for x in cogs] return cogs def getShapes(self): return [x for x in self.urls if x.endswith('.shp')] def checkIDs(self, testIDs): ''' Check if 1 or more of the ids in testIDs is in the current IDs''' for id in self.getIDs(): # Check each id type if id in testIDs: return True # Return if found return False # None present def getIDs(self): ''' Get the unique list of ids from the cog and shape files''' files = self.getCogs() + self.getShapes() fileIDs = [x.split('/')[-3].split('.')[0] for x in files] # Find ids return np.unique(fileIDs) # Return the unique ids @param.depends('Clear', watch=True) def clearData(self): self.resetData() self.Clear = False def resetData(self): self.products = [] self.urls = [] self.nUrls = 0 self.nProducts = 0 self.newProductCount = 0 self.dates = [] self.productList = [] self.results = pd.DataFrame(zip(self.dates, self.productList), columns=['date', 'product']) @param.depends('Search', watch=True) def findData(self, initSearch=False): '''Search NASA/NSIDC Catalog for dashboard parameters''' # Return if not a button push (e.g., first) if not self.Search and not initSearch: return # Start fresh for each search if not cumulative if not modes[self.mode]['cumulative']: self.resetData() # newUrls = self.getURLS() self.msg = len(newUrls) # append list. Use unique to avoid selecting same data set self.urls = list(np.unique(newUrls + self.urls)) self.nUrls = len(self.urls) self.updateProducts(newUrls) self.results = pd.DataFrame(zip(self.dates, self.productList), columns=['date', 'product']) # reset get Data self.Search = False def updateProducts(self, newUrls): ''' Generate a list of the products in the url list''' fileType = productGroups[self.productFilter][0] oldCount = self.nProducts # update list for url in newUrls: for fileType in productGroups[self.productFilter]: if fileType in url: productName = url.split('/')[-1] self.productList.append(productName) self.dates.append(url.split('/')[-2]) self.productList, uIndex = np.unique(self.productList, return_index=True) self.productList = list(self.productList) self.nProducts = len(self.productList) self.dates = [self.dates[i] for i in uIndex] self.newProductCount = self.nProducts - oldCount def boundingBox(self): ''' Create bounding box string for search''' return f'{self.LonMin.value:.2f},{self.LatMin.value:.2f},' \ f'{self.LonMax.value:.2f},{self.LatMax.value:.2f}' def getURLS(self): ''' Get list of URLs for the product ''' dateFormat1, dateFormat2 = '%Y-%m-%dT00:00:01Z', '%Y-%m-%dT00:23:59' version = versions[self.product] # Current Version for product polygon = None bounding_box = self.boundingBox() pattern = '*' if modes[self.mode]['boxNames'] and \ (self.product == 'NSIDC-0481' or self.product == 'NSIDC-0646'): pattern = f'*{self.productFilter}*' # Include TSX box for subset newUrls = [] # Future proof by increasing version if nothing found for i in range(0, 5): allUrls = grimp.get_urls(self.product, str(int(version) + i), self.firstDate.strftime(dateFormat1), self.lastDate.strftime(dateFormat2), bounding_box, polygon, pattern, verbose=self.verbose) if len(allUrls) > 0: # Some found so assume version current break for url in allUrls: # get all urls for group (e.g., vx) for productGroup in productGroups[self.productFilter]: for suffix in fileTypes[self.productFilter]: if productGroup in url and url.endswith(suffix): newUrls.append(url) # Return filtered list sorted. return sorted(newUrls) @param.depends('product', watch=True) def setProductOptions(self, productFilter=None): self.param.productFilter.objects = productOptions[self.product] if productFilter is None: productFilter = productOptions[self.product][0] # self.param.set_param('productFilter', productFilter) # Reset lat/lon bounds for coord in ['LatMin', 'LatMax', 'LonMin', 'LonMax']: if self.product not in ['NSIDC-0481', 'NSIDC-0646']: getattr(self, coord).value = defaultBounds[coord] getattr(self, coord).disabled = True else: getattr(self, coord).disabled = False @param.depends('LatMin.value', watch=True) def _latMinUpdate(self): ''' Ensure LatMin < LatMax ''' self.LatMax.value = max(self.LatMax.value, self.LatMin.value + 1.) @param.depends('LonMin.value', watch=True) def _lonMinUpdate(self): ''' Ensure LonMin < LonMax''' self.LonMax.value = max(self.LonMax.value, self.LonMin.value + 1.) @param.depends('LatMax.value', watch=True) def _latMaxUpdate(self): ''' Ensure LatMin < LatMax ''' self.LatMin.value = min(self.LatMin.value, self.LatMax.value - 1.) @param.depends('LonMax.value', watch=True) def _lonMaxUpdate(self): ''' Ensure LonMin < LonMax''' self.LonMin.value = min(self.LonMin.value, self.LonMax.value - 1.) def result_view(self): return pn.widgets.DataFrame(self.results, height=600, autosize_mode='fit_columns') def TSXBoxNames(self, product='NSIDC-0481'): ''' Get list of all TSX boxes''' params = {'NSIDC-0481': ('2009-01-01T00:00:01Z', '2029-01-01T00:00:01Z', 'TSX'), 'NSIDC-0646': ('2009-01-01T00:00:01Z', '2010-01-01T00:00:01Z', 'OPT')} date1, date2, pattern = params[product] for i in range(0, 5): TSXurls = grimp.get_urls(product, str(int(versions[product]) + i), date1, date2, self.boundingBox(), None, '*') if len(TSXurls) > 0: return self.findTSXBoxes(urls=TSXurls, pattern=pattern) def findTSXBoxes(self, urls=None, pattern='TSX'): ''' Return list of unique boxes for the cogs ''' if urls is None: urls = self.getCogs() boxes = list(np.unique([x.split('/')[-1].split('_')[1] for x in urls if pattern in x])) if not boxes: # Empty list, so fill with '' boxes = [''] return boxes def displayProductCount(self): return pn.pane.Markdown( f'### {self.newProductCount} New Products\n' f'### {self.nUrls} Total Products') def debugMessage(self): if self.debug: msg = f'debug {self.msg}' else: msg = '' return pn.pane.Markdown(msg) def view(self): ''' Display panel for getting data ''' # Directions directionsPanel = pn.pane.Markdown(''' ### Instructions: * Select a product, filter (e.g., speed), and date, and bounds * Press Search to find products, * Repeat procedure to append additional products. * Press Clear to remove all results and start over ''') # Data legend names = ['- **NSIDC-0642:** Terminus Locations<br/>', '- **NSIDC-0723:** S1A/B Image Mosaics<br/>', '- **NSIDC-0725:** Annual Velocity<br/>', '- **NSIDC-0727:** Quarterly Velocity<br/>', '- **NSIDC-0731:** Monthly Velocity<br/>', '- **NSIDC-0766:** 6/12-Day Velocity<br/>', '- **NSIDC-0481:** TSX Individual Glacier Velocity<br/>', '- **NSIDC-0646:** Optical Individual Glacier Velocity' ] searchWidgets = {'product': pn.widgets.RadioButtonGroup, 'productFilter': pn.widgets.Select, 'firstDate': pn.widgets.DatePicker, 'lastDate': pn.widgets.DatePicker, 'Search': pn.widgets.Button} names = [names[x] for x in modes[self.mode]['productIndexes']] # Clear precedence ensures this won't plot in subsetter mode searchWidgets['Clear'] = pn.widgets.Button # infoPanel = pn.Row( pn.pane.Markdown( f'''**Product Key: **<br/>{''.join(names[0:4])}'''), pn.pane.Markdown(f'''<br/>{''.join(names[4:])}''')) leftWidth = max(len(names) * 100, 300) # Search widges panel self.inputs = pn.Param(self.param, widgets=searchWidgets, name='Select Product & Parameters', width=leftWidth) # Merge with directions panels = [directionsPanel, self.inputs] # Add lat/lon search (for none) if not modes[self.mode]['boxNames'] and \ 6 in modes[self.mode]['productIndexes']: boundsPanel = pn.Column(pn.Row(self.LatMin, self.LatMax), pn.Row(self.LonMin, self.LonMax)) boundsLabel = pn.pane.Markdown('###Search Area (NSIDC-481 only)') panels += [boundsPanel, boundsLabel] panels += [infoPanel] return pn.Row(pn.Column(*panels, min_width=leftWidth), pn.Column(self.result_view, self.displayProductCount, self.debugMessage)) def _formatDate(self, myDate): return datetime.strptime(myDate, '%Y-%m-%d').date() def _checkParam(self, param, options, name): ''' Check that "param" with "name" is in the list of "options" ''' if param is None: return True if param not in options: print(f'Invalid value ({param}) for parameter ({name}).') print(f'Valid options are: {options}') return False # return True def _setDates(self, firstDate, lastDate): ''' Set dates if specified. ''' try: if firstDate is not None: self.param.set_param('firstDate', self._formatDate(firstDate)) if lastDate is not None: self.param.set_param('lastDate', self._formatDate(lastDate)) except Exception: print(f'Invalid Date(s): {firstDate} and/or {lastDate}') print('Use "YYYY-MM-DD"') return False return True def initialSearch(self, firstDate=None, lastDate=None, product=None, productFilter=None): ''' This will display the panel and do an initial search ''' # set Dates if not self._setDates(firstDate, lastDate): return # Set product if specified. if not self._checkParam(product, self.validProducts, 'product'): return if product is not None: self.param.set_param('product', product) # check productFilter if not self._checkParam(productFilter, self.param.productFilter.objects, 'productFilter'): return # Update product options self.setProductOptions(productFilter=productFilter) # Run the search self.findData(initSearch=True) return self.view()
class DatePicker(WiredBase): """wired-calendar""" component_type = param.String("inputgroup") html = param.String( '<wired-calendar initials="" role="dialog tabindex="0">Button</wired-calendar>' ) attributes_to_watch = param.Dict( { "elevation": "elevation", "firstdate": "firstdate", "lastdate": "lastdate", "locale": "locale", } ) properties_to_watch = param.Dict({"selected": "selected"}) events_to_watch = param.Dict(default={"selected": "selects"}) elevation = param.Integer(ELEVATION_DEFAULT, bounds=ELEVATION_BOUNDS) firstdate = param.String( doc=""" Example: firstdate="Apr 15, 2019""" ) lastdate = param.String( doc=""" Example: lastdate="Jul 15, 2019""" ) locale = param.ObjectSelector("en", objects=["en", "fr", "de"]) selected = param.String( doc=""" Example: selected="Jul 4, 2019""" ) selects = param.Integer(bounds=(0, None)) value = param.CalendarDate(default=None, bounds=DATE_BOUNDS) start = param.CalendarDate(bounds=DATE_BOUNDS) end = param.CalendarDate(bounds=DATE_BOUNDS) def __init__(self, min_height=340, min_width=300, **params): super().__init__(min_height=min_height, min_width=min_width, **params) @staticmethod def _to_date(value: Optional[str]) -> Optional[datetime.date]: if value: return datetime.datetime.strptime(value, "%b %d, %Y").date() return None @staticmethod def _to_string(value: datetime.date) -> Optional[str]: if value: return value.strftime("%b %e, %Y").replace(" ", " ") return None @param.depends("selected", watch=True) def _set_value(self): value = self._to_date(self.selected) if value != self.value: self.value = value @param.depends("value", watch=True) def _set_selected(self): selected = self._to_string(self.value) if selected != self.selected: self.selected = selected @param.depends("firstdate", watch=True) def _set_start(self): start = self._to_date(self.firstdate) if start != self.start: self.start = start @param.depends("start", watch=True) def _set_firstdate(self): firstdate = self._to_string(self.start) if firstdate != self.firstdate: self.firstdate = firstdate @param.depends("lastdate", watch=True) def _set_end(self): end = self._to_date(self.lastdate) if end != self.end: self.end = end @param.depends("end", watch=True) def _set_lastdate(self): lastdate = self._to_string(self.end) if lastdate != self.lastdate: self.lastdate = lastdate
class Test(param.Parameterized): a = param.CalendarDate()
class MyParamDate(param.Parameterized): date = param.CalendarDate(dt.date(2020, 1, 1))
class Q(param.Parameterized): q = param.CalendarDate(bounds=(dt.date(2017,2,1), dt.date(2017,2,26)), inclusive_bounds=(True, False))
class Q(param.Parameterized): q = param.CalendarDate(bounds=(dt.date(2017,2,1), dt.date(2017,2,26)))
class MyParamDate(param.Parameterized): datetime = param.Date(dt.datetime(2020, 1, 1, 0, 0, 0), bounds=(dt.datetime(2017, 1, 1, 0, 0, 0), dt.datetime(2021, 1, 1, 0, 0, 0))) date = param.CalendarDate(dt.date(2020, 1, 1))
def test_step_invalid_type_date_parameter(self): exception = "Step parameter can only be None or a date type" with self.assertRaisesRegexp(ValueError, exception): param.CalendarDate(dt.date(2017, 2, 27), step=3.2)