{"id":409092,"date":"2024-06-29T20:34:54","date_gmt":"2024-06-29T20:34:54","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=409092"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2024-06-29T20:34:54","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=409092","title":{"rendered":"<span>\u0421\u043e\u0437\u0434\u0430\u0451\u043c \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u043e\u0431\u0443\u0447\u0430\u044e\u0449\u0438\u0435 \u0432\u0438\u0434\u0435\u043e \u043d\u0430\u00a0Python \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Manim<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\u041f\u0440\u0438\u0432\u0435\u0442! \u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u041a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u0438\u043d \u041c\u043e\u0445\u043e\u0432, \u044f \u0442\u0438\u043c\u043b\u0438\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0434\u043d\u0430\u0436\u0434\u044b \u043f\u0440\u043e\u0448\u0451\u043b \u043a\u0443\u0440\u0441 \u041f\u0440\u0430\u043a\u0442\u0438\u043a\u0443\u043c\u0430 \u043f\u043e <a href=\"https:\/\/practicum.yandex.ru\/data-analyst?utm_source=pr&amp;utm_medium=content&amp;utm_content=21_09_21&amp;utm_campaign=pr_content_data-analyst_habr\">\u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0435 \u0434\u0430\u043d\u043d\u044b\u0445<\/a>, \u043f\u043e \u0431\u043e\u043b\u044c\u0448\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u0434\u043b\u044f \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u0432\u0438\u0442\u0438\u044f. \u0422\u0435\u043c\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0432\u0438\u0434\u0435\u043e \u043d\u0430 Python \u0437\u0430\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432\u0430\u043b\u0430 \u043c\u0435\u043d\u044f \u043f\u043e\u0437\u0436\u0435, \u043a\u043e\u0433\u0434\u0430 \u0432 <a href=\"https:\/\/t.me\/datalytx\">\u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c-\u043a\u0430\u043d\u0430\u043b\u0435<\/a> \u0410\u043b\u0435\u043a\u0441\u0435\u044f \u041c\u0430\u043a\u0430\u0440\u043e\u0432\u0430 \u0438\u0437 \u041f\u0440\u0430\u043a\u0442\u0438\u043a\u0443\u043c\u0430 \u043f\u043e\u044f\u0432\u0438\u043b\u043e\u0441\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435, \u0447\u0442\u043e \u0435\u0433\u043e \u043a\u043e\u043c\u0430\u043d\u0434\u0435 \u043d\u0443\u0436\u043d\u0430 \u043f\u043e\u043c\u043e\u0449\u044c \u0441 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0435\u0439. \u041c\u043d\u0435 \u0437\u0430\u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0435 \u0438 \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0435 \u043e\u0431\u0443\u0447\u0430\u044e\u0449\u0435\u0435 \u0432\u0438\u0434\u0435\u043e, \u0440\u0430\u0441\u043a\u0440\u044b\u0432\u0430\u044e\u0449\u0435\u0435 \u043e\u0434\u043d\u0443 \u0438\u0437 \u0442\u0435\u043c \u043a\u0443\u0440\u0441\u0430, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0433\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u044b. <\/p>\n<p>  \u042f \u0443\u0433\u043b\u0443\u0431\u0438\u043b\u0441\u044f \u0432 \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u0430 \u0438 \u043f\u0435\u0440\u0435\u0447\u0438\u0442\u0430\u043b \u043d\u0435\u043c\u0430\u043b\u043e \u0441\u0442\u0430\u0442\u0435\u0439 \u043d\u0430 \u0442\u0435\u043c\u0443 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u00ab\u043a\u0430\u043a \u0443 3Blue1Brown\u00bb, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u0431\u044b\u043b\u0438 \u043b\u0438\u0431\u043e \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430\u043c\u0438, \u043b\u0438\u0431\u043e \u043a\u043e\u043f\u0438\u0435\u0439 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u0430 \u0413\u0440\u0430\u043d\u0442\u0430 \u0421\u0430\u043d\u0434\u0435\u0440\u0441\u043e\u043d\u0430. \u0413\u0440\u0430\u043d\u0442 \u0441\u043e\u0437\u0434\u0430\u043b \u0438 \u0432\u044b\u043b\u043e\u0436\u0438\u043b \u0432 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0439 \u0434\u043e\u0441\u0442\u0443\u043f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u043d\u0430 Python \u2014 <a href=\"https:\/\/github.com\/3b1b\/manim\">Manim<\/a>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438. \u0412 \u0440\u043e\u043b\u0438\u043a\u0430\u0445, \u0437\u0430\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Manim, \u043e\u043d \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0435\u0442 \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0442\u0435\u043c\u044b \u043d\u0430 \u0441\u0432\u043e\u0451\u043c <a href=\"https:\/\/www.youtube.com\/channel\/UCYO_jab_esuFRV4b17AJtAw\">YouTube-\u043a\u0430\u043d\u0430\u043b\u0435<\/a>.<\/p>\n<p>  \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u043e\u0434\u0435\u043b\u044e\u0441\u044c \u043b\u0438\u0447\u043d\u044b\u043c \u043e\u043f\u044b\u0442\u043e\u043c: \u0440\u0435\u0446\u0435\u043f\u0442\u043e\u043c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439. \u0412\u043c\u0435\u0441\u0442\u0435 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043e\u0431\u0443\u0447\u0430\u044e\u0449\u0435\u0435 \u0432\u0438\u0434\u0435\u043e \u043e \u0433\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u0430\u0445. \u0412\u043e\u0442 \u043a\u0430\u043a \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0438\u0442\u043e\u0433\u043e\u0432\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/rd\/9p\/yp\/rd9pypqeiwclfrs7s2765vovpyw.gif\" data-src=\"https:\/\/habrastorage.org\/webt\/rd\/9p\/yp\/rd9pypqeiwclfrs7s2765vovpyw.gif\"\/><br \/>  <a name=\"habracut\"><\/a><br \/>  \u0410 \u0442\u0435\u043f\u0435\u0440\u044c \u043f\u043e\u0435\u0445\u0430\u043b\u0438!<\/p>\n<h3>\u0413\u043e\u0442\u043e\u0432\u0438\u043c \u043f\u0440\u043e\u0435\u043a\u0442 \u043a \u0437\u0430\u043f\u0443\u0441\u043a\u0443<\/h3>\n<p>  \u0414\u043b\u044f \u043d\u0430\u0447\u0430\u043b\u0430 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u043f\u0430\u043a\u0435\u0442\u044b LaTeX \u0438 FFmpeg \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0443 \u2014 \u043e\u043d\u0438 \u043d\u0443\u0436\u043d\u044b \u0434\u043b\u044f \u0440\u0435\u043d\u0434\u0435\u0440\u0430 \u0432\u0438\u0434\u0435\u043e \u0438 \u0442\u0435\u043a\u0441\u0442\u0430 (\u0432\u0441\u0435 \u043e\u043f\u0435\u0440\u0430\u0446\u0438\u0438 \u043f\u0440\u043e\u0438\u0437\u0432\u043e\u0434\u044f\u0442\u0441\u044f \u0432 macOS Big Sur). \u0414\u043b\u044f \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 LaTeX \u043f\u0435\u0440\u0435\u0439\u0434\u0451\u043c \u043d\u0430 \u0441\u0430\u0439\u0442 <a href=\"http:\/\/www.tug.org\/mactex\/\">www.tug.org\/mactex<\/a>, \u0441\u043a\u0430\u0447\u0430\u0435\u043c \u0438 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u043c \u043f\u0430\u043a\u0435\u0442 \u0432 \u0441\u0438\u0441\u0442\u0435\u043c\u0443. \u0415\u0441\u0442\u044c \u0438 \u0431\u043e\u043b\u0435\u0435 \u043a\u0430\u043d\u043e\u043d\u0438\u0447\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u2014 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c Brew \u0438 \u0441\u0440\u0430\u0437\u0443 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c \u043e\u0431\u0430 \u043f\u0430\u043a\u0435\u0442\u0430, \u043a\u0430\u043a \u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043e \u0432 Readme \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u044f:<\/p>\n<pre><code class=\"python\">> brew install ffmpeg mactex<\/code><\/pre>\n<p>  <b>\u0412\u0430\u0436\u043d\u043e! <\/b>\u0418\u043d\u043e\u0433\u0434\u0430 \u043f\u043e\u0441\u043b\u0435 \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0438 Manim \u043e\u0442\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u044c \u0432\u0438\u0434\u0435\u043e, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0435\u0441\u0442\u044c \u0440\u0443\u0441\u0441\u043a\u0438\u0439 \u0442\u0435\u043a\u0441\u0442 (\u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u044d\u0442\u043e \u043e\u0441\u043e\u0431\u0435\u043d\u043d\u043e\u0441\u0442\u0438 MacOS). \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u044f \u0433\u0440\u0435\u0448\u0438\u043b \u043d\u0430 \u043d\u0435\u043f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u0443\u044e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0443 LaTeX, \u0442\u0430\u043a \u043a\u0430\u043a \u043e\u0448\u0438\u0431\u043a\u0430 \u0443\u043a\u0430\u0437\u044b\u0432\u0430\u043b\u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u043d\u0430 \u043d\u0435\u0433\u043e, \u043d\u043e \u0434\u0435\u043b\u043e \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0432 \u0434\u0440\u0443\u0433\u043e\u043c. \u041e\u0431\u044a\u044f\u0441\u043d\u044e \u043d\u0438\u0436\u0435.<\/p>\n<p>  \u0421\u043e\u0431\u0438\u0440\u0430\u0442\u044c \u0438 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442 \u0431\u0443\u0434\u0435\u043c \u043f\u043e-\u043c\u043e\u0434\u043d\u043e\u043c\u0443 \u2014 \u0447\u0435\u0440\u0435\u0437 <a href=\"https:\/\/python-poetry.org\/\">Poetry<\/a>.<\/p>\n<pre><code class=\"python\">> poetry new habr_manim > cd habr_manim > poetry add manimlib > touch main.py > mkdir classes <\/code><\/pre>\n<p>  <\/p>\n<h3>\u041f\u0440\u043e\u0431\u0443\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043f\u0440\u043e\u0441\u0442\u0435\u0439\u0448\u0435\u0435 \u0432\u0438\u0434\u0435\u043e <\/h3>\n<p>  \u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0432\u0438\u0434\u0435\u043e \u043d\u0430\u043c \u043f\u043e\u0442\u0440\u0435\u0431\u0443\u044e\u0442\u0441\u044f:<\/p>\n<ul>\n<li>\u0442\u0435\u043a\u0441\u0442,<\/li>\n<li>\u0448\u0430\u0440\u0438\u043a\u0438 (\u0442\u043e\u0447\u043a\u0438),<\/li>\n<li>\u044d\u0444\u0444\u0435\u043a\u0442\u044b \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044f \u0438 \u0437\u0430\u0442\u0443\u0445\u0430\u043d\u0438\u044f.<\/li>\n<\/ul>\n<p>  \u0412 \u043d\u0430\u0448\u0435\u043c \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u043d\u043e\u0432\u044b\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c \u0431\u0443\u0434\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0442\u0435\u043a\u0441\u0442, \u0442\u0430\u043a \u043a\u0430\u043a \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0448\u0440\u0438\u0444\u0442\u0430 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u0435\u0440\u0435\u0433\u0440\u0443\u0437\u0438\u0442\u044c, \u0434\u043e\u0431\u0430\u0432\u0438\u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e \u043a\u043b\u0430\u0441\u0441\u0430 CONFIG. \u041e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u2014 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0435 \u043a\u043b\u0430\u0441\u0441\u044b \u0438\u0437 Manim.<\/p>\n<p>  \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0444\u0430\u0439\u043b histogram_text.py \u0441\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u044b\u043c:<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">classes\/histogram_text.py<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">from manimlib.imports import Text TEXT_FONT_FAMILY = \"Suisse Intl Regular\" class HistogramText(Text):    \"\"\"Overridden class of Text to assign a new font\"\"\"    CONFIG = {        \"font\": TEXT_FONT_FAMILY,    } <\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  \u0414\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0448\u0430\u0440\u0438\u043a\u043e\u0432 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 Dot, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u043a\u0443\u0447\u0443 \u0440\u0430\u0437\u043d\u044b\u0445 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432. \u041d\u0430\u043c \u043d\u0443\u0436\u043d\u044b \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435:<\/p>\n<ul>\n<li>point (\u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u043d\u0430 \u043f\u043b\u043e\u0441\u043a\u043e\u0441\u0442\u0438),<\/li>\n<li>radius (\u0440\u0430\u0437\u043c\u0435\u0440),<\/li>\n<li>stroke_width (\u0448\u0438\u0440\u0438\u043d\u0430 \u043e\u0431\u0432\u043e\u0434\u043a\u0438),<\/li>\n<li>stroke_color (\u0446\u0432\u0435\u0442 \u043e\u0431\u0432\u043e\u0434\u043a\u0438),<\/li>\n<li>color (\u0446\u0432\u0435\u0442 \u043a\u0440\u0443\u0436\u043a\u0430).<\/li>\n<\/ul>\n<p>  \u041f\u043e\u043b\u043d\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442 \u043a\u043e\u0434\u0430 \u0431\u0443\u0434\u0435\u0442 \u043d\u0438\u0436\u0435, \u0430 \u043f\u043e\u043a\u0430 \u043e\u043f\u0438\u0448\u0443 \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0438 \u043a\u043b\u0430\u0441\u0441\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0430\u043c \u043f\u0440\u0438\u0433\u043e\u0434\u044f\u0442\u0441\u044f:<\/p>\n<ul>\n<li>Scene \u2014 \u043a\u043b\u0430\u0441\u0441 \u0441\u0446\u0435\u043d\u044b,<\/li>\n<li>Scene.add() \u2014 \u043c\u0435\u0442\u043e\u0434 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u043d\u0430 \u0441\u0446\u0435\u043d\u0443,<\/li>\n<li>Scene.play() \u2014 \u043c\u0435\u0442\u043e\u0434 \u043f\u0440\u043e\u0438\u0433\u0440\u044b\u0432\u0430\u043d\u0438\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438,<\/li>\n<li>Scene.wait() \u2014 \u043c\u0435\u0442\u043e\u0434 \u043e\u0436\u0438\u0434\u0430\u043d\u0438\u044f,<\/li>\n<li>Dot() \u2014 \u043a\u043b\u0430\u0441\u0441 \u0442\u043e\u0447\u043a\u0438,<\/li>\n<li>VGroup() \u2014 \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u043e\u0432\u043a\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0441\u0446\u0435\u043d\u044b,<\/li>\n<li>HistogramText \u2014 \u043a\u043b\u0430\u0441\u0441 \u0442\u0435\u043a\u0441\u0442\u0430,<\/li>\n<li>HistogramText.move_to() \u2014 \u043c\u0435\u0442\u043e\u0434 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u0442\u0435\u043a\u0441\u0442\u0430 \u043d\u0430 \u0441\u0446\u0435\u043d\u0435,<\/li>\n<li>HistogramText.scale() \u2014 \u043c\u0435\u0442\u043e\u0434 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0440\u0430\u0437\u043c\u0435\u0440\u0430 \u0442\u0435\u043a\u0441\u0442\u0430,<\/li>\n<li>FadeIn \u2014 \u043a\u043b\u0430\u0441\u0441 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0432 \u0441\u0446\u0435\u043d\u0435,<\/li>\n<li>FadeOut \u2014 \u043a\u043b\u0430\u0441\u0441 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u0438\u0441\u0447\u0435\u0437\u043d\u043e\u0432\u0435\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u0430 \u0438\u0437 \u0441\u0446\u0435\u043d\u044b.<\/li>\n<\/ul>\n<p>  \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0432 \u043a\u043e\u0440\u043d\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0444\u0430\u0439\u043b scenario.py, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043e\u043f\u0438\u0448\u0435\u043c \u043e\u0441\u043d\u043e\u0432\u043d\u044b\u0435 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438 \u0434\u043b\u044f \u0440\u0430\u0437\u043d\u044b\u0445 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439. \u041a\u043e\u0434 \u0432 \u044d\u0442\u043e\u043c \u0444\u0430\u0439\u043b\u0435 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e\u0445\u043e\u0436 \u043d\u0430 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u044b\u0439 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439 (\u043e\u0431\u0440\u0430\u0442\u0438\u0442\u0435 \u0432\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u043d\u0430 \u043c\u0435\u0442\u043e\u0434 play_whole_scenario() \u2014 \u044f\u0440\u043a\u0438\u0439 \u043f\u0440\u0438\u043c\u0435\u0440 \u0442\u0430\u043a\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438), \u0430 \u0432\u0441\u044e \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u0441\u043f\u0440\u044f\u0447\u0435\u043c \u0432 \u043a\u043b\u0430\u0441\u0441\u044b-\u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0441\u0446\u0435\u043d\u044b. \u041d\u0430\u0447\u043d\u0451\u043c \u0441 \u0441\u0430\u043c\u043e\u0433\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e \u2014 \u043f\u0440\u0438\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u0432\u0438\u0434\u0435\u043e\u0437\u0430\u0441\u0442\u0430\u0432\u043a\u0438 \u00ab\u0413\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u044b\u00bb.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">scenario.py<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">from manimlib.imports import MovingCameraScene, Dot, VGroup, BLACK, FadeIn, FadeOut from numpy import array from random import randint from classes import HistogramText class Scenario:    def __init__(self, scene: Scene):        \"\"\"Main scenario class initialization.          Args:            scene (Scene): Instance of the Scene class.        \"\"\"        self.scene = scene      def play_first_scene(self):        # We are creating list for storing dots        dots = []          # Columns with dots will be placed one after another, so X position        # will be calculated automatically        start_x = -4          # Dot size        point_radius = 0.3          for _ in range(5):            # Dots inside columns will be placed one above the other, so Y position            # will be calculated automatically            start_y = -2              for _ in range(randint(2, 6)):                dots.append(                    Dot(                        point=array([start_x, start_y, 0]),  # Coordinates on the screen, assigned with x,y,z                        radius=point_radius,  # Dot size                        stroke_width=1,  # Border width                        stroke_color=BLACK,  # Border color                        color=\"#7fcc81\",  # Dot color                    )                )                start_y += 0.7            start_x += 2          # Grouping dots into VGroup that is the Scene's element        dots = VGroup(*dots)          # Adding dots to the scene        self.scene.add(dots)          # Creating text. We are using our own Overridden class.        heading = HistogramText(\"\u0413\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u044b\", color=BLACK)          # Changin text size with scale        heading.scale(2)          # Changing text location        heading.move_to(array([0, 2.5, 0]))          # Playing animation for the text appearing        self.scene.play(FadeIn(heading))          # Waiting        self.scene.wait(2)          # Playing animation for the text disappearing        self.scene.play(FadeOut(dots), FadeOut(heading))          # Waiting        self.scene.wait(1)<\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  \u0412\u0441\u0435 \u0444\u0430\u0439\u043b\u044b \u0433\u043e\u0442\u043e\u0432\u044b. \u0427\u0442\u043e\u0431\u044b \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442\u044c\u0441\u044f, \u043d\u0430\u043c \u043e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u043b\u0438\u0448\u044c \u0434\u043e\u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435, \u0432\u044b\u0437\u0432\u0430\u0432 \u0438\u0437 main.py \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439.<\/p>\n<p>  \u041a\u043b\u0430\u0441\u0441 MainScene \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0437\u0430\u043f\u0443\u0441\u043a \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0414\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0440\u0435\u043d\u0434\u0435\u0440\u0430 \u0432\u0438\u0434\u0435\u043e \u044d\u0442\u043e\u0442 \u043a\u043b\u0430\u0441\u0441 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u0434\u043e\u043b\u0436\u0435\u043d \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043e\u0442 CameraScene (\u043c\u044b \u0431\u0443\u0434\u0435\u043c \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u043e\u0442 MovingCameraScene, \u0442\u0430\u043a \u043a\u0430\u043a \u0434\u043b\u044f \u0434\u0430\u043b\u044c\u043d\u0435\u0439\u0448\u0435\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f \u043c\u0435\u0442\u043e\u0434\u044b \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u043a\u0430\u043c\u0435\u0440\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0435\u0442 \u0432 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0439 CameraScene). \u0412 \u043d\u0430\u0448\u0435\u043c \u043a\u043b\u0430\u0441\u0441\u0435 \u043e\u0431\u044a\u044f\u0432\u043b\u0435\u043d\u0430 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0430\u044f CONFIG, \u0432 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0441\u0446\u0435\u043d\u044b. \u041c\u0435\u0442\u043e\u0434 construct \u2014 \u0442\u043e\u0447\u043a\u0430 \u0432\u0445\u043e\u0434\u0430 \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435. \u0412\u043e\u0442 \u043a\u0430\u043a \u044d\u0442\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0432 \u043a\u043e\u0434\u0435:<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">main.py<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">import os from pathlib import Path   # We are importing MovingCamera, instead of CameraScene to be able to # move the camera around. from manimlib.imports import MovingCameraScene   from config import SCENE_BACKGROUND_COLOR from scenario import Scenario   # Adding flags to build animation. # -l (low quality) # -s (only screenshot) RESOLUTION = \"\" FLAGS = f\"-pl {RESOLUTION}\" SCENE = \"MainScene\"     class MainScene(MovingCameraScene):    # Scene background is black by default, to change it we need to    # override CONFIG dictionary.    CONFIG = {        \"camera_config\": {            \"background_color\": SCENE_BACKGROUND_COLOR,        },    }      def construct(self):        \"\"\"Construct method - enter point to create animation\"\"\"        hist = Scenario(self)        hist.play_first_scene()   if __name__ == \"__main__\":    script_name = Path(__file__).resolve()    os.system(f\"manim {script_name} {SCENE} {FLAGS}\")<\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  \u0418\u0442\u043e\u0433\u043e\u0432\u0430\u044f \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0430\u0441\u044c \u0442\u0430\u043a\u043e\u0439:<\/p>\n<pre><code class=\"python\">classes\/ __init__.py histogram_text.py main.py scenario.py pyproject.toml <\/code><\/pre>\n<p>  \u041f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0433\u043e\u0442\u043e\u0432\u043e \u043a \u043f\u0435\u0440\u0432\u043e\u043c\u0443 \u0437\u0430\u043f\u0443\u0441\u043a\u0443. \u0418\u0437\u043c\u0435\u043d\u0438\u043c pyproject.toml, \u0434\u043e\u0431\u0430\u0432\u0438\u0432 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e packages \u0441 \u043d\u0430\u0448\u0438\u043c\u0438 \u043a\u043b\u0430\u0441\u0441\u0430\u043c\u0438 \u0438 \u0441\u043e\u0431\u0435\u0440\u0451\u043c \u043f\u0440\u043e\u0435\u043a\u0442:<\/p>\n<pre><code class=\"python\">> vi pyproject.toml [tool.poetry] ... packages = [     { include = \"classes\" } ]  > poetry build > poetry install > poetry run python main.py <\/code><\/pre>\n<p>  \u041f\u0435\u0440\u0432\u0430\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044f \u0433\u043e\u0442\u043e\u0432\u0430!<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/dl\/n7\/pc\/dln7pcbiux8ss2ze0jwj7lahv64.gif\" data-src=\"https:\/\/habrastorage.org\/webt\/dl\/n7\/pc\/dln7pcbiux8ss2ze0jwj7lahv64.gif\"\/><\/p>\n<h3>\u0420\u0435\u0448\u0430\u0435\u043c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0443 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430 \u0440\u0443\u0441\u0441\u043a\u043e\u044f\u0437\u044b\u0447\u043d\u043e\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u0430<\/h3>\n<p>  \u0427\u0442\u043e \u0434\u0435\u043b\u0430\u0442\u044c, \u0435\u0441\u043b\u0438 \u0432\u044b \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0438\u0441\u044c \u0441 \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u043e\u0439 \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u043d\u0433\u0430 \u0440\u0443\u0441\u0441\u043a\u043e\u0433\u043e \u0442\u0435\u043a\u0441\u0442\u0430? \u0420\u0430\u0441\u0441\u043a\u0430\u0437\u044b\u0432\u0430\u044e:<\/p>\n<pre><code class=\"python\">> poetry env info<\/code><\/pre>\n<p>  \u041a\u043e\u043f\u0438\u0440\u0443\u0435\u043c \u043f\u0443\u0442\u044c \u043a venv, \u043e\u043d \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a: <i>~\/Library\/Caches\/pypoetry\/virtualenvs\/habr-manim-jyKtqU_G-py3.7<\/i><\/p>\n<p>  \u041d\u0430\u0445\u043e\u0434\u0438\u043c \u0444\u0430\u0439\u043b tex_template.tex \u0432 \u0432\u0438\u0440\u0442\u0443\u0430\u043b\u044c\u043d\u043e\u043c \u043e\u043a\u0440\u0443\u0436\u0435\u043d\u0438\u0438 \u0438 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u0443\u0435\u043c \u0435\u0433\u043e:<br \/>  <i>> vi ~\/Library\/Caches\/pypoetry\/virtualenvs\/habr-manim-jyKtqU_G-py3.7\/lib\/python3.7\/site-packages\/manimlib\/tex_template.tex<\/i><\/p>\n<p>  \u0421\u0432\u0435\u0440\u044f\u0435\u043c\u0441\u044f, \u0447\u0442\u043e\u0431\u044b \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u043c\u043e\u0435 \u0431\u044b\u043b\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u0433\u043e \u0432\u0438\u0434\u0430:<br \/>  \\documentclass[preview]{standalone}<\/p>\n<p>  \\usepackage[english]{babel}<br \/>  \\usepackage[utf8]{inputenc}<br \/>  \\usepackage[T1]{fontenc}<br \/>  \\usepackage{amsmath}<br \/>  \\usepackage{amssymb}<br \/>  \\usepackage{dsfont}<br \/>  \\usepackage{setspace}<br \/>  \\usepackage{tipa}<br \/>  \\usepackage{relsize}<br \/>  \\usepackage{textcomp}<br \/>  \\usepackage{mathrsfs}<br \/>  \\usepackage{calligra}<br \/>  \\usepackage{wasysym}<br \/>  \\usepackage{ragged2e}<br \/>  \\usepackage{physics}<br \/>  \\usepackage{xcolor}<br \/>  \\usepackage{microtype}<br \/>  \\DisableLigatures{encoding = *, family = * }<br \/>  %\\usepackage[UTF8]{ctex}<br \/>  \\linespread{1}<\/p>\n<p>  \\begin{document}<\/p>\n<p>  YourTextHere<\/p>\n<p>  \\end{document}<br \/>  \u0421\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0444\u0430\u0439\u043b. \u0422\u0435\u043f\u0435\u0440\u044c \u0440\u0443\u0441\u0441\u043a\u0438\u0439 \u0442\u0435\u043a\u0441\u0442 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c\u0441\u044f \u043d\u043e\u0440\u043c\u0430\u043b\u044c\u043d\u043e.<\/p>\n<p>  \u0418\u0442\u043e\u0433\u043e \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u043a\u0430\u0440\u043a\u0430\u0441 \u0434\u043b\u044f \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f, \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043b\u0438 \u0435\u0433\u043e \u043a \u0437\u0430\u043f\u0443\u0441\u043a\u0443, \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u0438 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441 \u0442\u0435\u043a\u0441\u0442\u0430, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0448\u0440\u0438\u0444\u0442, \u0438 \u0441\u043e\u0437\u0434\u0430\u043b\u0438 \u0432\u0438\u0434\u0435\u043e \u0434\u043b\u044f \u0432\u0441\u0442\u0443\u043f\u043b\u0435\u043d\u0438\u044f. \u041d\u043e \u0434\u0430\u043b\u044c\u0448\u0435 \u2014 \u0431\u043e\u043b\u044c\u0448\u0435. \u0411\u0443\u0434\u0435\u043c \u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0433\u0440\u0430\u0444\u0438\u043a, \u0442\u0430\u0431\u043b\u0438\u0446\u0443, \u0432\u043e\u0440\u043e\u043d\u043a\u0443 \u0438 \u0448\u0430\u0440\u0438\u043a\u0438. <\/p>\n<h3>\u041e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0435\u043c \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438<\/h3>\n<p>  <b>\u0414\u0438\u0441\u043a\u043b\u0435\u0439\u043c\u0435\u0440!<\/b> <i>\u041f\u0440\u043e\u0442\u0438\u0432\u043d\u0438\u043a\u0430\u043c \u041e\u041e\u041f \u043f\u043e\u0441\u043b\u0435 \u043f\u0440\u043e\u0447\u0442\u0435\u043d\u0438\u044f \u043c\u043e\u0436\u0435\u0442 \u0441\u0442\u0430\u0442\u044c \u043f\u043b\u043e\u0445\u043e<\/i>. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439 \u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u044b, \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u0434\u043b\u044f \u0435\u0433\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438:<\/p>\n<p>  <b>\u0421\u0446\u0435\u043d\u0430\u0440\u0438\u0439 1<\/b><\/p>\n<ol>\n<li>\u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0438 \u0448\u0430\u0440\u0438\u043a\u043e\u0432,<\/li>\n<li>\u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u0435 \u0433\u0440\u0430\u0444\u0438\u043a\u0430,<\/li>\n<li>\u043f\u0435\u0440\u0435\u043d\u043e\u0441 \u0448\u0430\u0440\u0438\u043a\u043e\u0432 \u0438\u0437 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u043d\u0430 \u0433\u0440\u0430\u0444\u0438\u043a.<\/li>\n<\/ol>\n<p>  <b>\u0421\u0446\u0435\u043d\u0430\u0440\u0438\u0439 2<\/b><\/p>\n<ol>\n<li>\u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0438 \u0448\u0430\u0440\u0438\u043a\u043e\u0432,<\/li>\n<li>\u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u0435 \u0433\u0440\u0430\u0444\u0438\u043a\u0430,<\/li>\n<li>\u043f\u0435\u0440\u0435\u043d\u043e\u0441 \u0448\u0430\u0440\u0438\u043a\u043e\u0432 \u0438\u0437 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u043d\u0430 \u0433\u0440\u0430\u0444\u0438\u043a,<\/li>\n<li>\u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u0435 \u043a\u043e\u0440\u0437\u0438\u043d (\u0432\u043e\u0440\u043e\u043d\u043e\u043a),<\/li>\n<li>\u043f\u0435\u0440\u0435\u043d\u043e\u0441 \u0448\u0430\u0440\u0438\u043a\u043e\u0432 \u0441 \u0433\u0440\u0430\u0444\u0438\u043a\u0430 \u0432 \u0432\u043e\u0440\u043e\u043d\u043a\u0443.<\/li>\n<\/ol>\n<p>  \u0418\u0441\u0445\u043e\u0434\u044f \u0438\u0437 \u044d\u0442\u0438\u0445 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u0432, \u043d\u0430\u043c \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b:<\/p>\n<ul>\n<li>\u0442\u0430\u0431\u043b\u0438\u0446\u0430 (\u0434\u043e\u043b\u0436\u043d\u0430 \u0431\u044b\u0442\u044c \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0434\u043b\u0438\u043d\u044b),<\/li>\n<li>\u0433\u0440\u0430\u0444\u0438\u043a (\u043d\u0443\u0436\u043d\u043e \u0434\u0432\u0430 \u0432\u0438\u0434\u0430, \u0434\u0438\u0441\u043a\u0440\u0435\u0442\u043d\u044b\u0439 \u0438 \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u044b\u0439),<\/li>\n<li>\u0448\u0430\u0440\u0438\u043a\u0438 (\u0434\u043e\u043b\u0436\u043d\u044b \u0445\u0440\u0430\u043d\u0438\u0442\u044c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435),<\/li>\n<li>\u0432\u043e\u0440\u043e\u043d\u043a\u0438 (\u0432\u043e\u0440\u043e\u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u043f\u0440\u043e\u043f\u0438\u0441\u0430\u0442\u044c \u0444\u0438\u0437\u0438\u043a\u0443 \u043f\u0430\u0434\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0448\u0430\u0440\u0438\u043a\u043e\u0432).<\/li>\n<\/ul>\n<p>  <\/p>\n<h3>\u0421\u043e\u0437\u0434\u0430\u0451\u043c \u0448\u0430\u0440\u0438\u043a\u0438<\/h3>\n<p>  \u041d\u0430\u0447\u043d\u0451\u043c \u0441 \u0441\u0430\u043c\u043e\u0433\u043e \u043f\u0440\u043e\u0441\u0442\u043e\u0433\u043e. \u0412 \u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0440\u0438\u044e classes \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u043d\u043e\u0432\u044b\u0439 \u0444\u0430\u0439\u043b \u2014 <b>histogram_dot.py<\/b>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0448\u0430\u0440\u0438\u043a\u0430. \u041a\u043e\u0434 \u043d\u0438\u0436\u0435 \u043f\u043e\u0434 \u0441\u043f\u043e\u0439\u043b\u0435\u0440\u043e\u043c, \u043d\u043e \u043a\u043b\u044e\u0447\u0435\u0432\u044b\u0435 \u043c\u043e\u043c\u0435\u043d\u0442\u044b \u043e\u0431\u044a\u044f\u0441\u043d\u044e \u0442\u0443\u0442:<\/p>\n<ul>\n<li>\u0412\u0441\u0435 \u043a\u043b\u0430\u0441\u0441\u044b \u043d\u043e\u0432\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0434\u043e\u043b\u0436\u043d\u044b \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u044c \u0443\u0436\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0435 \u043a\u043b\u0430\u0441\u0441\u044b Manim. \u0412 \u0441\u043b\u0443\u0447\u0430\u0435 \u0448\u0430\u0440\u0438\u043a\u0430 \u043c\u044b \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u043c \u043a\u043b\u0430\u0441\u0441 <b>VGroup<\/b>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u0442 \u0433\u0440\u0443\u043f\u043f\u0443 \u0438\u0437 \u0442\u0435\u043a\u0441\u0442\u0430 \u0438 \u0442\u043e\u0447\u043a\u0438. \u0422\u0430\u043a \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043b\u044e\u0431\u044b\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b, \u0433\u0440\u0443\u043f\u043f\u0438\u0440\u0443\u044f \u0438\u0445 \u0432 VGroup \u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u044f \u0441 \u043d\u0438\u043c\u0438 \u043a\u0430\u043a \u0441 \u043e\u0434\u043d\u0438\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c-\u0433\u0440\u0443\u043f\u043f\u043e\u0439.<\/li>\n<li>\u041f\u043e\u0441\u043b\u0435 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u043d\u0435 \u0437\u0430\u0431\u044b\u0432\u0430\u0435\u043c \u043f\u0440\u043e\u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0440\u043e\u0434\u0438\u0442\u0435\u043b\u044f (<b>super<\/b>) \u0441 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0435\u0439 \u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0445 \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432.<\/li>\n<\/ul>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">classes\/histogram_dot.py<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">from typing import Dict, Union   from colour import Color from manimlib.imports import BLACK, WHITE, Dot, VGroup from numpy import ndarray   from .histogram_text import HistogramText from .shape_point import ShapePoint     class HistogramDot(VGroup):    \"\"\"This class contains Dot, Text and all needed info that we want, such as 'value'\"\"\"      colors: Dict[int, str] = {        1: \"#7FCC81\",  # green        2: \"#FFE236\",  # yellow        3: \"#FFB742\",  # orange        4: \"#FF7555\",  # red    }      dot_scale_float: Union[int, float] = 0.25    dot_scale_int: Union[int, float] = 0.4    radius: Union[int, float] = 0.2      def __init__(        self,        value: int,        point: ndarray,        radius: float = None,        color: Color = None,    ):        \"\"\"Class initialization.          Args:            value (int): Text of the dot.            point (array): Location on the screen.            radius (float, optional): Dot radius. Defaults to None.            color (Color, optional): Dot color. Defaults to None.        \"\"\"        self.value = value          self.radius = radius or self.radius          if not color:            color = self.colors.get(value, WHITE)          dot = Dot(            point=point,            radius=self.radius,            color=color,            stroke_color=BLACK,            stroke_width=1,        )        text = HistogramText(str(self.value), color=BLACK)          self.point = ShapePoint(point)          # We are changing the text size to be able to add it inside a d        if isinstance(self.value, float):            text.scale(self.dot_scale_float)        else:            text.scale(self.dot_scale_int)          # Moving text inside a dot        text.move_to(dot.get_center())          super().__init__(dot, text)      def __repr__(self):        return f\"{self.__class__.__name__}({self.value}, {self.point}, {self.radius}, {self.color})\"<\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  <\/p>\n<h3>\u0421\u043e\u0437\u0434\u0430\u0451\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0443<\/h3>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0432 \u043d\u0435\u0433\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u0440\u0430\u0437\u043c\u0435\u0440\u043e\u0432 \u0438 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u0432. \u0412 \u0440\u0430\u043c\u043a\u0430\u0445 \u043d\u0430\u0448\u0435\u0439 \u0437\u0430\u0434\u0430\u0447\u0438 \u0443\u0434\u043e\u0431\u0441\u0442\u0432\u043e \u0438 \u0443\u043d\u0438\u0432\u0435\u0440\u0441\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0432\u0430\u0436\u043d\u0435\u0435, \u0447\u0435\u043c single-responsibility principle. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u043c\u044b \u0441\u0434\u0435\u043b\u0430\u0435\u043c \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0432\u044b\u0437\u044b\u0432\u0430\u043b\u043e\u0441\u044c \u043e\u0434\u043d\u0438\u043c \u043c\u0435\u0442\u043e\u0434\u043e\u043c \u0438 \u0440\u0430\u0431\u043e\u0442\u0430\u043b\u043e \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e. \u0421\u0430\u043c\u0430 \u0442\u0430\u0431\u043b\u0438\u0446\u0430 \u0432 \u044d\u0442\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0442\u043e\u0436\u0435 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c <b>VGroup<\/b> \u0438 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u043a\u0443\u0447\u0438 \u043b\u0438\u043d\u0438\u0439, \u0442\u0435\u043a\u0441\u0442\u0430 \u0438 \u0448\u0430\u0440\u0438\u043a\u043e\u0432.<\/p>\n<p>  \u0427\u0442\u043e\u0431\u044b \u043d\u0435 \u0437\u0430\u043f\u0443\u0442\u0430\u0442\u044c\u0441\u044f, \u0440\u0430\u0437\u0434\u0435\u043b\u0438\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u043d\u0430 \u043e\u0431\u044b\u0447\u043d\u0443\u044e (\u043a\u043b\u0430\u0441\u0441 <b>Table<\/b>, \u0441\u043e\u0441\u0442\u043e\u044f\u0449\u0438\u0439 \u0438\u0437 \u043b\u0438\u043d\u0438\u0439) \u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u043f\u043e\u043a\u0443\u043f\u0430\u0442\u0435\u043b\u0435\u0439 (\u043e\u043d\u0430 \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u0442 <b>Table<\/b> \u0438 \u0434\u043e\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u043b\u0438\u043d\u0438\u0438 \u0442\u0435\u043a\u0441\u0442\u043e\u043c \u0438 \u0448\u0430\u0440\u0438\u043a\u0430\u043c\u0438). \u0412 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u043d\u0430 \u0432\u0445\u043e\u0434 \u043f\u043e\u0434\u0430\u044e\u0442\u0441\u044f \u043a\u043e\u0440\u0442\u0435\u0436\u0438 \u0441 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430\u043c\u0438, \u0438\u0445 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044e \u043c\u044b \u0432\u044b\u043d\u043e\u0441\u0438\u043c \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0430\u0441\u0441-helper <b>ShapePoint<\/b>. \u041e\u043d \u0431\u0443\u0434\u0435\u0442 \u0432\u0430\u043b\u0438\u0434\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0438 \u043e\u0431\u043e\u0437\u043d\u0430\u0447\u0430\u0442\u044c \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u0442\u043e\u0447\u0435\u043a \u043d\u0430 \u043f\u043b\u043e\u0441\u043a\u043e\u0441\u0442\u0438.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">classes\/shape_point.py<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">from typing import Tuple, Union   from numpy import array, ndarray     class ShapePointException(Exception):    pass     class ShapePointTypeError(ShapePointException):    pass     class ShapePointTooManyValuesException(ShapePointException):    pass     class ShapePoint:    \"\"\"Class for validation and storing information about screen points\"\"\"      _coords: ndarray      def __init__(self, coords: Tuple[Union[int, float], Union[int, float]]):        self.coords = coords      @property    def coords(self):        return self._coords      @coords.setter    def coords(self, value: Tuple[Union[int, float], Union[int, float]]):        \"\"\"Method -setter for validation and storing coordinates.          Args:            value (Tuple[Union[int, float], Union[int, float]]): tuple with coordinates          Raises:            ShapePointTypeError: Wrong data type was passed.            ShapePointTooManyValuesException: You put too many variables inside tuple.            ShapePointTypeError: Data inside tuple is in the wrong format.        \"\"\"        if not isinstance(value, Tuple) and not isinstance(value, ndarray):            detail = f\"Coords must be a type of: [tuple, np.ndarray], got [{type(value)}] instead.\"            raise ShapePointTypeError(detail)          if isinstance(value, ndarray):            value = value[:2]          if len(value) != 2:            detail = \"Coords must contain 2 values\"            raise ShapePointTooManyValuesException(detail)          for coord in value:            if not isinstance(coord, int) and not isinstance(coord, float):                detail = f\"Values in coords must be a type of: [int, float], got [{coord}:{type(coord)}] instead.\"                raise ShapePointTypeError(detail)          self._coords = array([value[0], value[1], 0])      def __getitem__(self, item):        return self.coords[item]      def __repr__(self):        return f\"{self.__class__.__name__}({self.coords})\"<\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  \u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u044f \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b (\u043a\u043b\u0430\u0441\u0441 <b>Table<\/b>) \u043f\u0440\u043e\u0441\u0442\u043e\u0439: \u0437\u0430\u0434\u0430\u0451\u043c \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u043f\u0435\u0440\u0432\u043e\u0439 \u043b\u0438\u043d\u0438\u0438, \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u0442\u0440\u043e\u043a, \u0432\u044b\u0441\u043e\u0442\u0443 \u0441\u0442\u0440\u043e\u043a, \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043a\u043e\u043b\u043e\u043d\u043e\u043a, \u0448\u0438\u0440\u0438\u043d\u0443 \u043a\u043e\u043b\u043e\u043d\u043e\u043a \u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u0442\u0440\u043e\u043a, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432\u0438\u0434\u043d\u043e. \u041e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0430 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u0430 \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435 \u0437\u0430\u043d\u0438\u043c\u0430\u0435\u0442 \u0432\u0440\u0435\u043c\u044f \u0438 \u043f\u0430\u043c\u044f\u0442\u044c, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435, \u0433\u0434\u0435 \u0432\u0438\u0434\u043d\u043e \u0432\u0441\u0435\u0433\u043e 10 \u0441\u0442\u0440\u043e\u043a \u0438\u0437 100, \u043d\u0435\u0442 \u0441\u043c\u044b\u0441\u043b\u0430 \u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u0435\u0449\u0451 90. \u0422\u0430\u043a\u0436\u0435 \u0437\u0430\u0434\u0430\u0451\u043c \u0446\u0432\u0435\u0442 \u0438 \u0448\u0438\u0440\u0438\u043d\u0443 \u0433\u0440\u0430\u043d\u0438\u0446\u044b. \u0417\u0430\u0442\u0435\u043c \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u0441\u0442\u0440\u043e\u043a\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0433\u043e\u0440\u0438\u0437\u043e\u043d\u0442\u0430\u043b\u044c\u043d\u0443\u044e \u043b\u0438\u043d\u0438\u044e \u0438 \u0441\u0442\u043e\u043b\u044c\u043a\u043e \u0432\u0435\u0440\u0442\u0438\u043a\u0430\u043b\u044c\u043d\u044b\u0445 \u043b\u0438\u043d\u0438\u0439, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0443 \u043d\u0430\u0441 \u043a\u043e\u043b\u043e\u043d\u043e\u043a. \u0412 \u0438\u0442\u043e\u0433\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043d\u0430\u0431\u043e\u0440 <b>VGroup<\/b> \u0438\u0437 \u043b\u0438\u043d\u0438\u0439, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438 \u044f\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u0435\u0439.<\/p>\n<p>  \u041f\u043e\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0434\u043b\u044f \u043f\u043e\u043a\u0443\u043f\u0430\u0442\u0435\u043b\u0435\u0439 (<b>CustomerTable<\/b>) \u0442\u043e\u0436\u0435 \u043f\u0440\u043e\u0441\u0442\u043e: \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u043c\u0441\u044f \u043e\u0442 \u0431\u0430\u0437\u043e\u0432\u043e\u0433\u043e \u043a\u043b\u0430\u0441\u0441\u0430 \u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043d\u0430 \u043a\u0430\u0436\u0434\u0443\u044e \u0441\u0442\u0440\u043e\u0447\u043a\u0443 \u0442\u0435\u043a\u0441\u0442 \u0438 \u0448\u0430\u0440\u0438\u043a. \u0427\u0442\u043e\u0431\u044b \u0447\u0438\u0441\u043b\u0430 \u0432\u0441\u0435\u0433\u0434\u0430 \u043f\u043e\u043b\u0443\u0447\u0430\u043b\u0438\u0441\u044c \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u043c\u0438, \u0438 \u043d\u0435 \u0431\u044b\u043b\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438 \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u0432\u0432\u043e\u0434\u0438\u0442\u044c \u043a\u0443\u0447\u0443 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439, \u0432 \u043a\u043b\u0430\u0441\u0441 <b>CustomerTable<\/b> \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440 <b>start_dot_values<\/b>, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0438\u043c\u0435\u043d\u043d\u043e \u0442\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f, \u043e \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u0441\u044f \u0432 \u043e\u043f\u0438\u0441\u0430\u043d\u0438\u0438 \u0442\u0430\u0431\u043b\u0438\u0446\u044b. \u0412\u0441\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e <b>random.seed()<\/b> (\u044d\u0442\u043e \u043f\u0441\u0435\u0432\u0434\u043e\u0440\u0430\u043d\u0434\u043e\u043c, \u0442\u043e \u0435\u0441\u0442\u044c Python \u0433\u0435\u043d\u0435\u0440\u0438\u0440\u0443\u0435\u0442 \u043e\u0434\u043d\u0438 \u0438 \u0442\u0435 \u0436\u0435 \u0447\u0438\u0441\u043b\u0430 \u043a\u0430\u0436\u0434\u044b\u0439 \u0440\u0430\u0437, \u043a\u043e\u0433\u0434\u0430 \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u0448\u044c \u043f\u0440\u043e\u0435\u043a\u0442). \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0432 \u0441\u043a\u0440\u0438\u043f\u0442 500 \u0440\u0430\u0437, \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043c 500 \u043e\u0434\u0438\u043d\u0430\u043a\u043e\u0432\u044b\u0445 \u00ab\u0440\u0430\u043d\u0434\u043e\u043c\u043d\u044b\u0445\u00bb \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 (\u043b\u044e\u0431\u043b\u044e \u043f\u0438\u0442\u043e\u043d\u0447\u0438\u043a).<\/p>\n<p>  \u0424\u0430\u0439\u043b \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">classes\/table.py<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">import random from typing import Tuple, Union   from colour import Color from manimlib.imports import BLACK, LEFT_SIDE, Line, VGroup from numpy import array   from .histogram_dot import HistogramDot from .histogram_text import HistogramText from .shape_point import ShapePoint     class TableException(Exception):    pass     class TableLineEmptyException(TableException):    pass     class Table(VGroup):    \"\"\"Table class. Built from Lines\"\"\"      def __init__(        self,        start_end_points: Tuple[tuple, tuple],        row_count: int = 0,        row_height: Union[int, float] = 0.2,        column_count: int = 0,        visible_row_count: int = 0,        columns_width: tuple = None,        lines_color: Color = BLACK,        stroke_width: Union[int, float] = 1,        *args,        **kwargs,    ):        \"\"\"Class initialization.          Args:            start_end_points (Tuple[tuple, tuple]): Left top and right top points. ((x1,y1), (x2,y2)).            row_count (int, optional): Table row count. Defaults to 0.            row_height (Union[int, float], optional): Table row height. Defaults to 0.2.            column_count (int, optional): Table column count. Defaults to 0.            visible_row_count (int, optional): Table visible row count. Defaults to 0.            columns_width (tuple, optional): Table column width. For 3 columns it looks like                (.4, .4, .2). Defaults to None.            lines_color (Color, optional): Table lines color. Defaults to BLACK.            stroke_width (Union[int, float], optional): Table lines width. Defaults to 1.          Raises:            TableLineEmptyException: Raises when no start_end_points were passed.        \"\"\"        if not start_end_points:            detail = \"Can't create a graph with the empty start line.\"            raise TableLineEmptyException(detail)          if columns_width:            assert (                len(columns_width) == column_count            ), \"Columns count and list with their widths must be the same length.\"          self.horizontal_line = [            ShapePoint(start_end_points[0]),            ShapePoint(start_end_points[1]),        ]          self.row_count = row_count        self.row_height = row_height        self.column_count = column_count        self.visible_row_count = visible_row_count        self.columns_width = columns_width        self.lines_color = lines_color        self.stroke_width = stroke_width          self.lines = self._create_table()          super().__init__(*self.lines, *args, **kwargs)      def _create_table(self) -> VGroup:        \"\"\"Method for creating tables.          Returns:            VGroup: Object made from the list of lines (Line).        \"\"\"        lines = []        y_point = self.horizontal_line[0][1]        y_step = self.row_height        x_left_point = self.horizontal_line[0][0]        x_right_point = self.horizontal_line[1][0]        distance = abs(x_right_point - x_left_point)          # Drawing table        for i in range(self.row_count + 1):            # Adding horizontal line            lines.append(                Line(                    array([x_left_point, y_point, 0]),                    array([x_right_point, y_point, 0]),                    color=self.lines_color,                    stroke_width=self.stroke_width,                )            )              if i == self.row_count:                break              # Adding vertical lines            x_point = x_left_point            for j in range(self.column_count + 1):                lines.append(                    Line(                        array([x_point, y_point, 0]),                        array([x_point, y_point - y_step, 0]),                        color=self.lines_color,                        stroke_width=self.stroke_width,                    )                )                  if j == self.column_count:                    break                  if self.columns_width:                    temp_step = self.columns_width[j]                      assert isinstance(temp_step, float), \"Column width must be a float value\"                    assert 0 &lt; temp_step &lt;= 1, \"Column width must be in range [0 &lt; column_width &lt;= 1]\"                      x_point = x_point + (distance * temp_step)                else:                    x_point = x_point + (distance \/ self.column_count)              y_point -= y_step          lines = VGroup(*lines)          return lines     class CustomersTable(Table):    \"\"\"Overridden Table class. Custom text and dots were added.\"\"\"      def __init__(        self,        start_end_points: Tuple[tuple, tuple],        row_count: int = 0,        row_height: Union[int, float] = 0.5,        visible_row_count: int = 0,        colors: list = None,        bins: Union[int, float] = 0,        text: str = \"\",        start_dots_values: list = None,    ):        \"\"\"Class initialization.          Args:            start_end_points (Tuple[tuple, tuple]): Left top and right top points. ((x1,y1), (x2,y2)).            row_count (int, optional): Table row count. Defaults to 0.            row_height (Union[int, float], optional): Table row height. Defaults to 0.2.            visible_row_count (int, optional): Table visible row count. Defaults to 0.            colors (list, optional): List with dot colors. Defaults to None.            bins (Union[int, float], optional): Count of possible dots values.                Defaults to 0.            text (str, optional): Text for adding to the table. Ex \"Customer\"                Defaults to \"\".            start_dots_values (list, optional): List with initial values for the dots.                Defaults to None.        \"\"\"        self.horizontal_line = [            ShapePoint(start_end_points[0]),            ShapePoint(start_end_points[1]),        ]          self.colors = colors or list()        self.bins = bins        column_count = 2        columns_width = (0.8, 0.2)        self.text = text        self.text_scale = 0.6        self.start_dots_values = start_dots_values        self.default_color = \"red\"          self.customers, self.dots = self._add_dots_and_customers_to_table(            row_count=row_count,            row_height=row_height,            columns_width=columns_width,        )          super().__init__(            start_end_points,            row_count,            row_height,            column_count,            visible_row_count,            columns_width,            BLACK,            1,            *self.customers,            *self.dots,        )      def _add_dots_and_customers_to_table(        self,        row_height: Union[int, float],        row_count: int,        columns_width: Tuple,    ) -> Tuple[VGroup, VGroup]:        \"\"\"Method for creating dots and texts.          Args:            row_height (Union[int, float]): Table rows height.            row_count (int): Table rows count.            columns_width (Tuple): Table rows width.          Returns:            Tuple[VGroup, VGroup]: Tuple with all dots and texts.        \"\"\"        customers = []        dots = []        y_point = self.horizontal_line[0][1]        y_step = row_height        x_left_point = self.horizontal_line[0][0]        x_right_point = self.horizontal_line[1][0]        distance = abs(x_right_point - x_left_point)        step_x = distance * columns_width[0]          # Adding texts and dots        for i in range(row_count):              # Adding text to the table            customer = HistogramText(                f\"{self.text} {i+1}\",                color=BLACK,            )              # Changing text size            customer.scale(self.text_scale)              # Moving text to the table cell            customer.move_to(                array([x_left_point + 0.2, y_point - (y_step \/ 2), 0]),                aligned_edge=LEFT_SIDE,  # Aligning it at the left side of the cell            )            customers.append(customer)              # Forcing to generate always the same numbers            random.seed(i + 1)              # Adding dot value            if self.start_dots_values and i &lt; len(self.start_dots_values):                dot_value = self.start_dots_values[i]            else:                if isinstance(self.bins, int):                    dot_value = random.randrange(1, self.bins + 1)                else:                    dot_value = round(random.uniform(1.0, self.bins + 1.0), 1)              if len(self.colors) &lt; dot_value:                dot_color = self.default_color            else:                dot_color = self.colors[int(dot_value) - 1]              # Adding dot            dot = HistogramDot(                value=dot_value,                point=array([x_left_point + step_x + 0.3, y_point - (y_step \/ 2), 0]),                color=dot_color,            )              dots.append(dot)              y_point -= y_step          customers = VGroup(*customers)        dots = VGroup(*dots)          return customers, dots<\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  <\/p>\n<h3>\u0412\u044b\u043d\u043e\u0441\u0438\u043c \u0432\u0441\u044e \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0446\u0438\u044e \u0432 \u043a\u043b\u0430\u0441\u0441\u044b \u2014 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0447\u0438\u0442\u0430\u0431\u0435\u043b\u044c\u043d\u044b\u0439 \u043a\u043e\u0434<\/h3>\n<p>  \u0412\u044b \u0441\u043f\u0440\u043e\u0441\u0438\u0442\u0435 \u2014 \u0437\u0430\u0447\u0435\u043c \u0436\u0435 \u0441\u0442\u043e\u043b\u044c\u043a\u043e \u043a\u043e\u0434\u0430, \u0443\u0436\u0430\u0441\u043d\u043e\u0435 \u041e\u041e\u041f, \u043a\u0443\u0447\u0430 \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u044f \u0438 \u0442\u0430\u043a \u0434\u0430\u043b\u0435\u0435? \u0412\u0441\u0451 \u043f\u0440\u043e\u0441\u0442\u043e: \u0447\u0442\u043e\u0431\u044b \u0441\u043f\u0440\u044f\u0442\u0430\u0442\u044c \u043d\u0435\u043d\u0443\u0436\u043d\u0443\u044e \u0448\u0435\u043b\u0443\u0445\u0443 \u0432 \u043a\u043b\u0430\u0441\u0441\u044b. \u0422\u043e\u0433\u0434\u0430 \u043a\u043e\u0434 \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0447\u0438\u0442\u0430\u0431\u0435\u043b\u044c\u043d\u044b\u043c \u0438 \u043a\u0440\u0430\u0441\u0438\u0432\u044b\u043c. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u0447\u0442\u043e \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441 \u0443\u0436\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u043c.<\/p>\n<p>  \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043d\u043e\u0432\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 <b>play_second_scene<\/b> \u0432 \u043a\u043b\u0430\u0441\u0441\u0435 <b>Scenario<\/b>. \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0443: \u0443\u043a\u0430\u0436\u0435\u043c \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b, \u043e\u0431\u0449\u0435\u0435 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u0442\u0440\u043e\u043a, \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0441\u0442\u0440\u043e\u043a, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u0431\u0443\u0434\u0435\u0442 \u0432\u0438\u0434\u043d\u043e \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435, \u0438 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u043a\u043e\u0440\u0437\u0438\u043d \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435. \u0414\u043e\u0431\u0430\u0432\u0438\u043c \u043c\u0435\u0442\u043e\u0434 scene.play, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0432\u044b\u0437\u043e\u0432\u0435\u043c \u043c\u0435\u0442\u043e\u0434 \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b. \u0412 \u0444\u0430\u0439\u043b\u0435 <b>main.py<\/b> \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 <b>construct<\/b> \u0437\u0430\u043c\u0435\u043d\u0438\u043c <b>hist.play_first_scene()<\/b> \u043d\u0430 <b>hist.play_second_scene()<\/b>.<\/p>\n<p>  \u041f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0440\u0435\u043d\u0434\u0435\u0440 \u0432\u0438\u0434\u0435\u043e \u0438\u0437 \u043a\u043e\u043d\u0441\u043e\u043b\u0438 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043a\u043e\u043c\u0430\u043d\u0434\u044b<\/p>\n<pre><code class=\"python\">> poetry run python main.py<\/code><\/pre>\n<p>  \u2026 \u0438 \u043d\u0430\u0441\u043b\u0430\u0436\u0434\u0430\u0435\u043c\u0441\u044f \u0432\u0438\u0434\u043e\u043c \u043d\u0430\u0448\u0435\u0439 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u043f\u043e\u043a\u0443\u043f\u0430\u0442\u0435\u043b\u0435\u0439:<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">scenario.py<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">def play_second_scene(self):        table = CustomersTable(            ((-2, 2), (2, 2)),            row_count=10,            visible_row_count=10,            bins=2,        )          self.scene.play(FadeIn(table))          self.scene.wait(3)<\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0443 \u043d\u0430\u0441 \u043e\u0441\u0442\u0430\u043b\u0430\u0441\u044c \u0432\u0441\u0435\u0433\u043e \u043e\u0434\u043d\u0430 \u0438\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u0438 \u043e\u0434\u0438\u043d \u0432\u044b\u0437\u043e\u0432 \u043c\u0435\u0442\u043e\u0434\u0430 \u043f\u043e\u044f\u0432\u043b\u0435\u043d\u0438\u044f. \u041a\u043e\u0434 \u0447\u0438\u0441\u0442\u044b\u0439, \u043a\u0440\u0430\u0441\u0438\u0432\u044b\u0439, \u0441 \u043d\u0438\u043c \u043b\u0435\u0433\u043a\u043e \u0441\u043b\u0435\u0434\u0438\u0442\u044c \u0437\u0430 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0435\u043c \u0432\u0438\u0434\u0435\u043e, \u0435\u0433\u043e \u043b\u0435\u0433\u043a\u043e \u043f\u043e\u0434\u0434\u0435\u0440\u0436\u0438\u0432\u0430\u0442\u044c. \u0412\u0441\u044f \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0446\u0438\u044f \u0432\u044b\u043d\u0435\u0441\u0435\u043d\u0430 \u0432 \u043a\u043b\u0430\u0441\u0441\u044b, \u0438 \u043c\u044b \u043e \u043d\u0435\u0439 \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0435 \u0437\u0430\u0434\u0443\u043c\u044b\u0432\u0430\u0435\u043c\u0441\u044f.<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/by\/go\/ma\/bygomaoiygw7m2htubrvy0ih-14.gif\" data-src=\"https:\/\/habrastorage.org\/webt\/by\/go\/ma\/bygomaoiygw7m2htubrvy0ih-14.gif\"\/><\/p>\n<p>  \u041f\u043e\u0439\u0434\u0451\u043c \u0434\u0430\u043b\u044c\u0448\u0435 \u2014 \u0442\u0430\u043a\u0438\u043c \u0436\u0435 \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u043c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u043b\u0430\u0441\u0441\u044b \u0434\u043b\u044f \u0433\u0440\u0430\u0444\u0438\u043a\u0430 \u0438 \u0432\u043e\u0440\u043e\u043d\u043a\u0438.<\/p>\n<h3>\u0421\u0442\u0440\u043e\u0438\u043c \u0433\u0440\u0430\u0444\u0438\u043a<\/h3>\n<p>  \u0421\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f \u0437\u0430\u0434\u0430\u0447\u0430 \u2014 \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435 \u0433\u0440\u0430\u0444\u0438\u043a\u0430. \u041e\u043f\u0438\u0448\u0443 \u0435\u0433\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b:<\/p>\n<ul>\n<li>\u0413\u0440\u0430\u0444\u0438\u043a \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0434\u0432\u0443\u0445 \u0432\u0438\u0434\u043e\u0432: \u0434\u0438\u0441\u043a\u0440\u0435\u0442\u043d\u044b\u043c \u0438 \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u044b\u043c. <\/li>\n<li>\u0413\u0440\u0430\u0444\u0438\u043a\u0443 \u043d\u0443\u0436\u043d\u043e \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0437\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u0442\u044c \u0432\u0441\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u044e\u0442\u0441\u044f \u0448\u0430\u0440\u0438\u043a\u0438. \u041c\u044b \u0431\u0443\u0434\u0435\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u0442\u044c \u0448\u0430\u0440\u0438\u043a\u0438 \u0438\u0437 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u043d\u0430 \u0433\u0440\u0430\u0444\u0438\u043a, \u0438 \u043a\u043e\u0433\u0434\u0430 \u0443 \u043d\u0430\u0441 \u043f\u043e\u044f\u0432\u0438\u0442\u0441\u044f \u0434\u0432\u0430 \u0448\u0430\u0440\u0438\u043a\u0430 \u0441 \u0447\u0438\u0441\u043b\u043e\u043c 3, \u043e\u043d\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u0431\u0443\u0434\u0443\u0442 \u0432\u0441\u0442\u0430\u0442\u044c \u043e\u0434\u0438\u043d \u043d\u0430\u0434 \u0434\u0440\u0443\u0433\u0438\u043c, \u0432\u044b\u0441\u0442\u0440\u043e\u0438\u0432\u0448\u0438\u0441\u044c \u0432 \u0441\u0442\u043e\u043b\u0431\u0438\u043a. \u0422\u043e \u0435\u0441\u0442\u044c, \u0447\u0442\u043e\u0431\u044b \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0438\u0442\u044c \u0448\u0430\u0440\u0438\u043a \u043d\u0430 \u043f\u043b\u043e\u0441\u043a\u043e\u0441\u0442\u0438, \u043d\u0443\u0436\u043d\u043e \u0432\u0437\u044f\u0442\u044c \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0433\u043e \u0448\u0430\u0440\u0438\u043a\u0430, \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043a \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0435 Y \u0434\u0438\u0430\u043c\u0435\u0442\u0440 \u0448\u0430\u0440\u0438\u043a\u0430 \u0438 \u0440\u0430\u0441\u043f\u043e\u043b\u043e\u0436\u0438\u0442\u044c \u043d\u043e\u0432\u044b\u0439 \u0448\u0430\u0440\u0438\u043a \u043d\u0430 \u043d\u043e\u0432\u044b\u0445 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430\u0445.<\/li>\n<\/ul>\n<p>  \u041d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0435 \u043f\u043e\u044f\u0441\u043d\u0435\u043d\u0438\u0435 \u043a \u043a\u043e\u0434\u0443: \u0432\u043e-\u043f\u0435\u0440\u0432\u044b\u0445, \u043c\u044b \u0441\u043d\u043e\u0432\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043d\u0430\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u043d\u0438\u0435. \u0422\u043e \u0435\u0441\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u0451\u043c \u043a\u043b\u0430\u0441\u0441 <b>Graph<\/b> \u0438 \u0434\u0435\u043b\u0430\u0435\u043c \u0435\u0433\u043e \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u043c. \u0412 \u044d\u0442\u043e\u0442 \u043a\u043b\u0430\u0441\u0441 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043e\u0431\u0449\u0438\u0439 \u0434\u043b\u044f \u0432\u0441\u0435\u0445 \u043f\u043e\u0442\u043e\u043c\u043a\u043e\u0432 \u043c\u0435\u0442\u043e\u0434 <b>_prepare_next_dot_coords<\/b> \u0438 \u0430\u0431\u0441\u0442\u0440\u0430\u043a\u0442\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 <b>_create_graph<\/b>. \u041e\u0442 \u043a\u043b\u0430\u0441\u0441\u0430 <b>Graph<\/b> \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u044e\u0442\u0441\u044f \u0434\u0432\u0430 \u0434\u0440\u0443\u0433\u0438\u0445 \u043a\u043b\u0430\u0441\u0441\u0430: <b>CategoricalGraph<\/b> \u0438 <b>ContinuousGraph<\/b>. \u0412\u043e-\u0432\u0442\u043e\u0440\u044b\u0445, \u0431\u043b\u0430\u0433\u043e\u0434\u0430\u0440\u044f \u043f\u0438\u0442\u043e\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u043c\u0443 Multiple Inheritance \u0432 \u043a\u043b\u0430\u0441\u0441\u044b-\u043d\u0430\u0441\u043b\u0435\u0434\u043d\u0438\u043a\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f <b>VGroup<\/b>, \u0438 \u043d\u0430 \u0432\u044b\u0445\u043e\u0434\u0435 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u0442\u0441\u044f \u043d\u043e\u0432\u044b\u0439 \u043e\u0431\u044a\u0435\u043a\u0442, \u043a\u043e\u0442\u043e\u0440\u044b\u043c \u043c\u043e\u0436\u043d\u043e \u043c\u0430\u043d\u0438\u043f\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c (\u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0442\u044c \u0432 \u0441\u0446\u0435\u043d\u0443, \u0443\u0434\u0430\u043b\u044f\u0442\u044c, \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u0442\u044c \u0438 \u0442. \u0434.).<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">classes\/graph.py<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">from abc import ABC, abstractmethod from typing import Tuple   from manimlib.imports import BLACK, Line, VGroup from numpy import array   from .histogram_text import HistogramText from .shape_point import ShapePoint     class GraphException(Exception):    pass     class GraphLinesEmptyException(GraphException):    pass     class Graph(ABC):    \"\"\"Class for drawing Graphs\"\"\"      bins: int    color: str    annot: bool    text_scale: float = 0.6    dot_padding: float = 0.25    stroke_width: float      def __init__(        self,        start_end_points: Tuple[tuple, tuple] = None,        vertical_line: Tuple[tuple, tuple] = None,        bins: int = 1,        annot: bool = False,        color=BLACK,        stroke_width=1,    ):        \"\"\"Graph initialization          Args:            start_end_points (Tuple[tuple, tuple]): Left top and right top points. ((x1,y1), (x2,y2)).                Defaults to None.            vertical_line (Tuple[tuple, tuple], optional): Vertical line coordinates                ((x1, y1), (x2, y2)). Defaults to None.            bins (int, optional): Bins count for the graph. Defaults to 1.            annot (bool, optional): Do we need to annotate bins or not. Defaults to False.            color ([type], optional): Graph lines color. Defaults to BLACK.            stroke_width (int, optional): Graph lines width. Defaults to 1.          Raises:            GraphLinesEmptyException: Raises when start_end_points and vertical_line weren't passed.        \"\"\"        if not start_end_points and not vertical_line:            detail = \"Can't create a graph with empty lines.\"            raise GraphLinesEmptyException(detail)          # Initialise graph lines        self.horizontal_line = None        if start_end_points:            self.horizontal_line = [                ShapePoint(start_end_points[0]),                ShapePoint(start_end_points[1]),            ]            self.step_x = abs(start_end_points[0][0] - start_end_points[1][0]) \/ bins          self.vertical_line = None        if vertical_line:            self.vertical_line = [                ShapePoint(vertical_line[0]),                ShapePoint(vertical_line[1]),            ]            self.step_y = abs(vertical_line[0][1] - vertical_line[1][1]) \/ bins          self.bins = bins        self.color = color        self.annot = annot        self.stroke_width = stroke_width          lines, texts = self.create_graph()          super().__init__(*lines, *texts)      def _prepare_next_dot_coords(self) -> dict:        \"\"\"Dict preparation with information about the bin center.          Returns:            dict: Dictionary with filled bin center coordinates.        \"\"\"        d = {}        start_x = self.horizontal_line[0][0]        for i in range(1, int(self.bins) + 1):            d[i] = {                \"x\": start_x + (self.step_x \/ 2),                \"y\": self.horizontal_line[0][1] + 0.25,            }            start_x += self.step_x          return d      @abstractmethod    def create_graph(self) -> Tuple[list, list]:        pass     class CategoricalGraph(Graph, VGroup):    \"\"\"Categorical Graph. Inherited from Graph\"\"\"      def create_graph(self) -> Tuple[list, list]:        \"\"\"Implementation of create_graph method.          Returns:            Tuple[list, list]: Tuple of the list with lines and texts.        \"\"\"        lines = []        texts = []          if self.horizontal_line:            # Adding horizontal line            line = Line(                self.horizontal_line[0].coords,                self.horizontal_line[1].coords,                color=self.color,                stroke_width=self.stroke_width,            )              lines.append(line)              # Adding vertical lines            start_x = self.horizontal_line[0].coords[0]            y_coord = self.horizontal_line[0].coords[1]            for i in range(1, self.bins + 2):                lines.append(                    Line(                        array([start_x, y_coord + 0.3, 0]),                        array([start_x, y_coord - 0.3, 0]),                        color=self.color,                        stroke_width=self.stroke_width,                    )                )                  # Adding text for the bins                if self.annot and (i != self.bins + 1):                    text = HistogramText(str(i), color=BLACK)                    text.scale(self.text_scale)                    text.move_to(array([start_x + (self.step_x \/ 2), y_coord - 0.3, 0]))                    texts.append(text)                  start_x += self.step_x              if self.vertical_line:                # Adding vertical line                line = Line(                    self.vertical_line[0].coords,                    self.vertical_line[1].coords,                    color=self.color,                    stroke_width=self.stroke_width,                )                  lines.append(line)                  # Adding horizontal line                start_y = self.vertical_line[0].coords[1]                x_coord = self.vertical_line[0].coords[0]                  for i in range(1, self.bins + 2):                    lines.append(                        Line(                            array([x_coord - 0.3, start_y, 0]),                            array([x_coord + 0.3, start_y, 0]),                            color=self.color,                            stroke_width=self.stroke_width,                        )                    )                      if self.annot and (i != self.bins + 1):                        text = HistogramText(str(i), color=BLACK)                        text.scale(self.text_scale)                        text.move_to(array([x_coord - 0.3, start_y - (self.step_y \/ 2), 0]))                        texts.append(text)                      start_y -= self.step_y          return texts, lines     class ContinuousGraph(Graph, VGroup):    def create_graph(self) -> Tuple[list, list]:        \"\"\"Implementation of create_graph method.          Returns:            Tuple[list, list]: Tuple of the list with lines and texts.        \"\"\"        lines = []        texts = []          if self.horizontal_line:            # Adding horizontal line            lines.append(                Line(                    self.horizontal_line[0].coords,                    self.horizontal_line[1].coords,                    color=self.color,                    stroke_width=self.stroke_width,                )            )              y_coord = self.horizontal_line[0].coords[1]            # Adding 2 vertical lines            lines.extend(                [                    Line(                        array([self.horizontal_line[0].coords[0], y_coord + 0.3, 0]),                        array([self.horizontal_line[0].coords[0], y_coord - 0.3, 0]),                        color=self.color,                        stroke_width=self.stroke_width,                    ),                    Line(                        array([self.horizontal_line[1].coords[0], y_coord + 0.3, 0]),                        array([self.horizontal_line[1].coords[0], y_coord - 0.3, 0]),                        color=self.color,                        stroke_width=self.stroke_width,                    ),                ]            )              if self.annot:                text0 = HistogramText(str(0), color=BLACK)                text0.scale(self.text_scale)                text0.move_to(array([self.horizontal_line[0].coords[0], y_coord - 0.55, 0]))                  text1 = HistogramText(str(self.bins), color=BLACK)                text1.scale(self.text_scale)                text1.move_to(array([self.horizontal_line[1].coords[0], y_coord - 0.55, 0]))                texts.extend([text0, text1])          if self.vertical_line:            # Adding vertical line            lines.append(                Line(                    self.vertical_line[0].coords,                    self.vertical_line[1].coords,                    color=self.color,                    stroke_width=self.stroke_width,                )            )              x_coord = self.vertical_line[0].coords[0]            # Adding 2 horizontal lines            lines.extend(                [                    Line(                        array([x_coord - 0.3, self.vertical_line[0].coords[1], 0]),                        array([x_coord + 0.3, self.vertical_line[0].coords[1], 0]),                        color=self.color,                        stroke_width=self.stroke_width,                    ),                    Line(                        array([x_coord - 0.3, self.vertical_line[1].coords[1], 0]),                        array([x_coord + 0.3, self.vertical_line[1].coords[1], 0]),                        color=self.color,                        stroke_width=self.stroke_width,                    ),                ]            )              if self.annot:                text0 = HistogramText(str(0), color=BLACK)                text0.scale(self.text_scale)                text0.move_to(array([x_coord - 0.55, self.vertical_line[0].coords[1], 0]))                  text1 = HistogramText(str(self.bins), color=BLACK)                text1.scale(self.text_scale)                text1.move_to(array([x_coord - 0.55, self.vertical_line[1].coords[1], 0]))                texts.extend([text0, text1])          return lines, texts<\/code><\/pre>\n<\/div><\/div>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0431\u0435\u0440\u0451\u043c \u0432\u0441\u0451 \u0432 \u043c\u0435\u0442\u043e\u0434 <b>play_third_scene<\/b> \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0441\u0431\u043e\u0440\u043a\u0443, \u043a\u0430\u043a \u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u043c \u0432\u0430\u0440\u0438\u0430\u043d\u0442\u0435:<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">scenario.py<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">def play_third_scene(self):        cont_graph = ContinuousGraph(            ((-4, -1), (0, -1)),            ((-2, 1), (-2, -3)),            bins=4,            annot=False,        )          cat_graph = CategoricalGraph(            ((0, 2), (4, 2)),            None,            bins=4,            annot=True,        )          self.scene.play(FadeIn(cont_graph), FadeIn(cat_graph))          self.scene.wait(3)<\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  \u0412 \u0438\u0442\u043e\u0433\u0435 \u043c\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u0434\u0432\u0430 \u0433\u0440\u0430\u0444\u0438\u043a\u0430: \u043d\u0435\u043f\u0440\u0435\u0440\u044b\u0432\u043d\u044b\u0439 \u0438 \u0434\u0438\u0441\u043a\u0440\u0435\u0442\u043d\u044b\u0439. \u0423 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0441\u0432\u043e\u044f \u043b\u043e\u0433\u0438\u043a\u0430 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u043a\u043e\u0440\u0437\u0438\u043d \u0438 \u043f\u043e\u0434\u043f\u0438\u0441\u0438:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/1-\/wl\/mf\/1-wlmfpso3qwfbegl1ewvmewikw.gif\" data-src=\"https:\/\/habrastorage.org\/webt\/1-\/wl\/mf\/1-wlmfpso3qwfbegl1ewvmewikw.gif\"\/><\/p>\n<h3>\u0420\u0438\u0441\u0443\u0435\u043c \u0432\u043e\u0440\u043e\u043d\u043a\u0438<\/h3>\n<p>  \u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u043d\u0430\u0440\u0438\u0441\u043e\u0432\u0430\u0442\u044c \u0442\u043e\u043b\u044c\u043a\u043e \u0432\u043e\u0440\u043e\u043d\u043a\u0438. \u041a\u0430\u043a \u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u043b\u0438 \u0440\u0430\u043d\u0435\u0435, \u0432\u043e\u0440\u043e\u043d\u043a\u0438 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0442 \u0441\u043e\u0431\u043e\u0439 \u043d\u0430\u0431\u043e\u0440 \u043b\u0438\u043d\u0438\u0439 \u0441 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0451\u043d\u043d\u044b\u043c\u0438 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430\u043c\u0438. \u041e\u0434\u043d\u0430\u043a\u043e \u043f\u0435\u0440\u0435\u0434 \u0442\u0435\u043c, \u043a\u0430\u043a \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043a \u0438\u0445 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044e, \u0432\u0441\u043f\u043e\u043c\u043d\u0438\u043c \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e\u0435 \u0432\u0438\u0434\u0435\u043e \u0438 \u0432\u0442\u043e\u0440\u043e\u0439 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439. \u0428\u0430\u0440\u0438\u043a\u0438 \u0434\u043e\u043b\u0436\u043d\u044b \u043f\u0430\u0434\u0430\u0442\u044c \u0438\u043c\u0435\u043d\u043d\u043e \u0432 \u0441\u0432\u043e\u044e \u0432\u043e\u0440\u043e\u043d\u043a\u0443, \u0430 \u043d\u0435 \u0432 \u043a\u0430\u043a\u0443\u044e-\u0442\u043e \u0434\u0440\u0443\u0433\u0443\u044e, \u043f\u043b\u044e\u0441 \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u043f\u0435\u0440\u0435\u043d\u043e\u0441\u0438\u0442\u044c\u0441\u044f, \u0430 \u0438\u043c\u0435\u043d\u043d\u043e \u0441\u043a\u0430\u0442\u044b\u0432\u0430\u0442\u044c\u0441\u044f \u043f\u043e \u0433\u043e\u0440\u043b\u044b\u0448\u043a\u0443 \u0432\u043e\u0440\u043e\u043d\u043a\u0438. <\/p>\n<p>  \u0422\u0430\u043a\u0436\u0435 \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0432\u043e\u0440\u043e\u043d\u043a\u0430 \u0431\u044b\u043b\u0430 \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u044b\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u043c. \u042d\u0442\u043e \u0434\u0430\u0441\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0441\u0442\u0440\u043e\u0438\u0442\u044c \u0441\u0442\u043e\u043b\u044c\u043a\u043e \u0432\u043e\u0440\u043e\u043d\u043e\u043a, \u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043d\u0443\u0436\u043d\u043e. \u041c\u044b \u043d\u0430\u043f\u0438\u0448\u0435\u043c \u0434\u0432\u0430 \u043a\u043b\u0430\u0441\u0441\u0430: \u043e\u0434\u0438\u043d \u0434\u043b\u044f \u0432\u043e\u0440\u043e\u043d\u043a\u0438, \u0430 \u0432\u0442\u043e\u0440\u043e\u0439 \u0434\u043b\u044f \u0443\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043f\u043e\u0441\u0442\u0440\u043e\u0435\u043d\u0438\u0435\u043c \u0432\u043e\u0440\u043e\u043d\u043e\u043a. \u0417\u0432\u0443\u0447\u0438\u0442 \u0441\u043b\u043e\u0436\u043d\u043e, \u043d\u043e \u0437\u0434\u0435\u0441\u044c \u0438 \u043d\u0430\u0447\u0438\u043d\u0430\u0435\u0442\u0441\u044f \u0432\u0441\u0451 \u0441\u0430\u043c\u043e\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0435!<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">classes\/funnel.py<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">from typing import Tuple, Union   from colour import Color from manimlib.imports import BLACK, Line, VGroup from numpy import array, mean   from .histogram_text import HistogramText from .shape_point import ShapePoint     class Funnel(VGroup):    text_scale: Union[int, float] = 0.6      def __init__(        self,        start_end_points: Tuple[tuple, tuple],        height: Union[int, float],        point_radius: Union[int, float],        annot: bool = False,        annot_text: str = \"\",        lines_color: Color = BLACK,        stroke_width: Union[int, float] = 1,    ):        \"\"\"Funnel initialization.          Args:            start_end_points (Tuple[tuple, tuple]): Left top and right top points. ((x1,y1), (x2,y2)).            height (Union[int, float]): Funnel height.            point_radius (Union[int, float]): Point radius. With that value we could calculate the opening                of the funnel.            annot (bool, optional): Do we need to annotate the funnel or not. Defaults to False.            annot_text (str, optional): Text to annotate funnel. Defaults to \"\".            lines_color (Color, optional): Lines color for the funnel. Defaults to BLACK.            stroke_width (Union[int, float], optional): Line width for the funnel. Defaults to 1.        \"\"\"        self.left_top_point = ShapePoint(start_end_points[0])        self.right_top_point = ShapePoint(start_end_points[1])          self.height = height        self.point_radius = point_radius        self.point_diameter = point_radius * 1.5        self.lines_color = lines_color        self.stroke_width = stroke_width        self.annot = annot        self.annot_text = annot_text          self.y_point_top = self.left_top_point[1]        self.y_point_bottom = self.y_point_top - self.height        self.x_point_left = self.left_top_point[0]        self.x_point_right = self.right_top_point[0]        self.y_bottom_shift = 0.2          self.x_funnel_center = mean(array([self.right_top_point[0], self.left_top_point[0]]))          self.left_to_bottom = Line(            array([self.x_point_left, self.y_point_top, 0]),            array([self.x_point_left, self.y_point_bottom, 0]),            color=self.lines_color,            stroke_width=self.stroke_width,        )          self.left_to_bottom_right = Line(            array([self.x_point_left, self.y_point_top, 0]),            array([self.x_funnel_center - self.point_diameter, self.y_point_top - 0.5, 0]),            color=self.lines_color,            stroke_width=self.stroke_width,        )          self.right_to_bottom = Line(            array([self.x_point_right, self.y_point_top, 0]),            array([self.x_point_right, self.y_point_bottom, 0]),            color=self.lines_color,            stroke_width=self.stroke_width,        )          self.right_to_bottom_left = Line(            array([self.x_point_right, self.y_point_top, 0]),            array([self.x_funnel_center + self.point_diameter, self.y_point_top - 0.5, 0]),            color=self.lines_color,            stroke_width=self.stroke_width,        )          self.left_funnel_appendix = Line(            array([self.x_funnel_center + self.point_diameter, self.y_point_top - 0.5, 0]),            array([self.x_funnel_center + self.point_diameter, self.y_point_top - 0.7, 0]),            color=self.lines_color,            stroke_width=self.stroke_width,        )          self.right_funnel_appendix = Line(            array([self.x_funnel_center - self.point_diameter, self.y_point_top - 0.5, 0]),            array([self.x_funnel_center - self.point_diameter, self.y_point_top - 0.7, 0]),            color=self.lines_color,            stroke_width=self.stroke_width,        )          self.bottom_line = Line(            array([self.x_point_left - 0.2, self.y_point_bottom + self.y_bottom_shift, 0]),            array([self.x_point_right + 0.2, self.y_point_bottom + self.y_bottom_shift, 0]),            color=self.lines_color,            stroke_width=self.stroke_width,        )          texts = []        if annot:            text = HistogramText(annot_text, color=self.lines_color)            text.move_to(array([self.x_funnel_center, self.y_point_bottom, 0]))            text.scale(self.text_scale)            texts.append(text)          super().__init__(            self.left_to_bottom,            self.right_to_bottom,            self.left_to_bottom_right,            self.right_to_bottom_left,            self.left_funnel_appendix,            self.right_funnel_appendix,            self.bottom_line,            *texts,        )<\/code><\/pre>\n<\/div><\/div>\n<p>  \u0421\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0447\u0435\u0442\u0432\u0451\u0440\u0442\u0443\u044e \u0441\u0446\u0435\u043d\u0443, \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0432 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0432\u043e\u0440\u043e\u043d\u043e\u043a, \u0438 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0441\u0431\u043e\u0440\u043a\u0443:<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">scenario.py<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">def play_fourth_scene(self):        funnel = Funnel(            ((-2, 2), (1, -2)),            height=4,            point_radius=0.2,        )          self.scene.play(            FadeIn(funnel),        )          self.scene.wait(3)<\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0443 \u043d\u0430\u0441 \u043f\u043e\u044f\u0432\u0438\u043b\u0438\u0441\u044c \u043a\u0440\u0430\u0441\u0438\u0432\u044b\u0435 \u0432\u043e\u0440\u043e\u043d\u043a\u0438, \u0441 \u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u043c\u043e\u0436\u043d\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0434\u0430\u043b\u044c\u0448\u0435:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/ic\/bq\/dz\/icbqdzukxpjyg9dte3cwpzqfsyq.gif\" data-src=\"https:\/\/habrastorage.org\/webt\/ic\/bq\/dz\/icbqdzukxpjyg9dte3cwpzqfsyq.gif\"\/><\/p>\n<h3>\u0410\u043d\u0438\u043c\u0438\u0440\u0443\u0435\u043c \u043e\u0431\u044a\u0435\u043a\u0442\u044b<\/h3>\n<p>  \u0418\u0442\u0430\u043a, \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0432\u043e\u0440\u043e\u043d\u043a\u0438, \u0433\u0440\u0430\u0444\u0438\u043a\u0438, \u0442\u0430\u0431\u043b\u0438\u0446\u044b, \u0448\u0430\u0440\u0438\u043a\u0438\u2026 \u041d\u043e \u043c\u044b \u043f\u043e\u043a\u0430 \u0447\u0442\u043e \u043d\u0435 \u0441\u0434\u0435\u043b\u0430\u043b\u0438 \u043e\u0434\u043d\u0443 \u0432\u0430\u0436\u043d\u0443\u044e \u0432\u0435\u0449\u044c \u2014 \u0441\u0435\u0439\u0447\u0430\u0441 \u044d\u0442\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u044b \u0441\u0442\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435. \u0422\u043e \u0435\u0441\u0442\u044c \u043c\u044b \u0438\u0445 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043b\u0438, \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u043b\u0438 \u0438 \u043d\u0430 \u044d\u0442\u043e\u043c \u0432\u0441\u0451. \u041d\u0430\u043c \u0436\u0435 \u043d\u0443\u0436\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u0448\u0430\u0440\u0438\u043a\u0438 \u043c\u043e\u0433\u043b\u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u044b\u043c\u0438 \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u043c\u0438, \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u044f\u0441\u044c \u043f\u043e \u043d\u0438\u043c. <\/p>\n<p>  \u041f\u043e \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044e \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0442\u0430\u0431\u043b\u0438\u0446\u0430 \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u043e\u043c \u043f\u043e\u043a\u0443\u043f\u0430\u0442\u0435\u043b\u0435\u0439, \u0433\u0434\u0435 \u043d\u0430\u043f\u0440\u043e\u0442\u0438\u0432 \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u043f\u043e\u043a\u0443\u043f\u0430\u0442\u0435\u043b\u044f \u043d\u0430\u0440\u0438\u0441\u043e\u0432\u0430\u043d \u0448\u0430\u0440\u0438\u043a \u0441 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e\u043c \u043f\u043e\u043a\u0443\u043f\u043e\u043a (\u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u0448\u0430\u0440\u0438\u043a\u0430). \u0414\u043b\u044f \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0430 \u043f\u043e\u043a\u0443\u043f\u043e\u043a \u0432 \u0432\u0438\u0434\u0435 \u0433\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u044b \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0433\u0440\u0430\u0444\u0438\u043a, \u0432\u044b\u0432\u0435\u0441\u0442\u0438 \u0435\u0433\u043e \u043d\u0430 \u044d\u043a\u0440\u0430\u043d \u0438 \u0437\u0430\u0442\u0435\u043c \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u043d\u0430 \u043d\u0435\u0433\u043e \u0448\u0430\u0440\u0438\u043a\u0438 \u0442\u0430\u043a, \u0447\u0442\u043e\u0431\u044b \u043a\u0430\u0436\u0434\u043e\u043c\u0443 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e \u0448\u0430\u0440\u0438\u043a\u0430 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u043e\u0432\u0430\u043b\u043e \u0442\u0430\u043a\u043e\u0435 \u0436\u0435 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435 \u043d\u0430 \u0433\u0440\u0430\u0444\u0438\u043a\u0435.<\/p>\n<p>  \u0414\u043b\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u044d\u0442\u043e\u0439 \u043b\u043e\u0433\u0438\u043a\u0438 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c (\u043d\u0438 \u0437\u0430 \u0447\u0442\u043e \u043d\u0435 \u0434\u043e\u0433\u0430\u0434\u0430\u0435\u0442\u0435\u0441\u044c) \u043a\u043b\u0430\u0441\u0441! \u041d\u0430\u0437\u043e\u0432\u0435\u043c \u0435\u0433\u043e <b>Movable<\/b>. \u041a\u043b\u0430\u0441\u0441 \u0431\u0443\u0434\u0435\u0442 \u0438\u043c\u0435\u0442\u044c \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0439 \u0441\u043b\u043e\u0432\u0430\u0440\u044c <b>_next_dot_coords<\/b>, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043b\u0435\u0436\u0430\u0442 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u0432\u0441\u0435\u0445 \u0442\u043e\u0447\u0435\u043a, \u0443\u0436\u0435 \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0451\u043d\u043d\u044b\u0445 \u043d\u0430 \u0433\u0440\u0430\u0444\u0438\u043a, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043c\u0435\u0442\u043e\u0434 <b>_get_next_dot_coords<\/b>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044e \u0448\u0430\u0440\u0438\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u0434\u0430\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u043d\u0430 \u0433\u0440\u0430\u0444\u0438\u043a\u0435 \u0438, \u043d\u0430\u043a\u043e\u043d\u0435\u0446, \u043c\u0435\u0442\u043e\u0434 <b>drag_in_dots<\/b>, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0438\u0439 \u0437\u0430 \u00ab\u043f\u0440\u0438\u0442\u044f\u0436\u0435\u043d\u0438\u0435\u00bb \u043a \u0441\u0435\u0431\u0435 \u0432\u0441\u0435\u0445 \u0448\u0430\u0440\u0438\u043a\u043e\u0432. <\/p>\n<p>  \u041f\u043e\u044f\u0441\u043d\u0435\u043d\u0438\u0435: \u0435\u0441\u0442\u044c \u0442\u0430\u0431\u043b\u0438\u0446\u0430 \u0441 \u0448\u0430\u0440\u0438\u043a\u0430\u043c\u0438 \u0438 \u0433\u0440\u0430\u0444\u0438\u043a. \u0412\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u043c\u0435\u0442\u043e\u0434 \u0433\u0440\u0430\u0444\u0438\u043a\u0430 <b>drag_in_dots<\/b>, \u0432 \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u0451\u043c \u0448\u0430\u0440\u0438\u043a\u0438, \u043d\u0430\u0445\u043e\u0434\u044f\u0449\u0438\u0435\u0441\u044f \u0432 \u0434\u0430\u043d\u043d\u044b\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u0432 \u0442\u0430\u0431\u043b\u0438\u0446\u0435. \u0412 \u0446\u0438\u043a\u043b\u0435 \u043f\u0440\u043e\u0445\u043e\u0434\u0438\u043c\u0441\u044f \u043f\u043e \u0448\u0430\u0440\u0438\u043a\u0430\u043c, \u0433\u0434\u0435 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0448\u0430\u0440\u0438\u043a\u0430 \u0432\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u043c\u0435\u0442\u043e\u0434 \u0433\u0440\u0430\u0444\u0438\u043a\u0430 <b>_get_next_dot_coords<\/b>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0442\u0434\u0430\u0451\u0442 \u043d\u043e\u0432\u044b\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u0448\u0430\u0440\u0438\u043a\u0430, \u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u0435\u043c \u0448\u0430\u0440\u0438\u043a\u0438 \u043d\u0430 \u043d\u043e\u0432\u044b\u0435 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b. \u0413\u043e\u0442\u043e\u0432\u043e.<\/p>\n<p>  \u0418 \u0432\u0441\u0451-\u0442\u0430\u043a\u0438 \u0441\u043e\u0432\u0441\u0435\u043c \u043f\u043e\u043d\u044f\u0442\u043d\u043e \u0441\u0442\u0430\u043d\u0435\u0442 \u043f\u043e\u0441\u043b\u0435 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438. \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u0435\u0439 \u0438 \u0437\u0430\u0439\u043c\u0451\u043c\u0441\u044f:<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">classes\/movable_graph.py<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">from abc import ABC from copy import deepcopy from typing import Dict, Union   from manimlib.imports import DEFAULT_ANIMATION_RUN_TIME, ApplyMethod, Scene, Transform, VGroup from numpy import array, ndarray   from .graph import CategoricalGraph, ContinuousGraph from .histogram_dot import HistogramDot     class Movable(ABC):    \"\"\"Abstract class to add 'movable' functionality to the graph\"\"\"      _next_dot_coords: Dict[Union[int, float], Dict[str, Union[int, float]]] = {}    dot_padding: Union[int, float] = 0      def __init__(self, *args, **kwargs):        self._next_dots_coords = self._prepare_next_dot_coords()          super().__init__(*args, **kwargs)      def _get_next_dot_coords(self, dot: HistogramDot) -> ndarray:        \"\"\"Getting points for dots to move.          Args:            dot (HistogramDot): Dot from which we will calculate current coordinates.          Returns:            array: Next dot location.        \"\"\"        current_coord = self._next_dots_coords.get(int(dot.value), {})        bin_center = array([current_coord.get(\"x\", 0), current_coord.get(\"y\", 0), 0])          self._next_dots_coords[int(dot.value)][\"y\"] = current_coord.get(\"y\", 0) + dot.radius + self.dot_padding          return bin_center      def drag_in_dots(        self,        scene: Scene,        dots: VGroup,        animate_slow: int,        animate_rest: bool,        run_time: Union[int, float] = None,        delay: Union[int, float] = None,    ):        \"\"\"Moving dots to the graph.          Args:            scene (Scene): Scene where all our objects are located.            dots (VGroup): List of dots to move.            animate_slow (int): How many dots do we need to animate slowly.            animate_rest (bool): Do we need to move the rest of the dots or not.            run_time (Union[int, float]): How quickly we need to animate dots. Defaults to None.            delay (Union[int, float], optional): Delay between animations. Defaults to None.        \"\"\"        if not run_time:            run_time = DEFAULT_ANIMATION_RUN_TIME          for dot in dots[:animate_slow]:            scene.play(                ApplyMethod(dot.move_to, self._get_next_dot_coords(dot)),                run_time=run_time,            )              if delay:                scene.wait(delay)          if animate_rest:            dots_rest = deepcopy(dots[animate_slow:])              for dot in dots_rest:                dot.move_to(self._get_next_dot_coords(dot))              scene.play(Transform(dots[animate_slow:], dots_rest))              scene.remove(dots[animate_slow:])          else:            for dot in dots[animate_slow:]:                dot.move_to(self._get_next_dot_coords(dot))     class MovableContinuousGraph(ContinuousGraph, Movable):    \"\"\"Continuous graph that could move dots\"\"\"     class MovableCategoricalGraph(CategoricalGraph, Movable):    \"\"\"Categorical graph that could move dots\"\"\" <\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  \u0422\u0435\u043f\u0435\u0440\u044c \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u0432\u0438\u0434\u0435\u043e \u043f\u043e \u043f\u0435\u0440\u0432\u043e\u043c\u0443 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044e: \u0432\u044b\u0432\u0435\u0434\u0435\u043c \u043d\u0430 \u044d\u043a\u0440\u0430\u043d \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0441 \u0448\u0430\u0440\u0438\u043a\u0430\u043c\u0438, \u0437\u0430\u0442\u0435\u043c \u0433\u0440\u0430\u0444\u0438\u043a \u0438 \u043f\u0435\u0440\u0435\u043c\u0435\u0441\u0442\u0438\u043c \u043d\u0430 \u043d\u0435\u0433\u043e \u0448\u0430\u0440\u0438\u043a\u0438 \u0438\u0437 \u0442\u0430\u0431\u043b\u0438\u0446\u044b.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">scenario.py<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">def play_fifth_scene(self):        # Initial dot values, to keep them the same over several animation builds        start_dot_values = [1, 2, 1, 3, 4, 2, 1]          # Table initialization        table = CustomersTable(            ((-6, 2), (-2, 2)),            row_count=10,            visible_row_count=10,            bins=4,            start_dots_values=start_dot_values,        )          # Graph initialization        x_graph = MovableCategoricalGraph(            ((0, 0), (4, 0)),            None,            bins=4,            annot=True,        )          # Playing animation for the table and graph appearing        self.scene.play(FadeIn(table), FadeIn(x_graph))          self.scene.wait(2)          # Moving dots from the table to the graph        x_graph.drag_in_dots(self.scene, dots=table.dots, animate_slow=3, animate_rest=True)          self.scene.wait(3)  <\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  \u041f\u043e\u0441\u043b\u0435 \u0441\u0431\u043e\u0440\u043a\u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u0442\u0430\u043a\u0443\u044e \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u0443\u044e \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u044e:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/-n\/ks\/-9\/-nks-9qrxshqvkusl_jbkde43wq.gif\" data-src=\"https:\/\/habrastorage.org\/webt\/-n\/ks\/-9\/-nks-9qrxshqvkusl_jbkde43wq.gif\"\/><\/p>\n<p>  \u0412\u0441\u0451 \u0437\u0434\u043e\u0440\u043e\u0432\u043e, \u043e\u0441\u0442\u0430\u043b\u0441\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u044d\u043b\u0435\u043c\u0435\u043d\u0442 \u2014 \u0432\u043e\u0440\u043e\u043d\u043a\u0438 \u0442\u043e\u0436\u0435 \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0434\u0438\u043d\u0430\u043c\u0438\u0447\u0435\u0441\u043a\u0438\u043c\u0438. Movable-\u0432\u043e\u0440\u043e\u043d\u043a\u0430\u043c \u0434\u043b\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u0448\u0430\u0440\u0438\u043a\u043e\u0432 \u043d\u0435 \u043f\u043e\u0434\u043e\u0439\u0434\u0451\u0442 \u043f\u0440\u043e\u0441\u0442\u043e\u0439 drag_in, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043c\u0435\u0442\u043e\u0434 \u0434\u043e\u043b\u0436\u0435\u043d \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c, \u043a \u043a\u0430\u043a\u043e\u0439 \u0432\u043e\u0440\u043e\u043d\u043a\u0435 \u043e\u0442\u043d\u043e\u0441\u0438\u0442\u0441\u044f \u0448\u0430\u0440\u0438\u043a, \u0430 \u043f\u043e\u0441\u043b\u0435 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u0442\u044c, \u043a\u0430\u043a \u0448\u0430\u0440\u0438\u043a \u0441\u043a\u0430\u0442\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u043e \u043d\u0435\u0439 \u0432\u043d\u0443\u0442\u0440\u044c. \u0417\u0432\u0443\u0447\u0438\u0442 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e, \u0434\u0430\u0432\u0430\u0439\u0442\u0435 \u043f\u043e\u043f\u0440\u043e\u0431\u0443\u0435\u043c \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c.<\/p>\n<p>  \u0412\u043e \u0432\u0440\u0435\u043c\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0432\u043e\u0440\u043e\u043d\u043e\u043a \u043a\u043b\u0430\u0441\u0441 <b>Funnel<\/b> \u0437\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u0435\u0442 \u0432\u0441\u0435 \u043b\u0438\u043d\u0438\u0438 \u0441 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430\u043c\u0438. \u0422\u043e \u0435\u0441\u0442\u044c \u043c\u044b \u043b\u0435\u0433\u043a\u043e \u043c\u043e\u0436\u0435\u043c \u0441\u0440\u0430\u0432\u043d\u0438\u0442\u044c \u0438\u0445 \u0441 \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u0430\u043c\u0438 \u0448\u0430\u0440\u0438\u043a\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u043e\u043b\u0436\u0435\u043d \u0443\u043f\u0430\u0441\u0442\u044c \u0432 \u0432\u043e\u0440\u043e\u043d\u043a\u0443.<br \/>  \u0412\u0435\u0441\u044c \u0430\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u043f\u0443\u043d\u043a\u0442\u043e\u0432:<\/p>\n<ol>\n<li>\u0412\u044b\u0437\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 drag_in_dots, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u043f\u0443\u0441\u0442\u0438\u0442 \u0446\u0438\u043a\u043b \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0448\u0430\u0440\u0438\u043a\u043e\u0432.<\/li>\n<li>\u0414\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0448\u0430\u0440\u0438\u043a\u0430 \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 _get_next_dot_coords.<\/li>\n<li>\u0412 \u043c\u0435\u0442\u043e\u0434\u0435 _get_next_dot_coords \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0448\u0430\u0440\u0438\u043a\u0430 \u043d\u0443\u0436\u043d\u043e:<br \/> \n<ul>\n<li>\u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u0442\u0435\u043a\u0443\u0449\u0435\u0433\u043e \u0448\u0430\u0440\u0438\u043a\u0430;<\/li>\n<li>\u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u043b\u0435\u0432\u043e\u0439 \u0438 \u043f\u0440\u0430\u0432\u043e\u0439 \u00ab\u043a\u0440\u044b\u0448\u0438\u00bb;<\/li>\n<li>\u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u0446\u0435\u043d\u0442\u0440\u0430 \u0432\u043e\u0440\u043e\u043d\u043a\u0438.<\/li>\n<\/ul>\n<\/li>\n<\/ol>\n<p>  \u041f\u043e\u0441\u043b\u0435 \u043d\u0430\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442 \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0435\u043c \u0442\u0440\u0438 \u0442\u043e\u0447\u043a\u0438, \u043a\u0443\u0434\u0430 \u0434\u043e\u043b\u0436\u0435\u043d \u0443\u043f\u0430\u0441\u0442\u044c \u0448\u0430\u0440\u0438\u043a:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/webt\/c6\/kj\/9t\/c6kj9t1ddofup8mlej6sl0-a0z0.png\" data-src=\"https:\/\/habrastorage.org\/webt\/c6\/kj\/9t\/c6kj9t1ddofup8mlej6sl0-a0z0.png\"\/><\/p>\n<p>  \u041d\u0443 \u0430 \u0434\u0430\u043b\u044c\u0448\u0435 \u0441\u0430\u043c\u043e\u0435 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0435. \u0414\u043b\u044f \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u044f \u0448\u0430\u0440\u0438\u043a\u0430 \u0438\u0437 \u0442\u043e\u0447\u043a\u0438 0 \u0432 \u0442\u043e\u0447\u043a\u0443 1 \u043d\u0443\u0436\u043d\u043e \u0437\u043d\u0430\u0442\u044c X \u0438 Y \u0442\u043e\u0447\u043a\u0438 1. X \u043c\u044b \u0437\u043d\u0430\u0435\u043c \u2014 \u043e\u043d \u0442\u0430\u043a\u043e\u0439 \u0436\u0435, \u043a\u0430\u043a \u0438 \u0443 \u0448\u0430\u0440\u0438\u043a\u0430. \u0410 \u0432\u043e\u0442 \u0442\u043e\u0447\u043a\u0443 Y \u043f\u0440\u0438\u0434\u0451\u0442\u0441\u044f \u0432\u044b\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c. \u0423 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u043a\u043e\u043e\u0440\u0434\u0438\u043d\u0430\u0442\u044b \u043d\u0430\u0447\u0430\u043b\u0430 \u0438 \u043a\u043e\u043d\u0446\u0430 \u043b\u0438\u043d\u0438\u0438, \u043d\u0430 \u043a\u043e\u0442\u043e\u0440\u0443\u044e \u0431\u0443\u0434\u0435\u0442 \u043f\u0430\u0434\u0430\u0442\u044c \u0448\u0430\u0440\u0438\u043a, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u0430\u0442\u044c X \u0434\u043b\u044f \u0442\u043e\u0447\u043a\u0438 \u043f\u0430\u0434\u0435\u043d\u0438\u044f. \u041e\u0434\u043d\u0430\u043a\u043e \u0432\u0440\u0443\u0447\u043d\u0443\u044e \u0434\u0435\u043b\u0430\u0442\u044c \u044d\u0442\u043e \u043d\u0435 \u043d\u0443\u0436\u043d\u043e. <s>\u0425\u043e\u0440\u043e\u0448\u0438\u0439 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442 \u2014 \u043b\u0435\u043d\u0438\u0432\u044b\u0439 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442<\/s>. \u0425\u043e\u0440\u043e\u0448\u0438\u0439 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442 \u0447\u0438\u0442\u0430\u0435\u0442 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e. \u0410 \u0432 <a href=\"https:\/\/numpy.org\/doc\/stable\/reference\/generated\/numpy.interp.html\">\u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u043a \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0435 <b>numpy<\/b> \u043e\u043f\u0438\u0441\u0430\u043d \u043c\u0435\u0442\u043e\u0434 <b>interp<\/b><\/a>, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0434\u0435\u043b\u0430\u0435\u0442 \u0440\u043e\u0432\u043d\u043e \u0442\u043e, \u0447\u0442\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e: \u0438\u043d\u0442\u0435\u0440\u043f\u043e\u043b\u0438\u0440\u0443\u0435\u0442 X, \u0438\u0441\u0445\u043e\u0434\u044f \u0438\u0437 \u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0433\u043e \u043d\u0430\u0431\u043e\u0440\u0430 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439. \u041d\u0443 \u0430 \u0432\u0442\u043e\u0440\u0430\u044f \u0438 \u0442\u0440\u0435\u0442\u044c\u044f \u0442\u043e\u0447\u043a\u0430 \u043d\u0430\u0445\u043e\u0434\u044f\u0442\u0441\u044f \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u043f\u0440\u043e\u0441\u0442\u043e:<\/p>\n<pre><code class=\"python\">point_x = dot.get_x() first_point = None second_point = None   # Looking for the Line for Dot to move (fall) if self.x_point_left &lt;= point_x &lt;= x_left_to_bottom_right:     line = self.left_to_bottom_right   elif x_right_to_bottom_left &lt;= point_x &lt;= self.x_point_right:     line = self.right_to_bottom_left   elif x_left_to_bottom_right &lt; point_x &lt; x_right_to_bottom_left:     line = None   else:     return None, None, None   if line is not None:     # Getting all X, Y points from the line     line_x = [x[0] for x in line.get_all_points()]     line_y = [x[1] for x in line.get_all_points()]       # Where the magic happens. We're interpolating Y from other X, Y points.     point_y = interp(point_x, line_x, line_y, period=10)     point_y += 0.25       first_point = array([point_x, point_y, 0])       second_point = array([self.x_funnel_center, funnel_center_y, 0])   third_point = array([self.x_funnel_center, current_coord, 0])<\/code><\/pre>\n<p>  \u041f\u043e\u043b\u043d\u044b\u0439 \u043a\u043e\u0434 \u043a\u043b\u0430\u0441\u0441\u0430 <b>MovableFunnel<\/b>:<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">classes\/movalbe_funnel.py<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">from copy import deepcopy from typing import Dict, Tuple, Union   from manimlib.imports import ApplyMethod, Scene, Transform, VGroup from numpy import array, interp   from .funnel import Funnel from .histogram_dot import HistogramDot     class MovableFunnelException(Exception):    pass     class LineNotFoundException(MovableFunnelException):    pass     class MovableFunnel(Funnel):    \"\"\"Overridden Funnel class to add 'movable' functionality\"\"\"      _next_dot_coords: Dict[str, Union[int, float]] = {}    dot_padding: Union[int, float] = 0.22    animated_slowly: int = None      def __init__(        self,        start_end_points: Tuple[tuple, tuple],        run_time: Union[int, float],        *args,        **kwargs,    ):        \"\"\"Class initialization. It receives all parameters that the Funnel class needs.          Args:            start_end_points (Tuple[tuple, tuple]): Left top and right top points. ((x1,y1), (x2,y2)).            run_time (Union[int, float]): How quickly we need to animate dots.        \"\"\"        self.run_time = run_time          super().__init__(start_end_points, *args, **kwargs)          self._next_dots_coords = {            \"x\": self.x_funnel_center,            \"y\": self.y_point_bottom + (self.y_bottom_shift * 2),        }      def _get_next_dots_coords(        self, dot: HistogramDot    ) -> Union[Tuple[array, array, array], Tuple[None, None, array], Tuple[None, None, None]]:        \"\"\"Getting points for dots to move.          Args:            dot (HistogramDot): Dot from which we will calculate current coordinates.          Returns:            Union[                Tuple[array, array, array],                Tuple[None, None, array],                Tuple[None, None, None,]            ]: Tuple with the points for the next dot move (fall).        \"\"\"        # Getting all needed coordinates of the funnel        current_coord = self._next_dots_coords.get(\"y\")        x_left_to_bottom_right = self.left_to_bottom_right.get_all_points()[-1][0]        x_right_to_bottom_left = self.right_to_bottom_left.get_all_points()[-1][0]        funnel_center_y = self.left_to_bottom_right.get_all_points()[-1][1] + 0.1          point_x = dot.get_x()        first_point = None        second_point = None          # Looking for the Line for Dot to move (fall)        if self.x_point_left &lt;= point_x &lt;= x_left_to_bottom_right:            line = self.left_to_bottom_right          elif x_right_to_bottom_left &lt;= point_x &lt;= self.x_point_right:            line = self.right_to_bottom_left          elif x_left_to_bottom_right &lt; point_x &lt; x_right_to_bottom_left:            line = None          else:            return None, None, None          if line is not None:            # Getting all X, Y points from the line            line_x = [x[0] for x in line.get_all_points()]            line_y = [x[1] for x in line.get_all_points()]              # Where the magic happens. We're interpolating Y from other X, Y points.            point_y = interp(point_x, line_x, line_y, period=10)            point_y += 0.25              first_point = array([point_x, point_y, 0])              second_point = array([self.x_funnel_center, funnel_center_y, 0])          third_point = array([self.x_funnel_center, current_coord, 0])          # Remembering current position        self._next_dots_coords[\"y\"] = current_coord + dot.radius + self.dot_padding          return first_point, second_point, third_point      def drag_in_dots(self, scene: Scene, dots: VGroup, animate_slow: int, animate_rest: bool):        \"\"\"Moving dots from anywhere to the funnel.          Args:           scene (Scene): Scene where all our objects are located.           dots (VGroup): List of dots to move.           animate_slow (int): How many dots do we need to animate slowly.           animate_rest (bool): Do we need to move the rest of the dots or not.        \"\"\"        if animate_slow > len(dots):            animate_slow = len(dots)          animated_slowly = 0        for dot in dots[:animate_slow]:              first_point, second_point, third_point = self._get_next_dots_coords(dot)              if all(x is None for x in (first_point, second_point, third_point)):                continue              if first_point is not None:                scene.play(ApplyMethod(dot.move_to, first_point), run_time=self.run_time)                  scene.play(ApplyMethod(dot.move_to, second_point), run_time=self.run_time)              scene.play(ApplyMethod(dot.move_to, third_point), run_time=self.run_time)              animated_slowly += 1          dots_rest = deepcopy(dots[animate_slow:])          for dot in dots_rest:            *_, third_point = self._get_next_dots_coords(dot)            if third_point is None:                continue              dot.move_to(third_point)          if dots_rest:            if animate_rest:                scene.play(Transform(dots[animate_slow:], dots_rest))              else:                scene.add(dots_rest)              scene.remove(dots_rest)          self.animated_slowly = animated_slowly <\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  \u041f\u043e\u0441\u043b\u0435\u0434\u043d\u0438\u0439 \u043a\u043b\u0430\u0441\u0441 \u043d\u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u2014 Funnels \u2014 \u043d\u0443\u0436\u0435\u043d \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u0432\u043e\u0440\u043e\u043d\u043e\u043a \u0441\u0440\u0430\u0437\u0443, \u0430 \u0442\u0430\u043a\u0436\u0435 \u0447\u0442\u043e\u0431\u044b \u0432\u044b\u0437\u0432\u0430\u0442\u044c \u043c\u0435\u0442\u043e\u0434 drag_in_dots \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u0438\u0437 \u043d\u0438\u0445. <\/p>\n<p>  \u041f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043a\u0440\u0430\u0439\u043d\u0438\u0435 \u0442\u043e\u0447\u043a\u0438 \u0432\u043e\u0440\u043e\u043d\u043e\u043a \u0432 \u043c\u0435\u0442\u043e\u0434\u0435 init, \u0434\u0435\u043b\u0438\u043c \u0440\u0430\u0441\u0441\u0442\u043e\u044f\u043d\u0438\u0435 \u043d\u0430 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u043e \u0432\u043e\u0440\u043e\u043d\u043e\u043a, \u0430 \u0437\u0430\u0442\u0435\u043c \u0432 \u0446\u0438\u043a\u043b\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0433\u043e\u0442\u043e\u0432\u044b\u0435 \u043e\u0431\u044a\u0435\u043a\u0442\u044b Funnel. \u0414\u043b\u044f \u043c\u0435\u0442\u043e\u0434\u0430 drag_in_dots \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u0440\u0430\u0441\u0447\u0435\u0442 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 animmate_slow, \u0447\u0442\u043e\u0431\u044b \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043f\u0430\u0434\u0435\u043d\u0438\u0435 \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438, \u0430 \u043d\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0439 \u0432\u043e\u0440\u043e\u043d\u043a\u0438.<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">classes\/funnels.py<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">from typing import List, Tuple, Union   from manimlib.imports import Scene, VGroup   from classes.movable_funnel import MovableFunnel   from .funnel import Funnel from .shape_point import ShapePoint     class FunnelsExeption(Exception):    \"\"\"General exception for Funnels class\"\"\"     class Funnels(VGroup):    funnels: List[Funnel] = []      def __init__(        self,        start_end_points: Tuple[tuple, tuple],        funnel: Funnel,        count: int,        bins: Union[int, float],        annot: bool = False,        *args,        **kwargs,    ):        \"\"\"Object-constructor for the funnels. Inside init, you could pass all needed variables that will be            passed to the Funnel init as well.          Args:            start_end_points (Tuple[tuple, tuple]): Left top and right top points. ((x1,y1), (x2,y2)).            funnel (Funnel): Class for funnel building. Must be inherited from Funnel.            count (int): Funnels count.            bins (Union[int, float]): Bins count for funnels.            annot (bool, optional): Annotate funnels or not. Defaults to False.          Example:            funnels = Funnels(                start_end_points=((-6.5, -4), (6.5, -4)),                funnel=MovableFunnel,                count=5,                bins=bins,                annot=True,                point_radius=0.2,                run_time=0.8,                height=4,            )        \"\"\"          self.left_top_point = ShapePoint(start_end_points[0])        self.right_top_point = ShapePoint(start_end_points[1])        self.bins = bins        self.count = count          step = abs((self.right_top_point[0] - self.left_top_point[0]) \/ count)        x_start_point = self.left_top_point[0]        x_end_point = x_start_point + step        y_point = self.left_top_point[1]          # Creating list for the annotation texts        annot_step = int(self.bins \/ self.count)        annot_bins = [i for i in range(0, int(self.bins) + annot_step, annot_step)]        annots = [f\"{x+1}\u2013{y}\" for x, y in zip(annot_bins[:-1], annot_bins[1:])]          # Creating funnels in cycle        for i in range(self.count):            self.funnels.append(                funnel(                    *args,                    start_end_points=(                        (x_start_point, y_point),                        (x_end_point, y_point),                    ),                    annot=annot,                    annot_text=annots[i],                    **kwargs,                )            )              x_start_point, x_end_point = x_end_point, x_end_point + step          super().__init__(*self.funnels)      def drag_in_dots(self, scene: Scene, dots: VGroup, animate_slow: int, animate_rest: bool):        \"\"\"Method for moving dots into funnels. Calls the same method drag_in_dots for every funnel            in self.funnels.          Args:            scene (Scene): Scene class.            dots (VGroup): Dots that we need to move.            animate_slow (int): How many dots we need to animate slowly.            animate_rest (bool): Do we need to move the rest of the dots or not.          Raises:            FunnelsExeption: Raises when funnels were not created with MovableFunnel class.        \"\"\"        if any(not isinstance(x, MovableFunnel) for x in self.funnels):            raise FunnelsExeption('method \"drag_in_dots\" allowed only for \"MovableFunnel\"')        # We are sorting dots ascending to be able to play animation from the smallest dot to the biggest.        _dots = VGroup(*sorted(dots, key=lambda x: x.value))          for funnel in self.funnels:            funnel.drag_in_dots(                scene=scene,                dots=_dots,                animate_slow=animate_slow,                animate_rest=animate_rest,            )              animate_slow = animate_slow - funnel.animated_slowly<\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  \u0417\u0430\u043f\u0443\u0441\u0442\u0438\u043c \u0441\u0431\u043e\u0440\u043a\u0443 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u0434\u043e\u0431\u0430\u0432\u0438\u0432 \u043d\u043e\u0432\u044b\u0439 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439, \u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u043c, \u043a\u0430\u043a \u0432\u0441\u0451 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442:<\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">scenario.py<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">def play_sixth_scene(self):        bins = 100        funnels = Funnels(            start_end_points=((-6.5, 0), (6.5, 0)),            funnel=MovableFunnel,            count=5,            bins=bins,            annot=True,            point_radius=0.2,            run_time=0.8,            height=3,        )          start_dot_values = [1, 2, 1, 3, 4, 2, 1]          table = CustomersTable(            ((-5, 2), (-1, 2)),            row_count=3,            visible_row_count=3,            bins=4,            start_dots_values=start_dot_values,        )          self.scene.add(funnels, table)          funnels.drag_in_dots(            scene=self.scene,            dots=table.dots,            animate_slow=3,            animate_rest=False,        )<\/code><\/pre>\n<\/div><\/div>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/2b\/sh\/4h\/2bsh4h2xtucxisad0auga7fr-ie.gif\" data-src=\"https:\/\/habrastorage.org\/webt\/2b\/sh\/4h\/2bsh4h2xtucxisad0auga7fr-ie.gif\"\/><\/p>\n<h3>\u0421\u043e\u0437\u0434\u0430\u0451\u043c \u0444\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0435 \u0432\u0438\u0434\u0435\u043e<\/h3>\n<p>  \u0414\u0430\u0432\u0430\u0439\u0442\u0435 \u043d\u0430\u043a\u043e\u043d\u0435\u0446 \u0441\u043e\u0435\u0434\u0438\u043d\u0438\u043c \u0432\u0441\u0451 \u0442\u043e, \u0447\u0442\u043e \u043c\u044b \u0443\u0436\u0435 \u0441\u0434\u0435\u043b\u0430\u043b\u0438, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442 \u2014 \u0432\u0438\u0434\u0435\u043e \u043f\u043e \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044e \u043d\u043e\u043c\u0435\u0440 \u0434\u0432\u0430. \u0410\u043b\u0433\u043e\u0440\u0438\u0442\u043c \u0431\u0443\u0434\u0435\u0442 \u0442\u0430\u043a\u0438\u043c:<\/p>\n<ol>\n<li>\u0440\u0438\u0441\u0443\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0441 \u0448\u0430\u0440\u0438\u043a\u0430\u043c\u0438,<\/li>\n<li>\u0440\u0438\u0441\u0443\u0435\u043c \u0433\u0440\u0430\u0444\u0438\u043a,<\/li>\n<li>\u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u0435\u043c \u0448\u0430\u0440\u0438\u043a\u0438 \u0438\u0437 \u0442\u0430\u0431\u043b\u0438\u0446\u044b \u043d\u0430 \u0433\u0440\u0430\u0444\u0438\u043a,<\/li>\n<li>\u0443\u0431\u0438\u0440\u0430\u0435\u043c \u0442\u0430\u0431\u043b\u0438\u0446\u0443 \u0441 \u044d\u043a\u0440\u0430\u043d\u0430,<\/li>\n<li>\u0440\u0430\u0441\u0442\u044f\u0433\u0438\u0432\u0430\u0435\u043c \u0433\u0440\u0430\u0444\u0438\u043a \u043d\u0430 \u0432\u0435\u0441\u044c \u044d\u043a\u0440\u0430\u043d (\u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438 \u2014 \u0440\u0438\u0441\u0443\u0435\u043c \u0432\u0442\u043e\u0440\u043e\u0439 \u0433\u0440\u0430\u0444\u0438\u043a \u0438 \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c \u0433\u0440\u0430\u0444\u0438\u043a 1 \u0432 \u0433\u0440\u0430\u0444\u0438\u043a 2),<\/li>\n<li>\u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u0435\u043c \u0433\u0440\u0430\u0444\u0438\u043a \u043d\u0430\u0432\u0435\u0440\u0445 \u044d\u043a\u0440\u0430\u043d\u0430 (\u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438 \u0438\u0434\u0451\u0442 \u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0435\u043d\u0438\u0435 \u044d\u043a\u0440\u0430\u043d\u0430 \u0432\u043d\u0438\u0437),<\/li>\n<li>\u0440\u0438\u0441\u0443\u0435\u043c \u0432\u043e\u0440\u043e\u043d\u043a\u0438,<\/li>\n<li>\u043f\u0435\u0440\u0435\u043c\u0435\u0449\u0430\u0435\u043c \u0448\u0430\u0440\u0438\u043a\u0438 \u0438\u0437 \u0433\u0440\u0430\u0444\u0438\u043a\u0430 \u0432 \u0432\u043e\u0440\u043e\u043d\u043a\u0438.<\/li>\n<\/ol>\n<p>  <\/p>\n<div class=\"spoiler\" role=\"button\" tabindex=\"0\">                         <b class=\"spoiler_title\">classes\/scenario.py<\/b>                         <\/p>\n<div class=\"spoiler_text\">\n<pre><code class=\"python\">def play_whole_scenario(self):        # Dot bins maximum value        bins = 100          # Adding dot colors (from green to red)        dot_colors = list(Color(\"#7fcc81\").range_to(\"#ff7555\", int(bins)))          # Initial dot values, to keep them the same over several animation builds        start_dots_values = [31, 25, 63, 47, 82, 25, 49, 99, 21, 33, 37]          # Custom text for the table (Customer\/buyer)        table_text = \"\u0417\u0430\u043a\u0430\u0437\u0447\u0438\u043a\"          # Table initialization        table = CustomersTable(            ((-6.5, 3), (-2.5, 3)),            row_count=30,            visible_row_count=11,            bins=bins,            colors=dot_colors,            start_dots_values=start_dots_values,            text=table_text,        )          # Graph initialization        x_graph = MovableContinuousGraph(            ((-2, -3), (6.5, -3)),            None,            bins=bins,            annot=True,        )          # New graph that will be on the whole screen width        x_graph_second_position = MovableContinuousGraph(            ((-6.5, -3), (6.5, -3)),            None,            bins=bins,            annot=True,        )          # Copying dots. This is for future needs.        dots_second_position = deepcopy(table.dots)          # Playing animations        self.scene.play(FadeIn(table), FadeIn(x_graph))          self.scene.wait(2)          # Moving dots from the table to the graph        x_graph.drag_in_dots(            self.scene,            dots=table.dots,            animate_slow=3,            animate_rest=True,        )          self.scene.wait(3)          # Removing graph        self.scene.play(FadeOut(table.lines), FadeOut(table.customers))          # Moving dots from the first graph to the second        x_graph_second_position.drag_in_dots(            scene=self.scene,            dots=dots_second_position,            animate_slow=0,            animate_rest=False,        )          # Playing animation with moving graphs from position 1 to position 2, and same for the dots.        self.scene.play(            Transform(x_graph, x_graph_second_position),            Transform(table.dots, dots_second_position),        )          self.scene.wait(3)          # Adding funnels        funnels = Funnels(            start_end_points=((-6.5, -4), (6.5, -4)),            funnel=MovableFunnel,            count=5,            bins=bins,            annot=True,            point_radius=0.2,            run_time=0.8,            height=4,        )          # Adding funnels to the screen        self.scene.add(funnels)          # Moving camera to the bottom        self.scene.play(self.scene.camera_frame.move_to, array([0, -5.5, 0]))          self.scene.wait(1)          # Moving dots from the graph to the funnels        funnels.drag_in_dots(            scene=self.scene,            dots=table.dots,            animate_slow=9,            animate_rest=True,        )          self.scene.wait(3)          # Removing all objects from scene        self.scene.play(            FadeOut(funnels),            FadeOut(table.dots),            FadeOut(x_graph),            FadeOut(x_graph_second_position),        )          # Moving scene back to center        self.scene.play(self.scene.camera_frame.move_to, array([0, 0, 0]))          self.scene.wait(1)<\/code><\/pre>\n<p>  <\/div>\n<\/p><\/div>\n<p>  \u0412 main.py \u043c\u0435\u043d\u044f\u0435\u043c \u0432\u044b\u0437\u043e\u0432 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0435\u0433\u043e \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u044f \u043d\u0430 play_whole_scenario, \u0437\u0430\u043f\u0443\u0441\u043a\u0430\u0435\u043c \u0440\u0435\u043d\u0434\u0435\u0440 \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u0432\u0438\u0434\u0435\u043e:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/rd\/9p\/yp\/rd9pypqeiwclfrs7s2765vovpyw.gif\" data-src=\"https:\/\/habrastorage.org\/webt\/rd\/9p\/yp\/rd9pypqeiwclfrs7s2765vovpyw.gif\"\/><\/p>\n<p>  \u0412\u0443\u0430\u043b\u044f!<\/p>\n<p>  \u041d\u0430\u0434\u0435\u044e\u0441\u044c, \u043c\u043e\u0439 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u044b\u0439 \u0440\u0430\u0441\u0441\u043a\u0430\u0437 \u043e\u0431 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 Manim \u043d\u0430 \u043f\u0440\u0430\u043a\u0442\u0438\u043a\u0435 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0432\u0430\u043c \u0432 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u0445 \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0432\u0438\u0434\u0435\u043e. \u0422\u0430\u043a\u0436\u0435 \u0431\u0443\u0434\u0443 \u0440\u0430\u0434, \u0435\u0441\u043b\u0438 \u0432\u044b \u043f\u043e\u0434\u0435\u043b\u0438\u0442\u0435\u0441\u044c \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445 \u0441\u0432\u043e\u0438\u043c\u0438 \u043c\u044b\u0441\u043b\u044f\u043c\u0438 \u043f\u043e \u043f\u043e\u0432\u043e\u0434\u0443 \u0441\u0442\u0430\u0442\u044c\u0438 \u0438 \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u044b\u043c \u043e\u043f\u044b\u0442\u043e\u043c \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u044d\u0442\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u043e\u0439 \u2014 \u043d\u0430\u0432\u0435\u0440\u043d\u044f\u043a\u0430 \u0431\u0443\u0434\u0435\u0442, \u0447\u0442\u043e \u043e\u0431\u0441\u0443\u0434\u0438\u0442\u044c.<\/p>\n<p>  \u0414\u043b\u044f \u0437\u0430\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432\u0430\u0432\u0448\u0438\u0445\u0441\u044f \u0442\u0435\u043c\u043e\u0439 \u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e <a href=\"https:\/\/github.com\/mohovkm\/habr_manim\">\u0441\u0441\u044b\u043b\u043a\u0443 \u043d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442<\/a> \u043d\u0430 GitHub.<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/578910\/\"> https:\/\/habr.com\/ru\/articles\/578910\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-1\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\u041f\u0440\u0438\u0432\u0435\u0442! \u041c\u0435\u043d\u044f \u0437\u043e\u0432\u0443\u0442 \u041a\u043e\u043d\u0441\u0442\u0430\u043d\u0442\u0438\u043d \u041c\u043e\u0445\u043e\u0432, \u044f \u0442\u0438\u043c\u043b\u0438\u0434, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043e\u0434\u043d\u0430\u0436\u0434\u044b \u043f\u0440\u043e\u0448\u0451\u043b \u043a\u0443\u0440\u0441 \u041f\u0440\u0430\u043a\u0442\u0438\u043a\u0443\u043c\u0430 \u043f\u043e <a href=\"https:\/\/practicum.yandex.ru\/data-analyst?utm_source=pr&amp;utm_medium=content&amp;utm_content=21_09_21&amp;utm_campaign=pr_content_data-analyst_habr\">\u0430\u043d\u0430\u043b\u0438\u0442\u0438\u043a\u0435 \u0434\u0430\u043d\u043d\u044b\u0445<\/a>, \u043f\u043e \u0431\u043e\u043b\u044c\u0448\u0435\u0439 \u0447\u0430\u0441\u0442\u0438 \u0434\u043b\u044f \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0433\u043e \u0440\u0430\u0437\u0432\u0438\u0442\u0438\u044f. \u0422\u0435\u043c\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0430\u043d\u0438\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0432\u0438\u0434\u0435\u043e \u043d\u0430 Python \u0437\u0430\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043e\u0432\u0430\u043b\u0430 \u043c\u0435\u043d\u044f \u043f\u043e\u0437\u0436\u0435, \u043a\u043e\u0433\u0434\u0430 \u0432 <a href=\"https:\/\/t.me\/datalytx\">\u0442\u0435\u043b\u0435\u0433\u0440\u0430\u043c-\u043a\u0430\u043d\u0430\u043b\u0435<\/a> \u0410\u043b\u0435\u043a\u0441\u0435\u044f \u041c\u0430\u043a\u0430\u0440\u043e\u0432\u0430 \u0438\u0437 \u041f\u0440\u0430\u043a\u0442\u0438\u043a\u0443\u043c\u0430 \u043f\u043e\u044f\u0432\u0438\u043b\u043e\u0441\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435, \u0447\u0442\u043e \u0435\u0433\u043e \u043a\u043e\u043c\u0430\u043d\u0434\u0435 \u043d\u0443\u0436\u043d\u0430 \u043f\u043e\u043c\u043e\u0449\u044c \u0441 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0435\u0439. \u041c\u043d\u0435 \u0437\u0430\u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u043f\u043e\u043f\u0440\u043e\u0431\u043e\u0432\u0430\u0442\u044c \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e\u0435 \u0438 \u043d\u0430\u0433\u043b\u044f\u0434\u043d\u043e\u0435 \u043e\u0431\u0443\u0447\u0430\u044e\u0449\u0435\u0435 \u0432\u0438\u0434\u0435\u043e, \u0440\u0430\u0441\u043a\u0440\u044b\u0432\u0430\u044e\u0449\u0435\u0435 \u043e\u0434\u043d\u0443 \u0438\u0437 \u0442\u0435\u043c \u043a\u0443\u0440\u0441\u0430, \u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0433\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u044b. <\/p>\n<p>  \u042f \u0443\u0433\u043b\u0443\u0431\u0438\u043b\u0441\u044f \u0432 \u0438\u0437\u0443\u0447\u0435\u043d\u0438\u0435 \u0432\u043e\u043f\u0440\u043e\u0441\u0430 \u0438 \u043f\u0435\u0440\u0435\u0447\u0438\u0442\u0430\u043b \u043d\u0435\u043c\u0430\u043b\u043e \u0441\u0442\u0430\u0442\u0435\u0439 \u043d\u0430 \u0442\u0435\u043c\u0443 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438 \u00ab\u043a\u0430\u043a \u0443 3Blue1Brown\u00bb, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0432 \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u043c \u0431\u044b\u043b\u0438 \u043b\u0438\u0431\u043e \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430\u043c\u0438, \u043b\u0438\u0431\u043e \u043a\u043e\u043f\u0438\u0435\u0439 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u0442\u0443\u0442\u043e\u0440\u0438\u0430\u043b\u0430 \u0413\u0440\u0430\u043d\u0442\u0430 \u0421\u0430\u043d\u0434\u0435\u0440\u0441\u043e\u043d\u0430. \u0413\u0440\u0430\u043d\u0442 \u0441\u043e\u0437\u0434\u0430\u043b \u0438 \u0432\u044b\u043b\u043e\u0436\u0438\u043b \u0432 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0439 \u0434\u043e\u0441\u0442\u0443\u043f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u044c\u043d\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443 \u043d\u0430 Python \u2014 <a href=\"https:\/\/github.com\/3b1b\/manim\">Manim<\/a>, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043f\u0440\u0435\u0434\u043d\u0430\u0437\u043d\u0430\u0447\u0435\u043d\u0430 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0438. \u0412 \u0440\u043e\u043b\u0438\u043a\u0430\u0445, \u0437\u0430\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e Manim, \u043e\u043d \u043e\u0431\u044a\u044f\u0441\u043d\u044f\u0435\u0442 \u043c\u0430\u0442\u0435\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438\u0435 \u0442\u0435\u043c\u044b \u043d\u0430 \u0441\u0432\u043e\u0451\u043c <a href=\"https:\/\/www.youtube.com\/channel\/UCYO_jab_esuFRV4b17AJtAw\">YouTube-\u043a\u0430\u043d\u0430\u043b\u0435<\/a>.<\/p>\n<p>  \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u043e\u0434\u0435\u043b\u044e\u0441\u044c \u043b\u0438\u0447\u043d\u044b\u043c \u043e\u043f\u044b\u0442\u043e\u043c: \u0440\u0435\u0446\u0435\u043f\u0442\u043e\u043c \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043e\u0431\u044a\u0435\u043a\u0442\u043e\u0432 \u0438 \u0430\u043d\u0438\u043c\u0430\u0446\u0438\u0439. \u0412\u043c\u0435\u0441\u0442\u0435 \u043c\u044b \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043e\u0431\u0443\u0447\u0430\u044e\u0449\u0435\u0435 \u0432\u0438\u0434\u0435\u043e \u043e \u0433\u0438\u0441\u0442\u043e\u0433\u0440\u0430\u043c\u043c\u0430\u0445. \u0412\u043e\u0442 \u043a\u0430\u043a \u0431\u0443\u0434\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0438\u0442\u043e\u0433\u043e\u0432\u044b\u0439 \u0432\u0430\u0440\u0438\u0430\u043d\u0442:<\/p>\n<p>  <img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/rd\/9p\/yp\/rd9pypqeiwclfrs7s2765vovpyw.gif\" data-src=\"https:\/\/habrastorage.org\/webt\/rd\/9p\/yp\/rd9pypqeiwclfrs7s2765vovpyw.gif\"\/>  <\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-409092","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/409092","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=409092"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/409092\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=409092"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=409092"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=409092"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}