12 января 2021

πŸ“Š Π’ΡƒΡ‚ΠΎΡ€ΠΈΠ°Π»: визуализация Π΄Π°Π½Π½Ρ‹Ρ… Π² Π²Π΅Π±Π΅ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Python ΠΈ Dash

ΠŸΠΈΡˆΡƒ, ΠΏΠ΅Ρ€Π΅Π²ΠΎΠΆΡƒ ΠΈ ΠΈΠ»Π»ΡŽΡΡ‚Ρ€ΠΈΡ€ΡƒΡŽ IT-ΡΡ‚Π°Ρ‚ΡŒΠΈ. На proglib написал 140 ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»ΠΎΠ². УвлСкаюсь Python, Π²Π΅Π±ΠΎΠΌ ΠΈ Data Science. ΠžΡ‚ΠΊΡ€Ρ‹Ρ‚ ΠΊ Π΄ΠΈΠ°Π»ΠΎΠ³Ρƒ – ссылки Π½Π° соцсСти ΠΈ мСссСндТСры: https://matyushkin.github.io/links/ Если понравился ΡΡ‚ΠΈΠ»ΡŒ излоТСния, упорядочСнный список ΠΏΡƒΠ±Π»ΠΈΠΊΠ°Ρ†ΠΈΠΉ β€” https://github.com/matyushkin/lessons
Π’ этом руководствС ΠΌΡ‹ рассмотрим, ΠΊΠ°ΠΊ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Python ΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ Dash ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ, ΠΎΡ„ΠΎΡ€ΠΌΠΈΡ‚ΡŒ ΠΈ ΠΎΠΏΡƒΠ±Π»ΠΈΠΊΠΎΠ²Π°Ρ‚ΡŒ Π½Π° хостингС ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½ΠΎΠ΅ Π²Π΅Π±-ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ с Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Π°ΠΌΠΈ Π°Π½Π°Π»ΠΈΠ·Π° Π΄Π°Π½Π½Ρ‹Ρ….
πŸ“Š Π’ΡƒΡ‚ΠΎΡ€ΠΈΠ°Π»: визуализация Π΄Π°Π½Π½Ρ‹Ρ… Π² Π²Π΅Π±Π΅ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Python ΠΈ Dash

Данная публикация являСтся Π½Π΅Π·Π½Π°Ρ‡ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎ сокращСнным ΠΏΠ΅Ρ€Π΅Π²ΠΎΠ΄ΠΎΠΌ ΡΡ‚Π°Ρ‚ΡŒΠΈ Π”ΠΈΠ»Π°Π½Π° ΠšΠ°ΡΡ‚ΠΈΠ»ΡŒΠΎ Develop Data Visualization Interfaces in Python With Dash.

***

Если Π΅Ρ‰Π΅ Π½Π΅Π΄Π°Π²Π½ΠΎ созданиС аналитичСских Π²Π΅Π±-ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Ρ‚Ρ€Π΅Π±ΠΎΠ²Π°Π»ΠΎ знания Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… языков программирования, Ρ‚ΠΎ сСгодня Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ интСрфСйс Π²ΠΈΠ·ΡƒΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ Π΄Π°Π½Π½Ρ‹Ρ… Π½Π° чистом Python. Одним ΠΈΠ· популярных инструмСнтов для этого стал Dash, ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‰ΠΈΠΉ спСциалистам ΠΏΠΎ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠ΅ Π΄Π°Π½Π½Ρ‹Ρ… Π΄Π΅ΠΌΠΎΠ½ΡΡ‚Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚Ρ‹ Π² Π²ΠΈΠ΄Π΅ ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹Ρ… Π²Π΅Π±-ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ.

Π’ этом руководствС ΠΌΡ‹ рассмотрим:

  • Как ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Dash
  • ΠžΡΠ½ΠΎΠ²Π½Ρ‹Π΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ
  • Как Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ ΡΡ‚ΠΈΠ»ΡŒ прилоТСния
  • Как ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹ΠΌ
  • Как Ρ€Π°Π·Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π½Π° ΡƒΠ΄Π°Π»Π΅Π½Π½ΠΎΠΌ сСрвСрС (Π½Π° ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ Heroku)

Π§Ρ‚ΠΎ Ρ‚Π°ΠΊΠΎΠ΅ Dash?

Dash ― это ΠΏΠ»Π°Ρ‚Ρ„ΠΎΡ€ΠΌΠ° с ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚Ρ‹ΠΌ исходным ΠΊΠΎΠ΄ΠΎΠΌ для создания интСрфСйсов Π²ΠΈΠ·ΡƒΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ Π΄Π°Π½Π½Ρ‹Ρ…. ПослС выпуска Π² 2017 Π³ΠΎΠ΄Ρƒ Π² Π²ΠΈΠ΄Π΅ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ Python Dash вскорС Π±Ρ‹Π» Ρ€Π°ΡΡˆΠΈΡ€Π΅Π½ для R ΠΈ Julia.

Π‘ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ° создана ΠΈ поддСрТиваСтся канадской ΠΊΠΎΠΌΠΏΠ°Π½ΠΈΠ΅ΠΉ Plotly. Π’ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ, Π²Ρ‹ Π·Π½Π°Π΅Ρ‚Π΅ ΠΎ Π½Π΅ΠΉ ΠΏΠΎ популярным графичСским Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°ΠΌ, носящим Π΅Π΅ Π½Π°Π·Π²Π°Π½ΠΈΠ΅. Plotly ΠΎΡ‚ΠΊΡ€Ρ‹Π»Π° исходный ΠΊΠΎΠ΄ Dash ΠΈ выпустила Π΅Π³ΠΎ ΠΏΠΎ Π»ΠΈΡ†Π΅Π½Π·ΠΈΠΈ MIT, Ρ‚Π°ΠΊ Ρ‡Ρ‚ΠΎ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΡƒ ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ бСсплатно.

Π’ основС Dash Π»Π΅ΠΆΠ°Ρ‚ Ρ‚Ρ€ΠΈ Ρ‚Π΅Ρ…Π½ΠΎΠ»ΠΎΠ³ΠΈΠΈ:

  1. Flask прСдоставляСт Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎΡΡ‚ΡŒ Π²Π΅Π±-сСрвСра.
  2. React ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°Π΅Ρ‚ Π²Π΅Π±-интСрфСйс.
  3. Plotly.js Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΠ΅Ρ‚ Π΄ΠΈΠ°Π³Ρ€Π°ΠΌΠΌΡ‹.

НС Π½ΡƒΠΆΠ½ΠΎ Π±Π΅ΡΠΏΠΎΠΊΠΎΠΈΡ‚ΡŒΡΡ ΠΎ совмСстной Ρ€Π°Π±ΠΎΡ‚Π΅ этих Ρ‚Π΅Ρ…Π½ΠΎΠ»ΠΎΠ³ΠΈΠΉ. НСобходимо лишь Π½Π°ΠΏΠΈΡΠ°Ρ‚ΡŒ ΠΊΠΎΠ΄ Π½Π° Python, R ΠΈΠ»ΠΈ Julia ΠΈ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π½Π΅ΠΌΠ½ΠΎΠ³ΠΎ CSS.

Если Π²Ρ‹ ΠΏΡ€ΠΈΠ²Ρ‹ΠΊΠ»ΠΈ Π°Π½Π°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Python, Dash станСт ΠΏΠΎΠ»Π΅Π·Π½Ρ‹ΠΌ Π΄ΠΎΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ΠΌ вашСго Π½Π°Π±ΠΎΡ€Π° инструмСнтов. Π’ΠΎΡ‚ нСсколько практичСских ΠΏΡ€ΠΈΠΌΠ΅Ρ€ΠΎΠ² возмоТностСй Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ:

Π”Ρ€ΡƒΠ³ΠΈΠ΅ интСрСсныС Π²Π°Ρ€ΠΈΠ°Π½Ρ‚Ρ‹ использования Π²Ρ‹ Π½Π°ΠΉΠ΄Π΅Ρ‚Π΅ Π² Π³Π°Π»Π΅Ρ€Π΅Π΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Dash.

НачинаСм Ρ€Π°Π±ΠΎΡ‚Ρƒ с Dash Π½Π° Python

Π’ качСствС ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π° Π² этом руководствС ΠΌΡ‹ шаг Π·Π° шагом создадим ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΎΠ½Π½ΡƒΡŽ панСль для Π½Π°Π±ΠΎΡ€Π° Π΄Π°Π½Π½Ρ‹Ρ… Kaggle ΠΎ ΠΏΡ€ΠΎΠ΄Π°ΠΆΠ°Ρ… ΠΈ Ρ†Π΅Π½Π°Ρ… Π½Π° Π°Π²ΠΎΠΊΠ°Π΄ΠΎ Π² БША Π·Π° ΠΏΠ΅Ρ€ΠΈΠΎΠ΄ с 2015 ΠΏΠΎ 2018 Π³ΠΎΠ΄.

Настройка Π²ΠΈΡ€Ρ‚ΡƒΠ°Π»ΡŒΠ½ΠΎΠ³ΠΎ окруТСния

Для Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ прилоТСния понадобится ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³ для хранСния ΠΊΠΎΠ΄Π° ΠΈ Π΄Π°Π½Π½Ρ‹Ρ…, Π° Ρ‚Π°ΠΊΠΆΠ΅ чистая Π²ΠΈΡ€Ρ‚ΡƒΠ°Π»ΡŒΠ½Π°Ρ срСда Python 3. Π§Ρ‚ΠΎΠ±Ρ‹ ΠΈΡ… ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ, слСдуйтС ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌ инструкциям для вашСй ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΎΠ½Π½ΠΎΠΉ систСмы.

Windows. ΠžΡ‚ΠΊΡ€ΠΎΠΉΡ‚Π΅ ΠΊΠΎΠΌΠ°Π½Π΄Π½ΡƒΡŽ строку ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚Π΅ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠ΅ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹:

        mkdir avocado_analytics && cd avocado_analytics
python -m venv venv
venv\Scripts\activate.bat
    

ΠŸΠ΅Ρ€Π²Π°Ρ ΠΊΠΎΠΌΠ°Π½Π΄Π° создаст ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° ΠΈ помСняСт Ρ‚Π΅ΠΊΡƒΡ‰ΡƒΡŽ Ρ€Π°Π±ΠΎΡ‡ΡƒΡŽ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΡŽ. Вторая ΠΊΠΎΠΌΠ°Π½Π΄Π° создаст Π²ΠΈΡ€Ρ‚ΡƒΠ°Π»ΡŒΠ½ΡƒΡŽ срСду, Π° послСдняя ΠΊΠΎΠΌΠ°Π½Π΄Π° Π΅Ρ‘ Π°ΠΊΡ‚ΠΈΠ²ΠΈΡ€ΡƒΠ΅Ρ‚. ВмСсто ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ python ΠΌΠΎΠΆΠ΅Ρ‚ ΠΏΠΎΡ‚Ρ€Π΅Π±ΠΎΠ²Π°Ρ‚ΡŒΡΡ ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ ΠΏΡƒΡ‚ΡŒ ΠΊ Ρ„Π°ΠΉΠ»Ρƒ python.exe.

macOS ΠΈΠ»ΠΈ Linux. Бмысл ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΡ… ΠΊΠΎΠΌΠ°Π½Π΄ Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π»Π° ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ‡Π΅Π½ ΠΊΠΎΠΌΠ°Π½Π΄Π°ΠΌ для Windows:

        mkdir avocado_analytics && cd avocado_analytics
python3 -m venv venv
source venv/bin/activate
    

Π”Π°Π»Π΅Π΅ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ Π² Π²ΠΈΡ€Ρ‚ΡƒΠ°Π»ΡŒΠ½ΠΎΠ΅ ΠΎΠΊΡ€ΡƒΠΆΠ΅Π½ΠΈΠ΅ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠ΅ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ:

        python -m pip install dash==1.13.3 pandas==1.0.5
    

Π’ Π²ΠΈΡ€Ρ‚ΡƒΠ°Π»ΡŒΠ½ΡƒΡŽ срСду Π±ΡƒΠ΄ΡƒΡ‚ установлСны Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ Dash ΠΈ pandas. Π’ΠΈΡ€Ρ‚ΡƒΠ°Π»ΡŒΠ½ΠΎΠ΅ ΠΎΠΊΡ€ΡƒΠΆΠ΅Π½ΠΈΠ΅ позволяСт ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½Ρ‹Π΅ вСрсии Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊ, Π°Π½Π°Π»ΠΎΠ³ΠΈΡ‡Π½Ρ‹Π΅ Ρ‚Π΅ΠΌ, Ρ‡Ρ‚ΠΎ использовались Π² этом руководствС.

НаконСц, понадобятся Π½Π΅ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΠΎΠΆΠ½ΠΎ Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ ΠΈΠ· ΡΠΎΠΏΡ€ΠΎΠ²ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Ρ… ΠΌΠ°Ρ‚Π΅Ρ€ΠΈΠ°Π»ΠΎΠ² ΡƒΡ€ΠΎΠΊΠ°.

Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚Π΅ Ρ„Π°ΠΉΠ» с Π΄Π°Π½Π½Ρ‹ΠΌΠΈ avocado.csv Π² ΠΊΠΎΡ€Π½Π΅Π²ΠΎΠΌ ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Π΅ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°. К настоящСму ΠΌΠΎΠΌΠ΅Π½Ρ‚Ρƒ Ρƒ вас Π΄ΠΎΠ»ΠΆΠ½Π° Π±Ρ‹Ρ‚ΡŒ Π²ΠΈΡ€Ρ‚ΡƒΠ°Π»ΡŒΠ½Π°Ρ срСда с Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹ΠΌΠΈ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠ°ΠΌΠΈ ΠΈ Π΄Π°Π½Π½Ρ‹ΠΌΠΈ Π² ΠΊΠΎΡ€Π½Π΅Π²ΠΎΠΉ ΠΏΠ°ΠΏΠΊΠ΅ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°. Π‘Ρ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€Π° ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° выглядит Ρ‚Π°ΠΊ:

        avocado_analytics/
β”œβ”€β”€ venv/
└── avocado.csv
    

Как с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Dash ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅

РазобьСм процСсс создания прилоТСния Dash Π½Π° Π΄Π²Π° этапа:

  1. Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΠΌ внСшний Π²ΠΈΠ΄ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΌΠ°ΠΊΠ΅Ρ‚Π° прилоТСния (layout).
  2. ΠžΠΏΡ€Π΅Π΄Π΅Π»ΠΈΠΌ посрСдством ΠΎΠ±Ρ€Π°Ρ‚Π½Ρ‹Ρ… Π²Ρ‹Π·ΠΎΠ²ΠΎΠ² (callbacks), ΠΊΠ°ΠΊΠΈΠ΅ части прилоТСния ΡΠ²Π»ΡΡŽΡ‚ΡΡ ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹ΠΌΠΈ ΠΈ Π½Π° Ρ‡Ρ‚ΠΎ ΠΎΠ½ΠΈ Ρ€Π΅Π°Π³ΠΈΡ€ΡƒΡŽΡ‚.

Π˜Π½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ Dash-ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅

Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ пустой Ρ„Π°ΠΉΠ» app.py. Π”Π°Π»Π΅Π΅ ΠΌΡ‹ Π±ΡƒΠ΄Π΅ΠΌ шаг Π·Π° шагом Π΅Π³ΠΎ Π·Π°ΠΏΠΎΠ»Π½ΡΡ‚ΡŒ ΠΈ ΠΏΠΎΡΡΠ½ΡΡ‚ΡŒ происходящСС, Π° Π² ΠΊΠΎΠ½Ρ†Π΅ Ρ€Π°Π·Π΄Π΅Π»Π° Π²Ρ‹ Π½Π°ΠΉΠ΄Π΅Ρ‚Π΅ Π΅Π³ΠΎ содСрТимоС Ρ†Π΅Π»ΠΈΠΊΠΎΠΌ.

Π’ΠΎΡ‚ нСсколько ΠΏΠ΅Ρ€Π²Ρ‹Ρ… строк app.py:

        import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd

data = pd.read_csv("avocado.csv")
data = data.query("type == 'conventional' and region == 'Albany'")
data["Date"] = pd.to_datetime(data["Date"], format="%Y-%m-%d")
data.sort_values("Date", inplace=True)

app = dash.Dash(__name__)
    

Π’Π½Π°Ρ‡Π°Π»Π΅ ΠΌΡ‹ ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΡƒΠ΅ΠΌ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ:

  • dash ΠΏΠΎΠΌΠΎΠΆΠ΅Ρ‚ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅
  • dash_core_components позволяСт ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹Π΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹: Π³Ρ€Π°Ρ„ΠΈΠΊΠΈ, Ρ€Π°ΡΠΊΡ€Ρ‹Π²Π°ΡŽΡ‰ΠΈΠ΅ΡΡ списки, Π΄ΠΈΠ°ΠΏΠ°Π·ΠΎΠ½Ρ‹ Π΄Π°Ρ‚ ΠΈ Ρ‚. Π΄.
  • dash_html_components позволяСт ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ доступ ΠΊ Ρ‚Π΅Π³Π°ΠΌ HTML
  • pandas ΠΏΠΎΠΌΠΎΠ³Π°Π΅Ρ‚ Ρ‡ΠΈΡ‚Π°Ρ‚ΡŒ ΠΈ Π²Ρ‹Π²ΠΎΠ΄ΠΈΡ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅ Π² ΠΎΡ€Π³Π°Π½ΠΈΠ·ΠΎΠ²Π°Π½Π½ΠΎΠΉ Ρ„ΠΎΡ€ΠΌΠ΅

Π”Π°Π»Π΅Π΅ ΠΌΡ‹ считываСм Π΄Π°Π½Π½Ρ‹Π΅ ΠΈ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Π΅ΠΌ ΠΈΡ… для использования Π² ΠΏΠ°Π½Π΅Π»ΠΈ управлСния. Π’ послСднСй строкС ΠΌΡ‹ создаСм экзСмпляр класса Dash.

Если Π²Ρ‹ ΡƒΠΆΠ΅ использовали Flask, Ρ‚ΠΎ инициализация класса Dash Π²Π°ΠΌ ΡƒΠΆΠ΅ Π·Π½Π°ΠΊΠΎΠΌΠ°. Π’ΠΎ Flask ΠΌΡ‹ ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΡƒΠ΅ΠΌ WSGI-ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Flask(__name__). Для ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Dash ΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Dash(__name__).

ΠžΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½ΠΈΠ΅ ΠΌΠ°ΠΊΠ΅Ρ‚Π° прилоТСния Dash

Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΡ‹ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΠΌ ΠΌΠ°ΠΊΠ΅Ρ‚ прилоТСния, Π΅Π³ΠΎ внСшний Π²ΠΈΠ΄. Π’ нашСм случаС ΠΌΠ°ΠΊΠ΅Ρ‚ Π±ΡƒΠ΄Π΅Ρ‚ ΡΠΎΡΡ‚ΠΎΡΡ‚ΡŒ ΠΈΠ· Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠ°, описания ΠΈ Π΄Π²ΡƒΡ… Π΄ΠΈΠ°Π³Ρ€Π°ΠΌΠΌ.

        app.layout = html.Div(
    children=[
        html.H1(children="Avocado Analytics",),
        html.P(
            children="Analyze the behavior of avocado prices"
            " and the number of avocados sold in the US"
            " between 2015 and 2018",
        ),
        dcc.Graph(
            figure={
                "data": [
                    {
                        "x": data["Date"],
                        "y": data["AveragePrice"],
                        "type": "lines",
                    },
                ],
                "layout": {"title": "Average Price of Avocados"},
            },
        ),
        dcc.Graph(
            figure={
                "data": [
                    {
                        "x": data["Date"],
                        "y": data["Total Volume"],
                        "type": "lines",
                    },
                ],
                "layout": {"title": "Avocados Sold"},
            },
        ),
    ]
)
    

Π­Ρ‚ΠΎΡ‚ ΠΊΠΎΠ΄ опрСдСляСт свойство layout ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Π° app. Π’Π½Π΅ΡˆΠ½ΠΈΠΉ Π²ΠΈΠ΄ прилоТСния описываСтся с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Π΄Ρ€Π΅Π²ΠΎΠ²ΠΈΠ΄Π½ΠΎΠΉ структуры, состоящСй ΠΈΠ· Dash-ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ².

ΠœΡ‹ Π½Π°Ρ‡ΠΈΠ½Π°Π΅ΠΌ с опрСдСлСния Ρ€ΠΎΠ΄ΠΈΡ‚Π΅Π»ΡŒΡΠΊΠΎΠ³ΠΎ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π° html.Div, Π·Π°Ρ‚Π΅ΠΌ Π² качСствС Π΄ΠΎΡ‡Π΅Ρ€Π½ΠΈΡ… элСмСнтов добавляСм Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ html.H1 ΠΈ Π°Π±Π·Π°Ρ† html.P. Π­Ρ‚ΠΈ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ эквивалСнтны HTML-Ρ‚Π΅Π³Π°ΠΌ div, h1 ΠΈ p. Для измСнСния Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚ΠΎΠ² ΠΈΠ»ΠΈ содСрТимого Ρ‚Π΅Π³ΠΎΠ² ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡŽΡ‚ΡΡ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ². НапримСр, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΡƒΠΊΠ°Π·Π°Ρ‚ΡŒ, Ρ‡Ρ‚ΠΎ находится Π²Π½ΡƒΡ‚Ρ€ΠΈ Ρ‚Π΅Π³Π° div, ΠΌΡ‹ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ Π² html.Div Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ children.

Π’ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°Ρ… Π΅ΡΡ‚ΡŒ ΠΈ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹, Ρ‚Π°ΠΊΠΈΠ΅ ΠΊΠ°ΠΊ style, className ΠΈΠ»ΠΈ id, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ относятся ΠΊ Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚Π°ΠΌ HTML-Ρ‚Π΅Π³ΠΎΠ². Π’ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΌ Ρ€Π°Π·Π΄Π΅Π»Π΅ ΠΌΡ‹ ΡƒΠ²ΠΈΠ΄ΠΈΠΌ, ΠΊΠ°ΠΊ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ эти свойства для стилизации ΠΏΠ°Π½Π΅Π»ΠΈ инструмСнтов.

