-
Notifications
You must be signed in to change notification settings - Fork 148
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update to use dmc 0.15.1 #924
base: main
Are you sure you want to change the base?
Changes from all commits
1a962f1
7ff1b73
efbd801
7e1ff1c
4a091d2
fd2aeff
4189fa8
cfb1c3b
40aba6d
c216c98
e3d446c
5b50548
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,89 +1,24 @@ | ||
"""Dev app to try things out.""" | ||
|
||
from vizro import Vizro | ||
import vizro.models as vm | ||
import vizro.plotly.express as px | ||
|
||
df = px.data.gapminder() | ||
gapminder_data = ( | ||
df.groupby(by=["continent", "year"]).agg({"lifeExp": "mean", "pop": "sum", "gdpPercap": "mean"}).reset_index() | ||
) | ||
first_page = vm.Page( | ||
title="First Page", | ||
layout=vm.Layout(grid=[[0, 0], [1, 2], [1, 2], [1, 2]]), | ||
components=[ | ||
vm.Card( | ||
text=""" | ||
# First dashboard page | ||
This pages shows the inclusion of markdown text in a page and how components | ||
can be structured using Layout. | ||
""", | ||
), | ||
vm.Graph( | ||
id="box_cont", | ||
figure=px.box( | ||
gapminder_data, | ||
x="continent", | ||
y="lifeExp", | ||
color="continent", | ||
labels={"lifeExp": "Life Expectancy", "continent": "Continent"}, | ||
), | ||
), | ||
vm.Graph( | ||
id="line_gdp", | ||
figure=px.line( | ||
gapminder_data, | ||
x="year", | ||
y="gdpPercap", | ||
color="continent", | ||
labels={"year": "Year", "continent": "Continent", "gdpPercap": "GDP Per Cap"}, | ||
), | ||
), | ||
], | ||
controls=[ | ||
vm.Filter(column="continent", targets=["box_cont", "line_gdp"]), | ||
], | ||
) | ||
stocks = px.data.stocks(datetimes=True) | ||
|
||
iris_data = px.data.iris() | ||
second_page = vm.Page( | ||
title="Second Page", | ||
page = vm.Page( | ||
title="Page", | ||
components=[ | ||
vm.Graph( | ||
id="scatter_iris", | ||
figure=px.scatter( | ||
iris_data, | ||
x="sepal_width", | ||
y="sepal_length", | ||
color="species", | ||
color_discrete_map={"setosa": "#00b4ff", "versicolor": "#ff9222"}, | ||
labels={"sepal_width": "Sepal Width", "sepal_length": "Sepal Length", "species": "Species"}, | ||
), | ||
), | ||
vm.Graph( | ||
id="hist_iris", | ||
figure=px.histogram( | ||
iris_data, | ||
x="sepal_width", | ||
color="species", | ||
color_discrete_map={"setosa": "#00b4ff", "versicolor": "#ff9222"}, | ||
labels={"sepal_width": "Sepal Width", "count": "Count", "species": "Species"}, | ||
), | ||
figure=px.line(stocks, x="date", y="GOOG", title="Stocks Data"), | ||
), | ||
], | ||
controls=[ | ||
vm.Parameter( | ||
targets=["scatter_iris.color_discrete_map.virginica", "hist_iris.color_discrete_map.virginica"], | ||
selector=vm.Dropdown(options=["#ff5267", "#3949ab"], multi=False, value="#3949ab", title="Color Virginica"), | ||
), | ||
vm.Parameter( | ||
targets=["scatter_iris.opacity"], | ||
selector=vm.Slider(min=0, max=1, value=0.8, title="Opacity"), | ||
), | ||
vm.Filter(column="GOOG"), | ||
vm.Filter(column="date", selector=vm.DatePicker(title="Date Picker (Stocks - date)")), | ||
], | ||
) | ||
|
||
dashboard = vm.Dashboard(pages=[first_page, second_page]) | ||
dashboard = vm.Dashboard(pages=[page]) | ||
|
||
if __name__ == "__main__": | ||
Vizro().build(dashboard).run() | ||
Vizro().build(dashboard).run() |
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -21,7 +21,7 @@ dependencies = [ | |||||||||
"pandas>=2", | ||||||||||
"plotly>=5.12.0", | ||||||||||
"pydantic>=1.10.16", # must be synced with pre-commit mypy hook manually | ||||||||||
"dash_mantine_components<0.13.0", # 0.13.0 is not compatible with 0.12, | ||||||||||
"dash_mantine_components==0.15.1", # 0.13.0 is not compatible with 0.12, | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Due to https://iscinumpy.dev/post/bound-version-constraints/, I think we should remove the upper-bound version constraint (actually the version pinning in this case).
Suggested change
Or maybe:
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. With DMC I think it's best to pin an exact version. We are not yet at a major release (that's coming soon), plus there will be a breaking change when Dash 3.0 comes out that will require an update to DMC. Whenever this gets merged, I can help with managing dependencies (at least until we get to a major release) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sounds great! Thank you 😃 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would it be better to do There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Before, I was a huge fan of Actually, for this case, I prefer this ( |
||||||||||
"flask_caching>=2", | ||||||||||
"wrapt>=1", | ||||||||||
"black", | ||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ | |
from typing import TYPE_CHECKING, TypedDict, cast | ||
|
||
import dash | ||
import dash_mantine_components as dmc | ||
import plotly.io as pio | ||
from dash.development.base_component import ComponentRegistry | ||
from flask_caching import SimpleCache | ||
|
@@ -17,6 +18,9 @@ | |
from vizro.managers import data_manager, model_manager | ||
from vizro.models import Dashboard, Filter | ||
|
||
# this can be removed when Dash uses React 18 as a default (likely V3.0 https://github.com/plotly/dash/pull/3093) | ||
dash._dash_renderer._set_react_version("18.2.0") | ||
|
||
Comment on lines
+22
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In this comment, you said that:
I'm missing something here. I see that However, I'm a bit confused. Let's say that the following dependency is set in Vizro -> There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My understanding is that the React version used at runtime is controlled by the Dash renderer. The current default is React v16.14.0. Mantine requires a minimum of React 18, which is why it needs to be set explicitly. This won't be necessary in Dash 3.0 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oke 👍 It would be helpful if you can add a comment to consider removing this line when we increase the dash dependency to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is setting this react version likely to cause problems with anything else? I don't know whether some Dash components only function with React v16.14.0? |
||
logger = logging.getLogger(__name__) | ||
|
||
if TYPE_CHECKING: | ||
|
@@ -49,6 +53,13 @@ def __init__(self, **kwargs): | |
use_pages=True, | ||
) | ||
|
||
# Ensure external_stylesheets is a list and append the additional stylesheet | ||
external_stylesheets = self.dash.config.external_stylesheets | ||
self.dash.config.external_stylesheets = ( | ||
external_stylesheets if isinstance(external_stylesheets, list) else [external_stylesheets] | ||
) | ||
antonymilne marked this conversation as resolved.
Show resolved
Hide resolved
|
||
self.dash.config.external_stylesheets.append(dmc.styles.DATES) | ||
|
||
# When Vizro is used as a framework, we want to include the library and framework resources. | ||
# Dash serves resources in the order 1. external_stylesheets/scripts; 2. library resources from the | ||
# ComponentRegistry; 3. resources added by append_css/scripts. | ||
|
petar-qb marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,14 @@ | ||
from typing import Literal, Optional, Union | ||
|
||
import dash_mantine_components as dmc | ||
from dash import ClientsideFunction, Input, Output, State, clientside_callback, dcc, html | ||
from dash import html | ||
|
||
try: | ||
from pydantic.v1 import Field, PrivateAttr, validator | ||
except ImportError: # pragma: no cov | ||
from pydantic import Field, PrivateAttr, validator | ||
|
||
|
||
import datetime | ||
from datetime import date | ||
|
||
import dash_bootstrap_components as dbc | ||
|
@@ -42,6 +41,7 @@ class DatePicker(VizroBaseModel): | |
max: Optional[date] = Field(None, description="End date for date picker.") | ||
value: Optional[Union[list[date], date]] = Field(None, description="Default date for date picker") | ||
title: str = Field("", description="Title to be displayed.") | ||
|
||
range: bool = Field(True, description="Boolean flag for displaying range picker.") | ||
actions: list[Action] = [] | ||
|
||
|
@@ -55,57 +55,24 @@ class DatePicker(VizroBaseModel): | |
|
||
def build(self): | ||
init_value = self.value or ([self.min, self.max] if self.range else self.min) # type: ignore[list-item] | ||
date_range_picker_kwargs = {"allowSingleDateInRange": True} if self.range else {} | ||
|
||
output = [ | ||
Output(self.id, "value"), | ||
Output(f"{self.id}_input_store", "data"), | ||
] | ||
inputs = [ | ||
Input(self.id, "value"), | ||
State(f"{self.id}_input_store", "data"), | ||
] | ||
|
||
clientside_callback( | ||
ClientsideFunction(namespace="date_picker", function_name="update_date_picker_values"), | ||
output=output, | ||
inputs=inputs, | ||
) | ||
# clientside callback is required as a workaround when the date-picker is overflowing its parent container | ||
# if there is not enough space. Caused by another workaround for this issue: | ||
# https://github.com/snehilvj/dash-mantine-components/issues/219 | ||
clientside_callback( | ||
ClientsideFunction(namespace="date_picker", function_name="update_date_picker_position"), | ||
output=Output(self.id, "dropdownPosition"), | ||
inputs=Input(self.id, "n_clicks"), | ||
) | ||
petar-qb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
date_picker_class = dmc.DateRangePicker if self.range else dmc.DatePicker | ||
|
||
# dropdownPosition must be set to bottom-start as a workaround for issue: | ||
# https://github.com/snehilvj/dash-mantine-components/issues/219 | ||
# clearable must be set to False as a workaround for issue: | ||
# https://github.com/snehilvj/dash-mantine-components/issues/212 | ||
# maxDate must be increased by one day, and later on disabledDates must be set as maxDate + 1 day | ||
# as a workaround for issue: https://github.com/snehilvj/dash-mantine-components/issues/230 | ||
date_picker = date_picker_class( | ||
huong-li-nguyen marked this conversation as resolved.
Show resolved
Hide resolved
|
||
date_picker = dmc.DatePickerInput( | ||
petar-qb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
id=self.id, | ||
minDate=self.min, | ||
value=init_value, | ||
maxDate=self.max + datetime.timedelta(days=1) if self.max else None, | ||
maxDate=self.max, | ||
persistence=True, | ||
persistence_type="session", | ||
dropdownPosition="bottom-start", | ||
clearable=False, | ||
disabledDates=self.max + datetime.timedelta(days=1) if self.max else None, | ||
type="range" if self.range else "default", | ||
allowSingleDateInRange= True, | ||
className="datepicker", | ||
**date_range_picker_kwargs, | ||
# removes the default red color for weekend days | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we actually want this or was it just to demonstrate something? We don't normally do inline styles like this. @huong-li-nguyen @petar-qb There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. AM added this to demonstrate how to update some of the styles. I would ignore all CSS changes in this branch and wait for @nadijagraca PR today. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes, I think that would be OK
Plotly has been testing with React 18 for over a year. There hasn't been any issues that I know of. I was just reminded that Dash 3.0 will be using React 18.3.1, and in that version there will be a deprecation warning in the browser console for any components that use the
It would be better if the styles are applied in the theme prop in the I'd be happy to join a call to discuss CSS if you like. Mantine has a different way to style apps and components than Bootstrap, and I could help highlight the differences and leverage the Mantine system to make it easier to maintain going forward. In the meantime, here are a few links that might help:
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @nadijagraca has opened a PR here: AnnMarieW#1 @nadijagraca - could you check the links above and see whether we can refactor our CSS some more? :) For example, it seems that we could set a border-radius of 0 for all dmc components on the Mantine theme object etc. I also don't want to drag this PR for too long, so from my side, we can merge and refactor the CSS in another PR. |
||
styles={"day": {"color": "var(--mantine-color-text"}}, | ||
) | ||
|
||
return html.Div( | ||
children=[ | ||
dbc.Label(children=self.title, html_for=self.id) if self.title else None, | ||
date_picker, | ||
dcc.Store(id=f"{self.id}_input_store", storage_type="session", data=init_value), | ||
], | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ | |
|
||
import dash | ||
import dash_bootstrap_components as dbc | ||
import dash_mantine_components as dmc | ||
import plotly.io as pio | ||
from dash import ( | ||
ClientsideFunction, | ||
|
@@ -156,7 +157,7 @@ def build(self): | |
State("collapsable-left-side", "is_open"), | ||
) | ||
|
||
return html.Div( | ||
layout = html.Div( | ||
id="dashboard-container", | ||
children=[ | ||
html.Div(id="vizro_version", children=vizro.__version__, hidden=True), | ||
|
@@ -171,6 +172,11 @@ def build(self): | |
dash.page_container, | ||
], | ||
) | ||
return dmc.MantineProvider( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we actually need this? I read through the dmc docs and played around and as far as I can tell the only thing that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Apart from that, it seems like we need it anyway. I've added the
|
||
layout, | ||
# Use the `theme` to style all Mantine components with a Vizro theme. For more info see https://www.dash-mantine-components.com/components/mantineprovider | ||
theme = {"primaryColor": "gray"} | ||
) | ||
|
||
def _validate_logos(self): | ||
logo_img = self._infer_image(filename="logo") | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,109 +0,0 @@ | ||
.datepicker .mantine-Input-wrapper { | ||
font-family: unset; | ||
height: 2rem; | ||
} | ||
|
||
.datepicker .mantine-DateRangePicker-input, | ||
.datepicker .mantine-DatePicker-input { | ||
background-color: var(--field-enabled); | ||
border: none; | ||
border-radius: 0; | ||
box-shadow: var(--elevation-0); | ||
color: var(--text-secondary); | ||
font-size: 0.875rem; | ||
height: 2rem; | ||
line-height: 1rem; | ||
min-height: 2rem; | ||
padding: 0 0.5rem; | ||
} | ||
|
||
.datepicker .mantine-DateRangePicker-input:hover, | ||
.datepicker .mantine-DatePicker-input:hover { | ||
color: var(--text-primary); | ||
} | ||
|
||
.datepicker .mantine-DateRangePicker-dropdown, | ||
.datepicker .mantine-DatePicker-dropdown { | ||
background: var(--field-enabled); | ||
border: none; | ||
border-radius: 0; | ||
box-shadow: var(--elevation-1); | ||
padding: 1rem 11px; /* 11px otherwise not aligned with controls */ | ||
} | ||
|
||
.datepicker .mantine-UnstyledButton-root { | ||
border-radius: 0; | ||
color: var(--text-secondary); | ||
font-family: unset; | ||
font-weight: 400; | ||
} | ||
|
||
.datepicker .mantine-UnstyledButton-root:hover { | ||
background: var(--stateOverlays-hover); | ||
color: var(--text-primary); | ||
} | ||
|
||
.datepicker .mantine-DateRangePicker-weekday, | ||
.datepicker .mantine-DatePicker-weekday { | ||
color: var(--text-secondary); | ||
font-family: unset; | ||
padding: 0.5rem; | ||
} | ||
|
||
.datepicker .mantine-DateRangePicker-cell, | ||
.datepicker .mantine-DatePicker-cell { | ||
border: none; | ||
} | ||
|
||
.datepicker .mantine-DateRangePicker-day, | ||
.datepicker .mantine-DatePicker-day { | ||
background: var(--field-enabled); | ||
border-radius: 0; | ||
color: var(--text-secondary); | ||
font-family: unset; | ||
} | ||
|
||
.datepicker .mantine-DateRangePicker-day[data-outside], | ||
.datepicker .mantine-DateRangePicker-day:disabled, | ||
.datepicker .mantine-DatePicker-day[data-outside], | ||
.datepicker .mantine-DatePicker-day:disabled, | ||
.datepicker .mantine-UnstyledButton-root:disabled { | ||
color: var(--text-disabled); | ||
} | ||
|
||
.datepicker .mantine-DateRangePicker-day:hover, | ||
.datepicker .mantine-DateRangePicker-day:focus-visible, | ||
.datepicker .mantine-DatePicker-day:hover, | ||
.datepicker .mantine-DatePicker-day:focus-visible { | ||
background: var(--stateOverlays-hover); | ||
border: none; | ||
color: var(--text-primary); | ||
outline: none; | ||
text-decoration: none; | ||
} | ||
|
||
.datepicker .mantine-DateRangePicker-day[data-in-range] { | ||
background: var(--stateOverlays-selected); | ||
color: var(--text-primary); | ||
} | ||
|
||
.datepicker .mantine-DateRangePicker-day[data-selected], | ||
.datepicker .mantine-DateRangePicker-yearPickerControlActive, | ||
.datepicker .mantine-DateRangePicker-monthPickerControlActive, | ||
.datepicker .mantine-DatePicker-day[data-selected], | ||
.datepicker .mantine-DatePicker-yearPickerControlActive, | ||
.datepicker .mantine-DatePicker-monthPickerControlActive { | ||
background: var(--stateOverlays-selected-inverted); | ||
color: var(--text-primary-inverted); | ||
text-decoration: underline; | ||
} | ||
|
||
.datepicker | ||
.mantine-DateRangePicker-calendarHeader | ||
.mantine-UnstyledButton-root:hover, | ||
.datepicker | ||
.mantine-DatePicker-calendarHeader | ||
.mantine-UnstyledButton-root:hover { | ||
background: transparent; | ||
color: var(--text-primary); | ||
} | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to understand: why this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Previously it was like this:
Now it's like
So, previously, the app.layout.children was a list, and now it's a single component. If it's a common pattern to add components to the layout like in this app, then we should make sure that children is a list, like below: