Closed hkoppen closed 3 years ago
Ah, yes, you need to add the buildpack through the heroku GUI. Just go to the settings page of your heroku project and there you should find the add buildpack option. THere you can drop in the https://github.com/niteoweb/heroku-buildpack-shell.git
link and it should be added to your heroku slug.
also, you need to run pip uninstall -y xgboost
instead of pip install
...
(noticed that is actually a typo in the docs, just fixed it)
Did you manage to get it to work? I opened an issue with dtreeviz here to make the xgboost dependency optional, so that in the future it should be less of a headache.
Unfortunately, I'm not quite there. Building worked (after adding the Python buildpack as well 👼 ), but the app itself crashes due to 2020-12-07T10:45:58.008591+00:00 app[web.1]: bash: gunicorn: command not found
.
I am using
from unittest.mock import MagicMock
import sys
sys.modules["xgboost"] = MagicMock()
from explainerdashboard import ExplainerDashboard
app = ExplainerDashboard.from_config("dashboard_v3.yaml").flask_server()
server = app.server
if __name__ == '__main__':
app.run_server()
and the procfile
web: gunicorn app:server
following this article. Do I have to adapt to explainerdashboards' architecture somehow?
Ah, you need to add a requirements.txt file with:
explainerdashboard==0.2.13.2 gunicorn
Ok I forgot to mention the file, which was not contain gunicorn.
Now I am facing an en-/decoding error:
2020-12-07T11:25:14.091849+00:00 app[web.1]: [2020-12-07 11:25:14 +0000] [18] [ERROR] Exception in worker process
2020-12-07T11:25:14.091872+00:00 app[web.1]: Traceback (most recent call last):
2020-12-07T11:25:14.091873+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/arbiter.py", line 583, in spawn_worker
2020-12-07T11:25:14.091874+00:00 app[web.1]: worker.init_process()
2020-12-07T11:25:14.091874+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/workers/base.py", line 119, in init_process
2020-12-07T11:25:14.091874+00:00 app[web.1]: self.load_wsgi()
2020-12-07T11:25:14.091874+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/workers/base.py", line 144, in load_wsgi
2020-12-07T11:25:14.091875+00:00 app[web.1]: self.wsgi = self.app.wsgi()
2020-12-07T11:25:14.091875+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/app/base.py", line 67, in wsgi
2020-12-07T11:25:14.091876+00:00 app[web.1]: self.callable = self.load()
2020-12-07T11:25:14.091876+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/app/wsgiapp.py", line 49, in load
2020-12-07T11:25:14.091876+00:00 app[web.1]: return self.load_wsgiapp()
2020-12-07T11:25:14.091876+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/app/wsgiapp.py", line 39, in load_wsgiapp
2020-12-07T11:25:14.091877+00:00 app[web.1]: return util.import_app(self.app_uri)
2020-12-07T11:25:14.091877+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/util.py", line 358, in import_app
2020-12-07T11:25:14.091877+00:00 app[web.1]: mod = importlib.import_module(module)
2020-12-07T11:25:14.091877+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/importlib/__init__.py", line 126, in import_module
2020-12-07T11:25:14.091878+00:00 app[web.1]: return _bootstrap._gcd_import(name[level:], package, level)
2020-12-07T11:25:14.091878+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 994, in _gcd_import
2020-12-07T11:25:14.091879+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 971, in _find_and_load
2020-12-07T11:25:14.091879+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
2020-12-07T11:25:14.091879+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
2020-12-07T11:25:14.091879+00:00 app[web.1]: File "<frozen importlib._bootstrap_external>", line 678, in exec_module
2020-12-07T11:25:14.091880+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
2020-12-07T11:25:14.091880+00:00 app[web.1]: File "/app/app.py", line 7, in <module>
2020-12-07T11:25:14.091880+00:00 app[web.1]: app = ExplainerDashboard.from_config("dashboard_v3.yaml").flask_server()
2020-12-07T11:25:14.091881+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/explainerdashboard/dashboards.py", line 467, in from_config
2020-12-07T11:25:14.091881+00:00 app[web.1]: explainer = BaseExplainer.from_file(config['dashboard']['explainerfile'])
2020-12-07T11:25:14.091881+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/explainerdashboard/explainers.py", line 189, in from_file
2020-12-07T11:25:14.091881+00:00 app[web.1]: return joblib.load(filepath)
2020-12-07T11:25:14.091882+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/joblib/numpy_pickle.py", line 585, in load
2020-12-07T11:25:14.091882+00:00 app[web.1]: obj = _unpickle(fobj, filename, mmap_mode)
2020-12-07T11:25:14.091882+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/joblib/numpy_pickle.py", line 504, in _unpickle
2020-12-07T11:25:14.091882+00:00 app[web.1]: obj = unpickler.load()
2020-12-07T11:25:14.091882+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/pickle.py", line 1050, in load
2020-12-07T11:25:14.091883+00:00 app[web.1]: dispatch[key[0]](self)
2020-12-07T11:25:14.091883+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/pickle.py", line 1398, in load_reduce
2020-12-07T11:25:14.091883+00:00 app[web.1]: stack[-1] = func(*args)
2020-12-07T11:25:14.091883+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/numba/core/serialize.py", line 208, in _unpickle__CustomPickled
2020-12-07T11:25:14.091883+00:00 app[web.1]: ctor, states = loads(serialized)
2020-12-07T11:25:14.091884+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/numba/core/serialize.py", line 112, in _rebuild_function
2020-12-07T11:25:14.091884+00:00 app[web.1]: code = _rebuild_code(*code_reduced)
2020-12-07T11:25:14.091884+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/numba/core/serialize.py", line 132, in _rebuild_code
2020-12-07T11:25:14.091884+00:00 app[web.1]: raise RuntimeError("incompatible bytecode version")
2020-12-07T11:25:14.091890+00:00 app[web.1]: RuntimeError: incompatible bytecode version
2020-12-07T11:25:14.093752+00:00 app[web.1]: [2020-12-07 11:25:14 +0000] [18] [INFO] Worker exiting (pid: 18)
2020-12-07T11:25:14.169747+00:00 app[web.1]: [2020-12-07 11:25:14 +0000] [10] [ERROR] Exception in worker process
2020-12-07T11:25:14.169749+00:00 app[web.1]: Traceback (most recent call last):
2020-12-07T11:25:14.169756+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/arbiter.py", line 583, in spawn_worker
2020-12-07T11:25:14.169757+00:00 app[web.1]: worker.init_process()
2020-12-07T11:25:14.169757+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/workers/base.py", line 119, in init_process
2020-12-07T11:25:14.169757+00:00 app[web.1]: self.load_wsgi()
2020-12-07T11:25:14.169758+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/workers/base.py", line 144, in load_wsgi
2020-12-07T11:25:14.169758+00:00 app[web.1]: self.wsgi = self.app.wsgi()
2020-12-07T11:25:14.169759+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/app/base.py", line 67, in wsgi
2020-12-07T11:25:14.169759+00:00 app[web.1]: self.callable = self.load()
2020-12-07T11:25:14.169760+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/app/wsgiapp.py", line 49, in load
2020-12-07T11:25:14.169760+00:00 app[web.1]: return self.load_wsgiapp()
2020-12-07T11:25:14.169760+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/app/wsgiapp.py", line 39, in load_wsgiapp
2020-12-07T11:25:14.169761+00:00 app[web.1]: return util.import_app(self.app_uri)
2020-12-07T11:25:14.169761+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/gunicorn/util.py", line 358, in import_app
2020-12-07T11:25:14.169762+00:00 app[web.1]: mod = importlib.import_module(module)
2020-12-07T11:25:14.169762+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/importlib/__init__.py", line 126, in import_module
2020-12-07T11:25:14.169763+00:00 app[web.1]: return _bootstrap._gcd_import(name[level:], package, level)
2020-12-07T11:25:14.169763+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 994, in _gcd_import
2020-12-07T11:25:14.169764+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 971, in _find_and_load
2020-12-07T11:25:14.169764+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
2020-12-07T11:25:14.169765+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
2020-12-07T11:25:14.169765+00:00 app[web.1]: File "<frozen importlib._bootstrap_external>", line 678, in exec_module
2020-12-07T11:25:14.169765+00:00 app[web.1]: File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
2020-12-07T11:25:14.169766+00:00 app[web.1]: File "/app/app.py", line 7, in <module>
2020-12-07T11:25:14.169766+00:00 app[web.1]: app = ExplainerDashboard.from_config("dashboard_v3.yaml").flask_server()
2020-12-07T11:25:14.169767+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/explainerdashboard/dashboards.py", line 467, in from_config
2020-12-07T11:25:14.169767+00:00 app[web.1]: explainer = BaseExplainer.from_file(config['dashboard']['explainerfile'])
2020-12-07T11:25:14.169768+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/explainerdashboard/explainers.py", line 189, in from_file
2020-12-07T11:25:14.169768+00:00 app[web.1]: return joblib.load(filepath)
2020-12-07T11:25:14.169768+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/joblib/numpy_pickle.py", line 585, in load
2020-12-07T11:25:14.169769+00:00 app[web.1]: obj = _unpickle(fobj, filename, mmap_mode)
2020-12-07T11:25:14.169769+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/joblib/numpy_pickle.py", line 504, in _unpickle
2020-12-07T11:25:14.169770+00:00 app[web.1]: obj = unpickler.load()
2020-12-07T11:25:14.169770+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/pickle.py", line 1050, in load
2020-12-07T11:25:14.169771+00:00 app[web.1]: dispatch[key[0]](self)
2020-12-07T11:25:14.169771+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/pickle.py", line 1398, in load_reduce
2020-12-07T11:25:14.169771+00:00 app[web.1]: stack[-1] = func(*args)
2020-12-07T11:25:14.169772+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/numba/core/serialize.py", line 208, in _unpickle__CustomPickled
2020-12-07T11:25:14.169772+00:00 app[web.1]: ctor, states = loads(serialized)
2020-12-07T11:25:14.169778+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/numba/core/serialize.py", line 112, in _rebuild_function
2020-12-07T11:25:14.169778+00:00 app[web.1]: code = _rebuild_code(*code_reduced)
2020-12-07T11:25:14.169778+00:00 app[web.1]: File "/app/.heroku/python/lib/python3.6/site-packages/numba/core/serialize.py", line 132, in _rebuild_code
2020-12-07T11:25:14.169779+00:00 app[web.1]: raise RuntimeError("incompatible bytecode version")
2020-12-07T11:25:14.169779+00:00 app[web.1]: RuntimeError: incompatible bytecode version
Maybe it's because gunicorn is not designed for Windows and I should use waitress instead?
Ah, then the python version on heroku and the one you used to pickle the explainer is probably not compatible (pickle does not guarantee unpickles across versions):
You can learn about setting runtime versions here and here
Basically you should add a runtime.txt file with the python version:
python-3.8.6
Supported versions are python-3.9.0, python-3.8.6, python-3.7.9 and python-3.6.12
Maybe it's because gunicorn is not designed for Windows and I should use waitress instead?
Ah, yes. I don't know much about windows deployment (didnt even knew that heroku supported it to be honest :), but waitress is then probably the way to go. If you manage to get it to work could you let me know so that I can add instructions to the docs?
I managed to track down every bug/mistake and got it running with gunicorn :-)
For future reference, I'm using the following app.py:
from unittest.mock import MagicMock
import sys
sys.modules["xgboost"] = MagicMock()
from explainerdashboard import ExplainerDashboard
app = ExplainerDashboard.from_config("dashboard_v3.yaml").app
server = app.server
if __name__ == '__main__':
app.run_server()
Using .flask_server() is somehow not so smart.
ah, really? That is strange, should be equivalent. db.flask_server()
literally just returns self.app.server
. Anyway, I will just use the db.app.server
notation then in the documentation from now on. I've also clarified the deployment to heroku documentation a bit: https://explainerdashboard.readthedocs.io/en/latest/deployment.html#deploying-to-heroku Could you let me know if there is anything I should add to make the chance of accidental bugs smaller for future users?
Do you have a public link for the dashboard? Would be curious what you built.
Uh, never mind, I guess I put it into the wrong spot. The following works fine as well.
db = ExplainerDashboard.from_config("dashboard_v3.yaml")
app = db.app
server = db.flask_server()
The documentation looks great. Maybe you want to explain why you are using --preload --timeout 60
since it's strictly speaking not needed?
Sure, I will share it, but I have another problem: the plots are empty 😁 although I have loaded the data in the Github project. What could be the reason for this? Do you even need the data to be present when loading a dashboard from disk?
Ah yeah: --preload
is only needed when you have multiple workers. It assures that all the code is properly loaded for each worker, otherwise they somehow seem to get out of sync. The --timeout
is the amount of time that the startup of your server is allowed to take, so when you have some expensive imports or calculations to be done before starting the dashboard, it can help to to increase this.
If the plots are empty, something is definitely broken: you would want to check the logs for the stacktrace. All the data should be contained in the explainer.joblib
(or explainer.pkl
or whatever). So you would need to have both the explainer.joblib (or .pkl) and the dashboard.yaml in the repo to launch the dashboard.
I have the yaml and the explainer-file in the repo. Locally, loading works fine, but on Heroku, the plots are empty. I can't find anything in the logs:
2020-12-09T16:27:58.344000+00:00 heroku[web.1]: Starting process with command `gunicorn app:server`
2020-12-09T16:28:00.564417+00:00 app[web.1]: [2020-12-09 16:28:00 +0000] [4] [INFO] Starting gunicorn 20.0.4
2020-12-09T16:28:00.564982+00:00 app[web.1]: [2020-12-09 16:28:00 +0000] [4] [INFO] Listening at: http://0.0.0.0:12619 (4)
2020-12-09T16:28:00.565101+00:00 app[web.1]: [2020-12-09 16:28:00 +0000] [4] [INFO] Using worker: sync
2020-12-09T16:28:00.569038+00:00 app[web.1]: [2020-12-09 16:28:00 +0000] [10] [INFO] Booting worker with pid: 10
2020-12-09T16:28:00.603277+00:00 app[web.1]: [2020-12-09 16:28:00 +0000] [11] [INFO] Booting worker with pid: 11
2020-12-09T16:28:00.977409+00:00 heroku[web.1]: State changed from starting to up
2020-12-09T16:28:11.766502+00:00 app[web.1]: Building ExplainerDashboard..
2020-12-09T16:28:11.769214+00:00 app[web.1]: Building ExplainerDashboard..
2020-12-09T16:28:11.778317+00:00 app[web.1]: Generating layout...
2020-12-09T16:28:11.781447+00:00 app[web.1]: Generating layout...
2020-12-09T16:28:11.795301+00:00 app[web.1]: Calculating dependencies...
2020-12-09T16:28:11.795376+00:00 app[web.1]: Registering callbacks...
2020-12-09T16:28:11.798934+00:00 app[web.1]: Calculating dependencies...
2020-12-09T16:28:11.799016+00:00 app[web.1]: Registering callbacks...
2020-12-09T16:28:59.000000+00:00 app[api]: Build succeeded
2020-12-09T16:30:33.057134+00:00 heroku[router]: at=info method=GET path="/" host=... request_id=6fd55fb9-c7f6-4981-b2c3-c0a8ebb43632 fwd="62.216.209.193" dyno=web.1 connect=1ms service=28ms status=200 bytes=973 protocol=https
2020-12-09T16:30:33.051409+00:00 app[web.1]: 10.14.25.48 - - [09/Dec/2020:16:30:33 +0000] "GET / HTTP/1.1" 200 765 "https://dashboard.heroku.com/" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
2020-12-09T16:30:33.230979+00:00 app[web.1]: 10.35.77.100 - - [09/Dec/2020:16:30:33 +0000] "GET /_dash-component-suites/dash_renderer/react@16.v1_8_3m1607531128.14.0.min.js HTTP/1.1" 200 4898 "https://.../" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
2020-12-09T16:30:33.236167+00:00 app[web.1]: 10.14.25.48 - - [09/Dec/2020:16:30:33 +0000] "GET /_dash-component-suites/dash_renderer/polyfill@7.v1_8_3m1607531128.8.7.min.js HTTP/1.1" 200 34243 "https://.../" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
2020-12-09T16:30:33.235239+00:00 heroku[router]: at=info method=GET path="/_dash-component-suites/dash_renderer/react@16.v1_8_3m1607531128.14.0.min.js" host=... request_id=d6d60976-eb2a-41b6-9dfc-04c56486f20d fwd="62.216.209.193" dyno=web.1 connect=5ms service=11ms status=200 bytes=5153 protocol=https
2020-12-09T16:30:33.375435+00:00 heroku[router]: at=info method=GET path="/_dash-component-suites/dash_html_components/dash_html_components.v1_1_1m1607531134.min.js" host=... request_id=60ba5ea1-0689-4227-aa4d-7f9116124bb9 fwd="62.216.209.193" dyno=web.1 connect=4ms service=6ms status=200 bytes=19163 protocol=https
2020-12-09T16:30:33.357114+00:00 heroku[router]: at=info method=GET path="/_dash-component-suites/dash_core_components/dash_core_components-shared.v1_13_0m1607531133.js" host=... request_id=4ac3b6c0-2002-4b08-9470-b26216374cea fwd="62.216.209.193" dyno=web.1 connect=7ms service=6ms status=200 bytes=9940 protocol=https
2020-12-09T16:30:33.362676+00:00 heroku[router]: at=info method=GET path="/_dash-component-suites/dash_core_components/dash_core_components.v1_13_0m1607531133.min.js" host=... request_id=9df2dd92-7f4c-43db-adc4-00cf14ff37d9 fwd="62.216.209.193" dyno=web.1 connect=4ms service=24ms status=200 bytes=119092 protocol=https
2020-12-09T16:30:33.402190+00:00 heroku[router]: at=info method=GET path="/_dash-component-suites/dash_bootstrap_components/_components/dash_bootstrap_components.v0_10_7m1607531131.min.js" host=... request_id=def225a7-91a2-4f8c-8776-5102851f66cf fwd="62.216.209.193" dyno=web.1 connect=1ms service=14ms status=200 bytes=52759 protocol=https
2020-12-09T16:30:33.244014+00:00 heroku[router]: at=info method=GET path="/_dash-component-suites/dash_renderer/polyfill@7.v1_8_3m1607531128.8.7.min.js" host=... request_id=6e91a5c4-2867-489c-81bb-fecc106db2ed fwd="62.216.209.193" dyno=web.1 connect=2ms service=27ms status=200 bytes=34499 protocol=https
2020-12-09T16:30:33.342814+00:00 heroku[router]: at=info method=GET path="/_dash-component-suites/dash_table/bundle.v4_11_0m1607531132.js" host=... request_id=c08e9a18-2af6-4d16-9c9c-11264040ad02 fwd="62.216.209.193" dyno=web.1 connect=1ms service=5ms status=200 bytes=11269 protocol=https
2020-12-09T16:30:33.307532+00:00 app[web.1]: 10.35.77.100 - - [09/Dec/2020:16:30:33 +0000] "GET /_dash-component-suites/dash_renderer/react-dom@16.v1_8_3m1607531128.14.0.min.js HTTP/1.1" 200 38049 "https://.../" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
2020-12-09T16:30:33.329677+00:00 app[web.1]: 10.39.236.138 - - [09/Dec/2020:16:30:33 +0000] "GET /_dash-component-suites/dash_renderer/prop-types@15.v1_8_3m1607531128.7.2.min.js HTTP/1.1" 200 832 "https://.../" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
2020-12-09T16:30:33.342219+00:00 app[web.1]: 10.10.227.188 - - [09/Dec/2020:16:30:33 +0000] "GET /_dash-component-suites/dash_table/bundle.v4_11_0m1607531132.js HTTP/1.1" 200 11013 "https://.../" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
2020-12-09T16:30:33.353983+00:00 app[web.1]: 10.11.191.99 - - [09/Dec/2020:16:30:33 +0000] "GET /_dash-component-suites/dash_core_components/dash_core_components-shared.v1_13_0m1607531133.js HTTP/1.1" 200 9685 "https://.../" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
2020-12-09T16:30:33.355899+00:00 app[web.1]: 10.10.88.48 - - [09/Dec/2020:16:30:33 +0000] "GET /_dash-component-suites/dash_core_components/dash_core_components.v1_13_0m1607531133.min.js HTTP/1.1" 200 118835 "https://.../" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
2020-12-09T16:30:33.371658+00:00 app[web.1]: 10.14.25.48 - - [09/Dec/2020:16:30:33 +0000] "GET /_dash-component-suites/dash_html_components/dash_html_components.v1_1_1m1607531134.min.js HTTP/1.1" 200 18907 "https://.../" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
2020-12-09T16:30:33.396720+00:00 app[web.1]: 10.39.236.138 - - [09/Dec/2020:16:30:33 +0000] "GET /_dash-component-suites/dash_bootstrap_components/_components/dash_bootstrap_components.v0_10_7m1607531131.min.js HTTP/1.1" 200 52503 "https://.../" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
2020-12-09T16:30:33.425132+00:00 app[web.1]: 10.10.227.188 - - [09/Dec/2020:16:30:33 +0000] "GET /_dash-component-suites/dash_renderer/dash_renderer.v1_8_3m1607531128.min.js HTTP/1.1" 200 59285 "https://.../" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
2020-12-09T16:30:33.311666+00:00 heroku[router]: at=info method=GET path="/_dash-component-suites/dash_renderer/react-dom@16.v1_8_3m1607531128.14.0.min.js" host=... request_id=6ffa561e-09ac-485e-b804-4881c6a82682 fwd="62.216.209.193" dyno=web.1 connect=7ms service=9ms status=200 bytes=38305 protocol=https
2020-12-09T16:30:33.330282+00:00 heroku[router]: at=info method=GET path="/_dash-component-suites/dash_renderer/prop-types@15.v1_8_3m1607531128.7.2.min.js" host=... request_id=faee708b-efb1-4a18-9c66-9e3ccc437a23 fwd="62.216.209.193" dyno=web.1 connect=1ms service=2ms status=200 bytes=1086 protocol=https
2020-12-09T16:30:33.427968+00:00 heroku[router]: at=info method=GET path="/_dash-component-suites/dash_renderer/dash_renderer.v1_8_3m1607531128.min.js" host=... request_id=ba2d4b1e-dade-43ec-ba46-cd064861c039 fwd="62.216.209.193" dyno=web.1 connect=5ms service=13ms status=200 bytes=59541 protocol=https
2020-12-09T16:30:33.716655+00:00 heroku[router]: at=info method=GET path="/_dash-layout" host=... request_id=f3f91682-0f88-4e52-92c6-d2c034867c14 fwd="62.216.209.193" dyno=web.1 connect=2ms service=27ms status=200 bytes=131727 protocol=https
2020-12-09T16:30:33.694495+00:00 app[web.1]: 10.39.236.138 - - [09/Dec/2020:16:30:33 +0000] "GET /_dash-dependencies HTTP/1.1" 200 730 "https://.../" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
2020-12-09T16:30:33.711493+00:00 app[web.1]: 10.10.88.48 - - [09/Dec/2020:16:30:33 +0000] "GET /_dash-layout HTTP/1.1" 200 131524 "https://.../" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"
2020-12-09T16:30:33.696281+00:00 heroku[router]: at=info method=GET path="/_dash-dependencies" host=... request_id=4b5d7967-3082-4aa2-9f44-57819bd9665e fwd="62.216.209.193" dyno=web.1 connect=4ms service=4ms status=200 bytes=930 protocol=https
Hmm, that is quite strange. Two potential reasons:
Group cats is disabled atm, but choosing/changing an index in FeatureInputComponent does not show/change anything as well.
Logs - I'm using More > View Logs
in Heroku next to Open App
where I can only filter for web
processes (which I'm not), are there any alternatives to view the logs?
I tried loading the explainer file only, building the dashboard in app.py - no difference. I also tried constructing the dashboard it self in app.py, which is not working due to memory limitations on Heroku. My next & last idea is to deploy one of your Titanic dashboards ...
Yeah, probably handy to first test something that you know should work:
generate_dashboard.py:
from explainerdashboard import ClassifierExplainer, ExplainerDashboard
from explainerdashboard.custom import *
explainer = ClassifierExplainer(model, X_test, y_test)
# building an ExplainerDashboard ensures that all necessary properties
# get calculated:
db = ExplainerDashboard(explainer, [ShapDependenceComposite, WhatIfComposite],
title='Awesome Dashboard', hide_whatifpdp=True)
# store both the explainer and the dashboard configuration:
explainer.dump("explainer.joblib")
db.to_yaml("dashboard.yaml")
Now run python generate_dashboard.py
dashboard.py:
from explainerdashboard import ClassifierExplainer, ExplainerDashboard
explainer = ClassifierExplainer.from_file("explainer.joblib")
# you can override params during load from_config:
db = ExplainerDashboard.from_config(explainer, "dashboard.yaml", title="Awesomer Title")
app = db.flask_server()
Now run gunicorn dashboard:app
.
If it works, push the repo and see if it works on heroku as well.
Locally it works, but the result is https://hk-db-test.herokuapp.com/. :(
(Note that hide_whatifpdp=True
is not doing anything)
Hmm, weird. Do you maybe have the dashboard linked to a public github repo so that I can fork it and see if I can get it to work?
Yup, it's here: https://github.com/hkoppen/Dashboard_Test
Found the problem (now just need to find the solution):
(Btw, if you install the papertrail add-on (it's for free), you can see real time logs including stacktraces like below to help you debug)
Dec 15 02:06:02 db-test-oege app/web.1 Exception on /_dash-update-component [POST]
Dec 15 02:06:02 db-test-oege app/web.1 Traceback (most recent call last):
Dec 15 02:06:02 db-test-oege app/web.1 File "/app/.heroku/python/lib/python3.7/site-packages/dash/dash.py", line 1072, in dispatch
Dec 15 02:06:02 db-test-oege app/web.1 func = self.callback_map[output]["callback"]
Dec 15 02:06:02 db-test-oege app/web.1 KeyError: 'pdp-graph-AGdDw6dDQk.figure'
Dec 15 02:06:02 db-test-oege app/web.1 During handling of the above exception, another exception occurred:
Dec 15 02:06:02 db-test-oege app/web.1 Traceback (most recent call last):
Dec 15 02:06:02 db-test-oege app/web.1 File "/app/.heroku/python/lib/python3.7/site-packages/flask/app.py", line 2447, in wsgi_app
Dec 15 02:06:02 db-test-oege app/web.1 response = self.full_dispatch_request()
Dec 15 02:06:02 db-test-oege app/web.1 File "/app/.heroku/python/lib/python3.7/site-packages/flask/app.py", line 1952, in full_dispatch_request
Dec 15 02:06:02 db-test-oege app/web.1 rv = self.handle_user_exception(e)
Dec 15 02:06:02 db-test-oege app/web.1 File "/app/.heroku/python/lib/python3.7/site-packages/flask/app.py", line 1821, in handle_user_exception
Dec 15 02:06:02 db-test-oege app/web.1 reraise(exc_type, exc_value, tb)
Dec 15 02:06:02 db-test-oege app/web.1 File "/app/.heroku/python/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
Dec 15 02:06:02 db-test-oege app/web.1 raise value
Dec 15 02:06:02 db-test-oege app/web.1 File "/app/.heroku/python/lib/python3.7/site-packages/flask/app.py", line 1950, in full_dispatch_request
Dec 15 02:06:02 db-test-oege app/web.1 rv = self.dispatch_request()
Dec 15 02:06:02 db-test-oege app/web.1 File "/app/.heroku/python/lib/python3.7/site-packages/flask/app.py", line 1936, in dispatch_request
Dec 15 02:06:02 db-test-oege app/web.1 return self.view_functions[rule.endpoint](**req.view_args)
Dec 15 02:06:02 db-test-oege app/web.1 File "/app/.heroku/python/lib/python3.7/site-packages/dash/dash.py", line 1075, in dispatch
Dec 15 02:06:02 db-test-oege app/web.1 raise KeyError(msg.format(output))
Dec 15 02:06:02 db-test-oege app/web.1 KeyError: "Callback function not found for output 'pdp-graph-AGdDw6dDQk.figure', perhaps you forgot to prepend the '@'?"
So the callbacks are not working for some reason (hence why you don't see the graphs, nor does the random index button work)...
I will have to investigate why, but it is very odd that it works for the titanicexplainer.herokuapp.com deployment but not for this one. Hmm.
Got it: change Procfile
to:
web: gunicorn --preload dashboard:app
Not sure exactly what is so magical about preload
(not a gunicorn expert), but if you don't add it all kind of weird stuff starts to happen.
I think I have an idea what is going one:
https://docs.gunicorn.org/en/stable/settings.html:
preload_app
--preload
False
Load application code before the worker processes are forked.
In order to make sure that all dash elements are unique, I add a random uuid
string at the end of each component id
. This makes it so that you can include multiple ExplainerComponents
of the same type in the same layout, as they will all have unique id
s and callbacks. However if you do not pass --preload
then each gunicorn worker instantiates its own app with its own random uuid
strings at the end of components! So then the different workers do not agree on the names of the id
s and the callbacks fail.
Will add a clearer warning to the docs that --preload
is essential...
Yup, that's it. Damn it, we talked about it exactly 7 days ago!
Edit: Now I can move on to deploy the app via Docker ;-)
I'm having the same error about callbacks not found. The --preload option solves for running from one cotainer with gunicorn, but when scaling with docker swarm the error shows again. Should this be expected? :) Anything I can do to make it work? :)
Ahh, have never tried docker swarm, but could be the same issue: each docker container initializes the component id
s with different random uuid, and so they do not agree on the id's of the components.
The way to get around that is by simply passing every component explicit name
parameters.
Something that is easy to add for your own custom layouts, but I could also do it for the default Composites.
Could you perhaps try to get the following to run during docker swarm? So I set the name
of the ImportancesComponent
to "0"
and
pass block_selector_callbacks=True
to the ExplainerDashboard
.
class ImportancesCompositeWithName(ExplainerComponent):
def __init__(self, explainer):
super().__init__(explainer)
self.importances = ImportancesComponent(explainer, name="0")
self.register_components()
def layout(self):
return html.Div([self.importances.layout()])
db = ExplainerDashboard(explainer, ImportancesCompositeWithName, block_selector_callbacks=True)
db.run()
Figured out a way to make component names deterministic without too much hassle, try the new release: https://github.com/oegedijk/explainerdashboard/releases/tag/v0.2.16.1
hmm, heroku deployment still fails without --preload
even with 0.2.16.1
, so not sure it fixed the issue for docker swarm. But worth a try!
in any case this should make it easier to introduce url querystrings later!
Thanks for such as quick response and update. The error remains though.
I deployed it with the new version from pip (0.2.16.1). Double checked the logs so the correct version was installed.
ERROR Exception on /dashboard/_dash-update-component [POST]
Traceback (most recent call last):
File "/opt/venv/lib/python3.7/site-packages/dash/dash.py", line 1072, in dispatch
func = self.callback_map[output]["callback"]
KeyError: '..contributions-table-5f9XA4.children...contributions-table-depth-5f9XA4.options..'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/opt/venv/lib/python3.7/site-packages/flask/app.py", line 2447, in wsgi_app
response = self.full_dispatch_request()
File "/opt/venv/lib/python3.7/site-packages/flask/app.py", line 1952, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/opt/venv/lib/python3.7/site-packages/flask/app.py", line 1821, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/opt/venv/lib/python3.7/site-packages/flask/_compat.py", line 39, in reraise
raise value
File "/opt/venv/lib/python3.7/site-packages/flask/app.py", line 1950, in full_dispatch_request
rv = self.dispatch_request()
File "/opt/venv/lib/python3.7/site-packages/flask/app.py", line 1936, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/opt/venv/lib/python3.7/site-packages/dash/dash.py", line 1075, in dispatch
raise KeyError(msg.format(output))
KeyError: "Callback function not found for output '..contributions-table-5f9XA4.children...contributions-table-depth-5f9XA4.options..', perhaps you forgot to prepend the '@'?"
I still see a uuid
name: the 5f9XA4
in contributions-table-5f9XA4
.
Is this a custom layout or a default dashboard?
Ah, I guess you're probably using ExplainerDashboard.from_config()? I realize I had not adjusted that code yet, so the composites (tabs) still get random uuid names when you load it that way. Will have a look at a fix...
Yes, I am using the ExplainerDashboard.from_config().
Assuming this will contain the changes?
ExplainerDashboard(explainer, ...)
Yes, that should work. Need to still make sure I store the component name
and load it correctly with from_config
. Next release.
So with this latest release (https://github.com/oegedijk/explainerdashboard/releases/tag/v0.2.16.2), it should also work with .from_config()
, at least with the default Composites
. When you write your own custom components, you still need to make sure that the subcomponents get some definite and unique name
parameter. Will think of a way to autodetect when uuid
names get created so that I can issue warnings.
Also tested deploying to heroku without the --preload parameter and that seems to work as well now: https://db-test-oege.herokuapp.com/
Could you test it on your docker swarm? I'm actually also curious why you need to deploy on a docker swarm, do you have that many users simultaneously, or is it just that all dashboard by default are deployed to swarms at your organization?
Could you test it on your docker swarm? I'm actually also curious why you need to deploy on a docker swarm, do you have that many users simultaneously, or is it just that all dashboard by default are deployed to swarms at your organization?
Hi, it is still not working. All our dashboards are deployed by default via docker. It seems like it still assigns uuid names to callbacks. Could it have something to do with running the dashboard through gunicorn and wsgi?
Is this the default dashboard or did you make your own custom dashboards?
So for example, when I call:
db = ExplainerDashboard(explainer)
list(db.app.callback_map.values())
I get the following output, where you can see that all the callback id's end with two digits ('10', '23', etc) instead of a uuid string of length 5.
Do you see the same?
[{'inputs': [{'id': 'importances-depth-10', 'property': 'value'},
{'id': 'importances-group-cats-10', 'property': 'value'},
{'id': 'importances-permutation-or-shap-10', 'property': 'value'},
{'id': 'pos-label-10', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.overview_components.ImportancesComponent.component_callbacks.<locals>.update_importances(depth, cats, permutation_shap, pos_label)>},
{'inputs': [{'id': 'clas-model-summary-cutoff-20', 'property': 'value'},
{'id': 'pos-label-20', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.classifier_components.ClassifierModelSummaryComponent.component_callbacks.<locals>.update_classifier_summary(cutoff, pos_label)>},
{'inputs': [{'id': 'precision-binsize-or-quantiles-21', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.classifier_components.PrecisionComponent.component_callbacks.<locals>.update_div_visibility(bins_or_quantiles)>},
{'inputs': [{'id': 'precision-binsize-21', 'property': 'value'},
{'id': 'precision-quantiles-21', 'property': 'value'},
{'id': 'precision-binsize-or-quantiles-21', 'property': 'value'},
{'id': 'precision-cutoff-21', 'property': 'value'},
{'id': 'precision-multiclass-21', 'property': 'value'},
{'id': 'pos-label-21', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.classifier_components.PrecisionComponent.component_callbacks.<locals>.update_precision_graph(bin_size, quantiles, bins, cutoff, multiclass, pos_label)>},
{'inputs': [{'id': 'confusionmatrix-cutoff-22', 'property': 'value'},
{'id': 'confusionmatrix-percentage-22', 'property': 'value'},
{'id': 'confusionmatrix-binary-22', 'property': 'value'},
{'id': 'pos-label-22', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.classifier_components.ConfusionMatrixComponent.component_callbacks.<locals>.update_confusionmatrix_graph(cutoff, normalized, binary, pos_label)>},
{'inputs': [{'id': 'cumulative-precision-percentile-23', 'property': 'value'},
{'id': 'pos-label-23', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.classifier_components.CumulativePrecisionComponent.component_callbacks.<locals>.update_cumulative_precision_graph(percentile, pos_label)>},
{'inputs': [{'id': 'cumulative-precision-cutoff-23', 'property': 'value'},
{'id': 'pos-label-23', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.classifier_components.CumulativePrecisionComponent.component_callbacks.<locals>.update_cumulative_precision_percentile(cutoff, pos_label)>},
{'inputs': [{'id': 'liftcurve-cutoff-24', 'property': 'value'},
{'id': 'liftcurve-percentage-24', 'property': 'value'},
{'id': 'pos-label-24', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.classifier_components.LiftCurveComponent.component_callbacks.<locals>.update_precision_graph(cutoff, percentage, pos_label)>},
{'inputs': [{'id': 'classification-cutoff-25', 'property': 'value'},
{'id': 'classification-percentage-25', 'property': 'value'},
{'id': 'pos-label-25', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.classifier_components.ClassificationComponent.component_callbacks.<locals>.update_precision_graph(cutoff, percentage, pos_label)>},
{'inputs': [{'id': 'rocauc-cutoff-26', 'property': 'value'},
{'id': 'pos-label-26', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.classifier_components.RocAucComponent.component_callbacks.<locals>.update_precision_graph(cutoff, pos_label)>},
{'inputs': [{'id': 'prauc-cutoff-27', 'property': 'value'},
{'id': 'pos-label-27', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.classifier_components.PrAucComponent.component_callbacks.<locals>.update_precision_graph(cutoff, pos_label)>},
{'inputs': [{'id': 'cutoffconnector-percentile-28', 'property': 'value'},
{'id': 'pos-label-28', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.connectors.CutoffPercentileComponent.component_callbacks.<locals>.update_cutoff(percentile, pos_label)>},
{'inputs': [{'id': 'cutoffconnector-cutoff-28', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.connectors.CutoffConnector.component_callbacks.<locals>.update_cutoffs(cutoff)>},
{'inputs': [{'id': 'random-index-clas-button-30', 'property': 'n_clicks'}],
'state': [{'id': 'random-index-clas-slider-30', 'property': 'value'},
{'id': 'random-index-clas-labels-30', 'property': 'value'},
{'id': 'random-index-clas-pred-or-perc-30', 'property': 'value'},
{'id': 'pos-label-30', 'property': 'value'}],
'callback': <function explainerdashboard.dashboard_components.classifier_components.ClassifierRandomIndexComponent.component_callbacks.<locals>.update_index(n_clicks, slider_range, labels, pred_or_perc, pos_label)>},
{'inputs': [{'id': 'random-index-clas-pred-or-perc-30', 'property': 'value'},
{'id': 'pos-label-30', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.classifier_components.ClassifierRandomIndexComponent.component_callbacks.<locals>.update_slider_label(pred_or_perc, pos_label)>},
{'inputs': [{'id': 'clas-prediction-index-31', 'property': 'value'},
{'id': 'pos-label-31', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.classifier_components.ClassifierPredictionSummaryComponent.component_callbacks.<locals>.update_output_div(index, pos_label)>},
{'inputs': [{'id': 'contributions-graph-index-32', 'property': 'value'},
{'id': 'contributions-graph-depth-32', 'property': 'value'},
{'id': 'contributions-graph-sorting-32', 'property': 'value'},
{'id': 'contributions-graph-orientation-32', 'property': 'value'},
{'id': 'contributions-graph-group-cats-32', 'property': 'value'},
{'id': 'pos-label-32', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.shap_components.ShapContributionsGraphComponent.component_callbacks.<locals>.update_output_div(index, depth, sort, orientation, cats, pos_label)>},
{'inputs': [{'id': 'pdp-group-cats-33', 'property': 'value'}],
'state': [{'id': 'pos-label-33', 'property': 'value'}],
'callback': <function explainerdashboard.dashboard_components.overview_components.PdpComponent.component_callbacks.<locals>.update_pdp_graph(cats, pos_label)>},
{'inputs': [{'id': 'pdp-index-33', 'property': 'value'},
{'id': 'pdp-col-33', 'property': 'value'},
{'id': 'pdp-dropna-33', 'property': 'value'},
{'id': 'pdp-sample-33', 'property': 'value'},
{'id': 'pdp-gridlines-33', 'property': 'value'},
{'id': 'pdp-gridpoints-33', 'property': 'value'},
{'id': 'pos-label-33', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.overview_components.PdpComponent.component_callbacks.<locals>.update_pdp_graph(index, col, drop_na, sample, gridlines, gridpoints, pos_label)>},
{'inputs': [{'id': 'contributions-table-index-34', 'property': 'value'},
{'id': 'contributions-table-depth-34', 'property': 'value'},
{'id': 'contributions-table-sorting-34', 'property': 'value'},
{'id': 'contributions-table-group-cats-34', 'property': 'value'},
{'id': 'pos-label-34', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.shap_components.ShapContributionsTableComponent.component_callbacks.<locals>.update_output_div(index, depth, sort, cats, pos_label)>},
{'inputs': [{'id': 'random-index-clas-index-30', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.connectors.IndexConnector.component_callbacks.<locals>.update_indexes(index)>},
{'inputs': [{'id': 'feature-input-index-40', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.overview_components.FeatureInputComponent.component_callbacks.<locals>.update_whatif_inputs(index)>},
{'inputs': [{'id': 'random-index-clas-button-41', 'property': 'n_clicks'}],
'state': [{'id': 'random-index-clas-slider-41', 'property': 'value'},
{'id': 'random-index-clas-labels-41', 'property': 'value'},
{'id': 'random-index-clas-pred-or-perc-41', 'property': 'value'},
{'id': 'pos-label-41', 'property': 'value'}],
'callback': <function explainerdashboard.dashboard_components.classifier_components.ClassifierRandomIndexComponent.component_callbacks.<locals>.update_index(n_clicks, slider_range, labels, pred_or_perc, pos_label)>},
{'inputs': [{'id': 'random-index-clas-pred-or-perc-41', 'property': 'value'},
{'id': 'pos-label-41', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.classifier_components.ClassifierRandomIndexComponent.component_callbacks.<locals>.update_slider_label(pred_or_perc, pos_label)>},
{'inputs': [{'id': 'pos-label-42', 'property': 'value'},
{'id': 'feature-input-Sex-input-40', 'property': 'value'},
{'id': 'feature-input-Deck-input-40', 'property': 'value'},
{'id': 'feature-input-PassengerClass-input-40', 'property': 'value'},
{'id': 'feature-input-Fare-input-40', 'property': 'value'},
{'id': 'feature-input-Embarked-input-40', 'property': 'value'},
{'id': 'feature-input-Age-input-40', 'property': 'value'},
{'id': 'feature-input-No_of_siblings_plus_spouses_on_board-input-40',
'property': 'value'},
{'id': 'feature-input-No_of_parents_plus_children_on_board-input-40',
'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.classifier_components.ClassifierPredictionSummaryComponent.component_callbacks.<locals>.update_output_div(pos_label, *inputs)>},
{'inputs': [{'id': 'contributions-graph-depth-43', 'property': 'value'},
{'id': 'contributions-graph-sorting-43', 'property': 'value'},
{'id': 'contributions-graph-orientation-43', 'property': 'value'},
{'id': 'contributions-graph-group-cats-43', 'property': 'value'},
{'id': 'pos-label-43', 'property': 'value'},
{'id': 'feature-input-Sex-input-40', 'property': 'value'},
{'id': 'feature-input-Deck-input-40', 'property': 'value'},
{'id': 'feature-input-PassengerClass-input-40', 'property': 'value'},
{'id': 'feature-input-Fare-input-40', 'property': 'value'},
{'id': 'feature-input-Embarked-input-40', 'property': 'value'},
{'id': 'feature-input-Age-input-40', 'property': 'value'},
{'id': 'feature-input-No_of_siblings_plus_spouses_on_board-input-40',
'property': 'value'},
{'id': 'feature-input-No_of_parents_plus_children_on_board-input-40',
'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.shap_components.ShapContributionsGraphComponent.component_callbacks.<locals>.update_output_div(depth, sort, orientation, cats, pos_label, *inputs)>},
{'inputs': [{'id': 'contributions-table-depth-44', 'property': 'value'},
{'id': 'contributions-table-sorting-44', 'property': 'value'},
{'id': 'contributions-table-group-cats-44', 'property': 'value'},
{'id': 'pos-label-44', 'property': 'value'},
{'id': 'feature-input-Sex-input-40', 'property': 'value'},
{'id': 'feature-input-Deck-input-40', 'property': 'value'},
{'id': 'feature-input-PassengerClass-input-40', 'property': 'value'},
{'id': 'feature-input-Fare-input-40', 'property': 'value'},
{'id': 'feature-input-Embarked-input-40', 'property': 'value'},
{'id': 'feature-input-Age-input-40', 'property': 'value'},
{'id': 'feature-input-No_of_siblings_plus_spouses_on_board-input-40',
'property': 'value'},
{'id': 'feature-input-No_of_parents_plus_children_on_board-input-40',
'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.shap_components.ShapContributionsTableComponent.component_callbacks.<locals>.update_output_div(depth, sort, cats, pos_label, *inputs)>},
{'inputs': [{'id': 'pdp-group-cats-45', 'property': 'value'}],
'state': [{'id': 'pos-label-45', 'property': 'value'}],
'callback': <function explainerdashboard.dashboard_components.overview_components.PdpComponent.component_callbacks.<locals>.update_pdp_graph(cats, pos_label)>},
{'inputs': [{'id': 'pdp-col-45', 'property': 'value'},
{'id': 'pdp-dropna-45', 'property': 'value'},
{'id': 'pdp-sample-45', 'property': 'value'},
{'id': 'pdp-gridlines-45', 'property': 'value'},
{'id': 'pdp-gridpoints-45', 'property': 'value'},
{'id': 'pos-label-45', 'property': 'value'},
{'id': 'feature-input-Sex-input-40', 'property': 'value'},
{'id': 'feature-input-Deck-input-40', 'property': 'value'},
{'id': 'feature-input-PassengerClass-input-40', 'property': 'value'},
{'id': 'feature-input-Fare-input-40', 'property': 'value'},
{'id': 'feature-input-Embarked-input-40', 'property': 'value'},
{'id': 'feature-input-Age-input-40', 'property': 'value'},
{'id': 'feature-input-No_of_siblings_plus_spouses_on_board-input-40',
'property': 'value'},
{'id': 'feature-input-No_of_parents_plus_children_on_board-input-40',
'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.overview_components.PdpComponent.component_callbacks.<locals>.update_pdp_graph(col, drop_na, sample, gridlines, gridpoints, pos_label, *inputs)>},
{'inputs': [{'id': 'random-index-clas-index-41', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.connectors.IndexConnector.component_callbacks.<locals>.update_indexes(index)>},
{'inputs': [{'id': 'shap-summary-graph-50', 'property': 'clickData'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.shap_components.ShapSummaryComponent.component_callbacks.<locals>.display_scatter_click_data(clickdata)>},
{'inputs': [{'id': 'shap-summary-type-50', 'property': 'value'},
{'id': 'shap-summary-group-cats-50', 'property': 'value'},
{'id': 'shap-summary-depth-50', 'property': 'value'},
{'id': 'shap-summary-index-50', 'property': 'value'},
{'id': 'pos-label-50', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.shap_components.ShapSummaryComponent.component_callbacks.<locals>.update_shap_summary_graph(summary_type, cats, depth, index, pos_label)>},
{'inputs': [{'id': 'shap-dependence-col-51', 'property': 'value'}],
'state': [{'id': 'shap-dependence-group-cats-51', 'property': 'value'},
{'id': 'pos-label-51', 'property': 'value'}],
'callback': <function explainerdashboard.dashboard_components.shap_components.ShapDependenceComponent.component_callbacks.<locals>.set_color_col_dropdown(col, cats, pos_label)>},
{'inputs': [{'id': 'shap-dependence-color-col-51', 'property': 'value'},
{'id': 'shap-dependence-index-51', 'property': 'value'},
{'id': 'pos-label-51', 'property': 'value'}],
'state': [{'id': 'shap-dependence-col-51', 'property': 'value'}],
'callback': <function explainerdashboard.dashboard_components.shap_components.ShapDependenceComponent.component_callbacks.<locals>.update_dependence_graph(color_col, index, pos_label, col)>},
{'inputs': [{'id': 'shap-dependence-group-cats-51', 'property': 'value'}],
'state': [{'id': 'shap-dependence-col-51', 'property': 'value'}],
'callback': <function explainerdashboard.dashboard_components.shap_components.ShapDependenceComponent.component_callbacks.<locals>.update_dependence_shap_scatter_graph(cats, old_col)>},
{'inputs': [{'id': 'shap-summary-group-cats-50', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.shap_components.ShapSummaryDependenceConnector.component_callbacks.<locals>.update_dependence_shap_scatter_graph(cats)>},
{'inputs': [{'id': 'shap-summary-graph-50', 'property': 'clickData'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.shap_components.ShapSummaryDependenceConnector.component_callbacks.<locals>.display_scatter_click_data(clickdata)>},
{'inputs': [{'id': 'interaction-summary-graph-60', 'property': 'clickData'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.shap_components.InteractionSummaryComponent.component_callbacks.<locals>.display_scatter_click_data(clickdata)>},
{'inputs': [{'id': 'interaction-summary-group-cats-60', 'property': 'value'},
{'id': 'pos-label-60', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.shap_components.InteractionSummaryComponent.component_callbacks.<locals>.update_interaction_scatter_graph(cats, pos_label)>},
{'inputs': [{'id': 'interaction-summary-col-60', 'property': 'value'},
{'id': 'interaction-summary-depth-60', 'property': 'value'},
{'id': 'interaction-summary-type-60', 'property': 'value'},
{'id': 'interaction-summary-index-60', 'property': 'value'},
{'id': 'pos-label-60', 'property': 'value'},
{'id': 'interaction-summary-group-cats-60', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.shap_components.InteractionSummaryComponent.component_callbacks.<locals>.update_interaction_scatter_graph(col, depth, summary_type, index, pos_label, cats)>},
{'inputs': [{'id': 'interaction-dependence-group-cats-61',
'property': 'value'},
{'id': 'pos-label-61', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.shap_components.InteractionDependenceComponent.component_callbacks.<locals>.update_interaction_dependence_interact_col(cats, pos_label)>},
{'inputs': [{'id': 'interaction-dependence-col-61', 'property': 'value'},
{'id': 'pos-label-61', 'property': 'value'}],
'state': [{'id': 'interaction-dependence-group-cats-61',
'property': 'value'},
{'id': 'interaction-dependence-interact-col-61', 'property': 'value'}],
'callback': <function explainerdashboard.dashboard_components.shap_components.InteractionDependenceComponent.component_callbacks.<locals>.update_interaction_dependence_interact_col(col, pos_label, cats, old_interact_col)>},
{'inputs': [{'id': 'interaction-dependence-interact-col-61',
'property': 'value'},
{'id': 'interaction-dependence-index-61', 'property': 'value'},
{'id': 'pos-label-61', 'property': 'value'},
{'id': 'interaction-dependence-col-61', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.shap_components.InteractionDependenceComponent.component_callbacks.<locals>.update_dependence_graph(interact_col, index, pos_label, col)>},
{'inputs': [{'id': 'interaction-summary-group-cats-60', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.shap_components.InteractionSummaryDependenceConnector.component_callbacks.<locals>.update_dependence_shap_scatter_graph(cats)>},
{'inputs': [{'id': 'interaction-summary-col-60', 'property': 'value'},
{'id': 'interaction-summary-graph-60', 'property': 'clickData'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.shap_components.InteractionSummaryDependenceConnector.component_callbacks.<locals>.update_interact_col_highlight(col, clickdata)>},
{'inputs': [{'id': 'decisiontrees-index-70', 'property': 'value'},
{'id': 'decisiontrees-highlight-70', 'property': 'value'},
{'id': 'pos-label-70', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.decisiontree_components.DecisionTreesComponent.component_callbacks.<locals>.update_tree_graph(index, highlight, pos_label)>},
{'inputs': [{'id': 'decisiontrees-graph-70', 'property': 'clickData'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.decisiontree_components.DecisionTreesComponent.component_callbacks.<locals>.update_highlight(clickdata)>},
{'inputs': [{'id': 'decisionpath-table-index-71', 'property': 'value'},
{'id': 'decisionpath-table-highlight-71', 'property': 'value'},
{'id': 'pos-label-71', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.decisiontree_components.DecisionPathTableComponent.component_callbacks.<locals>.update_decisiontree_table(index, highlight, pos_label)>},
{'inputs': [{'id': 'random-index-clas-button-72', 'property': 'n_clicks'}],
'state': [{'id': 'random-index-clas-slider-72', 'property': 'value'},
{'id': 'random-index-clas-labels-72', 'property': 'value'},
{'id': 'random-index-clas-pred-or-perc-72', 'property': 'value'},
{'id': 'pos-label-72', 'property': 'value'}],
'callback': <function explainerdashboard.dashboard_components.classifier_components.ClassifierRandomIndexComponent.component_callbacks.<locals>.update_index(n_clicks, slider_range, labels, pred_or_perc, pos_label)>},
{'inputs': [{'id': 'random-index-clas-pred-or-perc-72', 'property': 'value'},
{'id': 'pos-label-72', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.classifier_components.ClassifierRandomIndexComponent.component_callbacks.<locals>.update_slider_label(pred_or_perc, pos_label)>},
{'inputs': [{'id': 'decisionpath-button-73', 'property': 'n_clicks'}],
'state': [{'id': 'decisionpath-index-73', 'property': 'value'},
{'id': 'decisionpath-highlight-73', 'property': 'value'},
{'id': 'pos-label-73', 'property': 'value'}],
'callback': <function explainerdashboard.dashboard_components.decisiontree_components.DecisionPathGraphComponent.component_callbacks.<locals>.update_tree_graph(n_clicks, index, highlight, pos_label)>},
{'inputs': [{'id': 'random-index-clas-index-72', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.connectors.IndexConnector.component_callbacks.<locals>.update_indexes(index)>},
{'inputs': [{'id': 'decisiontrees-highlight-70', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.connectors.HighlightConnector.component_callbacks.<locals>.update_highlights(highlight)>},
{'inputs': [{'id': 'pos-label-0', 'property': 'value'}],
'state': [],
'callback': <function explainerdashboard.dashboard_components.connectors.PosLabelConnector.component_callbacks.<locals>.update_pos_labels(pos_label)>}]
I am using the default dashboard, and just switch things off and on in the dashboard.yaml file.
So when i do
dashboard = ExplainerDashboard(explainer, server=app, url_base_pathname="/dashboard/", **params)
list(dashboard.app.callback_map.values())
i get the following output, which seems to have the uuid extension.
[{'inputs': [{'id': 'random-index-clas-button-DKVkx0', 'property': 'n_clicks'}], 'state': [{'id': 'random-index-clas-slider-DKVkx0', 'property': 'value'}, {'id': 'random-index-clas-labels-DKVkx0', 'property': 'value'}, {'id': 'random-index-clas-pred-or-perc-DKVkx0', 'property': 'value'}, {'id': 'pos-label-DKVkx0', 'property': 'value'}], 'callback': <function ClassifierRandomIndexComponent.component_callbacks.<locals>.update_index at 0x7efd29c67200>}, {'inputs': [{'id': 'random-index-clas-pred-or-perc-DKVkx0', 'property': 'value'}, {'id': 'pos-label-DKVkx0', 'property': 'value'}], 'state': [], 'callback': <function ClassifierRandomIndexComponent.component_callbacks.<locals>.update_slider_label at 0x7efd29c673b0>}, {'inputs': [{'id': 'clas-prediction-index-DKVkx1', 'property': 'value'}, {'id': 'pos-label-DKVkx1', 'property': 'value'}], 'state': [], 'callback': <function ClassifierPredictionSummaryComponent.component_callbacks.<locals>.update_output_div at 0x7efd29c674d0>}, {'inputs': [{'id': 'contributions-graph-index-DKVkx2', 'property': 'value'}, {'id': 'contributions-graph-depth-DKVkx2', 'property': 'value'}, {'id': 'contributions-graph-sorting-DKVkx2', 'property': 'value'}, {'id': 'contributions-graph-orientation-DKVkx2', 'property': 'value'}, {'id': 'contributions-graph-group-cats-DKVkx2', 'property': 'value'}, {'id': 'pos-label-DKVkx2', 'property': 'value'}], 'state': [], 'callback': <function ShapContributionsGraphComponent.component_callbacks.<locals>.update_output_div at 0x7efd29c675f0>}, {'inputs': [{'id': 'pdp-group-cats-DKVkx3', 'property': 'value'}], 'state': [{'id': 'pos-label-DKVkx3', 'property': 'value'}], 'callback': <function PdpComponent.component_callbacks.<locals>.update_pdp_graph at 0x7efd29c67710>}, {'inputs': [{'id': 'pdp-index-DKVkx3', 'property': 'value'}, {'id': 'pdp-col-DKVkx3', 'property': 'value'}, {'id': 'pdp-dropna-DKVkx3', 'property': 'value'}, {'id': 'pdp-sample-DKVkx3', 'property': 'value'}, {'id': 'pdp-gridlines-DKVkx3', 'property': 'value'}, {'id': 'pdp-gridpoints-DKVkx3', 'property': 'value'}, {'id': 'pos-label-DKVkx3', 'property': 'value'}], 'state': [], 'callback': <function PdpComponent.component_callbacks.<locals>.update_pdp_graph at 0x7efd29c677a0>}, {'inputs': [{'id': 'contributions-table-index-DKVkx4', 'property': 'value'}, {'id': 'contributions-table-depth-DKVkx4', 'property': 'value'}, {'id': 'contributions-table-sorting-DKVkx4', 'property': 'value'}, {'id': 'contributions-table-group-cats-DKVkx4', 'property': 'value'}, {'id': 'pos-label-DKVkx4', 'property': 'value'}], 'state': [], 'callback': <function ShapContributionsTableComponent.component_callbacks.<locals>.update_output_div at 0x7efd29c678c0>}, {'inputs': [{'id': 'random-index-clas-index-DKVkx0', 'property': 'value'}], 'state': [], 'callback': <function IndexConnector.component_callbacks.<locals>.update_indexes at 0x7efd29c679e0>}, {'inputs': [{'id': 'feature-input-index-a4zhT0', 'property': 'value'}], 'state': [], 'callback': <function FeatureInputComponent.component_callbacks.<locals>.update_whatif_inputs at 0x7efd29c67b00>}, {'inputs': [{'id': 'random-index-clas-button-a4zhT1', 'property': 'n_clicks'}], 'state': [{'id': 'random-index-clas-slider-a4zhT1', 'property': 'value'}, {'id': 'random-index-clas-labels-a4zhT1', 'property': 'value'}, {'id': 'random-index-clas-pred-or-perc-a4zhT1', 'property': 'value'}, {'id': 'pos-label-a4zhT1', 'property': 'value'}], 'callback': <function ClassifierRandomIndexComponent.component_callbacks.<locals>.update_index at 0x7efd29c67c20>}, {'inputs': [{'id': 'random-index-clas-pred-or-perc-a4zhT1', 'property': 'value'}, {'id': 'pos-label-a4zhT1', 'property': 'value'}], 'state': [], 'callback': <function ClassifierRandomIndexComponent.component_callbacks.<locals>.update_slider_label at 0x7efd29c67dd0>}, {'inputs': [{'id': 'pos-label-a4zhT2', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_mitkundeoverblik_login-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-rejse_antal-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-sum_bestandspraemie-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-alder-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-avg_police_levetid-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_tilbud-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-max_police_levetid-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-nyeste_forsikringsprodukt-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-har_haft_ulykke-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_nyeste_forsikringsprodukt-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-har_haft_rejse-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg_rejse-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-min_police_levetid-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-uddannelsesfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-indbo_antal-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_skade-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg_personbil-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg_indbo-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-postcode-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-ejd_vaerdi-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-bebo_arl-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-personbil_seneste_salgsdato_id-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-habitation_zone_navn-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-bilfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-ejerforholdsfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-ulykke_antal-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-conzoom_gruppe_navn-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg_ulykke-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-har_haft_indbo-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-boernefaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-civilstandsfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-rejse_seneste_salgsdato_id-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-har_haft_personbil-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-boligtypefaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-conzoom_type_navn-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-formuefaktor_v2-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-seneste_salgskanal_mds-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-personindkomstfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-indbo_seneste_salgsdato_id-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-personbil_antal-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_policelinje-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-ulykke_seneste_salgsdato_id-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-husstandsindkomstfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_acc-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_police-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-beskaeftigelsesfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_svar_nps-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-aldersfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_forste_varsling-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_motor_acc_1y-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-har_haft_barn_ulykke-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg_barn_ulykke-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_varsling-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_personbil_3m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_rejse_3m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_personbil_1m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_rejse_1m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg_motorcykel-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_motorcykel_3m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-max_nps_svar-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-min_nps_svar-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-seneste_svar_nps-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-barn_ulykke_seneste_salgsdato_id-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-mest_brugte_bil_nyvaerdi-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-AU_overall-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-mest_brugte_bil_aarlig_koersel-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-sum_personbil_nyvaerdi-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-sum_aarlig_koersel-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_indbo_1m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-AU_pos-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-motorcykel_seneste_salgsdato_id-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-barn_ulykke_antal-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_indbo_3m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-mest_brugte_bil_segment-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-AU_neg-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-HU_pos-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_ulykke_3m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_varslinger-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_ulykke_1m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-mest_brugte_bil_marketing_segment-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-HU_overall-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_motorcykel_1m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-RP_pos-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_biler_i_huset-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-RP_overall-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-unikke_varslinger-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-motorcykel_antal-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-har_haft_motorcykel-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-FP_neg-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_forste_redning-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-HU_neg-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_redninger-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-UP_pos-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_redning-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-unikke_redninger-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_barn_ulykke_3m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-RP_neg-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-UP_neg-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-FP_pos-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-UP_overall-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-FP_overall-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_personer-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_barn_ulykke_1m-input-a4zhT0', 'property': 'value'}], 'state': [], 'callback': <function ClassifierPredictionSummaryComponent.component_callbacks.<locals>.update_output_div at 0x7efd29c67e60>}, {'inputs': [{'id': 'contributions-graph-depth-a4zhT3', 'property': 'value'}, {'id': 'contributions-graph-sorting-a4zhT3', 'property': 'value'}, {'id': 'contributions-graph-orientation-a4zhT3', 'property': 'value'}, {'id': 'contributions-graph-group-cats-a4zhT3', 'property': 'value'}, {'id': 'pos-label-a4zhT3', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_mitkundeoverblik_login-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-rejse_antal-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-sum_bestandspraemie-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-alder-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-avg_police_levetid-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_tilbud-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-max_police_levetid-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-nyeste_forsikringsprodukt-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-har_haft_ulykke-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_nyeste_forsikringsprodukt-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-har_haft_rejse-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg_rejse-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-min_police_levetid-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-uddannelsesfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-indbo_antal-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_skade-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg_personbil-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg_indbo-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-postcode-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-ejd_vaerdi-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-bebo_arl-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-personbil_seneste_salgsdato_id-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-habitation_zone_navn-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-bilfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-ejerforholdsfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-ulykke_antal-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-conzoom_gruppe_navn-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg_ulykke-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-har_haft_indbo-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-boernefaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-civilstandsfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-rejse_seneste_salgsdato_id-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-har_haft_personbil-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-boligtypefaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-conzoom_type_navn-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-formuefaktor_v2-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-seneste_salgskanal_mds-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-personindkomstfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-indbo_seneste_salgsdato_id-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-personbil_antal-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_policelinje-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-ulykke_seneste_salgsdato_id-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-husstandsindkomstfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_acc-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_police-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-beskaeftigelsesfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_svar_nps-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-aldersfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_forste_varsling-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_motor_acc_1y-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-har_haft_barn_ulykke-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg_barn_ulykke-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_varsling-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_personbil_3m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_rejse_3m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_personbil_1m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_rejse_1m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg_motorcykel-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_motorcykel_3m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-max_nps_svar-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-min_nps_svar-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-seneste_svar_nps-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-barn_ulykke_seneste_salgsdato_id-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-mest_brugte_bil_nyvaerdi-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-AU_overall-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-mest_brugte_bil_aarlig_koersel-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-sum_personbil_nyvaerdi-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-sum_aarlig_koersel-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_indbo_1m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-AU_pos-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-motorcykel_seneste_salgsdato_id-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-barn_ulykke_antal-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_indbo_3m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-mest_brugte_bil_segment-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-AU_neg-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-HU_pos-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_ulykke_3m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_varslinger-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_ulykke_1m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-mest_brugte_bil_marketing_segment-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-HU_overall-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_motorcykel_1m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-RP_pos-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_biler_i_huset-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-RP_overall-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-unikke_varslinger-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-motorcykel_antal-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-har_haft_motorcykel-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-FP_neg-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_forste_redning-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-HU_neg-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_redninger-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-UP_pos-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_redning-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-unikke_redninger-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_barn_ulykke_3m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-RP_neg-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-UP_neg-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-FP_pos-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-UP_overall-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-FP_overall-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_personer-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_barn_ulykke_1m-input-a4zhT0', 'property': 'value'}], 'state': [], 'callback': <function ShapContributionsGraphComponent.component_callbacks.<locals>.update_output_div at 0x7efd29bc6050>}, {'inputs': [{'id': 'contributions-table-depth-a4zhT4', 'property': 'value'}, {'id': 'contributions-table-sorting-a4zhT4', 'property': 'value'}, {'id': 'contributions-table-group-cats-a4zhT4', 'property': 'value'}, {'id': 'pos-label-a4zhT4', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_mitkundeoverblik_login-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-rejse_antal-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-sum_bestandspraemie-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-alder-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-avg_police_levetid-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_tilbud-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-max_police_levetid-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-nyeste_forsikringsprodukt-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-har_haft_ulykke-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_nyeste_forsikringsprodukt-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-har_haft_rejse-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg_rejse-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-min_police_levetid-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-uddannelsesfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-indbo_antal-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_skade-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg_personbil-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg_indbo-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-postcode-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-ejd_vaerdi-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-bebo_arl-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-personbil_seneste_salgsdato_id-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-habitation_zone_navn-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-bilfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-ejerforholdsfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-ulykke_antal-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-conzoom_gruppe_navn-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg_ulykke-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-har_haft_indbo-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-boernefaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-civilstandsfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-rejse_seneste_salgsdato_id-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-har_haft_personbil-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-boligtypefaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-conzoom_type_navn-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-formuefaktor_v2-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-seneste_salgskanal_mds-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-personindkomstfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-indbo_seneste_salgsdato_id-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-personbil_antal-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_policelinje-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-ulykke_seneste_salgsdato_id-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-husstandsindkomstfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_acc-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_police-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-beskaeftigelsesfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_svar_nps-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-aldersfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_forste_varsling-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_motor_acc_1y-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-har_haft_barn_ulykke-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg_barn_ulykke-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_varsling-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_personbil_3m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_rejse_3m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_personbil_1m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_rejse_1m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg_motorcykel-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_motorcykel_3m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-max_nps_svar-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-min_nps_svar-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-seneste_svar_nps-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-barn_ulykke_seneste_salgsdato_id-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-mest_brugte_bil_nyvaerdi-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-AU_overall-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-mest_brugte_bil_aarlig_koersel-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-sum_personbil_nyvaerdi-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-sum_aarlig_koersel-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_indbo_1m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-AU_pos-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-motorcykel_seneste_salgsdato_id-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-barn_ulykke_antal-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_indbo_3m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-mest_brugte_bil_segment-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-AU_neg-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-HU_pos-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_ulykke_3m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_varslinger-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_ulykke_1m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-mest_brugte_bil_marketing_segment-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-HU_overall-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_motorcykel_1m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-RP_pos-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_biler_i_huset-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-RP_overall-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-unikke_varslinger-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-motorcykel_antal-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-har_haft_motorcykel-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-FP_neg-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_forste_redning-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-HU_neg-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_redninger-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-UP_pos-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_redning-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-unikke_redninger-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_barn_ulykke_3m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-RP_neg-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-UP_neg-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-FP_pos-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-UP_overall-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-FP_overall-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_personer-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_barn_ulykke_1m-input-a4zhT0', 'property': 'value'}], 'state': [], 'callback': <function ShapContributionsTableComponent.component_callbacks.<locals>.update_output_div at 0x7efd29bc6170>}, {'inputs': [{'id': 'pdp-group-cats-a4zhT5', 'property': 'value'}], 'state': [{'id': 'pos-label-a4zhT5', 'property': 'value'}], 'callback': <function PdpComponent.component_callbacks.<locals>.update_pdp_graph at 0x7efd29bc6290>}, {'inputs': [{'id': 'pdp-col-a4zhT5', 'property': 'value'}, {'id': 'pdp-dropna-a4zhT5', 'property': 'value'}, {'id': 'pdp-sample-a4zhT5', 'property': 'value'}, {'id': 'pdp-gridlines-a4zhT5', 'property': 'value'}, {'id': 'pdp-gridpoints-a4zhT5', 'property': 'value'}, {'id': 'pos-label-a4zhT5', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_mitkundeoverblik_login-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-rejse_antal-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-sum_bestandspraemie-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-alder-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-avg_police_levetid-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_tilbud-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-max_police_levetid-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-nyeste_forsikringsprodukt-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-har_haft_ulykke-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_nyeste_forsikringsprodukt-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-har_haft_rejse-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg_rejse-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-min_police_levetid-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-uddannelsesfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-indbo_antal-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_skade-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg_personbil-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg_indbo-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-postcode-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-ejd_vaerdi-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-bebo_arl-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-personbil_seneste_salgsdato_id-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-habitation_zone_navn-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-bilfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-ejerforholdsfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-ulykke_antal-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-conzoom_gruppe_navn-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg_ulykke-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-har_haft_indbo-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-boernefaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-civilstandsfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-rejse_seneste_salgsdato_id-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-har_haft_personbil-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-boligtypefaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-conzoom_type_navn-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-formuefaktor_v2-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-seneste_salgskanal_mds-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-personindkomstfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-indbo_seneste_salgsdato_id-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-personbil_antal-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_policelinje-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-ulykke_seneste_salgsdato_id-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-husstandsindkomstfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_acc-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_police-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-beskaeftigelsesfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_svar_nps-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-aldersfaktor-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_forste_varsling-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_motor_acc_1y-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-har_haft_barn_ulykke-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg_barn_ulykke-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_varsling-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_personbil_3m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_rejse_3m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_personbil_1m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_rejse_1m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_nysalg_motorcykel-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_motorcykel_3m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-max_nps_svar-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-min_nps_svar-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-seneste_svar_nps-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-barn_ulykke_seneste_salgsdato_id-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-mest_brugte_bil_nyvaerdi-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-AU_overall-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-mest_brugte_bil_aarlig_koersel-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-sum_personbil_nyvaerdi-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-sum_aarlig_koersel-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_indbo_1m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-AU_pos-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-motorcykel_seneste_salgsdato_id-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-barn_ulykke_antal-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_indbo_3m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-mest_brugte_bil_segment-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-AU_neg-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-HU_pos-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_ulykke_3m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_varslinger-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_ulykke_1m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-mest_brugte_bil_marketing_segment-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-HU_overall-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_motorcykel_1m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-RP_pos-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_biler_i_huset-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-RP_overall-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-unikke_varslinger-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-motorcykel_antal-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-har_haft_motorcykel-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-FP_neg-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_forste_redning-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-HU_neg-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_redninger-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-UP_pos-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-dage_siden_seneste_redning-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-unikke_redninger-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_barn_ulykke_3m-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-RP_neg-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-UP_neg-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-FP_pos-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-UP_overall-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-FP_overall-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_personer-input-a4zhT0', 'property': 'value'}, {'id': 'feature-input-antal_tilbud_barn_ulykke_1m-input-a4zhT0', 'property': 'value'}], 'state': [], 'callback': <function PdpComponent.component_callbacks.<locals>.update_pdp_graph at 0x7efd29bc63b0>}, {'inputs': [{'id': 'random-index-clas-index-a4zhT1', 'property': 'value'}], 'state': [], 'callback': <function IndexConnector.component_callbacks.<locals>.update_indexes at 0x7efd29bc6440>}, {'inputs': [{'id': 'shap-summary-graph-64E3o0', 'property': 'clickData'}], 'state': [], 'callback': <function ShapSummaryComponent.component_callbacks.<locals>.display_scatter_click_data at 0x7efd29bc6560>}, {'inputs': [{'id': 'shap-summary-type-64E3o0', 'property': 'value'}, {'id': 'shap-summary-group-cats-64E3o0', 'property': 'value'}, {'id': 'shap-summary-depth-64E3o0', 'property': 'value'}, {'id': 'shap-summary-index-64E3o0', 'property': 'value'}, {'id': 'pos-label-64E3o0', 'property': 'value'}], 'state': [], 'callback': <function ShapSummaryComponent.component_callbacks.<locals>.update_shap_summary_graph at 0x7efd29bc6680>}, {'inputs': [{'id': 'shap-dependence-col-64E3o1', 'property': 'value'}], 'state': [{'id': 'shap-dependence-group-cats-64E3o1', 'property': 'value'}, {'id': 'pos-label-64E3o1', 'property': 'value'}], 'callback': <function ShapDependenceComponent.component_callbacks.<locals>.set_color_col_dropdown at 0x7efd29bc67a0>}, {'inputs': [{'id': 'shap-dependence-color-col-64E3o1', 'property': 'value'}, {'id': 'shap-dependence-index-64E3o1', 'property': 'value'}, {'id': 'pos-label-64E3o1', 'property': 'value'}], 'state': [{'id': 'shap-dependence-col-64E3o1', 'property': 'value'}], 'callback': <function ShapDependenceComponent.component_callbacks.<locals>.update_dependence_graph at 0x7efd29bc6950>}, {'inputs': [{'id': 'shap-dependence-group-cats-64E3o1', 'property': 'value'}], 'state': [{'id': 'shap-dependence-col-64E3o1', 'property': 'value'}], 'callback': <function ShapDependenceComponent.component_callbacks.<locals>.update_dependence_shap_scatter_graph at 0x7efd29bc6a70>}, {'inputs': [{'id': 'shap-summary-group-cats-64E3o0', 'property': 'value'}], 'state': [], 'callback': <function ShapSummaryDependenceConnector.component_callbacks.<locals>.update_dependence_shap_scatter_graph at 0x7efd29bc6b00>}, {'inputs': [{'id': 'shap-summary-graph-64E3o0', 'property': 'clickData'}], 'state': [], 'callback': <function ShapSummaryDependenceConnector.component_callbacks.<locals>.display_scatter_click_data at 0x7efd29bc6c20>}, {'inputs': [{'id': 'pos-label-0', 'property': 'value'}], 'state': [], 'callback': <function PosLabelConnector.component_callbacks.<locals>.update_pos_labels at 0x7efd29bc6d40>}]
Are you sure you're on the latest (pypi) version (0.2.17)?
In case you're installing through conda: the conda version is a bit behind (0.2.15) because we're dealing with some conda-forge dependency conflicts, and that version has not yet has the uuid
fix implemented.
Im quite sure it is version 0.2.17 we are deploying through docker
looking in indexes: http://artifactory-singlep.p001.alm.brand.dk/artifactory/api/pypi/pypi-virtual/simple Processing /project Requirement already satisfied: explainerdashboard in /opt/venv/lib/python3.7/site-packages (from for-p-afgang-dashboard==0.1.0) (**_0.2.17_**)
but we are also building a venv. So maybe that messes something up?
Shouldn't mess things up, using virtual envs myself. Only thing I can think of right now is that you have a cached build step from the docker build that is still using 0.2.15. So could try to prune the cache and see if that helps.
Will build a dashboard myself inside a docker container, and see if I run into the same issue. Do you have a reproducible example with Dockerfile that generates the error? (can just be with the titanic dataset)
This seems to work fine, with no uuid
strings. Haven't tried with docker swarm though:
generate_dashboard.py
from sklearn.ensemble import RandomForestClassifier
from explainerdashboard import *
from explainerdashboard.datasets import *
X_train, y_train, X_test, y_test = titanic_survive()
model = RandomForestClassifier(n_estimators=50, max_depth=5)
model.fit(X_train, y_train)
explainer = ClassifierExplainer(model, X_test, y_test,
cats=["Sex", 'Deck', 'Embarked'],
labels=['Not Survived', 'Survived'],
descriptions=feature_descriptions)
db = ExplainerDashboard(explainer)
db.to_yaml("dashboard.yaml", explainerfile="explainer.joblib", dump_explainer=True)
run_dashboard.py
import waitress
from explainerdashboard import *
db = ExplainerDashboard.from_config("dashboard.yaml")
print(list(db.app.callback_map.values()))
if __name__ == "__main__":
waitress.serve(db.app.server, host='0.0.0.0', port=9050)
Dockerfile
FROM python:3.8
RUN pip install explainerdashboard
COPY generate_dashboard.py ./
COPY run_dashboard.py ./
RUN python generate_dashboard.py
EXPOSE 9050
CMD ["python", "./run_dashboard.py"]
$ docker build -t explainerdashboard .
$ docker run -p 9050:9050 explainerdashboard
@moeller84 Did you manage to get it to work?
@moeller84 Did you manage to get it to work?
Sorry. No i did not, unfortunatly.
When i read the source code it seems like you are still generating uuids when name is None, but then just suffixing a number in the end.
EDIT: when i recreate your example from above i dont get the generated uuids.
I just tried to deploy my app on Heroku by directly importing the github project. However, I did not manage to "add the buildpack" correctly - I'm still generating a slug larger than 500MB. I did