Π’Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, Python-ΠΊΠΎΠ΄ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ Π² ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ HTML-ΠΊΠΎΠ΄:

        <div>
  <h1>Avocado Analytics</h1>
  <p>
    Analyze the behavior of avocado prices and the number
    of avocados sold in the US between 2015 and 2018
  </p>
  <!-- ΠžΡΡ‚Π°Π»ΡŒΠ½Π°Ρ Ρ‡Π°ΡΡ‚ΡŒ прилоТСния -->
</div>
    

Π”Π°Π»Π΅Π΅ описаны Π΄Π²Π° ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π° dcc.Graph. ΠŸΠ΅Ρ€Π²Π°Ρ Π΄ΠΈΠ°Π³Ρ€Π°ΠΌΠΌΠ° ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°Π΅Ρ‚ срСдниС Ρ†Π΅Π½Ρ‹ Π½Π° Π°Π²ΠΎΠΊΠ°Π΄ΠΎ Π·Π° ΠΏΠ΅Ρ€ΠΈΠΎΠ΄ исслСдования, Π° вторая ― количСство Π°Π²ΠΎΠΊΠ°Π΄ΠΎ, ΠΏΡ€ΠΎΠ΄Π°Π½Π½Ρ‹Ρ… Π² БША Π·Π° Ρ‚ΠΎΡ‚ ΠΆΠ΅ ΠΏΠ΅Ρ€ΠΈΠΎΠ΄.

Под ΠΊΠ°ΠΏΠΎΡ‚ΠΎΠΌ Dash ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ для создания Π³Ρ€Π°Ρ„ΠΈΠΊΠΎΠ² Plotly.js. ΠšΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ dcc.Graph ΠΎΠΆΠΈΠ΄Π°ΡŽΡ‚ figure object ΠΈΠ»ΠΈ ΡΠ»ΠΎΠ²Π°Ρ€ΡŒ Python, содСрТащий Π΄Π°Π½Π½Ρ‹Π΅ Π³Ρ€Π°Ρ„ΠΈΠΊΠ° ΠΈ layout, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ ΠΈ ΠΏΠ΅Ρ€Π΅Π΄Π°Π΅ΠΌ Π² нашСм случаС.

ΠžΡΡ‚Π°Π»ΠΈΡΡŒ Π΄Π²Π΅ строки ΠΊΠΎΠ΄Π°, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΠΎΠΌΠΎΠ³ΡƒΡ‚ Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅:

        if __name__ == "__main__":
    app.run_server(debug=True,
                   host = '127.0.0.1')
    

Π­Ρ‚ΠΈ строки ΠΏΠΎΠ·Π²ΠΎΠ»ΡΡŽΡ‚ Π·Π°ΠΏΡƒΡΠΊΠ°Ρ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Dash локально, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΡ встроСнный сСрвСр Flask. ΠŸΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ debug = True ΠΈΠ· app.run_server Ρ€Π°Π·Ρ€Π΅ΡˆΠ°Π΅Ρ‚ Π³ΠΎΡ€ΡΡ‡ΡƒΡŽ ΠΏΠ΅Ρ€Π΅Π·Π°Π³Ρ€ΡƒΠ·ΠΊΡƒ: ΠΊΠΎΠ³Π΄Π° ΠΌΡ‹ вносим измСнСния Π² ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅, ΠΎΠ½ΠΎ автоматичСски пСрСзагруТаСтся Π±Π΅Π· пСрСзапуска сСрвСра.

НаконСц, полная вСрсия app.py. Π’Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΡΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΊΠΎΠ΄ Π² пустой app.py ΠΈ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚.

app.py
        import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd

data = pd.read_csv("avocado.csv")
data = data.query("type == 'conventional' and region == 'Albany'")
data["Date"] = pd.to_datetime(data["Date"], format="%Y-%m-%d")
data.sort_values("Date", inplace=True)

app = dash.Dash(__name__)

app.layout = html.Div(
    children=[
        html.H1(children="Avocado Analytics",),
        html.P(
            children="Analyze the behavior of avocado prices"
            " and the number of avocados sold in the US"
            " between 2015 and 2018",
        ),
        dcc.Graph(
            figure={
                "data": [
                    {
                        "x": data["Date"],
                        "y": data["AveragePrice"],
                        "type": "lines",
                    },
                ],
                "layout": {"title": "Average Price of Avocados"},
            },
        ),
        dcc.Graph(
            figure={
                "data": [
                    {
                        "x": data["Date"],
                        "y": data["Total Volume"],
                        "type": "lines",
                    },
                ],
                "layout": {"title": "Avocados Sold"},
            },
        ),
    ]
)

if __name__ == "__main__":
    app.run_server(debug=True,
                   host = '127.0.0.1')
    

ΠŸΡ€ΠΈΡˆΠ»ΠΎ врСмя Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅. ΠžΡ‚ΠΊΡ€ΠΎΠΉΡ‚Π΅ Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π» Π² ΠΊΠΎΡ€Π½Π΅Π²ΠΎΠΌ ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Π΅ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° ΠΈ Π² Π²ΠΈΡ€Ρ‚ΡƒΠ°Π»ΡŒΠ½ΠΎΠΉ срСдС ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°. ЗапуститС python app.py, Π·Π°Ρ‚Π΅ΠΌ ΠΏΠ΅Ρ€Π΅ΠΉΠ΄ΠΈΡ‚Π΅ ΠΏΠΎ адрСсу http://localhost:8050.

ПанСль управлСния Π΄ΠΎΠ»ΠΆΠ½Π° Π²Ρ‹Π³Π»ΡΠ΄Π΅Ρ‚ΡŒ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π½ΠΎ Ρ‚Π°ΠΊ:

πŸ“Š Π’ΡƒΡ‚ΠΎΡ€ΠΈΠ°Π»: визуализация Π΄Π°Π½Π½Ρ‹Ρ… Π² Π²Π΅Π±Π΅ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Python ΠΈ Dash

Π’Π΅ΠΏΠ΅Ρ€ΡŒ Ρƒ нас Π΅ΡΡ‚ΡŒ рабочая вСрсия, Π½ΠΎ ΠΌΡ‹ Π΅Π΅ Π΅Ρ‰Π΅ ΡƒΠ»ΡƒΡ‡ΡˆΠΈΠΌ.

Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΎΡ„ΠΎΡ€ΠΌΠ»Π΅Π½ΠΈΠ΅ΠΌ ΠΏΠ°Π½Π΅Π»ΠΈ

Dash ΠΎΡ‡Π΅Π½ΡŒ Π³ΠΈΠ±ΠΎΠΊ Π² настройкС внСшнСго Π²ΠΈΠ΄Π° прилоТСния. ΠœΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ собствСнныС Ρ„Π°ΠΉΠ»Ρ‹ CSS ΠΈΠ»ΠΈ JavaScript, Π²ΡΡ‚Ρ€Π°ΠΈΠ²Π°Ρ‚ΡŒ изобраТСния ΠΈ Π½Π°ΡΡ‚Ρ€Π°ΠΈΠ²Π°Ρ‚ΡŒ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡ‚Π΅Π»ΡŒΠ½Ρ‹Π΅ ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹.

Как ΠΏΡ€ΠΈΠΌΠ΅Π½ΠΈΡ‚ΡŒ ΡΡ‚ΠΈΠ»ΡŒ ΠΊ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°ΠΌ Dash

Π‘Ρ‚ΠΈΠ»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ ΠΌΠΎΠΆΠ½ΠΎ двумя способами:

  • Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ style ΠΎΡ‚Π΄Π΅Π»ΡŒΠ½Ρ‹Ρ… ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ².
  • ΠŸΡ€Π΅Π΄ΠΎΡΡ‚Π°Π²ΠΈΡ‚ΡŒ внСшний CSS-Ρ„Π°ΠΉΠ».

АргумСнт style ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ ΡΠ»ΠΎΠ²Π°Ρ€ΡŒ Python с ΠΏΠ°Ρ€Π°ΠΌΠΈ ΠΊΠ»ΡŽΡ‡-Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅, состоящими ΠΈΠ· ΠΈΠΌΠ΅Π½ свойств CSS ΠΈ Π·Π½Π°Ρ‡Π΅Π½ΠΈΠΉ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΡ‹ Ρ…ΠΎΡ‚ΠΈΠΌ ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ.

ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΠ΅
ΠŸΡ€ΠΈ ΡƒΠΊΠ°Π·Π°Π½ΠΈΠΈ свойств CSS Π² Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π΅ style Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ синтаксис Π²ΠΈΠ΄Π° mixedCase вмСсто слов, Ρ€Π°Π·Π΄Π΅Π»Π΅Π½Π½Ρ‹Ρ… дСфисом. НапримСр, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Ρ†Π²Π΅Ρ‚ Ρ„ΠΎΠ½Π° элСмСнта, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Ρ‚ΡŒ backgroundColor, Π° Π½Π΅ background-color.

Π—Π°Ρ…ΠΎΡ‚Π΅Π² ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Ρ€Π°Π·ΠΌΠ΅Ρ€ ΠΈ Ρ†Π²Π΅Ρ‚ элСмСнта H1 Π² app.py, ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ style ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ:

        html.H1(
    children="Avocado Analytics",
    style={"fontSize": "48px", "color": "red"},
),
    

Π’ этом случаС Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΡ„ΠΎΡ€ΠΌΠ»Π΅Π½ красным ΡˆΡ€ΠΈΡ„Ρ‚ΠΎΠΌ Ρ€Π°Π·ΠΌΠ΅Ρ€ΠΎΠΌ Π² 48 пиксСлСй.

ΠžΠ±Ρ€Π°Ρ‚Π½Π°Ρ сторона простоты использования style ― Ρ‚Π°ΠΊΠΎΠΉ ΠΊΠΎΠ΄ Π±ΡƒΠ΄Π΅Ρ‚ всё Ρ‚Ρ€ΡƒΠ΄Π½Π΅Π΅ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Ρ‚ΡŒ ΠΏΠΎ ΠΌΠ΅Ρ€Π΅ роста ΠΊΠΎΠ΄ΠΎΠ²ΠΎΠΉ Π±Π°Π·Ρ‹. Если Π½Π° ΠΏΠ°Π½Π΅Π»ΠΈ управлСния присутствуСт нСсколько ΠΎΠ΄ΠΈΠ½Π°ΠΊΠΎΠ²Ρ‹Ρ… ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ², большая Ρ‡Π°ΡΡ‚ΡŒ ΠΊΠΎΠ΄Π° Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠΎΠ²Ρ‚ΠΎΡ€ΡΡ‚ΡŒΡΡ. ВмСсто этого ΠΌΠΎΠΆΠ½ΠΎ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ CSS-Ρ„Π°ΠΉΠ».

