diff --git a/python/cuxfilter/charts/core/aggregate/core_aggregate.py b/python/cuxfilter/charts/core/aggregate/core_aggregate.py index e9f9676b..afe97acc 100644 --- a/python/cuxfilter/charts/core/aggregate/core_aggregate.py +++ b/python/cuxfilter/charts/core/aggregate/core_aggregate.py @@ -25,6 +25,7 @@ class BaseAggregateChart(BaseChart): datatile_active_color = DATATILE_ACTIVE_COLOR stride = None data_points = None + _x_dtype = float @property def datatile_loaded_state(self): @@ -48,10 +49,32 @@ def datatile_loaded_state(self, state: bool): else: self.filter_widget.bar_color = DATATILE_INACTIVE_COLOR + @property + def x_dtype(self): + """ + override core_chart x_dtype and make it constant, as panel 0.11 seems + to update the datetime x_axis type to float during runtime + """ + return self._x_dtype + + @x_dtype.setter + def x_dtype(self, value): + self._x_dtype = value + @property def custom_binning(self): return self._stride is not None or self._data_points is not None + def _transformed_source_data(self, property): + """ + this fixes a bug introduced with panel 0.11, where bokeh CDS + x-axis datetime is converted to float, and the only way to + convert it back to datetime is using datetime64[ms] + """ + if self.x_dtype in CUDF_DATETIME_TYPES: + return self.source.data[property].astype("datetime64[ms]") + return self.source.data[property] + def __init__( self, x, @@ -110,15 +133,14 @@ def __init__( self.y_axis_tick_formatter = y_axis_tick_formatter self.library_specific_params = library_specific_params - def _compute_array_all_bins( - self, source_x, source_y, update_data_x, update_data_y - ): + def _compute_array_all_bins(self, source_x, update_data_x, update_data_y): """ source_x: current_source_x, np.array() - source_y: current_source_y, np.array() update_data_x: updated_data_x, np.array() update_data_y: updated_data_x, np.array() """ + if self.x_dtype in CUDF_DATETIME_TYPES: + source_x = source_x.astype("datetime64[ms]") result_array = np.zeros(shape=source_x.shape) indices = [np.where(x_ == source_x)[0][0] for x_ in update_data_x] np.put(result_array, indices, update_data_y) @@ -154,7 +176,7 @@ def initiate_chart(self, dashboard_cls): Ouput: """ - self.source = dashboard_cls._cuxfilter_df.data + self.x_dtype = dashboard_cls._cuxfilter_df.data[self.x].dtype # reset data_point to input _data_points self.data_points = self._data_points # reset stride to input _stride @@ -248,19 +270,18 @@ def calculate_source(self, data, patch_update=False): } if patch_update and len(dict_temp["X"]) < len( - self.source.data[self.data_x_axis] + self._transformed_source_data(self.data_x_axis) ): # if not all X axis bins are provided, filling bins not updated # with zeros y_axis_data = self._compute_array_all_bins( - self.source.data[self.data_x_axis], - self.source.data[self.data_y_axis], + self._transformed_source_data(self.data_x_axis), dict_temp["X"], dict_temp["Y"], ) dict_temp = { - "X": self.source.data[self.data_x_axis], + "X": self._transformed_source_data(self.data_x_axis), "Y": y_axis_data, } @@ -393,10 +414,13 @@ def query_chart_by_range(self, active_chart, query_tuple, datatile): round((max_val - active_chart.min_value) / active_chart.stride) ) if self.custom_binning: - datatile_indices = self.source.data[self.data_x_axis] + datatile_indices = self._transformed_source_data(self.data_x_axis) else: datatile_indices = ( - (self.source.data[self.data_x_axis] - self.min_value) + ( + self._transformed_source_data(self.data_x_axis) + - self.min_value + ) / self.stride ).astype(int) @@ -473,10 +497,13 @@ def query_chart_by_indices_for_mean( Ouput: """ if self.custom_binning: - datatile_indices = self.source.data[self.data_x_axis] + datatile_indices = self._transformed_source_data(self.data_x_axis) else: datatile_indices = ( - (self.source.data[self.data_x_axis] - self.min_value) + ( + self._transformed_source_data(self.data_x_axis) + - self.min_value + ) / self.stride ).astype(int) if len(new_indices) == 0 or new_indices == [""]: @@ -525,10 +552,13 @@ def query_chart_by_indices_for_count( Ouput: """ if self.custom_binning: - datatile_indices = self.source.data[self.data_x_axis] + datatile_indices = self._transformed_source_data(self.data_x_axis) else: datatile_indices = ( - (self.source.data[self.data_x_axis] - self.min_value) + ( + self._transformed_source_data(self.data_x_axis) + - self.min_value + ) / self.stride ).astype(int) if len(new_indices) == 0 or new_indices == [""]: @@ -577,10 +607,13 @@ def query_chart_by_indices_for_minmax( Ouput: """ if self.custom_binning: - datatile_indices = self.source.data[self.data_x_axis] + datatile_indices = self._transformed_source_data(self.data_x_axis) else: datatile_indices = ( - (self.source.data[self.data_x_axis] - self.min_value) + ( + self._transformed_source_data(self.data_x_axis) + - self.min_value + ) / self.stride ).astype(int) diff --git a/python/cuxfilter/charts/core/core_widget.py b/python/cuxfilter/charts/core/core_widget.py index 5bd52056..4f228e47 100644 --- a/python/cuxfilter/charts/core/core_widget.py +++ b/python/cuxfilter/charts/core/core_widget.py @@ -43,6 +43,11 @@ def stride(self, value): self.stride_type = type(value) self._stride = value + @property + def x_dtype(self): + # default x_dtype + return float + def _xaxis_np_dt64_transform(self, dates): """ Description: convert to datetime64 if self.x_dtype is of type datetime diff --git a/python/cuxfilter/dashboard.py b/python/cuxfilter/dashboard.py index fd000986..57a95b9c 100644 --- a/python/cuxfilter/dashboard.py +++ b/python/cuxfilter/dashboard.py @@ -688,8 +688,6 @@ def _calc_data_tiles(self, cumsum=True): """ Calculate data tiles for all aggregate type charts. """ - # query_str = self._generate_query_str(self._active_view) - # NO DATATILES for scatter types, as they are essentially all # points in the dataset query = self._generate_query_str(ignore_chart=self._active_view) diff --git a/python/cuxfilter/layouts/custom_react_template.py b/python/cuxfilter/layouts/custom_react_template.py index 57d1c87c..3c32c1f1 100644 --- a/python/cuxfilter/layouts/custom_react_template.py +++ b/python/cuxfilter/layouts/custom_react_template.py @@ -66,6 +66,10 @@ class ReactTemplate(BasicTemplate): } def _template_resources(self): + # resolves bug in panel where theme is expected to have base_css even + # when css property is present + self.theme.base_css = self.theme.css + resources = super()._template_resources() # CSS files base_css = os.path.basename(self._css) diff --git a/python/cuxfilter/themes/assets/rapids.css b/python/cuxfilter/themes/assets/rapids.css index fa4af68c..b3a36005 100644 --- a/python/cuxfilter/themes/assets/rapids.css +++ b/python/cuxfilter/themes/assets/rapids.css @@ -1,50 +1,50 @@ body { - color: white; - background-color: #121212; - } - - #header { - background-color: #8735fb; - } - - .panel-df tbody tr:nth-child(odd){ - background-color: #000 !important; - } - - .drag-handle, .react-resizable-handle { - filter: brightness(0) invert(1); - } - - #main { - color: white; - background-color: #121212; - } - - #sidebar { - color: white; - border-color: #292929 !important; - background-color: #121212 !important; - } - - .bk.card { - color: white; - background-color: #2f2f2f; - } - - .bk-root .bk-input{ - color: white; - background-color: #2f2f2f; - } - - #header-items { - color: white; - } - - .bk.card-header { - color: white; - background-color: #292929 !important; - } - - .indicator > div > div { - color: white !important; - } + color: white; + background-color: #121212; +} + +#header { + background-color: #8735fb; +} + +.panel-df tbody tr:nth-child(odd){ + background-color: #000 !important; +} + +.drag-handle, .react-resizable-handle { + filter: brightness(0) invert(1); +} + +#main { + color: white; + background-color: #121212; +} + +#sidebar { + color: white; + border-color: #292929 !important; + background-color: #121212 !important; +} + +.bk.card { + color: white; + background-color: #2f2f2f; +} + +.bk-root .bk-input{ + color: white; + background-color: #2f2f2f; +} + +#header-items { + color: white; +} + +.bk.card-header { + color: white; + background-color: #292929 !important; +} + +.indicator > div > div { + color: white !important; +} diff --git a/python/cuxfilter/themes/rapids.py b/python/cuxfilter/themes/rapids.py index 5f173b96..6b892411 100644 --- a/python/cuxfilter/themes/rapids.py +++ b/python/cuxfilter/themes/rapids.py @@ -7,7 +7,7 @@ class RapidsTheme(Theme): - DARK = { + RAPIDS = { "attrs": { "Figure": { "background_fill_color": "#2f2f2f", @@ -71,7 +71,7 @@ class RapidsTheme(Theme): } } - bokeh_theme = _BkTheme(json=DARK) + bokeh_theme = _BkTheme(json=RAPIDS) map_style = "mapbox://styles/mapbox/dark-v9" map_style_without_token = ( "https://basemaps.cartocdn.com/gl/dark-matter-gl-style/style.json"