Если Π²Ρ‹ Ρ…ΠΎΡ‚ΠΈΡ‚Π΅ Π²ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ собствСнныС Π»ΠΎΠΊΠ°Π»ΡŒΠ½Ρ‹Π΅ CSS- ΠΈΠ»ΠΈ JavaScript-Ρ„Π°ΠΉΠ»Ρ‹, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ Π² ΠΊΠΎΡ€Π½Π΅Π²ΠΎΠΌ ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Π΅ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° ΠΏΠ°ΠΏΠΊΡƒ с ΠΈΠΌΠ΅Π½Π΅ΠΌ assets/ ΠΈ ΡΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ Π² Π½Π΅ΠΉ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ Ρ„Π°ΠΉΠ»Ρ‹.

Π—Π°Ρ‚Π΅ΠΌ Π²Ρ‹ ΠΌΠΎΠΆΠ΅Ρ‚Π΅ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹ className ΠΈΠ»ΠΈ id ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ², Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ CSS ΠΈΡ… стили. ΠŸΡ€ΠΈ ΠΏΡ€Π΅ΠΎΠ±Ρ€Π°Π·ΠΎΠ²Π°Π½ΠΈΠΈ Π² HTML-Ρ‚Π΅Π³ΠΈ эти Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Ρ‹ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‚ Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚Π°ΠΌ class ΠΈ id.

Π—Π°Ρ…ΠΎΡ‚Π΅Π² Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ Ρ€Π°Π·ΠΌΠ΅Ρ€ ΡˆΡ€ΠΈΡ„Ρ‚Π° ΠΈ Ρ†Π²Π΅Ρ‚ тСкста элСмСнта H1 Π² app.py, ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ className:

        html.H1(
    children="Avocado Analytics",
    className="header-title",
),

    

Установка Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π° className опрСдСляСт Π°Ρ‚Ρ€ΠΈΠ±ΡƒΡ‚ класса для элСмСнта H1. Π—Π°Ρ‚Π΅ΠΌ Π² CSS-Ρ„Π°ΠΉΠ»Π΅ style.css Π² ΠΏΠ°ΠΏΠΊΠ΅ assets/ ΠΌΡ‹ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅ΠΌ, ΠΊΠ°ΠΊ Ρ…ΠΎΡ‚ΠΈΠΌ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΠ½ выглядСл:

        .header-title {
  font-size: 48px;
  color: red;
}
    

Как ΡƒΠ»ΡƒΡ‡ΡˆΠΈΡ‚ΡŒ внСшний Π²ΠΈΠ΄ ΠΏΠ°Π½Π΅Π»ΠΈ инструмСнтов

Π”Π°Π²Π°ΠΉΡ‚Π΅ ΡƒΠ·Π½Π°Π΅ΠΌ, ΠΊΠ°ΠΊ Π½Π°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ внСшний Π²ΠΈΠ΄ ΠΏΠ°Π½Π΅Π»ΠΈ инструмСнтов. ВнСсСм ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠ΅ ΡƒΠ»ΡƒΡ‡ΡˆΠ΅Π½ΠΈΡ:

  • Π”ΠΎΠ±Π°Π²ΠΈΠΌ ΠΈΠΊΠΎΠ½ΠΊΡƒ сайта (favicon) ΠΈ title.
  • ИзмСним сСмСйство ΡˆΡ€ΠΈΡ„Ρ‚ΠΎΠ².
  • Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌ внСшний CSS-Ρ„Π°ΠΉΠ» для стилизации ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ² Dash.

Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ Π² ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π²Π½Π΅ΡˆΠ½ΠΈΡ… рСсурсов

Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ ΠΏΠ°ΠΏΠΊΡƒ assets/ Π² ΠΊΠΎΡ€Π½Π΅Π²ΠΎΠΌ ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Π΅ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°. Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΠΌ Π² Π½Π΅ΠΉ Π·Π½Π°Ρ‡ΠΎΠΊ favicon.ico ΠΈ Ρ„Π°ΠΉΠ» style.css.

К настоящСму ΠΌΠΎΠΌΠ΅Π½Ρ‚Ρƒ структура ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° Π΄ΠΎΠ»ΠΆΠ½Π° Π²Ρ‹Π³Π»ΡΠ΄Π΅Ρ‚ΡŒ Ρ‚Π°ΠΊ:

        avocado_analytics/
β”œβ”€β”€ assets/
β”‚   β”œβ”€β”€ favicon.ico
β”‚   └── style.css
β”œβ”€β”€ venv/
β”œβ”€β”€ app.py
└── avocado.csv
    

app.py Ρ‚Ρ€Π΅Π±ΡƒΠ΅Ρ‚ Π½Π΅ΡΠΊΠΎΠ»ΡŒΠΊΠΈΡ… ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΉ. НСобходимо Π²ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ внСшнюю Ρ‚Π°Π±Π»ΠΈΡ†Ρƒ стилСй, Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ Π½Π° панСль инструмСнтов ΠΈ ΡΡ‚ΠΈΠ»ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Ρ„Π°ΠΉΠ»Π° style.css:

        external_stylesheets = [
    {
        "href": "https://fonts.googleapis.com/css2?"
                "family=Lato:wght@400;700&display=swap",
        "rel": "stylesheet",
    },
]
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.title = "Avocado Analytics: Understand Your Avocados!"
    

Π—Π΄Π΅ΡΡŒ ΠΌΡ‹ ΡƒΠΊΠ°Π·Ρ‹Π²Π°Π΅ΠΌ CSS-Ρ„Π°ΠΉΠ» ΠΈ сСмСйство ΡˆΡ€ΠΈΡ„Ρ‚ΠΎΠ², ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Ρ…ΠΎΡ‚ΠΈΠΌ Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ Π² ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅. Π’Π½Π΅ΡˆΠ½ΠΈΠ΅ Ρ„Π°ΠΉΠ»Ρ‹ Π·Π°Π³Ρ€ΡƒΠΆΠ°ΡŽΡ‚ΡΡ Π΄ΠΎ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ Ρ‚Π΅Π»Π° прилоТСния. АргумСнт external_stylesheets ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ для добавлСния Π²Π½Π΅ΡˆΠ½ΠΈΡ… CSS-Ρ„Π°ΠΉΠ»ΠΎΠ², Π° external_scripts ― для Π²Π½Π΅ΡˆΠ½ΠΈΡ… Ρ„Π°ΠΉΠ»ΠΎΠ² JavaScript, Ρ‚Π°ΠΊΠΈΡ… ΠΊΠ°ΠΊ скрипт Google Analytics.

Настройка стилСй ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ²

Π’ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½ΠΎΠΌ Π½ΠΈΠΆΠ΅ ΠΊΠΎΠ΄Π΅ ΠΌΡ‹ добавляСм className с ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΌ сСлСктором классов ΠΊ ΠΊΠ°ΠΆΠ΄ΠΎΠΌΡƒ ΠΈΠ· ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠ², ΠΏΡ€Π΅Π΄ΡΡ‚Π°Π²Π»ΡΡŽΡ‰ΠΈΡ… Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΎΠΊ ΠΈΠ½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΠΎΠ½Π½ΠΎΠΉ ΠΏΠ°Π½Π΅Π»ΠΈ:

        app.layout = html.Div(
    children=[
        html.Div(
            children=[
                html.P(children="πŸ₯‘", className="header-emoji"),
                html.H1(
                    children="Avocado Analytics", className="header-title"
                ),
                html.P(
                    children="Analyze the behavior of avocado prices"
                    " and the number of avocados sold in the US"
                    " between 2015 and 2018",
                    className="header-description",
                ),
            ],
            className="header",
        ),
    

Класс header-description, Π½Π°Π·Π½Π°Ρ‡Π΅Π½Π½Ρ‹ΠΉ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρƒ Π°Π±Π·Π°Ρ†Π°, ΠΈΠΌΠ΅Π΅Ρ‚ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΉ сСлСктор Π² style.css:

        .header-description {
    color: #CFCFCF;
    margin: 4px auto;
    text-align: center;
    max-width: 384px;
}
    

Π”Ρ€ΡƒΠ³ΠΎΠ΅ сущСствСнноС ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ ― Π³Ρ€Π°Ρ„ΠΈΠΊΠΈ. Новый ΠΊΠΎΠ΄ для Π³Ρ€Π°Ρ„ΠΈΠΊΠ° Ρ†Π΅Π½Ρ‹:

        html.Div(
    children=[
        html.Div(
            children=dcc.Graph(
                id="price-chart",
                config={"displayModeBar": False},
                figure={
                    "data": [
                        {
                            "x": data["Date"],
                            "y": data["AveragePrice"],
                            "type": "lines",
                            "hovertemplate": "$%{y:.2f}"
                                                "<extra></extra>",
                        },
                    ],
                    "layout": {
                        "title": {
                            "text": "Average Price of Avocados",
                            "x": 0.05,
                            "xanchor": "left",
                        },
                        "xaxis": {"fixedrange": True},
                        "yaxis": {
                            "tickprefix": "$",
                            "fixedrange": True,
                        },
                        "colorway": ["#17B897"],
                    },
                },
            ),
            className="card",
        ),
    

ΠœΡ‹ ΡƒΠ΄Π°Π»ΠΈΠ»ΠΈ полоску, которая отобраТаСтся Π½Π° Π³Ρ€Π°Ρ„ΠΈΠΊΠ΅ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ, установили шаблон навСдСния Ρ‚Π°ΠΊΠΈΠΌ ΠΎΠ±Ρ€Π°Π·ΠΎΠΌ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΡ€ΠΈ Π½Π°Π²Π΅Π΄Π΅Π½ΠΈΠΈ курсора Π½Π° Ρ‚ΠΎΡ‡ΠΊΡƒ Π΄Π°Π½Π½Ρ‹Ρ… ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°Π»Π°ΡΡŒ Ρ†Π΅Π½Π° Π² Π΄ΠΎΠ»Π»Π°Ρ€Π°Ρ…. ВмСсто 2.5 Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°Ρ‚ΡŒΡΡ $2.5.

Π’Π°ΠΊ ΠΆΠ΅ ΠΌΡ‹ настроили ось, Ρ†Π²Π΅Ρ‚ рисунка, Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ Π·Π°Π³ΠΎΠ»ΠΎΠ²ΠΊΠ° Π² Ρ€Π°Π·Π΄Π΅Π»Π΅ ΠΌΠ°ΠΊΠ΅Ρ‚Π° Π³Ρ€Π°Ρ„ΠΈΠΊΠ°. Π•Ρ‰Π΅ ΠΌΡ‹ ΠΎΠ±Π΅Ρ€Π½ΡƒΠ»ΠΈ Π³Ρ€Π°Ρ„ΠΈΠΊ Π² html.Div с классом card. Π­Ρ‚ΠΎ придаст Π³Ρ€Π°Ρ„ΠΈΠΊΡƒ Π±Π΅Π»Ρ‹ΠΉ Ρ„ΠΎΠ½ ΠΈ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ Π½Π΅Π±ΠΎΠ»ΡŒΡˆΡƒΡŽ Ρ‚Π΅Π½ΡŒ ΠΏΠΎΠ΄ Π½ΠΈΠΌ. АналогичныС измСнСния внСсСны Π² Π³Ρ€Π°Ρ„ΠΈΠΊΠΈ ΠΏΡ€ΠΎΠ΄Π°ΠΆ ΠΈ объСмов. Π’ΠΎΡ‚ ΠΏΠΎΠ»Π½Ρ‹ΠΉ ΠΊΠΎΠ΄ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½Π½ΠΎΠ³ΠΎ app.py:

app.py
        import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd

data = pd.read_csv("avocado.csv")
data = data.query("type == 'conventional' and region == 'Albany'")
data["Date"] = pd.to_datetime(data["Date"], format="%Y-%m-%d")
data.sort_values("Date", inplace=True)

external_stylesheets = [
    {
        "href": "https://fonts.googleapis.com/css2?"
        "family=Lato:wght@400;700&display=swap",
        "rel": "stylesheet",
    },
]
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.title = "Avocado Analytics: Understand Your Avocados!"

app.layout = html.Div(
    children=[
        html.Div(
            children=[
                html.P(children="πŸ₯‘", className="header-emoji"),
                html.H1(
                    children="Avocado Analytics", className="header-title"
                ),
                html.P(
                    children="Analyze the behavior of avocado prices"
                    " and the number of avocados sold in the US"
                    " between 2015 and 2018",
                    className="header-description",
                ),
            ],
            className="header",
        ),
        html.Div(
            children=[
                html.Div(
                    children=dcc.Graph(
                        id="price-chart",
                        config={"displayModeBar": False},
                        figure={
                            "data": [
                                {
                                    "x": data["Date"],
                                    "y": data["AveragePrice"],
                                    "type": "lines",
                                    "hovertemplate": "$%{y:.2f}"
                                                     "<extra></extra>",
                                },
                            ],
                            "layout": {
                                "title": {
                                    "text": "Average Price of Avocados",
                                    "x": 0.05,
                                    "xanchor": "left",
                                },
                                "xaxis": {"fixedrange": True},
                                "yaxis": {
                                    "tickprefix": "$",
                                    "fixedrange": True,
                                },
                                "colorway": ["#17B897"],
                            },
                        },
                    ),
                    className="card",
                ),
                html.Div(
                    children=dcc.Graph(
                        id="volume-chart",
                        config={"displayModeBar": False},
                        figure={
                            "data": [
                                {
                                    "x": data["Date"],
                                    "y": data["Total Volume"],
                                    "type": "lines",
                                },
                            ],
                            "layout": {
                                "title": {
                                    "text": "Avocados Sold",
                                    "x": 0.05,
                                    "xanchor": "left",
                                },
                                "xaxis": {"fixedrange": True},
                                "yaxis": {"fixedrange": True},
                                "colorway": ["#E12D39"],
                            },
                        },
                    ),
                    className="card",
                ),
            ],
            className="wrapper",
        ),
    ]
)

if __name__ == "__main__":
    app.run_server(debug=True)

    

ПанСль ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½Π½ΠΎΠΉ вСрсии app.py выглядит Ρ‚Π°ΠΊ:

πŸ“Š Π’ΡƒΡ‚ΠΎΡ€ΠΈΠ°Π»: визуализация Π΄Π°Π½Π½Ρ‹Ρ… Π² Π²Π΅Π±Π΅ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Python ΠΈ Dash

ДобавляСм Π² Dash-ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹Π΅ элСмСнты

Π˜Π½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½ΠΎΡΡ‚ΡŒ Dash базируСтся Π½Π° ΠΏΠ°Ρ€Π°Π΄ΠΈΠ³ΠΌΠ΅ Ρ€Π΅Π°ΠΊΡ‚ΠΈΠ²Π½ΠΎΠ³ΠΎ программирования. Π­Ρ‚ΠΎ ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚, Ρ‡Ρ‚ΠΎ ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΡΠ²ΡΠ·Ρ‹Π²Π°Ρ‚ΡŒ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ ΠΈ элСмСнты прилоТСния, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Ρ…ΠΎΡ‚ΠΈΠΌ ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ. Если ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ взаимодСйствуСт с ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠΌ Π²Π²ΠΎΠ΄Π°, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, с Ρ€Π°ΡΠΊΡ€Ρ‹Π²Π°ΡŽΡ‰ΠΈΠΌΡΡ списком ΠΈΠ»ΠΈ ΠΏΠΎΠ»Π·ΡƒΠ½ΠΊΠΎΠΌ, Ρ‚ΠΎ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ Π²Ρ‹Π²ΠΎΠ΄Π° Π΄Π°Π½Π½Ρ‹Ρ…, Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Π³Ρ€Π°Ρ„ΠΈΠΊ, Π±ΡƒΠ΄Π΅Ρ‚ автоматичСски Ρ€Π΅Π°Π³ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π½Π° измСнСния Π²Π²ΠΎΠ΄Π°.

Π”Π°Π²Π°ΠΉΡ‚Π΅ сдСлаСм панСль управлСния ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½ΠΎΠΉ. Новая вСрсия ΠΏΠΎΠ·Π²ΠΎΠ»ΠΈΡ‚ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŽ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ со ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌΠΈ Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°ΠΌΠΈ:

  • Π Π΅Π³ΠΈΠΎΠ½ производства.
  • Π’ΠΈΠΏ Π°Π²ΠΎΠΊΠ°Π΄ΠΎ.
  • Π”ΠΈΠ°ΠΏΠ°Π·ΠΎΠ½ Π΄Π°Ρ‚.

НачнСм с Π·Π°ΠΌΠ΅Π½Ρ‹ локального app.py Π½Π° Π½ΠΎΠ²ΡƒΡŽ Π²Π΅Ρ€ΡΠΈΡŽ.

        import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import numpy as np
from dash.dependencies import Output, Input

data = pd.read_csv("avocado.csv")
data["Date"] = pd.to_datetime(data["Date"], format="%Y-%m-%d")
data.sort_values("Date", inplace=True)

external_stylesheets = [
    {
        "href": "https://fonts.googleapis.com/css2?"
        "family=Lato:wght@400;700&display=swap",
        "rel": "stylesheet",
    },
]
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.title = "Avocado Analytics: Understand Your Avocados!"

app.layout = html.Div(
    children=[
        html.Div(
            children=[
                html.P(children="πŸ₯‘", className="header-emoji"),
                html.H1(
                    children="Avocado Analytics", className="header-title"
                ),
                html.P(
                    children="Analyze the behavior of avocado prices"
                    " and the number of avocados sold in the US"
                    " between 2015 and 2018",
                    className="header-description",
                ),
            ],
            className="header",
        ),
        html.Div(
            children=[
                html.Div(
                    children=[
                        html.Div(children="Region", className="menu-title"),
                        dcc.Dropdown(
                            id="region-filter",
                            options=[
                                {"label": region, "value": region}
                                for region in np.sort(data.region.unique())
                            ],
                            value="Albany",
                            clearable=False,
                            className="dropdown",
                        ),
                    ]
                ),
                html.Div(
                    children=[
                        html.Div(children="Type", className="menu-title"),
                        dcc.Dropdown(
                            id="type-filter",
                            options=[
                                {"label": avocado_type, "value": avocado_type}
                                for avocado_type in data.type.unique()
                            ],
                            value="organic",
                            clearable=False,
                            searchable=False,
                            className="dropdown",
                        ),
                    ],
                ),
                html.Div(
                    children=[
                        html.Div(
                            children="Date Range",
                            className="menu-title"
                            ),
                        dcc.DatePickerRange(
                            id="date-range",
                            min_date_allowed=data.Date.min().date(),
                            max_date_allowed=data.Date.max().date(),
                            start_date=data.Date.min().date(),
                            end_date=data.Date.max().date(),
                        ),
                    ]
                ),
            ],
            className="menu",
        ),
        html.Div(
            children=[
                html.Div(
                    children=dcc.Graph(
                        id="price-chart", config={"displayModeBar": False},
                    ),
                    className="card",
                ),
                html.Div(
                    children=dcc.Graph(
                        id="volume-chart", config={"displayModeBar": False},
                    ),
                    className="card",
                ),
            ],
            className="wrapper",
        ),
    ]
)


@app.callback(
    [Output("price-chart", "figure"), Output("volume-chart", "figure")],
    [
        Input("region-filter", "value"),
        Input("type-filter", "value"),
        Input("date-range", "start_date"),
        Input("date-range", "end_date"),
    ],
)
def update_charts(region, avocado_type, start_date, end_date):
    mask = (
        (data.region == region)
        & (data.type == avocado_type)
        & (data.Date >= start_date)
        & (data.Date <= end_date)
    )
    filtered_data = data.loc[mask, :]
    price_chart_figure = {
        "data": [
            {
                "x": filtered_data["Date"],
                "y": filtered_data["AveragePrice"],
                "type": "lines",
                "hovertemplate": "$%{y:.2f}<extra></extra>",
            },
        ],
        "layout": {
            "title": {
                "text": "Average Price of Avocados",
                "x": 0.05,
                "xanchor": "left",
            },
            "xaxis": {"fixedrange": True},
            "yaxis": {"tickprefix": "$", "fixedrange": True},
            "colorway": ["#17B897"],
        },
    }

    volume_chart_figure = {
        "data": [
            {
                "x": filtered_data["Date"],
                "y": filtered_data["Total Volume"],
                "type": "lines",
            },
        ],
        "layout": {
            "title": {"text": "Avocados Sold", "x": 0.05, "xanchor": "left"},
            "xaxis": {"fixedrange": True},
            "yaxis": {"fixedrange": True},
            "colorway": ["#E12D39"],
        },
    }
    return price_chart_figure, volume_chart_figure


if __name__ == "__main__":
    app.run_server(debug=True,
                   host='127.0.0.1')
    

Π—Π°Ρ‚Π΅ΠΌ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ΡŒ style.css ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌ ΠΊΠΎΠ΄ΠΎΠΌ.

        body {
    font-family: "Lato", sans-serif;
    margin: 0;
    background-color: #F7F7F7;
}

.header {
    background-color: #222222;
    height: 288px;
    padding: 16px 0 0 0;
}

.header-emoji {
    font-size: 48px;
    margin: 0 auto;
    text-align: center;
}

.header-title {
    color: #FFFFFF;
    font-size: 48px;
    font-weight: bold;
    text-align: center;
    margin: 0 auto;
}

.header-description {
    color: #CFCFCF;
    margin: 4px auto;
    text-align: center;
    max-width: 384px;
}

.wrapper {
    margin-right: auto;
    margin-left: auto;
    max-width: 1024px;
    padding-right: 10px;
    padding-left: 10px;
    margin-top: 32px;
}

.card {
    margin-bottom: 24px;
    box-shadow: 0 4px 6px 0 rgba(0, 0, 0, 0.18);
}

.menu {
    height: 112px;
    width: 912px;
    display: flex;
    justify-content: space-evenly;
    padding-top: 24px;
    margin: -80px auto 0 auto;
    background-color: #FFFFFF;
    box-shadow: 0 4px 6px 0 rgba(0, 0, 0, 0.18);
}

.Select-control {
    width: 256px;
    height: 48px;
}

.Select--single > .Select-control .Select-value, .Select-placeholder {
    line-height: 48px;
}

.Select--multi .Select-value-label {
    line-height: 32px;
}

.menu-title {
    margin-bottom: 6px;
    font-weight: bold;
    color: #079A82;
}
    

Как ΡΠΎΠ·Π΄Π°Π²Π°Ρ‚ΡŒ ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½Ρ‹Π΅ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹

Новый html.Div Π½Π°Π΄ Π΄ΠΈΠ°Π³Ρ€Π°ΠΌΠΌΠ°ΠΌΠΈ Π²ΠΊΠ»ΡŽΡ‡Π°Π΅Ρ‚ Π² сСбя Π΄Π²Π° Ρ€Π°ΡΠΊΡ€Ρ‹Π²Π°ΡŽΡ‰ΠΈΡ…ΡΡ списка ΠΈ сСлСктор Π΄ΠΈΠ°ΠΏΠ°Π·ΠΎΠ½Π° Π΄Π°Ρ‚, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ для Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°Ρ†ΠΈΠΈ Π΄Π°Π½Π½Ρ‹Ρ… ΠΈ обновлСния Π³Ρ€Π°Ρ„ΠΈΠΊΠΎΠ².

Π’ΠΎΡ‚ ΠΊΠ°ΠΊ это выглядит Π² app.py:

        html.Div(
    children=[
        html.Div(
            children=[
                html.Div(children="Region", className="menu-title"),
                dcc.Dropdown(
                    id="region-filter",
                    options=[
                        {"label": region, "value": region}
                        for region in np.sort(data.region.unique())
                    ],
                    value="Albany",
                    clearable=False,
                    className="dropdown",
                ),
            ]
        ),
        html.Div(
            children=[
                html.Div(children="Type", className="menu-title"),
                dcc.Dropdown(
                    id="type-filter",
                    options=[
                        {"label": avocado_type, "value": avocado_type}
                        for avocado_type in data.type.unique()
                    ],
                    value="organic",
                    clearable=False,
                    searchable=False,
                    className="dropdown",
                ),
            ],
        ),
        html.Div(
            children=[
                html.Div(
                    children="Date Range",
                    className="menu-title"
                    ),
                dcc.DatePickerRange(
                    id="date-range",
                    min_date_allowed=data.Date.min().date(),
                    max_date_allowed=data.Date.max().date(),
                    start_date=data.Date.min().date(),
                    end_date=data.Date.max().date(),
                ),
            ]
        ),
    ],
    className="menu",
),
    

Π Π°ΡΠΊΡ€Ρ‹Π²Π°ΡŽΡ‰ΠΈΠ΅ΡΡ списки ΠΈ сСлСктор Π΄ΠΈΠ°ΠΏΠ°Π·ΠΎΠ½Π° Π΄Π°Ρ‚ слуТат Π² качСствС мСню для взаимодСйствия с Π΄Π°Π½Π½Ρ‹ΠΌΠΈ:

πŸ“Š Π’ΡƒΡ‚ΠΎΡ€ΠΈΠ°Π»: визуализация Π΄Π°Π½Π½Ρ‹Ρ… Π² Π²Π΅Π±Π΅ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Python ΠΈ Dash

ΠŸΠ΅Ρ€Π²Ρ‹ΠΉ ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ Π² мСню ― это Ρ€Π°ΡΠΊΡ€Ρ‹Π²Π°ΡŽΡ‰ΠΈΠΉΡΡ список Region. Код ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°:

        html.Div(
    children=[
        html.Div(children="Region", className="menu-title"),
        dcc.Dropdown(
            id="region-filter",
            options=[
                {"label": region, "value": region}
                for region in np.sort(data.region.unique())
            ],
            value="Albany",
            clearable=False,
            className="dropdown",
        ),
    ]
),
    

Π’ΠΎΡ‚ Ρ‡Ρ‚ΠΎ ΠΎΠ·Π½Π°Ρ‡Π°Π΅Ρ‚ ΠΊΠ°ΠΆΠ΄Ρ‹ΠΉ ΠΈΠ· ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€ΠΎΠ²:

  • id ― ΠΈΠ΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ элСмСнта.
  • options ― ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Ρ‹, ΠΎΡ‚ΠΎΠ±Ρ€Π°ΠΆΠ°Π΅ΠΌΡ‹Π΅ ΠΏΡ€ΠΈ Π²Ρ‹Π±ΠΎΡ€Π΅ Ρ€Π°ΡΠΊΡ€Ρ‹Π²Π°ΡŽΡ‰Π΅Π³ΠΎΡΡ списка. ΠžΠΆΠΈΠ΄Π°Π΅Ρ‚ ΡΠ»ΠΎΠ²Π°Ρ€ΡŒ с ΠΌΠ΅Ρ‚ΠΊΠ°ΠΌΠΈ ΠΈ значСниями.
  • value ― Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ ΠΏΠΎ ΡƒΠΌΠΎΠ»Ρ‡Π°Π½ΠΈΡŽ ΠΏΡ€ΠΈ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠ΅ страницы.
  • clearable ― позволяСт ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŽ ΠΎΡΡ‚Π°Π²ΠΈΡ‚ΡŒ ΠΏΠΎΠ»Π΅ пустым, Ссли установлСно Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅ True.
  • className ― сСлСктор классов, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡ‹ΠΉ для примСнСния стилСй

Π‘Π΅Π»Π΅ΠΊΡ‚ΠΎΡ€Ρ‹ Type ΠΈ Data Range ΠΈΠΌΠ΅ΡŽΡ‚ Ρ‚Ρƒ ΠΆΠ΅ структуру, Ρ‡Ρ‚ΠΎ ΠΈ Ρ€Π°ΡΠΊΡ€Ρ‹Π²Π°ΡŽΡ‰Π΅Π΅ΡΡ мСню Region.

Π’Π΅ΠΏΠ΅Ρ€ΡŒ взглянСм Π½Π° ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Ρ‹ dcc.Graphs:

        html.Div(
    children=[
        html.Div(
            children=dcc.Graph(
                id="price-chart", config={"displayModeBar": False},
            ),
            className="card",
        ),
        html.Div(
            children=dcc.Graph(
                id="volume-chart", config={"displayModeBar": False},
            ),
            className="card",
        ),
    ],
    className="wrapper",
),
    

По ΡΡ€Π°Π²Π½Π΅Π½ΠΈΡŽ с ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅ΠΉ вСрсиСй ΠΏΠ°Π½Π΅Π»ΠΈ инструмСнтов Π² ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚Π°Ρ… отсутствуСт Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ figure. Π­Ρ‚ΠΎ связано с Ρ‚Π΅ΠΌ, Ρ‡Ρ‚ΠΎ Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚ figure Ρ‚Π΅ΠΏΠ΅Ρ€ΡŒ Π±ΡƒΠ΄Π΅Ρ‚ Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒΡΡ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠ΅ΠΉ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎΠ³ΠΎ Π²Ρ‹Π·ΠΎΠ²Π° с использованиСм Π²Ρ…ΠΎΠ΄Π½Ρ‹Ρ… Π΄Π°Π½Π½Ρ‹Ρ…, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ устанавливаСт с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ сСлСкторов Region, Type ΠΈ Data Range.

Как ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ΡŒ ΠΎΠ±Ρ€Π°Ρ‚Π½Ρ‹Π΅ Π²Ρ‹Π·ΠΎΠ²Ρ‹

ΠœΡ‹ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΠ»ΠΈ, ΠΊΠ°ΠΊ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ Π±ΡƒΠ΄Π΅Ρ‚ Π²Π·Π°ΠΈΠΌΠΎΠ΄Π΅ΠΉΡΡ‚Π²ΠΎΠ²Π°Ρ‚ΡŒ с ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ΠΌ. Π’Π΅ΠΏΠ΅Ρ€ΡŒ Π½ΡƒΠΆΠ½ΠΎ Π·Π°ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Ρ€Π΅Π°Π³ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π½Π° дСйствия ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Ρ. Для этого ΠΌΡ‹ Π²ΠΎΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΡΡ функциями ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎΠ³ΠΎ Π²Ρ‹Π·ΠΎΠ²Π° (callbacks).

Π€ΡƒΠ½ΠΊΡ†ΠΈΠΈ ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎΠ³ΠΎ Π²Ρ‹Π·ΠΎΠ²Π° Dash ― это ΠΎΠ±Ρ‹Ρ‡Π½Ρ‹Π΅ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ Python с Π΄Π΅ΠΊΠΎΡ€Π°Ρ‚ΠΎΡ€ΠΎΠΌ app.callback. ΠŸΡ€ΠΈ ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠΈ Π²Π²ΠΎΠ΄Π° запускаСтся функция ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎΠ³ΠΎ Π²Ρ‹Π·ΠΎΠ²Π°, выполняСт Π·Π°Ρ€Π°Π½Π΅Π΅ ΠΎΠΏΡ€Π΅Π΄Π΅Π»Π΅Π½Π½Ρ‹Π΅ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ (Π½Π°ΠΏΡ€ΠΈΠΌΠ΅Ρ€, Ρ„ΠΈΠ»ΡŒΡ‚Ρ€Π°Ρ†ΠΈΡ Π½Π°Π±ΠΎΡ€Π° Π΄Π°Π½Π½Ρ‹Ρ…), ΠΈ Π²ΠΎΠ·Π²Ρ€Π°Ρ‰Π°Π΅Ρ‚ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ Π² ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅. По сути, ΠΎΠ±Ρ€Π°Ρ‚Π½Ρ‹Π΅ Π²Ρ‹Π·ΠΎΠ²Ρ‹ ΡΠ²ΡΠ·Ρ‹Π²Π°ΡŽΡ‚ Π² ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΈ Π²Ρ…ΠΎΠ΄Π½Ρ‹Π΅ ΠΈ Π²Ρ‹Ρ…ΠΎΠ΄Π½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅.

Π’ΠΎΡ‚ функция ΠΎΠ±Ρ€Π°Ρ‚Π½ΠΎΠ³ΠΎ Π²Ρ‹Π·ΠΎΠ²Π°, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅ΠΌΠ°Ρ для обновлСния Π³Ρ€Π°Ρ„ΠΈΠΊΠΎΠ²:

        @app.callback(
    [Output("price-chart", "figure"), Output("volume-chart", "figure")],
    [
        Input("region-filter", "value"),
        Input("type-filter", "value"),
        Input("date-range", "start_date"),
        Input("date-range", "end_date"),
    ],
)
def update_charts(region, avocado_type, start_date, end_date):
    mask = (
        (data.region == region)
        & (data.type == avocado_type)
        & (data.Date >= start_date)
        & (data.Date <= end_date)
    )
    filtered_data = data.loc[mask, :]
    price_chart_figure = {
        "data": [
            {
                "x": filtered_data["Date"],
                "y": filtered_data["AveragePrice"],
                "type": "lines",
                "hovertemplate": "$%{y:.2f}<extra></extra>",
            },
        ],
        "layout": {
            "title": {
                "text": "Average Price of Avocados",
                "x": 0.05,
                "xanchor": "left",
            },
            "xaxis": {"fixedrange": True},
            "yaxis": {"tickprefix": "$", "fixedrange": True},
            "colorway": ["#17B897"],
        },
    }

    volume_chart_figure = {
        "data": [
            {
                "x": filtered_data["Date"],
                "y": filtered_data["Total Volume"],
                "type": "lines",
            },
        ],
        "layout": {
            "title": {
                "text": "Avocados Sold",
                "x": 0.05,
                "xanchor": "left"
            },
            "xaxis": {"fixedrange": True},
            "yaxis": {"fixedrange": True},
            "colorway": ["#E12D39"],
        },
    }
    return price_chart_figure, volume_chart_figure
    

Π‘Π½Π°Ρ‡Π°Π»Π° ΠΌΡ‹ опрСдСляСм Π²Ρ‹Ρ…ΠΎΠ΄Π½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² Output. Π­Ρ‚ΠΈ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°ΡŽΡ‚ Π΄Π²Π° Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π°:

  • Π˜Π΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ элСмСнта, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ ΠΎΠ½ΠΈ измСнят ΠΏΡ€ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΈΠΈ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ.
  • Бвойство измСняСмого элСмСнта НапримСр, Output("price-chart", "figure") ΠΎΠ±Π½ΠΎΠ²ΠΈΡ‚ свойство figure элСмСнта "price-chart".

Π—Π°Ρ‚Π΅ΠΌ ΠΌΡ‹ опрСдСляСм Π²Ρ…ΠΎΠ΄Ρ‹ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚ΠΎΠ² Input, ΠΎΠ½ΠΈ Ρ‚Π°ΠΊΠΆΠ΅ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°ΡŽΡ‚ Π΄Π²Π° Π°Ρ€Π³ΡƒΠΌΠ΅Π½Ρ‚Π°:

  • Π˜Π΄Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ‚ΠΎΡ€ элСмСнта, Π·Π° измСнСниями ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ ΠΎΠ½ΠΈ Π±ΡƒΠ΄ΡƒΡ‚ ΡΠ»Π΅Π΄ΠΈΡ‚ΡŒ.
  • Бвойство наблюдаСмого элСмСнта, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ ΠΎΠ½ΠΈ Π΄ΠΎΠ»ΠΆΠ½Ρ‹ ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Ρ‚ΡŒ, ΠΊΠΎΠ³Π΄Π° происходит ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅.

Π’ΠΎ Π΅ΡΡ‚ΡŒ Input("region-filter", "value") Π±ΡƒΠ΄Π΅Ρ‚ ΡΠ»Π΅Π΄ΠΈΡ‚ΡŒ Π·Π° измСнСниями элСмСнта "region-filter" ΠΈ ΠΏΡ€ΠΈΠΌΠ΅Ρ‚ Π΅Π³ΠΎ свойство value, Ссли элСмСнт измСнится.

ΠŸΡ€ΠΈΠΌΠ΅Ρ‡Π°Π½ΠΈΠ΅
ΠžΠ±ΡΡƒΠΆΠ΄Π°Π΅ΠΌΡ‹ΠΉ здСсь ΠΎΠ±ΡŠΠ΅ΠΊΡ‚InputΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½ ΠΈΠ·dash.dependencies. НС спутайтС Π΅Π³ΠΎ с ΠΊΠΎΠΌΠΏΠΎΠ½Π΅Π½Ρ‚ΠΎΠΌ, ΠΏΠΎΡΡ‚ΡƒΠΏΠ°ΡŽΡ‰ΠΈΠΌ ΠΈΠ·dash_core_components. Π­Ρ‚ΠΈ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ Π½Π΅ взаимозамСняСмы ΠΈ ΠΈΠΌΠ΅ΡŽΡ‚ Ρ€Π°Π·Π½ΠΎΠ΅ Π½Π°Π·Π½Π°Ρ‡Π΅Π½ΠΈΠ΅.

Π’ послСдних строках ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½ΠΎΠ³ΠΎ Π±Π»ΠΎΠΊΠ° ΠΌΡ‹ опрСдСляСм Ρ‚Π΅Π»ΠΎ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΠΈ. Π’ ΠΏΡ€ΠΈΠ²Π΅Π΄Π΅Π½Π½ΠΎΠΌ ΠΏΡ€ΠΈΠΌΠ΅Ρ€Π΅ функция ΠΏΡ€ΠΈΠ½ΠΈΠΌΠ°Π΅Ρ‚ Π²Ρ…ΠΎΠ΄Π½Ρ‹Π΅ Π΄Π°Π½Π½Ρ‹Π΅ (Ρ€Π΅Π³ΠΈΠΎΠ½, Ρ‚ΠΈΠΏ Π°Π²ΠΎΠΊΠ°Π΄ΠΎ ΠΈ Π΄ΠΈΠ°ΠΏΠ°Π·ΠΎΠ½ Π΄Π°Ρ‚), Ρ„ΠΈΠ»ΡŒΡ‚Ρ€ΡƒΠ΅Ρ‚ ΠΈΡ… ΠΈ Π³Π΅Π½Π΅Ρ€ΠΈΡ€ΡƒΠ΅Ρ‚ ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹ для Π³Ρ€Π°Ρ„ΠΈΠΊΠΎΠ² Ρ†Π΅Π½ ΠΈ объСмов.

Π­Ρ‚ΠΎ послСдняя вСрсия нашСй ΠΏΠ°Π½Π΅Π»ΠΈ инструмСнтов. ΠœΡ‹ сдСлали Π΅Π΅ Π½Π΅ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ красивой, Π½ΠΎ ΠΈ ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½ΠΎΠΉ. ЕдинствСнный Π½Π΅Π΄ΠΎΡΡ‚Π°ΡŽΡ‰ΠΈΠΉ шаг ― ΡΠ΄Π΅Π»Π°Ρ‚ΡŒ Ρ‚Π°ΠΊ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚ΠΎΠΌ Π±Ρ‹Π»ΠΎ ΠΌΠΎΠΆΠ½ΠΎ ΠΏΠΎΠ΄Π΅Π»ΠΈΡ‚ΡŒΡΡ с Π΄Ρ€ΡƒΠ³ΠΈΠΌΠΈ.

Π Π°Π·Π²ΠΎΡ€Π°Ρ‡ΠΈΠ²Π°Π΅ΠΌ Dash-ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π½Π° Heroku

ΠœΡ‹ Π·Π°ΠΊΠΎΠ½Ρ‡ΠΈΠ»ΠΈ сборку прилоТСния. Π£ нас Π΅ΡΡ‚ΡŒ красивая, ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ интСрактивная панСль инструмСнтов. Π’Π΅ΠΏΠ΅Ρ€ΡŒ ΠΌΡ‹ ΡƒΠ·Π½Π°Π΅ΠΌ, ΠΊΠ°ΠΊ Π΅Π΅ Ρ€Π°Π·Π²Π΅Ρ€Π½ΡƒΡ‚ΡŒ.

ЀактичСски прилоТСния Dash ― Ρ‚ΠΎ ΠΆΠ΅, Ρ‡Ρ‚ΠΎ прилоТСния Flask, поэтому ΠΎΠ½ΠΈ ΠΈΠΌΠ΅ΡŽΡ‚ Ρ‚Π΅ ΠΆΠ΅ возмоТности для развСртывания. Π’ этом Ρ€Π°Π·Π΄Π΅Π»Π΅ ΠΌΡ‹ Ρ€Π°Π·Π²Π΅Ρ€Π½Π΅ΠΌ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π½Π° хостингС Heroku (с бСсплатным Ρ‚Π°Ρ€ΠΈΡ„Π½Ρ‹ΠΌ ΠΏΠ»Π°Π½ΠΎΠΌ).

ΠŸΡ€Π΅ΠΆΠ΄Π΅ Ρ‡Π΅ΠΌ Π½Π°Ρ‡Π°Ρ‚ΡŒ, ΡƒΠ±Π΅Π΄ΠΈΡ‚Π΅ΡΡŒ, Ρ‡Ρ‚ΠΎ Π²Ρ‹ установили интСрфСйс ΠΊΠΎΠΌΠ°Π½Π΄Π½ΠΎΠΉ строки Heroku (CLI) ΠΈ Git. Π§Ρ‚ΠΎΠ±Ρ‹ ΡƒΠ±Π΅Π΄ΠΈΡ‚ΡŒΡΡ, Ρ‡Ρ‚ΠΎ ΠΎΠ±Π΅ ΠΏΡ€ΠΎΠ³Ρ€Π°ΠΌΠΌΡ‹ ΠΏΡ€ΠΈΡΡƒΡ‚ΡΡ‚Π²ΡƒΡŽΡ‚ Π² систСмС, Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚Π΅ Π² Ρ‚Π΅Ρ€ΠΌΠΈΠ½Π°Π»Π΅ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΊΠΈ вСрсий:

        git --version
heroku --version
    

Π”Π°Π»Π΅Π΅ Π½Π°ΠΌ Π½ΡƒΠΆΠ½ΠΎ внСсти нСбольшоС ΠΈΠ·ΠΌΠ΅Π½Π΅Π½ΠΈΠ΅ Π² app.py. ПослС ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ прилоТСния Π΄ΠΎΠ±Π°Π²ΠΈΠΌ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½ΡƒΡŽ с ΠΈΠΌΠ΅Π½Π΅ΠΌ server:

        app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
server = app.server
    

Π­Ρ‚ΠΎ Π΄ΠΎΠΏΠΎΠ»Π½Π΅Π½ΠΈΠ΅ Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΠΎ для запуска прилоТСния с использованиСм WSGI-сСрвСра. ВстроСнный сСрвСр Flask Π½Π΅ рСкомСндуСтся ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π² производствСнной срСдС, ΠΏΠΎΡΠΊΠΎΠ»ΡŒΠΊΡƒ ΠΎΠ½ Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΎΠ±Ρ€Π°Π±Π°Ρ‚Ρ‹Π²Π°Ρ‚ΡŒ большой объСм Ρ‚Ρ€Π°Ρ„ΠΈΠΊΠ°.

Π’ ΠΊΠΎΡ€Π½Π΅Π²ΠΎΠΌ ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Π΅ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° создадим Ρ„Π°ΠΉΠ» с ΠΈΠΌΠ΅Π½Π΅ΠΌ runtime.txt, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ ΡƒΠΊΠ°ΠΆΠ΅ΠΌ Π²Π΅Ρ€ΡΠΈΡŽ Python для прилоТСния Heroku:

        python-3.8.6
    

ΠŸΡ€ΠΈ Ρ€Π°Π·Π²Π΅Ρ€Ρ‚Ρ‹Π²Π°Π½ΠΈΠΈ Heroku автоматичСски ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚, Ρ‡Ρ‚ΠΎ это ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Python, ΠΈ Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΡΠΎΠΎΡ‚Π²Π΅Ρ‚ΡΡ‚Π²ΡƒΡŽΡ‰ΠΈΠΉ ΠΏΠ°ΠΊΠ΅Ρ‚ сборки. Если Π²Ρ‹ Ρ‚Π°ΠΊΠΆΠ΅ прСдоставитС Ρ„Π°ΠΉΠ» runtime.txt, сСрвСр ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΡ‚ Π²Π΅Ρ€ΡΠΈΡŽ Python, ΠΊΠΎΡ‚ΠΎΡ€ΡƒΡŽ Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅.

Π—Π°Ρ‚Π΅ΠΌ Π² ΠΊΠΎΡ€Π½Π΅Π²ΠΎΠΌ ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Π΅ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° создадим Ρ„Π°ΠΉΠ» requirements.txt, Π³Π΄Π΅ пСрСчислим Π±ΠΈΠ±Π»ΠΈΠΎΡ‚Π΅ΠΊΠΈ, Π½Π΅ΠΎΠ±Ρ…ΠΎΠ΄ΠΈΠΌΡ‹Π΅ для установки Dash-прилоТСния Π½Π° Π²Π΅Π±-сСрвСрС:

        dash==1.13.3
pandas==1.0.5
gunicorn==20.0.4
    

Π’ Ρ„Π°ΠΉΠ»Π΅ requirements.txt Π΅ΡΡ‚ΡŒ ΠΏΠ°ΠΊΠ΅Ρ‚, ΠΎ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ ΠΌΡ‹ Ρ€Π°Π½ΡŒΡˆΠ΅ Π½Π΅ ΡƒΠΏΠΎΠΌΠΈΠ½Π°Π»ΠΈ: gunicorn. Gunicorn ― это HTTP-сСрвСр WSGI, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ часто ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ для развСртывания ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ Flask Π² производствСнной срСдС.

Π’Π΅ΠΏΠ΅Ρ€ΡŒ создадим Ρ„Π°ΠΉΠ» с ΠΈΠΌΠ΅Π½Π΅ΠΌ Procfile со ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌ содСрТимым:

        web: gunicorn app:server
    

Π­Ρ‚ΠΎΡ‚ Ρ„Π°ΠΉΠ» сообщаСт ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡŽ Heroku, ΠΊΠ°ΠΊΠΈΠ΅ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ слСдуСт Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ для запуска нашСго прилоТСния.

Π—Π°Ρ‚Π΅ΠΌ Π½ΡƒΠΆΠ½ΠΎ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ Git. Для этого ΠΏΠ΅Ρ€Π΅ΠΉΠ΄Π΅ΠΌ Π² ΠΊΠΎΡ€Π½Π΅Π²ΠΎΠΉ ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³ ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° ΠΈ Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΠΌ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΡƒΡŽ ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ:

        git init
    

Π­Ρ‚Π° ΠΊΠΎΠΌΠ°Π½Π΄Π° ΠΈΠ½ΠΈΡ†ΠΈΠΈΡ€ΡƒΠ΅Ρ‚ созданиС рСпозитория Git для avocado_analytics/. Π’ΠΎ Π΅ΡΡ‚ΡŒ Git Π±ΡƒΠ΄Π΅Ρ‚ ΠΎΡ‚ΡΠ»Π΅ΠΆΠΈΠ²Π°Ρ‚ΡŒ измСнСния, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ ΠΌΡ‹ вносим Π² Ρ„Π°ΠΉΠ»Ρ‹ Π² этом ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Π΅.

Однако Π΅ΡΡ‚ΡŒ Ρ„Π°ΠΉΠ»Ρ‹, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Π½Π΅ стоит ΠΎΡ‚ΡΠ»Π΅ΠΆΠΈΠ²Π°Ρ‚ΡŒ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Git. НапримСр, ΠΎΠ±Ρ‹Ρ‡Π½ΠΎ ΠΌΡ‹ Π½Π΅ Ρ…ΠΎΡ‚ΠΈΠΌ ΠΎΡ‚ΡΠ»Π΅ΠΆΠΈΠ²Π°Ρ‚ΡŒ содСрТимоС ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Π° Π²ΠΈΡ€Ρ‚ΡƒΠ°Π»ΡŒΠ½ΠΎΠΉ срСды, Ρ„Π°ΠΉΠ»ΠΎΠ² с Π±Π°ΠΉΡ‚-ΠΊΠΎΠ΄ΠΎΠΌ ΠΈ Ρ„Π°ΠΉΠ»ΠΎΠ² ΠΌΠ΅Ρ‚Π°Π΄Π°Π½Π½Ρ‹Ρ…, Ρ‚Π°ΠΊΠΈΡ… ΠΊΠ°ΠΊ .DS_Store.

Π‘ΠΎΠ·Π΄Π°Π΄ΠΈΠΌ Π² ΠΊΠΎΡ€Π½Π΅Π²ΠΎΠΌ ΠΊΠ°Ρ‚Π°Π»ΠΎΠ³Π΅ Ρ„Π°ΠΉΠ» с ΠΈΠΌΠ΅Π½Π΅ΠΌ .gitignore ΠΈ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΌ содСрТимым:

        venv
*.pyc
.DS_Store # Only if you are using macOS
    

Π­Ρ‚ΠΎ Π³Π°Ρ€Π°Π½Ρ‚ΠΈΡ€ΡƒΠ΅Ρ‚, Ρ‡Ρ‚ΠΎ Ρ€Π΅ΠΏΠΎΠ·ΠΈΡ‚ΠΎΡ€ΠΈΠΉ Π½Π΅ отслСТиваСт Π½Π΅Π½ΡƒΠΆΠ½Ρ‹Π΅ Ρ„Π°ΠΉΠ»Ρ‹. Π’Π΅ΠΏΠ΅Ρ€ΡŒ зафиксируСм состояниС ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π°:

        git add .
git commit -m 'Add dashboard files'
    

ΠŸΠ΅Ρ€Π΅Π΄ послСдним шагом ΡƒΠ±Π΅Π΄ΠΈΡ‚Π΅ΡΡŒ, Ρ‡Ρ‚ΠΎ всё Π½Π° мСстС. Π‘Ρ‚Ρ€ΡƒΠΊΡ‚ΡƒΡ€Π° ΠΏΡ€ΠΎΠ΅ΠΊΡ‚Π° Π΄ΠΎΠ»ΠΆΠ½Π° Π²Ρ‹Π³Π»ΡΠ΄Π΅Ρ‚ΡŒ Ρ‚Π°ΠΊ:

        avocado_analytics/
β”œβ”€β”€ assets/
β”‚   β”œβ”€β”€ favicon.ico
β”‚   └── style.css
β”œβ”€β”€ venv/
β”œβ”€β”€ app.py
β”œβ”€β”€ avocado.csv
β”œβ”€β”€ Procfile
β”œβ”€β”€ requirements.txt
└── runtime.txt
    

НаконСц, Π½ΡƒΠΆΠ½ΠΎ ΡΠΎΠ·Π΄Π°Ρ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π² Heroku, ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ Ρ‚ΡƒΠ΄Π° свой ΠΊΠΎΠ΄ с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Git ΠΈ Π·Π°ΠΏΡƒΡΡ‚ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Π½Π° ΠΎΠ΄Π½ΠΎΠΌ ΠΈΠ· бСсплатных сСрвСрных Π²Π°Ρ€ΠΈΠ°Π½Ρ‚ΠΎΠ² Heroku. Для этого Π²Ρ‹ΠΏΠΎΠ»Π½ΠΈΠΌ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠ΅ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹:

        heroku create APP-NAME  # ΠŸΠΎΠ΄ΡΡ‚Π°Π²ΡŒΡ‚Π΅ имя прилоТСния
git push heroku master
heroku ps:scale web=1
    

Π’ΠΎΡ‚ ΠΈ всё. ΠœΡ‹ создали ΠΈ Ρ€Π°Π·Π²Π΅Ρ€Π½ΡƒΠ»ΠΈ панСль управлСния Π΄Π°Π½Π½Ρ‹ΠΌΠΈ. Π§Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ доступ ΠΊ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡŽ, достаточно ΡΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ссылку https://APP-NAME.herokuapp.com/ ΠΈ Π·Π°ΠΌΠ΅Π½ΠΈΡ‚Π΅ APP-NAME Π½Π° имя, ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ΅ Π²Ρ‹ ΠΎΠΏΡ€Π΅Π΄Π΅Π»ΠΈΠ»ΠΈ Π½Π° ΠΏΡ€Π΅Π΄Ρ‹Π΄ΡƒΡ‰Π΅ΠΌ шагС.

Если Π²Π°ΠΌ интСрСсно ΡΡ€Π°Π²Π½ΠΈΡ‚ΡŒ ΠΏΠΎΠ»ΡƒΡ‡ΠΈΠ²ΡˆΠΈΠΉΡΡ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚, взглянитС Π½Π° ΠΎΠ±Ρ€Π°Π·Π΅Ρ† прилоТСния.

Π—Π°ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅

ΠŸΠΎΠ·Π΄Ρ€Π°Π²Π»ΡΠ΅ΠΌ! Π’Ρ‹ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ‡Ρ‚ΠΎ создали, настроили ΠΈ Ρ€Π°Π·Π²Π΅Ρ€Π½ΡƒΠ»ΠΈ панСль управлСния с ΠΏΠΎΠΌΠΎΡ‰ΡŒΡŽ Dash. ΠœΡ‹ ΠΏΠ΅Ρ€Π΅ΡˆΠ»ΠΈ ΠΎΡ‚ простой ΠΏΠ°Π½Π΅Π»ΠΈ инструмСнтов ΠΊ ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ ΠΈΠ½Ρ‚Π΅Ρ€Π°ΠΊΡ‚ΠΈΠ²Π½ΠΎΠΉ ΠΈ Ρ€Π°Π·Π²Π΅Ρ€Π½ΡƒΡ‚ΠΎΠΉ Π½Π° ΡƒΠ΄Π°Π»Π΅Π½Π½ΠΎΠΌ сСрвСрС. Обладая этими знаниями, ΠΌΡ‹ ΠΌΠΎΠΆΠ΅ΠΌ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Dash для создания аналитичСских ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΌΠΈ ΠΌΠΎΠΆΠ½ΠΎ Π΄Π΅Π»ΠΈΡ‚ΡŒΡΡ с ΠΊΠΎΠ»Π»Π΅Π³Π°ΠΌΠΈ ΠΈ Π·Π°ΠΊΠ°Π·Ρ‡ΠΈΠΊΠ°ΠΌΠΈ.

Π˜ΡΡ‚ΠΎΡ‡Π½ΠΈΠΊΠΈ

ΠœΠ•Π ΠžΠŸΠ Π˜Π―Π’Π˜Π―

ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΈ

Π’ΠΠšΠΠΠ‘Π˜Π˜

Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ вакансию
Go-Ρ€Π°Π·Ρ€Π°Π±ΠΎΡ‚Ρ‡ΠΈΠΊ
ΠΏΠΎ ΠΈΡ‚ΠΎΠ³Π°ΠΌ собСсСдования
Java Team Lead
Москва, ΠΏΠΎ ΠΈΡ‚ΠΎΠ³Π°ΠΌ собСсСдования

Π›Π£Π§Π¨Π˜Π• БВАВЬИ ПО Π’Π•ΠœΠ•