From d83e783719702e99910f80240684613d866fcb83 Mon Sep 17 00:00:00 2001 From: Murat Semerci <91904304+SemerciMurat@users.noreply.github.com> Date: Tue, 26 Jul 2022 23:18:59 +0200 Subject: [PATCH 01/38] Started Turkish translation of the main README.md --- translations/README.tr.md | 172 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 172 insertions(+) create mode 100644 translations/README.tr.md diff --git a/translations/README.tr.md b/translations/README.tr.md new file mode 100644 index 00000000..b0e74b85 --- /dev/null +++ b/translations/README.tr.md @@ -0,0 +1,172 @@ +[![GitHub license](https://img.shields.io/github/license/microsoft/AI-For-Beginners.svg)](https://github.com/microsoft/AI-For-Beginners/blob/main/LICENSE) +[![GitHub contributors](https://img.shields.io/github/contributors/microsoft/AI-For-Beginners.svg)](https://GitHub.com/microsoft/AI-For-Beginners/graphs/contributors/) +[![GitHub issues](https://img.shields.io/github/issues/microsoft/AI-For-Beginners.svg)](https://GitHub.com/microsoft/AI-For-Beginners/issues/) +[![GitHub pull-requests](https://img.shields.io/github/issues-pr/microsoft/AI-For-Beginners.svg)](https://GitHub.com/microsoft/AI-For-Beginners/pulls/) +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) + +[![GitHub watchers](https://img.shields.io/github/watchers/microsoft/AI-For-Beginners.svg?style=social&label=Watch)](https://GitHub.com/microsoft/AI-For-Beginners/watchers/) +[![GitHub forks](https://img.shields.io/github/forks/microsoft/AI-For-Beginners.svg?style=social&label=Fork)](https://GitHub.com/microsoft/AI-For-Beginners/network/) +[![GitHub stars](https://img.shields.io/github/stars/microsoft/AI-For-Beginners.svg?style=social&label=Star)](https://GitHub.com/microsoft/AI-For-Beginners/stargazers/) +[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/microsoft/ai-for-beginners/HEAD) +[![Gitter](https://badges.gitter.im/Microsoft/ai-for-beginners.svg)](https://gitter.im/Microsoft/ai-for-beginners?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) + +# Yeni Başlayanlar İçin Yapay Zeka - Müfredat + +|![ Çizim notu [(@girlie_mac)](https://twitter.com/girlie_mac) ](../lessons/sketchnotes/ai-overview.png)| +|:---:| +| Yeni Başlayanlar İçin YZ - _Sketchnote by [@girlie_mac](https://twitter.com/girlie_mac)_ | + +Microsoft'taki Azure Bulut Savunucuları, **Yapay Zeka** ile ilgili her şeyi içeren 12 haftalık, 24 derslik bir müfredat sunmaktan memnuniyet duyar. + +Bu müfredatta şunları öğreneceksiniz: + +* "Eski bilindik" sembolik yaklaşım ile **Bilgi Temsili** ve akıl yürütme dahil olmak üzere Yapay Zekaya farklı yaklaşımlar ([GOFAI](https://en.wikipedia.org/wiki/Symbolic_artificial_intelligence)). +* Modern YZ'nin merkezinde yer alan **Sinir Ağları** ve **Derin Öğrenme**. En popüler çerçevelerden ikisinde kod kullanarak bu önemli konuların arkasındaki kavramları göstereceğiz - [TensorFlow](http://Tensorflow.org) ve [PyTorch](http://pytorch.org). +* İmgelerle ve metinlerle çalışmak için **Sinir Mimarileri**. Yakın dönem modellerini ele alacağız, ancak en son teknoloji biraz eksik olabilir. +* **Genetik Algoritmalar** ve **Çok Etmenli Sistemler** gibi daha az popüler olan yapay zeka yaklaşımları. + +Bu müfredatta neleri ele almayacağız: + +* **İşte YZ** kullanımına ilişkin iş vakaları. Microsoft Öğrenme yolunundaki [İş için YZ'ye Giriş](https://docs.microsoft.com/learn/paths/introduction-ai-for-business-users/?WT.mc_id=academic-57639-dmitryso)'i veya [INSEAD](https://www.insead.edu/) ile işbirliğiyle geliştirilmiş [YZ İş Okulu](https://www.microsoft.com/ai/ai-business-school/?WT.mc_id=academic-57639-dmitryso)'nu almayı düşünün. +* **Klasik Yapay Öğrenme**, [Yeni Başlayanlar için Yapay Öğrenme Müfredatı](http://github.com/Microsoft/ML-for-Beginners)'mızda iyice açıklanmıştır. +* **[Bilişsel Hizmetler](https://azure.microsoft.com/services/cognitive-services/?WT.mc_id=academic-57639-dmitryso)** kullanılarak oluşturulmuş pratik YZ uygulamaları. Bunun gibi [görme](https://docs.microsoft.com/learn/paths/create-computer-vision-solutions-azure-cognitive-services/?WT.mc_id=academic-57639-dmitryso), [doğal dil işleme](https://docs.microsoft.com/learn/paths/explore-natural-language-processing/?WT.mc_id=academic-57639-dmitryso) ve diğerleri için Microsoft Öğrenme modülleriyle başlamanızı öneririz. +* [Azure Yapay Öğrenme](https://azure.microsoft.com/services/machine-learning/?WT.mc_id=academic-57639-dmitryso) veya [Azure Databricks](https://docs.microsoft.com/learn/paths/data-engineer-azure-databricks?WT.mc_id=academic-57639-dmitryso) gibi belli YÖ **Bulut Çerçeveleri**. [Azure Yapay Öğrenme ile yapay öğrenme çözümleri oluşturma ve çalıştırma](https://docs.microsoft.com/learn/paths/build-ai-solutions-with-azure-ml-service/?WT.mc_id=academic-57639-dmitryso) ve [Azure Databricks ile yapay öğrenme çözümleri oluşturma ve çalıştırma](https://docs.microsoft.com/learn/paths/build-operate-machine-learning-solutions-azure-databricks/?WT.mc_id=academic-57639-dmitryso) öğrenme yollarını kullanmayı düşünün. +* **Konuşkan YZ** ve **Sohbet Botları**. Ayrı bir [konuşkan YZ çözümleri yaratma](https://docs.microsoft.com/learn/paths/create-conversational-ai-solutions/?WT.mc_id=academic-57639-dmitryso) öğrenme yolu vardır, ayrıca daha fazla ayrıntı için [bu blog gönderisine](https://soshnikov.com/azure/hello-bot-conversational-ai-on-microsoft-platform/) bakın. +* Derin öğrenmenin ardındaki **Derin Matematik**. Bunun için Ian Goodfellow, Yoshua Bengio ve Aaron Courville tarafından yazılmış [Derin Öğrenme](https://www.amazon.com/Deep-Learning-Adaptive-Computation-Machine/dp/0262035618) adlı [https://www.deeplearningbook.org/](https://www.deeplearningbook.org/) adresinden de ulaşılabilir kitabı tavsiye ediyoruz. + +For a gentle introduction to *AI in the Cloud* topics you may consider taking the [Get started with artificial intelligence on Azure](https://docs.microsoft.com/learn/paths/get-started-with-artificial-intelligence-on-azure/?WT.mc_id=academic-57639-dmitryso) Learning Path. + +*Bulutta Yapay Zeka* konularına nazik bir giriş için [Azure'de yapay zekayı kullanmaya başlama](https://docs.microsoft.com/learn/paths/get-started-with-artificial-intelligence-on-azure/?WT.mc_id=academic-57639-dmitryso) öğrenme yolunu almayı düşünebilirsiniz. + +--- +# İçerik + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NumaraDersGirişPyTorchKeras/TensorFlowLab
IYZ'ye Giriş
1YZ'ye Giriş ve TarihçesiMetin
IISimgesel YZ
2 Bilgi Temsili ve Uzman SistemlerMetinUzman Sistem, Ontoloji, Kavram Çizgesi
IIISinir Ağlarına Giriş
3AlgılayıcıMetin + DefterLab
4 Çok Katmanlı Algılayıcı ve Kendi Çerçevemizi OluşturmaMetinDefterLab
5Çerçevelere Giriş (PyTorch/TensorFlow)
Aşırı Öğrenme
Metin
Metin
PyTorchKeras/TensorFlowLab
IVBilgisayarla GörmeYZ Temelleri: Bilgisayarla Görmeyi Keşfedin
Bilgisayarla Görmede Microsoft Öğrenme ModülüPyTorchTensorFlow
6Bilgisayarla Görmeye Giriş. OpenCVMetinDefterLab
7Evrişimli Sinir Ağları
CNN Mimarileri
Metin
Metin
PyTorchTensorFlowLab
8Önceden Eğitilmiş Ağlar ve Öğrenme Aktarımı
Eğitim Püf Noktaları
Metin
Metin
PyTorchTensorFlow
Hattan düşürme örneklemi
Düşman kedi
Lab
9Autoencoders and VAEsTextPyTorchTensorFlow
10Generative Adversarial Networks
Artistic Style Transfer
TextPyTorchTensorFlow GAN
Style Transfer
11Object DetectionTextPyTorchTensorFlowLab
12Semantic Segmentation. U-NetTextPyTorchTensorFlow
VNatural Language ProcessingAI Fundamentals: Explore Natural Language Processing
Microsoft Learn Module on Natural LanguagePyTorchTensorFlow
13Text Representation. Bow/TF-IDFTextPyTorchTensorFlow
14Semantic word embeddings. Word2Vec and GloVeTextPyTorchTensorFlow
15Language Modeling. Training your own embeddingsTextTensorFlowLab
16Recurrent Neural NetworksTextPyTorchTensorFlow
17Generative Recurrent NetworksTextPyTorchTensorFlowLab
18Transformers. BERT.TextPyTorchTensorFlow
19Named Entity RecognitionTextTensorFlowLab
20Large Language Models, Prompt Programming and Few-Shot TasksTextPyTorch
VIOther AI Techniques
21Genetic AlgorithmsTextNotebook
22Deep Reinforcement LearningTextTensorFlowLab
23Multi-Agent SystemsText
VIIAI Ethics
24AI Ethics and Responsible AITextMS Learn: Responsible AI Principles
Extras
X1Multi-Modal Networks, CLIP and VQGANTextNotebook
+ +**[Mindmap of the Course](http://soshnikov.com/courses/ai-for-beginners/mindmap.html)** + +Each lesson contains some pre-reading material (linked as **Text** above), and some executable Jupyter Notebooks, which are often specific to the framework (**PyTorch** or **TensorFlow**). The executable notebook also contains a lot of theoretical material, so to understand the topic you need to go through at least one version of the notebooks (either PyTorch or TensorFlow). There are also **Labs** available for some topics, which give you an opportunity to try applying the material you have learned to a specific problem. + +Some sections also contain links to **MS Learn** modules that cover related topics. Microsoft Learn provides a convenient GPU-enabled learning environment, although in terms of content you can expect this curriculum to go a bit deeper. + +# Getting Started + +**Students**, there are a couple of ways to use the curriculum. First of all, you can just read the text and look through the code directly on GitHub. If you want to run the code in any of the notebooks - [read our instructions](./etc/how-to-run.md), and find more advice on how to do it [in this blog post](https://soshnikov.com/education/how-to-execute-notebooks-from-github/). + +> **Note**: [Instructions on how to run the code in this curriculum](./etc/how-to-run.md) + +However, if you would like to take the course as a self-study project, we suggest that you fork the entire repo to your own GitHub account and complete the exercises on your own or with a group: + +- Start with a pre-lecture quiz +- Read the intro text for the lecture +- If the lecture has additional notebooks, go through them, reading and executing the code. If both TensorFlow and PyTorch notebooks are provided, you can focus on one of them - chose your favorite framework +- Notebooks often contain some of the challenges that require you to tweak the code a little bit to experiment +- Take the post-lecture quiz +- If there is a lab attached to the module - complete the assignment +- Visit the [Discussion board](https://github.com/microsoft/AI-For-Beginners/discussions) to "learn out loud". +- Chat with other learners [on Gitter](https://gitter.im/Microsoft/ai-for-beginners) or [in Telegram channel](http://t.me/ai_for_beginners). + +> For further study, we recommend following these [Microsoft Learn](https://docs.microsoft.com/en-us/users/dmitrysoshnikov-9132/collections/31zgizg2p418yo/?WT.mc_id=academic-57639-dmitryso) modules and learning paths. + +**Teachers**, we have [included some suggestions](/etc/for-teachers.md) on how to use this curriculum. + +--- + +## Credits + +**✍️ Primary Author:** [Dmitry Soshnikov](http://soshnikov.com), PhD
+**🔥 Editor:** [Jen Looper](https://twitter.com/jenlooper), PhD
+**🎨 Sketchnote illustrator:** [Tomomi Imura](https://twitter.com/girlie_mac)
+**✅ Quiz Creator:** [Lateefah Bello](https://github.com/CinnamonXI), [MLSA](https://studentambassadors.microsoft.com/)
+**🙏 Core Contributors:** [Evgenii Pishchik](https://github.com/Pe4enIks) + +## Meet the Team + +[![Promo video](/lessons/sketchnotes/ai-for-beginners.png)](https://youtu.be/m2KrAk0cC1c "Promo video") + +> 🎥 Click the image above for a video about the project and the folks who created it! + +--- + +## Pedagogy + +We have chosen two pedagogical tenets while building this curriculum: ensuring that it is hands-on **project-based** and that it includes **frequent quizzes**. + +By ensuring that the content aligns with projects, the process is made more engaging for students and retention of concepts will be augmented. In addition, a low-stakes quiz before a class sets the intention of the student towards learning a topic, while a second quiz after class ensures further retention. This curriculum was designed to be flexible and fun and can be taken in whole or in part. The projects start small and become increasingly complex by the end of the 12 week cycle. + +> Find our [Code of Conduct](etc/CODE_OF_CONDUCT.md), [Contributing](etc/CONTRIBUTING.md), and [Translation](etc/TRANSLATIONS.md) guidelines. Find our [Support Documentation here](etc/SUPPORT.md) and [security information here](etc/SECURITY.md). We welcome your constructive feedback! + +> **A note about quizzes**: All quizzes are contained [in this app](https://red-field-0a6ddfd03.1.azurestaticapps.net/), for 50 total quizzes of three questions each. They are linked from within the lessons but the quiz app can be run locally; follow the instruction in the `etc/quiz-app` folder. + +## Offline access + +You can run this documentation offline by using [Docsify](https://docsify.js.org/#/). Fork this repo, [install Docsify](https://docsify.js.org/#/quickstart) on your local machine, and then in the `etc/docsify` folder of this repo, type `docsify serve`. The website will be served on port 3000 on your localhost: `localhost:3000`. A pdf of the curriculum is available [at this link](/etc/pdf/readme.pdf). + +## Help Wanted! + +Would you like to contribute a translation? Please read our [translation guidelines](etc/TRANSLATIONS.md). + +## Other Curricula + +Our team produces other curricula! Check out: + +- [Web Dev for Beginners](https://aka.ms/webdev-beginners) +- [IoT for Beginners](https://aka.ms/iot-beginners) +- [Machine Learning for Beginners](https://aka.ms/ml-beginners) +- [Data Science for Beginners](https://aka.ms/datascience-beginners) From e9bc0f12430121b7869dd53bdaf5925ebbf110b7 Mon Sep 17 00:00:00 2001 From: semercim Date: Tue, 26 Jul 2022 23:28:11 +0200 Subject: [PATCH 02/38] Turkish translation of the main README.md --- translations/README.tr.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/translations/README.tr.md b/translations/README.tr.md index b0e74b85..f597af09 100644 --- a/translations/README.tr.md +++ b/translations/README.tr.md @@ -70,8 +70,8 @@ For a gentle introduction to *AI in the Cloud* topics you may consider taking th 6Bilgisayarla Görmeye Giriş. OpenCVMetinDefterLab 7Evrişimli Sinir Ağları
CNN MimarileriMetin
MetinPyTorchTensorFlowLab 8Önceden Eğitilmiş Ağlar ve Öğrenme Aktarımı
Eğitim Püf NoktalarıMetin
MetinPyTorchTensorFlow
Hattan düşürme örneklemi
Düşman kediLab -9Autoencoders and VAEsTextPyTorchTensorFlow -10Generative Adversarial Networks
Artistic Style TransferTextPyTorchTensorFlow GAN
Style Transfer +9Otomatik kodlayıcılar and Değişken otomatik kodlayıcılarsMetinPyTorchTensorFlow +10Üretken Çekişmeli Ağları
Sanatsal Tarz AktarımıMetinPyTorchTensorFlow GAN
Tarz Aktarımı 11Object DetectionTextPyTorchTensorFlowLab 12Semantic Segmentation. U-NetTextPyTorchTensorFlow VNatural Language Processing From 4b2d81a2684b4e9a1ade001153103d791d75fa68 Mon Sep 17 00:00:00 2001 From: semercim Date: Wed, 27 Jul 2022 21:59:26 +0200 Subject: [PATCH 03/38] Finished Turkish translation of the main README.md --- README.md | 2 +- translations/README.tr.md | 124 +++++++++++++++++++------------------- 2 files changed, 63 insertions(+), 63 deletions(-) diff --git a/README.md b/README.md index 358c6603..a4af7e1d 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ However, if you would like to take the course as a self-study project, we sugges - Start with a pre-lecture quiz - Read the intro text for the lecture -- If the lecture has additional notebooks, go through them, reading and executing the code. If both TensorFlow and PyTorch notebooks are provided, you can focus on one of them - chose your favorite framework +- If the lecture has additional notebooks, go through them, reading and executing the code. If both TensorFlow and PyTorch notebooks are provided, you can focus on one of them - choose your favorite framework - Notebooks often contain some of the challenges that require you to tweak the code a little bit to experiment - Take the post-lecture quiz - If there is a lab attached to the module - complete the assignment diff --git a/translations/README.tr.md b/translations/README.tr.md index f597af09..e8b66af2 100644 --- a/translations/README.tr.md +++ b/translations/README.tr.md @@ -72,101 +72,101 @@ For a gentle introduction to *AI in the Cloud* topics you may consider taking th 8Önceden Eğitilmiş Ağlar ve Öğrenme Aktarımı
Eğitim Püf NoktalarıMetin
MetinPyTorchTensorFlow
Hattan düşürme örneklemi
Düşman kediLab 9Otomatik kodlayıcılar and Değişken otomatik kodlayıcılarsMetinPyTorchTensorFlow 10Üretken Çekişmeli Ağları
Sanatsal Tarz AktarımıMetinPyTorchTensorFlow GAN
Tarz Aktarımı -11Object DetectionTextPyTorchTensorFlowLab -12Semantic Segmentation. U-NetTextPyTorchTensorFlow -VNatural Language Processing - AI Fundamentals: Explore Natural Language Processing +11Nesne TespitiMetinPyTorchTensorFlowLab +12Anlamsal Bölünme. U-NetMetinPyTorchTensorFlow +VDoğal Dil İşleme + YZ Temelleri: Doğal Dil İşlemeyi Keşfedin -Microsoft Learn Module on Natural Language +Doğal Dil Üstüne Microsoft Öğrenme Modülü PyTorch TensorFlow -13Text Representation. Bow/TF-IDFTextPyTorchTensorFlow -14Semantic word embeddings. Word2Vec and GloVeTextPyTorchTensorFlow -15Language Modeling. Training your own embeddingsTextTensorFlowLab -16Recurrent Neural NetworksTextPyTorchTensorFlow -17Generative Recurrent NetworksTextPyTorchTensorFlowLab -18Transformers. BERT.TextPyTorchTensorFlow -19Named Entity RecognitionTextTensorFlowLab -20Large Language Models, Prompt Programming and Few-Shot TasksTextPyTorch -VIOther AI Techniques -21Genetic AlgorithmsTextNotebook -22Deep Reinforcement LearningTextTensorFlowLab -23Multi-Agent SystemsText -VIIAI Ethics -24AI Ethics and Responsible AITextMS Learn: Responsible AI Principles -Extras -X1Multi-Modal Networks, CLIP and VQGANTextNotebook +13Metin Temsili. Bow/TF-IDFMetinPyTorchTensorFlow +14Anlamsal kelime gömmeleri. Word2Vec and GloVeMetinPyTorchTensorFlow +15Dil Modelleme. Kendi gömmelerinizi eğitmeTextTensorFlowLab +16Yinelemeli Sinir AğlarıMetinPyTorchTensorFlow +17Üretken Yinelemeli AğlarMetinPyTorchTensorFlowLab +18Dönüştürücüler. BERT.MetinPyTorchTensorFlow +19Adlandırılmış Varlık TanımaMetinTensorFlowLab +20Büyük Dil Modelleri, Anlık Programlama ve Birkaç Atışlı GörevlerMetinPyTorch +VIDiğer YZ Teknikleri +21Genetik AlgoritmalarMetinDefter +22Derin Pekiştirmeli ÖğrenmeMetinTensorFlowLab +23Çok Etmenli SistemlerMetin +VIIYZ Etiği +24YZ Etiği ve Sorumlu YZMetinMicrosoft Öğrenme Modülü: Sorumlu YZ İlkeleri +Ekstralar +X1Çok Modlu Ağlar, CLIP and VQGANMetinDefter -**[Mindmap of the Course](http://soshnikov.com/courses/ai-for-beginners/mindmap.html)** +**[Dersin Zihinsel Haritası](http://soshnikov.com/courses/ai-for-beginners/mindmap.html)** -Each lesson contains some pre-reading material (linked as **Text** above), and some executable Jupyter Notebooks, which are often specific to the framework (**PyTorch** or **TensorFlow**). The executable notebook also contains a lot of theoretical material, so to understand the topic you need to go through at least one version of the notebooks (either PyTorch or TensorFlow). There are also **Labs** available for some topics, which give you an opportunity to try applying the material you have learned to a specific problem. +Her ders, bazı ön okuma materyalleri (yukarıda **Metin** olarak bağlantılandırılmıştır) ve genellikle (**PyTorch** veya **TensorFlow**) çerçevelerine özel bazı yürütülebilir Jupyter Defterleri içerir. Yürütülebilir not defteri ayrıca birçok teorik materyal içerir, bu nedenle konuyu anlamak için not defterlerinin en az bir sürümünü (PyTorch veya TensorFlow) üzerinden gitmeniz gerekir. Ayrıca bazı konular için öğrendiğiniz materyali belirli bir probleme uygulamayı deneme fırsatı veren laboratuvarlar (**Labs**) da vardır. -Some sections also contain links to **MS Learn** modules that cover related topics. Microsoft Learn provides a convenient GPU-enabled learning environment, although in terms of content you can expect this curriculum to go a bit deeper. +Bazı bölümler, ilgili konuları kapsayan **MS Öğrenme** modüllerine bağlantılar da içerir. Microsoft Öğrenme, uygun bir GPU etkin öğrenme ortamı sağlar, ancak içerik açısından bu müfredatın biraz daha derine inmesini bekleyebilirsiniz. -# Getting Started +# Başlarken -**Students**, there are a couple of ways to use the curriculum. First of all, you can just read the text and look through the code directly on GitHub. If you want to run the code in any of the notebooks - [read our instructions](./etc/how-to-run.md), and find more advice on how to do it [in this blog post](https://soshnikov.com/education/how-to-execute-notebooks-from-github/). +**Öğrenciler**, müfredatı kullanmanın birkaç yolu vardır. Her şeyden önce, metni okuyabilir ve kodu doğrudan GitHub'da inceleyebilirsiniz. Kodu not defterlerinden herhangi birinde çalıştırmak istiyorsanız [talimatlarımızı okuyun](./etc/how-to-run.md) ve bunu nasıl yapacağınızla ilgili daha fazlasını [bu blog yayınında](https://soshnikov.com/education/how-to-execute-notebooks-from-github/) bulabilirsiniz. -> **Note**: [Instructions on how to run the code in this curriculum](./etc/how-to-run.md) +> **Not**: [Bu müfredattaki kodun nasıl çalıştırılacağına ilişkin talimatlar](./etc/how-to-run.md) -However, if you would like to take the course as a self-study project, we suggest that you fork the entire repo to your own GitHub account and complete the exercises on your own or with a group: +Ancak, dersi kendi kendine çalışma projesi olarak almak istiyorsanız, tüm depoyu kendi GitHub hesabınıza çatallamanızı ve alıştırmaları kendi başınıza veya bir grupla tamamlamanızı öneririz: -- Start with a pre-lecture quiz -- Read the intro text for the lecture -- If the lecture has additional notebooks, go through them, reading and executing the code. If both TensorFlow and PyTorch notebooks are provided, you can focus on one of them - chose your favorite framework -- Notebooks often contain some of the challenges that require you to tweak the code a little bit to experiment -- Take the post-lecture quiz -- If there is a lab attached to the module - complete the assignment -- Visit the [Discussion board](https://github.com/microsoft/AI-For-Beginners/discussions) to "learn out loud". -- Chat with other learners [on Gitter](https://gitter.im/Microsoft/ai-for-beginners) or [in Telegram channel](http://t.me/ai_for_beginners). +- Bir ders öncesi sınavı ile başlayın. +- Dersin giriş metnini okuyun. +- Derste ek not defterleri varsa, bunları gözden geçirin, kodu okuyun ve yürütün. Hem TensorFlow hem de PyTorch not defterleri sağlanmışsa bunlardan birine odaklanabilirsiniz - en sevdiğiniz çerçeveyi seçin. +- Defterler genellikle, deney yapmak için kodu biraz değiştirmenizi gerektiren bazı zorluklar içerir. +- Ders sonrası sınavını yapın. +- Eğer modüle bağlı bir laboratuvar varsa - o zaman ödevi tamamlayın. +- "Yüksek sesle öğrenmek" için [tartışma panosunu](https://github.com/microsoft/AI-For-Beginners/discussions) ziyaret edin. +- Diğer öğrencilerle [Gitter](https://gitter.im/Microsoft/ai-for-beginners)'da veya [Telegram kanalı](http://t.me/ai_for_beginners)nda konuşun. -> For further study, we recommend following these [Microsoft Learn](https://docs.microsoft.com/en-us/users/dmitrysoshnikov-9132/collections/31zgizg2p418yo/?WT.mc_id=academic-57639-dmitryso) modules and learning paths. +> Daha fazla çalışma için bu [Microsoft Öğrenme](https://docs.microsoft.com/en-us/users/dmitrysoshnikov-9132/collections/31zgizg2p418yo/?WT.mc_id=academic-57639-dmitryso) modüllerini ve öğrenme yollarını takip etmenizi öneririz. -**Teachers**, we have [included some suggestions](/etc/for-teachers.md) on how to use this curriculum. +**Eğitimciler**, bu müfredatın nasıl kullanılacağına ilişkin [bazı öneriler ekledik](/etc/for-teachers.md). --- -## Credits +## Katkıda Bulunanlar -**✍️ Primary Author:** [Dmitry Soshnikov](http://soshnikov.com), PhD
-**🔥 Editor:** [Jen Looper](https://twitter.com/jenlooper), PhD
-**🎨 Sketchnote illustrator:** [Tomomi Imura](https://twitter.com/girlie_mac)
-**✅ Quiz Creator:** [Lateefah Bello](https://github.com/CinnamonXI), [MLSA](https://studentambassadors.microsoft.com/)
-**🙏 Core Contributors:** [Evgenii Pishchik](https://github.com/Pe4enIks) +**✍️ Ana Yazar:** [Dmitry Soshnikov](http://soshnikov.com), PhD
+**🔥 Editör:** [Jen Looper](https://twitter.com/jenlooper), PhD
+**🎨 Sketchnote Ressamı:** [Tomomi Imura](https://twitter.com/girlie_mac)
+**✅ Sınav Yaratıcı:** [Lateefah Bello](https://github.com/CinnamonXI), [MLSA](https://studentambassadors.microsoft.com/)
+**🙏 Temel Katkıda Bulunanlar:** [Evgenii Pishchik](https://github.com/Pe4enIks) -## Meet the Team +## Ekiple Tanışın -[![Promo video](/lessons/sketchnotes/ai-for-beginners.png)](https://youtu.be/m2KrAk0cC1c "Promo video") +[![Tanıtım videosu](/lessons/sketchnotes/ai-for-beginners.png)](https://youtu.be/m2KrAk0cC1c "Promo video") -> 🎥 Click the image above for a video about the project and the folks who created it! +> 🎥 Proje ve onu oluşturan kişiler hakkındaki video için yukarıdaki resme tıklayın! --- -## Pedagogy +## Eğitbilim -We have chosen two pedagogical tenets while building this curriculum: ensuring that it is hands-on **project-based** and that it includes **frequent quizzes**. +Bu müfredatı oluştururken iki eğitbilimsel ilke seçtik: Uygulamalı **proje tabanlı** olmasını ve **sıkça sınavlar** içermesini sağlamak. -By ensuring that the content aligns with projects, the process is made more engaging for students and retention of concepts will be augmented. In addition, a low-stakes quiz before a class sets the intention of the student towards learning a topic, while a second quiz after class ensures further retention. This curriculum was designed to be flexible and fun and can be taken in whole or in part. The projects start small and become increasingly complex by the end of the 12 week cycle. +İçeriğin projelerle uyumlu olması sağlanarak süreç öğrenciler için daha ilgi çekici hale getirilecek ve kavramların akılda kalıcılığı artırılacaktır. Buna ek olarak, bir dersten önce düşük riskli bir sınav, öğrencinin bir konuyu öğrenmeye yönelik niyetini belirlerken, dersten sonra ikinci bir sınav daha fazla akılda kalmasını sağlar. Bu müfredat esnek ve eğlenceli olacak şekilde tasarlanmıştır ve kısmen veya tamamen çalışılabilir. Projeler küçük başlar ve 12 haftalık döngünün sonunda giderek daha karmaşık hale gelir. -> Find our [Code of Conduct](etc/CODE_OF_CONDUCT.md), [Contributing](etc/CONTRIBUTING.md), and [Translation](etc/TRANSLATIONS.md) guidelines. Find our [Support Documentation here](etc/SUPPORT.md) and [security information here](etc/SECURITY.md). We welcome your constructive feedback! +> [Davranış Kuralları](etc/CODE_OF_CONDUCT.md), [Katkıda Bulunma](etc/CONTRIBUTING.md) ve [Çeviri](etc/TRANSLATIONS.md) yönergelerimizi bakın. [Destek belgelerimizi burada](etc/SUPPORT.md) ve [güvenlik bilgilerini burada](etc/SECURITY.md) bulabilirsiniz. Yapıcı geri bildiriminizi memnuniyetle karşılıyoruz! -> **A note about quizzes**: All quizzes are contained [in this app](https://red-field-0a6ddfd03.1.azurestaticapps.net/), for 50 total quizzes of three questions each. They are linked from within the lessons but the quiz app can be run locally; follow the instruction in the `etc/quiz-app` folder. +> **Sınavlarla ilgili bir not**: Her biri üç sorudan oluşan toplam 50 sınav için tüm sınavlar [bu uygulamada](https://red-field-0a6ddfd03.1.azurestaticapps.net/) bulunur. Bunlar derslerin içerisinden bağlantılıdır ancak sınav uygulaması yerel olarak çalıştırılabilir; `etc/quiz-app` klasöründeki talimatları izleyin. -## Offline access +## Çevrimdışı erişim -You can run this documentation offline by using [Docsify](https://docsify.js.org/#/). Fork this repo, [install Docsify](https://docsify.js.org/#/quickstart) on your local machine, and then in the `etc/docsify` folder of this repo, type `docsify serve`. The website will be served on port 3000 on your localhost: `localhost:3000`. A pdf of the curriculum is available [at this link](/etc/pdf/readme.pdf). +[Docsify](https://docsify.js.org/#/) kullanarak bu belgeleri çevrimdışı çalıştırabilirsiniz. Bu depoyu çatallayın, yerel makinenize [Docsify'ı yükleyin](https://docsify.js.org/#/quickstart) ve ardından bu deponun `etc/docsify` klasörüne `docsify serve` yazın. Web sitesi, localhost'unuzdaki 3000 numaralı bağlantı noktasında hizmet sağlayacak: `localhost:3000`. Müfredatın bir pdf'i [bu bağlantıda](/etc/pdf/readme.pdf) mevcuttur. -## Help Wanted! +## Yardım Aranıyor! -Would you like to contribute a translation? Please read our [translation guidelines](etc/TRANSLATIONS.md). +Bir çeviriye katkıda bulunmak ister misiniz? Lütfen [çeviri yönergelerimizi](etc/TRANSLATIONS.md) okuyun. -## Other Curricula +## Diğer Müfredatlar -Our team produces other curricula! Check out: +Ekibimiz başka müfredatlar da üretiyor! Bir bakın: -- [Web Dev for Beginners](https://aka.ms/webdev-beginners) -- [IoT for Beginners](https://aka.ms/iot-beginners) -- [Machine Learning for Beginners](https://aka.ms/ml-beginners) -- [Data Science for Beginners](https://aka.ms/datascience-beginners) +- [Yeni Başlayanlar için Web Geliştirme](https://aka.ms/webdev-beginners) +- [Yeni Başlayanlar için IoT](https://aka.ms/iot-beginners) +- [Yeni Başlayanlar için Yapay Öğrenme](https://aka.ms/ml-beginners) +- [Yeni Başlayanlar için Veri Bilimi](https://aka.ms/datascience-beginners) From 6e3426918e1d816a485b8f8244de0a2a2938caab Mon Sep 17 00:00:00 2001 From: semercim Date: Sat, 20 Aug 2022 13:36:25 +0200 Subject: [PATCH 04/38] Translating lesson 1. --- lessons/1-Intro/translations/README.tr.md | 148 ++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 lessons/1-Intro/translations/README.tr.md diff --git a/lessons/1-Intro/translations/README.tr.md b/lessons/1-Intro/translations/README.tr.md new file mode 100644 index 00000000..6fce2312 --- /dev/null +++ b/lessons/1-Intro/translations/README.tr.md @@ -0,0 +1,148 @@ +# YZ'ye Giriş + +![Bir doodle'da yapay zekaya giriş içeriğinin özeti](../sketchnotes/ai-intro.png) + +> Çizim: [Tomomi Imura](https://twitter.com/girlie_mac) + +## [Ders öncesi sınavı](https://red-field-0a6ddfd03.1.azurestaticapps.net/quiz/101) + +**Yapay Zeka**, bilgisayarların nasıl akıllı davranışlar sergilemesini sağlayabileceğimizi inceleyen heyecan verici bir bilimsel disiplindir, ör. insanoğlunun yapmakta iyi olduğu şeyleri yapmak. + +Başlangıçta bilgisayarlar [Charles Babbage](https://en.wikipedia.org/wiki/Charles_Babbage) tarafından, iyi tanımlanmış bir prosedürü, yani bir algoritmayı izleyerek sayılar üzerinde çalışmak üzere icat edildi. Modern bilgisayarlar, 19. yüzyılda önerilen orijinal modelden önemli ölçüde daha gelişmiş olmasına rağmen, hala aynı kontrollü hesaplama fikrini takip ediyor. Bu nedenle, hedefe ulaşmak için yapmamız gereken adımların tam sırasını biliyorsak, bir bilgisayarı bir şeyler yapmak üzere programlamak mümkündür. + +![Bir insanın fotoğrafı](images/dsh_age.png) + +> Fotoğraf: [Vickie Soshnikova](http://twitter.com/vickievalerie) + +> ✅ Bir kişinin fotoğrafından yaşını belirlemek, açık şekilde programlanamayan bir iştir, çünkü bunu yaparken kafamızın içinde bir sayıyı nasıl bulduğumuzu bilmiyoruz. + +--- + +Bununla birlikte, nasıl çözeceğimizi açıkça bilmediğimiz bazı görevler var. Bir kişinin yaşını fotoğrafından belirlemeyi düşünün. Bir şekilde yapmayı öğreniyoruz, çünkü farklı yaştaki birçok insan örneğini gördük, ancak bunu nasıl yaptığımızı açıkça ifade edemediğimiz gibi bilgisayarı da bunu yapmaya programlayamayız. Bu tam olarak **yapay zeka**nın (kısaca YZ) ilgisinde olan türden bir görevdir. + +✅ Yapay zekadan yararlanabilecek bazı görevleri bir bilgisayara yükleyebileceğinizi düşünün. Finans, tıp ve sanat alanlarını düşünün - bu alanlar bugün yapay zekadan nasıl yararlanıyor? + +## Zayıf YZ ve Güçlü YZ + +Bir fotoğraftan bir kişinin yaşını belirleme gibi, belirli bir insani problemi çözme görevi, **zayıf YZ** olarak adlandırılabilir, çünkü bir insanın yapabileceği gibi birçok görevi çözebilecek bir sistem değil, yalnızca bir görev için bir sistem oluşturuyoruz. Tabii ki, genel olarak akıllı bir bilgisayar sistemi geliştirmek, bilinç felsefesi öğrencileri için olanlar da dahil olmak üzere birçok açıdan son derece ilginçtir. Bu tür bir sisteme **güçlü YZ** veya **[Genel Yapay Zeka](https://en.wikipedia.org/wiki/Artificial_general_intelligence)** (GYZ) adı verilir. + +## Zekanın Tanımı ve Turing Testi + +**[Zeka](https://en.wikipedia.org/wiki/Intelligence)** terimiyle uğraşırken karşılaşılan sorunlardan biri, bu terimin net bir tanımının olmamasıdır. Zekanın **soyut düşünme** veya **öz farkındalık** ile bağlantılı olduğu iddia edilebilir, ancak onu tam olarak tanımlayamıyoruz. + +![Kedi Fotoğrafı](images/photo-cat.jpg) + +> [Fotoğraf](https://unsplash.com/photos/75715CVEJhI) sahibi Unsplash'tan [Amber Kipp](https://unsplash.com/@sadmax) + +*Zeka* teriminin belirsizliğini görmek için şu soruyu yanıtlamayı deneyin: "Bir kedi zeki midir?". İddianın doğru olup olmadığını kanıtlarken evrensel olarak kabul edilmiş bir test olmadığı için, farklı insanlar bu soruya farklı cevaplar verme eğilimindedir. Fakat olduğunu düşünüyorsanız - kedinizi bir IQ testine sokmayı deneyin... + +✅ Bir an için zekayı nasıl tanımladığınızı düşünün. Bir labirenti çözebilen ve yiyecek bir şeyler bulabilen bir karga zeki midir? Çocuk zeki midir? + +--- + +GYZ hakkında konuşurken, gerçekten zeki bir sistem oluşturup oluşturmadığımızı anlamanın bir yolunu bulmamız gerekiyor. [Alan Turing](https://en.wikipedia.org/wiki/Alan_Turing) **[Turing Testi](https://en.wikipedia.org/wiki/Turing_test)** diye adlandırılan bir yol önerdi, ki zekanın bir tanımı gibi de davranır. Test, belirli bir sistemi doğası gereği akıllı bir şeyle - gerçek bir insanla karşılaştırır ve herhangi bir otomatik karşılaştırma bir bilgisayar programı tarafından aşılabileceğinden, bir insan sorgulayıcı kullanırız. Yani, bir insan metin tabanlı diyalogda gerçek bir kişi ile bir bilgisayar sistemini ayırt edemiyorsa - sistem akıllı olarak kabul edilir. + +> St.Petersburg'da geliştirilen [Eugene Goostman](https://en.wikipedia.org/wiki/Eugene_Goostman) adlı bir sohbet botu, zekice bir kişilik numarası kullanarak 2014'te Turing testini geçmeye çok yaklaştı. Önce 13 yaşında Ukraynalı bir çocuk olduğunu söyledi, bu da metindeki bilgi eksikliklerini ve bazı tutarsızlıkları açıklayacaktı. Bot, Turing'in bir makinenin 2000 yılına kadar geçebileceğine inandığı bir ölçüm olan 5 dakikalık bir diyalogdan sonra değerlendiricilerin %30'unu insan olduğuna inandırdı. Ancak, bunun akıllı bir sistem yarattığımızı göstermediğini ya da bir bilgisayar sisteminin insan sorgulayıcıyı kandırmadığını anlamalıyız - sistem insanları kandırmadı, aksine bot yaratıcıları kandırdı! + +✅ Hiç bir sohbet botu tarafından bir insanla konuştuğunuzu düşünerek kandırıldınız mı? Sizi nasıl ikna etti? + +#gitYZ'ya Farklı Yaklaşımlar + +If we want a computer to behave like a human, we need somehow to model inside a computer our way of thinking. Consequently, we need to try to understand what makes a human being intelligent. + +> To be able to program intelligence into a machine, we need to understand how our own processes of making decisions work. If you do a little self-introspection, you will realize that there are some processes that happen subconsciously – eg. we can distinguish a cat from a dog without thinking about it - while some others involve reasoning. + +There are two possible approaches to this problem: + +Top-down Approach (Symbolic Reasoning) | Bottom-up Approach (Neural Networks) +---------------------------------------|------------------------------------- +A top-down approach models the way a person reasons to solve a problem. It involves extracting **knowledge** from a human being, and representing it in a computer-readable form. We also need to develop a way to model **reasoning** inside a computer. | A bottom-up approach models the structure of a human brain, consisting of huge number of simple units called **neurons**. Each neuron acts like a weighted average of its inputs, and we can train a network of neurons to solve useful problems by providing **training data**. + +There are also some other possible approaches to intelligence: + +* An **Emergent**, **Synergetic** or **multi-agent approach** are based on the fact that complex intelligent behaviour can be obtained by an interaction of a large number of simple agents. According to [evolutionary cybernetics](https://en.wikipedia.org/wiki/Global_brain#Evolutionary_cybernetics), intelligence can *emerge* from more simple, reactive behaviour in the process of *metasystem transition*. + +* An **Evolutionary approach**, or **genetic algorithm** is an optimization process based on the principles of evolution. + +We will consider those approaches later in the course, but right now we will focus on two main directions: top-down and bottom-up. + +### The Top-Down Approach + +In a **top-down approach**, we try to model our reasoning. Because we can follow our thoughts when we reason, we can try to formalize this process and program it inside the computer. This is called **symbolic reasoning**. + +People tend to have some rules in their head that guide their decision making processes. For example, when a doctor is diagnosing a patient, he or she may realize that a person has a fever, and thus there might be some inflammation going on inside the body. By applying a large set of rules to a specific problem a doctor may be able to come up with the final diagnosis. + +This approach relies heavily on **knowledge representation** and **reasoning**. Extracting knowledge from a human expert might be the most difficult part, because a doctor in many cases would not know exactly why he or she is coming up with a particular diagnosis. Sometimes the solution just comes up in his or her head without explicit thinking. Some tasks, such as determining the age of a person from a photograph, cannot be at all reduced to manipulating knowledge. + +### Bottom-Up Approach + +Alternately, we can try to model the simplest elements inside our brain – a neuron. We can construct a so-called **artificial neural network** inside a computer, and then try to teach it to solve problems by giving it examples. This process is similar to how a newborn child learns about his or her surroundings by making observations. + +✅ Do a little research on how babies learn. What are the basic elements of a baby's brain? + +> | What about ML? | | +> |--------------|-----------| +> | Part of Artificial Intelligence that is based on computer learning to solve a problem based on some data is called **Machine Learning**. We will not consider classical machine learning in this course - we refer you to a separate [Machine Learning for Beginners](http://aka.ms/ml-beginners) curriculum. | ![ML for Beginners](images/ml-for-beginners.png) | + +## A Brief History of AI + +Artificial Intelligence was started as a field in the middle of the twentieth century. Initially symbolic reasoning was a prevalent approach, and it led to a number of important successes, such as expert systems – computer programs that were able to act as an expert in some limited problem domain. However, it soon became clear that such approach does not scale well. Extracting the knowledge from an expert, representing it in a computer, and keeping that knowledgebase accurate turns out to be a very complex task, and too expensive to be practical in many cases. This led to so-called [AI Winter](https://en.wikipedia.org/wiki/AI_winter) in the 1970s. + +Brief History of AI + +> Image by [Dmitry Soshnikov](http://soshnikov.com) + +As time passed, computing resources became cheaper, and more data has become available, so neural network approaches started demonstrating great performance in competing with human beings in many areas, such as computer vision or speech understanding. In the last decade, the term Artificial Intelligence has been mostly used as a synonym for Neural Networks, because most of the AI successes that we hear about are based on them. + +We can observe how the approaches changed, for example, in creating a chess playing computer program: + +* Early chess programs were based on search – a program explicitly tried to estimate possible moves of an opponent for a given number of next moves, and selected an optimal move based on the optimal position that can be achieved in a few moves. It led to the development of the so-called [alpha-beta pruning](https://en.wikipedia.org/wiki/Alpha%E2%80%93beta_pruning) search algorithm. +* Search strategies work well towards the end of the game, where the search space is limited by a small number of possible moves. However, in the beginning of the game the search space is huge, and the algorithm can be improved by learning from existing matches between human players. Subsequent experiments employed so-called [case-based reasoning](https://en.wikipedia.org/wiki/Case-based_reasoning), where the program looked for cases in the knowledge base very similar to the current position in the game. +* Modern programs that win over human players are based on neural networks and [reinforcement learning](https://en.wikipedia.org/wiki/Reinforcement_learning), where the programs learn to play solely by playing a long time against itself and learning from its own mistakes – much like human beings do when learning to play chess. However, a computer program can play many more games in much less time, and thus can learn much faster. + +✅ Do a little research on other games that have been played by AI. + +Similarly, we can see how the approach towards creating “talking programs” (that might pass the Turing test) changed: + +* Early programs of this kind such as [Eliza](https://en.wikipedia.org/wiki/ELIZA), were based on very simple grammatical rules and the re-formulation of the input sentence into a question. +* Modern assistants, such as Cortana, Siri or Google Assistant are all hybrid systems that use Neural networks to convert speech into text and to recognize our intent, and then employ some reasoning or explicit algorithms to perform required actions. +* In the future, we may expect complete neural-based model to handle dialogue by itself. The recent GPT and [Turing-NLG](https://turing.microsoft.com/) family of neural networks show great success in this. + +the Turing test's evolution + +> Image by Dmitry Soshnikov, [photo](https://unsplash.com/photos/r8LmVbUKgns) by [Marina Abrosimova](https://unsplash.com/@abrosimova_marina_foto), Unsplash + +## Recent AI Research + +The huge recent growth in neural network research started around 2010, when large public datasets started to become available. A huge collection of images called [ImageNet](https://en.wikipedia.org/wiki/ImageNet), which contains around 14 million annotated images, gave birth to the [ImageNet Large Scale Visual Recognition Challenge](https://image-net.org/challenges/LSVRC/). + +![ILSVRC Accuracy](images/ilsvrc.gif) + +> Image by [Dmitry Soshnikov](http://soshnikov.com) + +In 2012, [Convolutional Neural Networks](../4-ComputerVision/07-ConvNets/README.md) were first used in image classification, which led to a significant drop in classification errors (from almost 30% to 16.4%). In 2015, ResNet architecture from Microsoft Research [achieved human-level accuracy](https://doi.org/10.1109/ICCV.2015.123). + +Since then, Neural Networks demonstrated very successful behaviour in many tasks: + +--- + +Year | Human Parity achieved +-----|-------- +2015 | [Image Classification](https://doi.org/10.1109/ICCV.2015.123) +2016 | [Conversational Speech Recognition](https://arxiv.org/abs/1610.05256) +2018 | [Automatic Machine Translation](https://arxiv.org/abs/1803.05567) (Chinese-to-English) +2020 | [Image Captioning](https://arxiv.org/abs/2009.13682) + +Over the past few years we have witnessed huge successes with large language models, such as BERT and GPT-3. This happen happened mostly due to the fact that there is a lot of general text data available that allows us to train models to capture the structure and meaning of texts, pre-train them on general text collections, and then specialize those models for more specific tasks. We will learn more about [Natural Language Processing](../5-NLP/README.md) later in this course. + +## 🚀 Challenge + +Do a tour of the internet to determine where, in your opinion, AI is most effectively used. Is it in a Mapping app, or some speech-to-text service or a video game? Research how the system was built. + +## [Post-lecture quiz](https://red-field-0a6ddfd03.1.azurestaticapps.net/quiz/201) + +## Review & Self Study + +Review the history of AI and ML by reading through [this lesson](https://github.com/microsoft/ML-For-Beginners/tree/main/1-Introduction/2-history-of-ML). Take an element from the sketchnote at the top of that lesson or this one and research it in more depth to understand the cultural context informing its evolution. + +**Assignment**: [Game Jam](assignment.md) From 85436a5ac5229b938b853bce67475d9961bd6ba4 Mon Sep 17 00:00:00 2001 From: semercim Date: Mon, 22 Aug 2022 18:00:49 +0200 Subject: [PATCH 05/38] Finished Turkish translation of lesson 1 --- etc/quiz-app/src/assets/translations/index.js | 2 + lessons/1-Intro/translations/README.tr.md | 108 +++++++++--------- 2 files changed, 56 insertions(+), 54 deletions(-) diff --git a/etc/quiz-app/src/assets/translations/index.js b/etc/quiz-app/src/assets/translations/index.js index 36c626f2..3bf331e7 100644 --- a/etc/quiz-app/src/assets/translations/index.js +++ b/etc/quiz-app/src/assets/translations/index.js @@ -1,8 +1,10 @@ import englishQuizzes from './en'; import spanishQuizzes from './es'; +import turkishQuizzes from './tr'; const messages = { en: englishQuizzes, es: spanishQuizzes, + tr: turkishQuizzes, }; export default messages; diff --git a/lessons/1-Intro/translations/README.tr.md b/lessons/1-Intro/translations/README.tr.md index 6fce2312..bca67d45 100644 --- a/lessons/1-Intro/translations/README.tr.md +++ b/lessons/1-Intro/translations/README.tr.md @@ -46,103 +46,103 @@ GYZ hakkında konuşurken, gerçekten zeki bir sistem oluşturup oluşturmadığ ✅ Hiç bir sohbet botu tarafından bir insanla konuştuğunuzu düşünerek kandırıldınız mı? Sizi nasıl ikna etti? -#gitYZ'ya Farklı Yaklaşımlar +#YZ'ya Farklı Yaklaşımlar -If we want a computer to behave like a human, we need somehow to model inside a computer our way of thinking. Consequently, we need to try to understand what makes a human being intelligent. +Bir bilgisayarın insan gibi davranmasını istiyorsak, bir şekilde düşünme şeklimizi bilgisayar içinde modellememiz gerekir. Sonuç olarak, bir insanı zeki yapan şeyin ne olduğunu anlamaya çalışmalıyız. -> To be able to program intelligence into a machine, we need to understand how our own processes of making decisions work. If you do a little self-introspection, you will realize that there are some processes that happen subconsciously – eg. we can distinguish a cat from a dog without thinking about it - while some others involve reasoning. +> Zekayı bir makineye programlayabilmek için kendi karar verme süreçlerimizin nasıl çalıştığını anlamamız gerekir. Biraz iç gözlem yaparsanız, bilinçaltında gerçekleşen bazı süreçlerin olduğunu fark edeceksiniz – örn. bir kediyi bir köpekten düşünmeden ayırt edebiliriz - bazı süreçlerse ise akıl yürütmeyi içerir. -There are two possible approaches to this problem: +Bu soruna iki olası yaklaşım vardır: -Top-down Approach (Symbolic Reasoning) | Bottom-up Approach (Neural Networks) ----------------------------------------|------------------------------------- -A top-down approach models the way a person reasons to solve a problem. It involves extracting **knowledge** from a human being, and representing it in a computer-readable form. We also need to develop a way to model **reasoning** inside a computer. | A bottom-up approach models the structure of a human brain, consisting of huge number of simple units called **neurons**. Each neuron acts like a weighted average of its inputs, and we can train a network of neurons to solve useful problems by providing **training data**. +Yukarıdan Aşağıya Yaklaşım (Simgesel Akıl Yürütme) | Aşağıdan Yukarıya Yaklaşım (Sinir Ağları) +---------------------------------------------------|------------------------------------------ +Yukarıdan aşağıya bir yaklaşım, bir kişinin bir sorunu çözmek için akıl yürütme şeklini modeller. Bir insandan **bilgiyi** çıkarmayı ve onu bilgisayar tarafından okunabilir bir biçimde temsil etmeyi içerir. Ayrıca bir bilgisayarda **akıl yürütmeyi** modellemek için bir yol geliştirmemiz gerekiyor. | Aşağıdan yukarıya bir yaklaşım, **nöronlar** olarak adlandırılan çok sayıda basit birimden oluşan insan beyninin yapısını modeller. Her nöron, girdilerinin ağırlıklı ortalaması gibi davranır ve **eğitim verileri** sağlayarak yararlı sorunları çözmek için bir nöron ağını eğitebiliriz. -There are also some other possible approaches to intelligence: +Zekaya başka olası yaklaşımlar da vardır: -* An **Emergent**, **Synergetic** or **multi-agent approach** are based on the fact that complex intelligent behaviour can be obtained by an interaction of a large number of simple agents. According to [evolutionary cybernetics](https://en.wikipedia.org/wiki/Global_brain#Evolutionary_cybernetics), intelligence can *emerge* from more simple, reactive behaviour in the process of *metasystem transition*. +* Bir **ortaya çıkan**, **sinerjik** veya **çoklu etmen yaklaşımı**, karmaşık akıllı davranışın çok sayıda basit etmenin etkileşimi ile elde edilebileceği gerçeğine dayanır. [Evrimsel sibernetik](https://en.wikipedia.org/wiki/Global_brain#Evolutionary_cybernetics)'e göre, zeka *başkalaşım-sistemi geçişi* sürecinde daha basit, tepkisel davranışlardan *ortaya çıkabilir*. -* An **Evolutionary approach**, or **genetic algorithm** is an optimization process based on the principles of evolution. +* **Evrimsel yaklaşım** veya **genetik algoritma**, evrim ilkelerine dayalı bir optimizasyon sürecidir. -We will consider those approaches later in the course, but right now we will focus on two main directions: top-down and bottom-up. +Bu yaklaşımları dersin ilerleyen bölümlerinde ele alacağız, ancak şu anda iki ana yöne odaklanacağız: Yukarıdan aşağıya ve aşağıdan yukarıya. -### The Top-Down Approach +### Yukarıdan Aşağıya Yaklaşım -In a **top-down approach**, we try to model our reasoning. Because we can follow our thoughts when we reason, we can try to formalize this process and program it inside the computer. This is called **symbolic reasoning**. +**Yukarıdan aşağıya bir yaklaşımla**, akıl yürütmemizi modellemeye çalışırız. Akıl yürüttüğümüzde düşüncelerimizi takip edebildiğimiz için, bu süreci formüle dökmeye ve bilgisayar içinde programlamaya çalışabiliriz. Buna **simgesel akıl yürütme** denir. -People tend to have some rules in their head that guide their decision making processes. For example, when a doctor is diagnosing a patient, he or she may realize that a person has a fever, and thus there might be some inflammation going on inside the body. By applying a large set of rules to a specific problem a doctor may be able to come up with the final diagnosis. +İnsanlar kafalarında karar verme süreçlerine yön veren bazı kurallara sahip olma eğilimindedir. Örneğin, bir doktor bir hastayı teşhis ederken, bir kişinin ateşi olduğunu fark edebilir, öyle ki vücudun içinde bir miktar iltihap olabilir. Bir doktor, belirli bir soruna çok sayıda kural uygulayarak nihai teşhisi koyabilir. -This approach relies heavily on **knowledge representation** and **reasoning**. Extracting knowledge from a human expert might be the most difficult part, because a doctor in many cases would not know exactly why he or she is coming up with a particular diagnosis. Sometimes the solution just comes up in his or her head without explicit thinking. Some tasks, such as determining the age of a person from a photograph, cannot be at all reduced to manipulating knowledge. +Bu yaklaşım büyük ölçüde **bilgi temsiline** ve **akıl yürütmeye** dayanır. Bir insan uzmandan bilgi çıkarmak en zor kısım olabilir, çünkü çoğu durumda bir doktor neden belirli bir teşhis koyduğunu tam olarak bilemez. Bazen çözüm, açıkça düşünmeden kafasında ortaya çıkar. Bir fotoğraftan bir kişinin yaşını belirlemek gibi bazı görevler, hiçbir şekilde bilgi üzerinde oynama yapmaya indirgenemez. -### Bottom-Up Approach +### Aşağıdan Yukarıya Yaklaşım -Alternately, we can try to model the simplest elements inside our brain – a neuron. We can construct a so-called **artificial neural network** inside a computer, and then try to teach it to solve problems by giving it examples. This process is similar to how a newborn child learns about his or her surroundings by making observations. +Alternatif olarak, beynimizin içindeki en basit öğeleri, yani bir nöronu modellemeye çalışabiliriz. Bir bilgisayarın içinde **yapay sinir ağı** denilen bir yapı oluşturabilir ve ardından ona örnekler vererek problem çözmeyi öğretmeye çalışabiliriz. Bu süreç, yeni doğmuş bir çocuğun gözlem yaparak çevresini öğrenmesine benzer. -✅ Do a little research on how babies learn. What are the basic elements of a baby's brain? +✅ Bebeklerin nasıl öğrendiği hakkında biraz araştırma yapın. Bir bebeğin beyninin temel unsurları nelerdir? -> | What about ML? | | +> | ML'ye ne demeli? | | > |--------------|-----------| -> | Part of Artificial Intelligence that is based on computer learning to solve a problem based on some data is called **Machine Learning**. We will not consider classical machine learning in this course - we refer you to a separate [Machine Learning for Beginners](http://aka.ms/ml-beginners) curriculum. | ![ML for Beginners](images/ml-for-beginners.png) | +> | Yapay Zekanın bazı verilere dayalı bir sorunu çözmek için bilgisayar öğrenmesine dayanan kısmına **Makine Öğrenmesi** denir. Bu derste klasik makine öğrenmesini ele almayacağız - sizi ayrı bir [Yeni Başlayanlar için Makine Öğrenmesi](http://aka.ms/ml-beginners) müfredatına yönlendiriyoruz. | ![Yeni Başlayanlar için MÖ](images/ml-for-beginners.png) | -## A Brief History of AI +## YZ'nin Kısa Tarihi -Artificial Intelligence was started as a field in the middle of the twentieth century. Initially symbolic reasoning was a prevalent approach, and it led to a number of important successes, such as expert systems – computer programs that were able to act as an expert in some limited problem domain. However, it soon became clear that such approach does not scale well. Extracting the knowledge from an expert, representing it in a computer, and keeping that knowledgebase accurate turns out to be a very complex task, and too expensive to be practical in many cases. This led to so-called [AI Winter](https://en.wikipedia.org/wiki/AI_winter) in the 1970s. +Yapay Zeka, yirminci yüzyılın ortalarında bir alan olarak kullanılmaya başlandı. Başlangıçta simgesel akıl yürütme yaygın bir yaklaşımdı ve uzman sistemler - bazı sınırlı sorun alanlarında uzman olarak hareket edebilen bilgisayar programları - gibi bir dizi önemli başarıya yön verdi. Ancak, kısa süre sonra bu yaklaşımın iyi ölçeklenmediği anlaşıldı. Bilgiyi bir uzmandan çıkarmak, bir bilgisayarda temsil etmek ve bu bilgi tabanını doğru tutmak çok karmaşık görevlerdir ve çoğu durumda pratik olamayacak kadar pahalıdır. Bu, 1970'lerde [YZ Kışı](https://en.wikipedia.org/wiki/AI_winter) olarak adlandırılan döneme yol açtı. -Brief History of AI +YZ'nin Kısa Tarihi -> Image by [Dmitry Soshnikov](http://soshnikov.com) +> İmge sahibi [Dmitry Soshnikov](http://soshnikov.com) -As time passed, computing resources became cheaper, and more data has become available, so neural network approaches started demonstrating great performance in competing with human beings in many areas, such as computer vision or speech understanding. In the last decade, the term Artificial Intelligence has been mostly used as a synonym for Neural Networks, because most of the AI successes that we hear about are based on them. +Zaman ilerdikçe, hesaplama kaynakları daha ucuz hale geldi ve daha fazla veri kullanılabilir hale geldi, böylece sinir ağı yaklaşımları, bilgisayarla görme veya konuşmayı anlama gibi birçok alanda insanlarla rekabet etmede büyük başarım göstermeye başladı. Son on yılda, Yapay Zeka terimi çoğunlukla Sinir Ağları ile eşanlamlı olarak kullanılmıştır, çünkü duyduğumuz YZ başarılarının çoğu onlara dayanmaktadır. -We can observe how the approaches changed, for example, in creating a chess playing computer program: +Yaklaşımların nasıl değiştiğini, mesela satranç oynayan bir bilgisayar programı yaratırken, gözlemleyebiliriz: -* Early chess programs were based on search – a program explicitly tried to estimate possible moves of an opponent for a given number of next moves, and selected an optimal move based on the optimal position that can be achieved in a few moves. It led to the development of the so-called [alpha-beta pruning](https://en.wikipedia.org/wiki/Alpha%E2%80%93beta_pruning) search algorithm. -* Search strategies work well towards the end of the game, where the search space is limited by a small number of possible moves. However, in the beginning of the game the search space is huge, and the algorithm can be improved by learning from existing matches between human players. Subsequent experiments employed so-called [case-based reasoning](https://en.wikipedia.org/wiki/Case-based_reasoning), where the program looked for cases in the knowledge base very similar to the current position in the game. -* Modern programs that win over human players are based on neural networks and [reinforcement learning](https://en.wikipedia.org/wiki/Reinforcement_learning), where the programs learn to play solely by playing a long time against itself and learning from its own mistakes – much like human beings do when learning to play chess. However, a computer program can play many more games in much less time, and thus can learn much faster. +* Evvelki satranç programları aramaya dayalıydı - bir program, belirli sayıda sonraki hamle için rakibin olası hamlelerini açıkça tahmin etmeye çalışırdı ve birkaç hamlede elde edilebilecek en uygun konuma dayalı olarak en uygun hamleyi seçerdi. Bu, [alfa-beta budama](https://en.wikipedia.org/wiki/Alpha%E2%80%93beta_pruning) denen arama algoritmasının geliştirilmesine yön verdi. +* Arama stratejileri, arama alanının az sayıda olası hareketle sınırlı olduğu oyunun sonuna doğru iyi çalışır. Ancak oyunun başında arama alanı çok büyüktür ve algoritma, insan oyuncular arasındaki mevcut karşılamalardan öğrenilerek geliştirilebilir. Sonraki deneyler, programın bilgi tabanında oyundaki mevcut duruma çok benzeyen vakaları aradığı sözde [vakaya dayalı akıl yürütme](https://en.wikipedia.org/wiki/Case-based_reasoning)yi kullandı. +* İnsan oyunculara karşı kazanan modern programlar, sinir ağları ve programların yalnızca kendisine karşı uzun süre oynayarak - tıpkı insanların satranç oynamayı öğrenirken yaptığı gibi - kendi hatalarından oynamayı öğrendiği [pekiştirmeli öğrenme](https://en.wikipedia.org/wiki/Reinforcement_learning) üzerine kuruludur. Ancak bir bilgisayar programı çok daha fazla oyunu çok daha kısa sürede oynayabilir ve böylece çok daha hızlı öğrenebilir. -✅ Do a little research on other games that have been played by AI. +✅ YZ tarafından oynanan diğer oyunlar hakkında biraz araştırma yapın. -Similarly, we can see how the approach towards creating “talking programs” (that might pass the Turing test) changed: +Benzer şekilde, (Turing testini geçebilecek) “konuşan programlar” oluşturmaya yönelik yaklaşımın nasıl değiştiğini görebiliriz: -* Early programs of this kind such as [Eliza](https://en.wikipedia.org/wiki/ELIZA), were based on very simple grammatical rules and the re-formulation of the input sentence into a question. -* Modern assistants, such as Cortana, Siri or Google Assistant are all hybrid systems that use Neural networks to convert speech into text and to recognize our intent, and then employ some reasoning or explicit algorithms to perform required actions. -* In the future, we may expect complete neural-based model to handle dialogue by itself. The recent GPT and [Turing-NLG](https://turing.microsoft.com/) family of neural networks show great success in this. +* [Eliza](https://en.wikipedia.org/wiki/ELIZA) gibi bu türün ilk programları, çok basit dilbilgisi kurallarına ve girdi cümlesinin bir soru olarak yeniden formüle edilmesine dayanıyordu. +* Cortana, Siri veya Google Asistan gibi modern asistanların tümü, konuşmayı metne dönüştürmek ve niyetimizi tanımak için Sinir ağlarını kullanan ve ardından gerekli eylemleri gerçekleştirmek için bazı akıl yürütmeler veya açık algoritmalar kullanan karma sistemlerdir. +* Gelecekte, tamamen sinir tabanlı bir modelin diyaloğu tek başına idare etmesini bekleyebiliriz. En son GPT ve [Turing-NLG](https://turing.microsoft.com/) sinir ağları ailesi bu konuda büyük başarı gösteriyor. -the Turing test's evolution +Turing testinin evrimi -> Image by Dmitry Soshnikov, [photo](https://unsplash.com/photos/r8LmVbUKgns) by [Marina Abrosimova](https://unsplash.com/@abrosimova_marina_foto), Unsplash +> İmge sahibi Dmitry Soshnikov, [fotoğraf](https://unsplash.com/photos/r8LmVbUKgns) ve [Marina Abrosimova](https://unsplash.com/@abrosimova_marina_foto), Unsplash -## Recent AI Research +## Yakın Zaman YZ Araştırmaları -The huge recent growth in neural network research started around 2010, when large public datasets started to become available. A huge collection of images called [ImageNet](https://en.wikipedia.org/wiki/ImageNet), which contains around 14 million annotated images, gave birth to the [ImageNet Large Scale Visual Recognition Challenge](https://image-net.org/challenges/LSVRC/). +Sinir ağı araştırmalarındaki yakın zamanlardaki büyük büyüme, büyük halka açık veri kümelerinin kullanıma sunulmaya başladığı 2010 civarında başladı. Yaklaşık 14 milyon açıklamalı resim içeren [ImageNet](https://en.wikipedia.org/wiki/ImageNet) adlı devasa bir resim koleksiyonu, [ImageNet Büyük Ölçekli Görsel Tanıma Yarışmasını](https://image-net.org/challenges/LSVRC/) doğurdu. -![ILSVRC Accuracy](images/ilsvrc.gif) +![ILSVRC Doğruluğu](images/ilsvrc.gif) -> Image by [Dmitry Soshnikov](http://soshnikov.com) +> İmge sahibi [Dmitry Soshnikov](http://soshnikov.com) -In 2012, [Convolutional Neural Networks](../4-ComputerVision/07-ConvNets/README.md) were first used in image classification, which led to a significant drop in classification errors (from almost 30% to 16.4%). In 2015, ResNet architecture from Microsoft Research [achieved human-level accuracy](https://doi.org/10.1109/ICCV.2015.123). +2012 yılında, [Evrişimli Sinir Ağları](../4-ComputerVision/07-ConvNets/README.tr.md) ilk olarak imge sınıflandırmada kullanıldı ve bu da sınıflandırma hatalarında önemli bir düşüşe neden oldu (neredeyse %30'dan %16.4'e). 2015 yılında, Microsoft Araştırma'nın ResNet mimarisi [insan düzeyinde doğruluk elde etti](https://doi.org/0.1109/ICCV.2015.123). -Since then, Neural Networks demonstrated very successful behaviour in many tasks: +O zamandan beri, Sinir Ağları birçok görevde çok başarılı davranışlar sergiledi: --- -Year | Human Parity achieved +Yıl | İnsana denklik elde edildi -----|-------- -2015 | [Image Classification](https://doi.org/10.1109/ICCV.2015.123) -2016 | [Conversational Speech Recognition](https://arxiv.org/abs/1610.05256) -2018 | [Automatic Machine Translation](https://arxiv.org/abs/1803.05567) (Chinese-to-English) -2020 | [Image Captioning](https://arxiv.org/abs/2009.13682) +2015 | [İmge Sınıflandırma](https://doi.org/10.1109/ICCV.2015.123) +2016 | [Sohbetli Konuşma Tanıma](https://arxiv.org/abs/1610.05256) +2018 | [Otomatik Makine Çevirisi](https://arxiv.org/abs/1803.05567) (Çince-İngilizce) +2020 | [İmge Altyazısı](https://arxiv.org/abs/2009.13682) -Over the past few years we have witnessed huge successes with large language models, such as BERT and GPT-3. This happen happened mostly due to the fact that there is a lot of general text data available that allows us to train models to capture the structure and meaning of texts, pre-train them on general text collections, and then specialize those models for more specific tasks. We will learn more about [Natural Language Processing](../5-NLP/README.md) later in this course. +Geçtiğimiz birkaç yılda, BERT ve GPT-3 gibi büyük dil modelleriyle büyük başarılara tanık olduk. Bu, çoğunlukla, onları genel metin koleksiyonları üzerinde önceden eğitmemize ve daha sonra bu modelleri daha belirli görevler için özelleştirmemize olanak tanıyarak metinlerin yapısını ve anlamını yakalamak için modelleri eğitmemizi sağlayan çok sayıda genel metin verisi olduğu gerçeğinden kaynaklanmaktadır. Bu dersin ilerleyen bölümlerinde [Doğal Dil İşleme](../5-NLP/README.tr.md) hakkında daha fazla bilgi edineceğiz. -## 🚀 Challenge +## 🚀 Kendini Sınama -Do a tour of the internet to determine where, in your opinion, AI is most effectively used. Is it in a Mapping app, or some speech-to-text service or a video game? Research how the system was built. +Yapay zekanın size göre en etkili nerede kullanıldığını belirlemek için internette bir tur yapın. Bir eşleme uygulamasında mı, yoksa bir konuşmadan metne hizmetinde mi ya da bir video oyununda mı? Sistemin nasıl inşa edildiği araştırın. -## [Post-lecture quiz](https://red-field-0a6ddfd03.1.azurestaticapps.net/quiz/201) +## [Ders sonrası sınavı](https://red-field-0a6ddfd03.1.azurestaticapps.net/quiz/201) -## Review & Self Study +## Gözden Geçirme ve Bireysel Çalışma -Review the history of AI and ML by reading through [this lesson](https://github.com/microsoft/ML-For-Beginners/tree/main/1-Introduction/2-history-of-ML). Take an element from the sketchnote at the top of that lesson or this one and research it in more depth to understand the cultural context informing its evolution. +[Bu dersi](https://github.com/microsoft/ML-For-Beginners/tree/main/1-Introduction/2-history-of-ML) okuyarak YZ ve MÖ'nün geçmişini inceleyin. O dersin veya bu dersin üstündeki eskiz notundan bir öğe alın ve evrimini bildiren kültürel bağlamı anlamak için daha derinlemesine araştırın. -**Assignment**: [Game Jam](assignment.md) +**Ödev**: [Oyun Özeti](assignment.tr.md) From a18965e780117bef9023a7d3b3a5f0864db2b148 Mon Sep 17 00:00:00 2001 From: semercim Date: Mon, 22 Aug 2022 18:02:28 +0200 Subject: [PATCH 06/38] Finished Turkish translation of lesson 1's assignment and quiz. --- .../src/assets/translations/tr/index.js | 7 ++ .../src/assets/translations/tr/lesson-1.json | 115 ++++++++++++++++++ lessons/1-Intro/translations/assignment.tr.md | 3 + 3 files changed, 125 insertions(+) create mode 100644 etc/quiz-app/src/assets/translations/tr/index.js create mode 100644 etc/quiz-app/src/assets/translations/tr/lesson-1.json create mode 100644 lessons/1-Intro/translations/assignment.tr.md diff --git a/etc/quiz-app/src/assets/translations/tr/index.js b/etc/quiz-app/src/assets/translations/tr/index.js new file mode 100644 index 00000000..ad1d78d5 --- /dev/null +++ b/etc/quiz-app/src/assets/translations/tr/index.js @@ -0,0 +1,7 @@ +import tr1 from './lesson-1.json'; +//add items here +const quiz = { + 0: tr1[0] +}; + +export default quiz; diff --git a/etc/quiz-app/src/assets/translations/tr/lesson-1.json b/etc/quiz-app/src/assets/translations/tr/lesson-1.json new file mode 100644 index 00000000..b630e307 --- /dev/null +++ b/etc/quiz-app/src/assets/translations/tr/lesson-1.json @@ -0,0 +1,115 @@ +[ + { + "title": "Yeni Başlayanlar İçin YZ: Sınavlar", + "complete": "Tebrikler, sınavı tamamladınız!", + "error": "Üzgünüz, tekrar deneyin", + "quizzes": [ + { + "id": 101, + "title": "YZ'ye giriş: Ön Sınav", + "quiz": [ + { + "questionText": "19. yüzyılın ünlü bir öncü-bilgisayar mühendisidir", + "answerOptions": [ + { + "answerText": "Charles Barkley", + "isCorrect": false + }, + { + "answerText": "Charles Babbage", + "isCorrect": true + }, + { + "answerText": "Charles Darwin", + "isCorrect": false + } + ] + }, + { + "questionText": "Zayıf AI, birçok görevi çözmek için tasarlanmış bir sistemdir", + "answerOptions": [ + { + "answerText": "True", + "isCorrect": false + }, + { + "answerText": "False", + "isCorrect": true + } + ] + }, + { + "questionText": "Sohbet botları gerçekten akıllı sistemlerin bir örneğidir.", + "answerOptions": [ + { + "answerText": "Yanlış, genellikle bir dizi kuralla tasarlanırlar.", + "isCorrect": false + }, + { + "answerText": "Doğru, genellikle zeki olarak kabul edilirler.", + "isCorrect": false + }, + { + "answerText": "Yanlış, ancak daha karmaşık hale geldikçe Turing testlerini giderek daha fazla geçebiliyorlar.", + "isCorrect": true + } + ] + } + ] + }, + { + "id": 201, + "title": "YZ'ye giriş: Ders Sonrası Sınavı", + "quiz": [ + { + "questionText": "Hangisi YZ'ye yukarıdan aşağıya bir yaklaşım, bir akıl yürütme modelidir.", + "answerOptions": [ + { + "answerText": "stratejik akıl yürütme", + "isCorrect": false + }, + { + "answerText": "simgesel akıl yürütme", + "isCorrect": true + }, + { + "answerText": "sinerjik akıl yürütme", + "isCorrect": false + } + ] + }, + { + "questionText": "YZ'ye aşağıdan yukarıya bir yaklaşım, sinir ağlarına dayanmaktadır.", + "answerOptions": [ + { + "answerText": "Doğru", + "isCorrect": true + }, + { + "answerText": "Yanlış", + "isCorrect": false + } + ] + }, + { + "questionText": "YZ Kışı bu dönemde meydana geldi.", + "answerOptions": [ + { + "answerText": "1950ler", + "isCorrect": false + }, + { + "answerText": "1960lar", + "isCorrect": false + }, + { + "answerText": "1970ler", + "isCorrect": true + } + ] + } + ] + } + ] + } +] \ No newline at end of file diff --git a/lessons/1-Intro/translations/assignment.tr.md b/lessons/1-Intro/translations/assignment.tr.md new file mode 100644 index 00000000..14fea9b4 --- /dev/null +++ b/lessons/1-Intro/translations/assignment.tr.md @@ -0,0 +1,3 @@ +# Oyun Özeti + +Oyunlar, YZ ve MÖ'deki gelişmelerden büyük ölçüde etkilenen bir alandır. Bu ödevde, YZ'nin evriminden etkilenmiş sevdiğiniz bir oyun hakkında kısa bir makale yazın. Birkaç tür bilgisayar işleme sisteminden etkilenecek kadar eski bir oyun olsun. İyi bir örnek Satranç veya Go'dur, ancak pong veya Pac-Man gibi video oyunlarına da bir göz atın. Oyunun geçmişini, bugününü ve yapay zekanın geleceğini tartışan bir makale yazın. \ No newline at end of file From efb9f5d73dbada53759f63c107e29133bffa27fc Mon Sep 17 00:00:00 2001 From: semercim Date: Mon, 22 Aug 2022 22:13:50 +0200 Subject: [PATCH 07/38] Fixed relative image paths. --- lessons/1-Intro/translations/README.tr.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lessons/1-Intro/translations/README.tr.md b/lessons/1-Intro/translations/README.tr.md index bca67d45..cb2cd234 100644 --- a/lessons/1-Intro/translations/README.tr.md +++ b/lessons/1-Intro/translations/README.tr.md @@ -1,6 +1,6 @@ # YZ'ye Giriş -![Bir doodle'da yapay zekaya giriş içeriğinin özeti](../sketchnotes/ai-intro.png) +![Bir doodle'da yapay zekaya giriş içeriğinin özeti](../../sketchnotes/ai-intro.png) > Çizim: [Tomomi Imura](https://twitter.com/girlie_mac) @@ -10,7 +10,7 @@ Başlangıçta bilgisayarlar [Charles Babbage](https://en.wikipedia.org/wiki/Charles_Babbage) tarafından, iyi tanımlanmış bir prosedürü, yani bir algoritmayı izleyerek sayılar üzerinde çalışmak üzere icat edildi. Modern bilgisayarlar, 19. yüzyılda önerilen orijinal modelden önemli ölçüde daha gelişmiş olmasına rağmen, hala aynı kontrollü hesaplama fikrini takip ediyor. Bu nedenle, hedefe ulaşmak için yapmamız gereken adımların tam sırasını biliyorsak, bir bilgisayarı bir şeyler yapmak üzere programlamak mümkündür. -![Bir insanın fotoğrafı](images/dsh_age.png) +![Bir insanın fotoğrafı](../images/dsh_age.png) > Fotoğraf: [Vickie Soshnikova](http://twitter.com/vickievalerie) @@ -30,7 +30,7 @@ Bir fotoğraftan bir kişinin yaşını belirleme gibi, belirli bir insani probl **[Zeka](https://en.wikipedia.org/wiki/Intelligence)** terimiyle uğraşırken karşılaşılan sorunlardan biri, bu terimin net bir tanımının olmamasıdır. Zekanın **soyut düşünme** veya **öz farkındalık** ile bağlantılı olduğu iddia edilebilir, ancak onu tam olarak tanımlayamıyoruz. -![Kedi Fotoğrafı](images/photo-cat.jpg) +![Kedi Fotoğrafı](../images/photo-cat.jpg) > [Fotoğraf](https://unsplash.com/photos/75715CVEJhI) sahibi Unsplash'tan [Amber Kipp](https://unsplash.com/@sadmax) @@ -82,13 +82,13 @@ Alternatif olarak, beynimizin içindeki en basit öğeleri, yani bir nöronu mod > | ML'ye ne demeli? | | > |--------------|-----------| -> | Yapay Zekanın bazı verilere dayalı bir sorunu çözmek için bilgisayar öğrenmesine dayanan kısmına **Makine Öğrenmesi** denir. Bu derste klasik makine öğrenmesini ele almayacağız - sizi ayrı bir [Yeni Başlayanlar için Makine Öğrenmesi](http://aka.ms/ml-beginners) müfredatına yönlendiriyoruz. | ![Yeni Başlayanlar için MÖ](images/ml-for-beginners.png) | +> | Yapay Zekanın bazı verilere dayalı bir sorunu çözmek için bilgisayar öğrenmesine dayanan kısmına **Makine Öğrenmesi** denir. Bu derste klasik makine öğrenmesini ele almayacağız - sizi ayrı bir [Yeni Başlayanlar için Makine Öğrenmesi](http://aka.ms/ml-beginners) müfredatına yönlendiriyoruz. | ![Yeni Başlayanlar için MÖ](../images/ml-for-beginners.png) | ## YZ'nin Kısa Tarihi Yapay Zeka, yirminci yüzyılın ortalarında bir alan olarak kullanılmaya başlandı. Başlangıçta simgesel akıl yürütme yaygın bir yaklaşımdı ve uzman sistemler - bazı sınırlı sorun alanlarında uzman olarak hareket edebilen bilgisayar programları - gibi bir dizi önemli başarıya yön verdi. Ancak, kısa süre sonra bu yaklaşımın iyi ölçeklenmediği anlaşıldı. Bilgiyi bir uzmandan çıkarmak, bir bilgisayarda temsil etmek ve bu bilgi tabanını doğru tutmak çok karmaşık görevlerdir ve çoğu durumda pratik olamayacak kadar pahalıdır. Bu, 1970'lerde [YZ Kışı](https://en.wikipedia.org/wiki/AI_winter) olarak adlandırılan döneme yol açtı. -YZ'nin Kısa Tarihi +YZ'nin Kısa Tarihi > İmge sahibi [Dmitry Soshnikov](http://soshnikov.com) @@ -108,7 +108,7 @@ Benzer şekilde, (Turing testini geçebilecek) “konuşan programlar” oluştu * Cortana, Siri veya Google Asistan gibi modern asistanların tümü, konuşmayı metne dönüştürmek ve niyetimizi tanımak için Sinir ağlarını kullanan ve ardından gerekli eylemleri gerçekleştirmek için bazı akıl yürütmeler veya açık algoritmalar kullanan karma sistemlerdir. * Gelecekte, tamamen sinir tabanlı bir modelin diyaloğu tek başına idare etmesini bekleyebiliriz. En son GPT ve [Turing-NLG](https://turing.microsoft.com/) sinir ağları ailesi bu konuda büyük başarı gösteriyor. -Turing testinin evrimi +Turing testinin evrimi > İmge sahibi Dmitry Soshnikov, [fotoğraf](https://unsplash.com/photos/r8LmVbUKgns) ve [Marina Abrosimova](https://unsplash.com/@abrosimova_marina_foto), Unsplash @@ -116,11 +116,11 @@ Benzer şekilde, (Turing testini geçebilecek) “konuşan programlar” oluştu Sinir ağı araştırmalarındaki yakın zamanlardaki büyük büyüme, büyük halka açık veri kümelerinin kullanıma sunulmaya başladığı 2010 civarında başladı. Yaklaşık 14 milyon açıklamalı resim içeren [ImageNet](https://en.wikipedia.org/wiki/ImageNet) adlı devasa bir resim koleksiyonu, [ImageNet Büyük Ölçekli Görsel Tanıma Yarışmasını](https://image-net.org/challenges/LSVRC/) doğurdu. -![ILSVRC Doğruluğu](images/ilsvrc.gif) +![ILSVRC Doğruluğu](../images/ilsvrc.gif) > İmge sahibi [Dmitry Soshnikov](http://soshnikov.com) -2012 yılında, [Evrişimli Sinir Ağları](../4-ComputerVision/07-ConvNets/README.tr.md) ilk olarak imge sınıflandırmada kullanıldı ve bu da sınıflandırma hatalarında önemli bir düşüşe neden oldu (neredeyse %30'dan %16.4'e). 2015 yılında, Microsoft Araştırma'nın ResNet mimarisi [insan düzeyinde doğruluk elde etti](https://doi.org/0.1109/ICCV.2015.123). +2012 yılında, [Evrişimli Sinir Ağları](../../4-ComputerVision/07-ConvNets/README.tr.md) ilk olarak imge sınıflandırmada kullanıldı ve bu da sınıflandırma hatalarında önemli bir düşüşe neden oldu (neredeyse %30'dan %16.4'e). 2015 yılında, Microsoft Araştırma'nın ResNet mimarisi [insan düzeyinde doğruluk elde etti](https://doi.org/0.1109/ICCV.2015.123). O zamandan beri, Sinir Ağları birçok görevde çok başarılı davranışlar sergiledi: @@ -133,7 +133,7 @@ Yıl | İnsana denklik elde edildi 2018 | [Otomatik Makine Çevirisi](https://arxiv.org/abs/1803.05567) (Çince-İngilizce) 2020 | [İmge Altyazısı](https://arxiv.org/abs/2009.13682) -Geçtiğimiz birkaç yılda, BERT ve GPT-3 gibi büyük dil modelleriyle büyük başarılara tanık olduk. Bu, çoğunlukla, onları genel metin koleksiyonları üzerinde önceden eğitmemize ve daha sonra bu modelleri daha belirli görevler için özelleştirmemize olanak tanıyarak metinlerin yapısını ve anlamını yakalamak için modelleri eğitmemizi sağlayan çok sayıda genel metin verisi olduğu gerçeğinden kaynaklanmaktadır. Bu dersin ilerleyen bölümlerinde [Doğal Dil İşleme](../5-NLP/README.tr.md) hakkında daha fazla bilgi edineceğiz. +Geçtiğimiz birkaç yılda, BERT ve GPT-3 gibi büyük dil modelleriyle büyük başarılara tanık olduk. Bu, çoğunlukla, onları genel metin koleksiyonları üzerinde önceden eğitmemize ve daha sonra bu modelleri daha belirli görevler için özelleştirmemize olanak tanıyarak metinlerin yapısını ve anlamını yakalamak için modelleri eğitmemizi sağlayan çok sayıda genel metin verisi olduğu gerçeğinden kaynaklanmaktadır. Bu dersin ilerleyen bölümlerinde [Doğal Dil İşleme](../../5-NLP/README.tr.md) hakkında daha fazla bilgi edineceğiz. ## 🚀 Kendini Sınama From e4ea76b3f46d37ebb4e7255a7d9f132cf22fc955 Mon Sep 17 00:00:00 2001 From: semercim Date: Thu, 25 Aug 2022 23:11:29 +0200 Subject: [PATCH 08/38] Translating lesson 2. --- lessons/2-Symbolic/translations/README.tr.md | 239 ++++++++++++++++++ .../2-Symbolic/translations/assignment.tr.md | 3 + 2 files changed, 242 insertions(+) create mode 100644 lessons/2-Symbolic/translations/README.tr.md create mode 100644 lessons/2-Symbolic/translations/assignment.tr.md diff --git a/lessons/2-Symbolic/translations/README.tr.md b/lessons/2-Symbolic/translations/README.tr.md new file mode 100644 index 00000000..a9a8d990 --- /dev/null +++ b/lessons/2-Symbolic/translations/README.tr.md @@ -0,0 +1,239 @@ +# Bilgi Temsili ve Uzman Sistemler + +![Simgesel YZ içerik özeti](../../sketchnotes/ai-symbolic.png) + +> Çizim sahibi [Tomomi Imura](https://twitter.com/girlie_mac) + +Yapay zeka arayışı, insanların yaptığı gibi dünyayı anlamlandırmak için bilgi aramaya dayanır. Ama bunu yapmak için nasıl bir yol izleyebilirsin? + +## [Ders öncesi sınavı](https://red-field-0a6ddfd03.1.azurestaticapps.net/quiz/102) + +YZ'nin ilk günlerinde, akıllı sistemler oluşturmaya yönelik yukarıdan aşağıya yaklaşım (önceki derste tartışılmıştı) popülerdi. Buradaki fikir, insanlardan bilgiyi makine tarafından okunabilen bir forma döndürmek ve sonra bunu problemleri otomatik olarak çözmek için kullanmaktı. Bu yaklaşım iki büyük fikre dayanıyordu: + +* Bilgi Temsili +* Akıl Yürütme + +## Bilgi Temsili + +Simgesel YZ'deki önemli kavramlardan biri **bilgidir**. Bilgiyi *enformasyondan* veya *veriden* ayırt etmek önemlidir. Örneğin, kitapların bilgi içerdiği söylenebilir, çünkü kişi kitaplara çalışabilir ve uzman olabilir. Ancak kitapların içerdiği şeye aslında *veri* denir ve kitap okuyarak ve bu verileri dünya modelimizle bütünleştirerek bilgiye dönüştürürüz. + +> ✅ **Bilgi** kafamızın içinde yer alan ve dünyaya ilişkin anlayışımızı temsil eden bir şeydir. Aldığımız enformasyon parçalarını aktif dünya modelimizle bütünleştiren aktif bir **öğrenme** süreci ile elde edilir. + +Çoğu zaman bilgiyi kesin olarak tanımlamayız, ancak [DIKW Piramidi](https://en.wikipedia.org/wiki/DIKW_pyramid) kullanarak onu diğer ilgili kavramlarla hizalarız. Aşağıdaki kavramları içerir: + +* **Veri**, yazılı metin veya sözlü kelimeler gibi fiziksel ortamda temsil edilen bir şeydir. Veriler insanlardan bağımsız olarak var olur ve insanlar arasında aktarılabilir. +* **Enformasyon** verileri kafamızda nasıl yorumladığımızdır. Örneğin, *bilgisayar* kelimesini duyduğumuzda, onun ne olduğunu biraz anlarız. +* **Bilgi**, dünya modelimizle bütünleşen bilgidir. Örneğin, bir bilgisayarın ne olduğunu öğrendiğimizde nasıl çalıştığı, ne kadara mal olduğu ve ne için kullanılabileceği hakkında bazı fikirler edinmeye başlarız. Bu birbiriyle ilişkili kavramlar ağı bilgimizi oluşturur. +* **Bilgelik** dünyayı anlamamızın bir başka seviyesidir ve *başkalaşım-bilgisini* temsil eder, ör. bilginin nasıl ve ne zaman kullanılması gerektiğine dair biraz kanı. + + + +*İmge [Wikipedia'dan](https://commons.wikimedia.org/w/index.php?curid=37705247), By Longlivetheux - Own work, CC BY-SA 4.0* + +Bu nedenle, **bilgi temsili** sorunu, bilgiyi bir bilgisayar içinde veri biçiminde temsil etmenin, otomatik olarak kullanılabilir hale getirmenin etkili bir yolunu bulmaktır. Bu bir spektrum olarak görülebilir: + +![Bilgi temsili spektrumu](../images/knowledge-spectrum.png) + +> İmge sahibi [Dmitry Soshnikov](http://soshnikov.com) + +* Solda, bilgisayarlar tarafından etkin bir şekilde kullanılabilecek çok basit bilgi temsili türleri vardır. En basit olanı, bilgi bir bilgisayar programı tarafından temsil edildiğinde algoritmiktir. Ancak bu, bilgiyi temsil etmenin en iyi yolu değildir, çünkü esnek değildir. Kafamızın içindeki bilgi genellikle algoritmik değildir. +* Sağda doğal metin gibi temsiller vardır. En güçlüsüdür, ancak otomatik akıl yürütme için kullanılamaz. + +> ✅ Bir an için bilgiyi kafanızda nasıl temsil ettiğinizi düşünün ve onu notlara dönüştürün. Akılda tutmaya yardımcı olmada iyi çalışan belirli bir format var mı? + +## Bilgisayar Bilgi Temsillerini Sınıflandırma + +Farklı bilgisayar bilgisi temsil yöntemlerini aşağıdaki kategorilerde sınıflandırabiliriz: + +* **Ağ temsilleri** kafamızın içinde birbiriyle ilişkili kavramlardan oluşan bir ağımız olduğu gerçeğine dayanmaktadır. Aynı ağları bir bilgisayarın içindeki bir çizge olarak yeniden üretmeyi deneyebiliriz - sözde **anlamsal ağ**. + +1. **Nesne-Nitelik-Değer üçlüleri** veya **nitelik-değer çiftleri**. Bir öizge bir bilgisayar içinde düğümler ve kenarların bir listesi olarak gösterilebildiğinden, anlamsal bir ağı nesneler, nitelikler ve değerler içeren bir üçlüler listesiyle temsil edebiliriz. Örneğin, programlama dilleriyle ilgili aşağıdaki üçlüleri oluşturuyoruz: + +Nesne | Nitelik | Değer +-------|-----------|------ +Python | olmak | türsüz dil +Python | icat edilmek | Guido van Rossum +Python | blok sözdizimi | girinti +Türsüz dil | sahip olmamak | tür tanımları + +> ✅ Diğer bilgi türlerini temsil etmek için üçlülerin nasıl kullanılabileceğini düşünün. + +2. **Hiyerarşik temsiller**, genellikle kafamızın içinde bir nesneler hiyerarşisi oluşturduğumuz gerçeğini vurgular. Örneğin, kanarya bir kuştur ve tüm kuşların kanatları vardır. Ayrıca genellikle kanarya renginin ne olduğu ve uçuş hızlarının ne olduğu hakkında da bir fikrimiz var. + + - **Çerçeve temsili**, her bir nesneyi veya nesne sınıfını **yuvalar** içeren bir **çerçeve** olarak temsil etmeye dayanır. Yuvaların, bir yuvanın değerini elde etmek için çağrılabilecek olası varsayılan değerleri, değer kısıtlamaları veya saklı yordamları vardır. Tüm çerçeveler, nesne yönelimli programlama dillerindeki nesne hiyerarşisine benzer bir hiyerarşi oluşturur. + - **Senaryolar**, zaman içinde ortaya çıkabilecek karmaşık durumları temsil eden özel tür çerçevelerdir. + +**Python** +Yuva | Değer | Varsayılan Değer | Aralık | +-----|-------|---------------|----------| +İsim | Python | | | +Örneği Olmak | Türsüz Dil | | | +Değişken Harf Boyutu | | Deve Harf Boyutu (CamelCase) | | +Program Uzunluğu | | | 5-5000 satır | +Blok Sözdizimi | Girinti | | | + +3. **Yöntemsel temsiller**, belirli bir koşul oluştuğunda yürütülebilecek bir eylemler listesiyle bilgiyi temsil etmeye dayanır. + - Üretme kuralları, sonuç çıkarmamıza izin veren eğer-öyleyse ifadelerdir. Örneğin, bir doktorun, kan testinde **EĞER** bir hastanın ateşi yüksek **VEYA** yüksek düzeyde C-reaktif proteini varsa **O ZAMAN** iltihabı olduğunu söyleyen bir kuralı olabilir. Koşullardan biriyle karşılaştığımızda, iltihaplanma hakkında bir sonuca varabilir ve daha sonra bunu daha fazla akıl yürütmede kullanabiliriz. + - Algoritmalar, neredeyse hiçbir zaman doğrudan bilgi tabanlı sistemlerde kullanılmamalarına rağmen, yöntemsel temsilin başka bir biçimi olarak düşünülebilir. + +4. **Mantık** ilk olarak Aristo tarafından evrensel insan bilgisini temsil etmenin bir yolu olarak önerildi. + - Matematiksel bir teori olarak Yüklem Mantığı, hesaplanamayacak kadar zengindir, bu nedenle normal olarak Prolog'da kullanılan Horn cümlecikleri gibi bazı alt kümeleri kullanılır. + - Tanımlayıcı Mantık, *anlamsal ağ* gibi dağıtılmış bilgi temsilleri olan nesnelerin hiyerarşilerini temsil etmek ve bunlar hakkında akıl yürütmek için kullanılan bir mantıksal sistemler ailesidir. + +## Uzman Sistemler + +Simgesel YZ'nin ilk başarılarından biri, **uzman sistemler** olarak adlandırıldı - bazı sınırlı problem alanlarında uzman olarak davranmak üzere tasarlanmış bilgisayar sistemleridir. Bir veya daha fazla insan uzmanından alınan bir **bilgi tabanına** dayanıyorlardı ve bunun üzerinden bazı akıl yürütmeler yapan bir **çıkarsama motoru** içeriyorlardı. + +![İnsan Mimarisi](../images/arch-human.png) | ![Bilgi Tabanlı Sistem](../images/arch-kbs.png) +---------------------------------------------|------------------------------------------------ +Bir insan sinir sisteminin basitleştirilmiş yapısı | Bilgi tabanlı bir sistemin mimarisi + +Uzman sistemler, **kısa süreli bellek** ve **uzun süreli bellek** içeren insan akıl yürütme sistemi gibi oluşturulmuştur. Benzer şekilde, bilgi tabanlı sistemlerde aşağıdaki bileşenleri fark edebiliriz: + +* **Problem belleği**: Şu anda çözülmekte olan problem hakkındaki bilgileri, yani bir hastanın ateşi veya tansiyonu, iltihabı olup olmadığı vb. bilgileri içerir. Bu bilgi aynı zamanda **statik bilgi** olarak da adlandırılır, çünkü sorun hakkında şu anda bildiklerimizin bir anlık görüntüsünü içerir - sözde *problem durumu*. +* **Bilgi tabanı**: Bir problem alanı hakkında uzun vadeli bilgiyi temsil eder. İnsan uzmanlardan manuel olarak elde edilir ve muayeneden muayeneye değişmez. Bir problem durumundan diğerine geçmemize izin verdiği için **dinamik bilgi** olarak da adlandırılır. +* **Çıkarsama motoru**: Gerektiğinde kullanıcıya sorular sorarak, problem durumu alanında tüm arama sürecini düzenler. Ayrıca her duruma uygulanacak doğru kuralları bulmaktan da sorumludur. + +Örnek olarak, bir hayvanın fiziksel özelliklerine göre belirleyen aşağıdaki uzman sistemi ele alalım: + +![VE-VEYA Ağacı](../images/AND-OR-Tree.png) + +> İmge sahibi [Dmitry Soshnikov](http://soshnikov.com) + +Bu diyagrama **VE-VEYA ağacı** denir ve bir dizi üretme kuralının çizgesel bir temsilidir. Bir ağaç çizmek, uzmandan bilgi elde etmenin başlangıcında faydalıdır. Bilgisayardaki bilgiyi temsil etmek için kuralları kullanmak daha uygundur: + +``` +EĞER hayvan et yerse +VEYA (hayvan keskin dişleri varsa + VE hayvanın pençeleri varsa + VE hayvanın ileriye bakan gözleri varsa +) +O ZAMAN hayvan bir etoburdur +``` + +Kuralın ve eylemin sol tarafındaki her koşulun esasen nesne-nitelik-değer (NND) üçlüleri olduğunu fark edebilirsiniz. **Çalışan bellek**, o anda çözülmekte olan probleme karşılık gelen NND üçlüler kümesini içerir. Bir **kural motoru**, bir koşulun sağlandığı kuralları arar ve bunları uygulayarak, çalışan belleğe başka bir üçlü ekler. + +> ✅ Beğendiğiniz bir konu üzerine kendi VE-VEYA ağacınızı yazın! + +### İleri ve Geri Çıkarsama + +Yukarıda açıklanan sürece **ileri çıkarsama** denir. Çalışma belleğinde bulunan problemle ilgili bazı başlangıç verileriyle başlar ve ardından aşağıdaki akıl yürütme döngüsünü yürütür: + +1. Çalışan bellekte hedef niteliği mevcutsa - durun ve sonucu döndürün. +2. Şu anda koşulu sağlanan tüm kuralları arayın - kuralların **çatışma kümesini** edinin. +3. **Çatışma gidermeyi** gerçekleştirin - bu adımda yürütülecek bir kural seçin. Farklı çatışma giderme stratejileri olabilir: + - Bilgi tabanındaki ilk geçerli kuralı seçin. + - Rastgele bir kural seçin. + - *Daha özgül* bir kural seçin, mesela "sol tarafta" en çok koşulu karşılayanı. +4. Seçili kuralı uygula ve problem durumuna yeni bilgi parçası ekle. +5. 1. adımdan itibaren tekrarlayın. + +Ancak bazı durumlarda problem hakkında boş bir bilgiyle başlamak ve sonuca varmamıza yardımcı olacak sorular sormak isteyebiliriz. Örneğin tıbbi teşhis yaparken genellikle hastaya teşhis koymadan önce tüm tıbbi analizleri yapmıyoruz. Bir karar verilmesi gerektiğinde analizler yapmayı tercih ediyoruz. + +Bu süreç **geriye çıkarsama** kullanılarak modellenebilir. Bulmak istediğimiz nitelik değeri olan **hedef** tarafından yönlendirilir: + +1. Bize bir hedefin değerini verebilecek tüm kuralları seçin (yani, ST'deki hedef ("sağ taraf") ile) - bir çatışma kümesi +1. Bu nitelik için herhangi bir kural yoksa veya değeri kullanıcıdan istememiz gerektiğini söyleyen bir kural varsa - kullanıcıya sorun, aksi takdirde: +1. *Hipotez* olarak kullanacağımız bir kuralı seçmek için çatışma giderme stratejisini kullanın - bunu kanıtlamaya çalışacağız +1. Kuralın sol tarafındaki tüm nitelikler için süreci tekrarlayarak, bunları hedef olarak kanıtlamaya çalışın +1. Herhangi bir noktada süreç başarısız olursa - 3. adımda başka bir kural kullanın. + +> ✅ Hangi durumlarda ileriye çıkarsama daha uygundur? Geriye çıkarsamaya ne demeli? + +### Uzman Sistemlerin Uygulanması + +Uzman sistemler farklı araçlar kullanılarak uygulanabilir: + +* Bunları doğrudan bazı üst düzey programlama dillerinde programlamak. Bu en iyi fikir değildir, çünkü bilgiye dayalı bir sistemin ana avantajı, bilginin çıkarsamadan ayrılmasıdır ve potansiyel olarak bir problem alanı uzmanı, çıkarsama sürecinin ayrıntılarını anlamadan kurallar yazabilmelidir. +* **Uzman sistemler kabuğu**, yani bazı bilgi temsil dili kullanılarak bilgi tarafından doldurulmak üzere özel olarak tasarlanmış bir sistem kullanmak. + +## ✍️ Alıştırma: Hayvan Çıkarsama + +İleri ve geri çıkarsama uzman sistemi uygulama örneği için [Animals.tr.ipynb](Animals.tr.ipynb) bölümüne bakın. + +> **Not**: Bu örnek oldukça basittir ve yalnızca bir uzman sistemin nasıl göründüğü hakkında fikir verir. Böyle bir sistem oluşturmaya başladığınızda, yalnızca belirli sayıda kurala ulaştığınızda, yaklaşık 200'den fazlaysa, *akıllı* davranış fark edeceksiniz. Bir noktada, kurallar hepsini akılda tutamayacak kadar karmaşık hale gelir ve bu noktada bir sistemin neden belirli kararlar aldığını merak etmeye başlayabilirsiniz. Bununla birlikte, bilgi tabanlı sistemlerin önemli özelliği, kararlardan herhangi birinin nasıl verildiğini her zaman tam olarak *açıklayabilmenizdir. + +## Ontologies and the Semantic Web + +At the end of 20th century there was an initiative to use knowledge representation to annotate Internet resources, so that it would be possible to find resources that correspond to very specific queries. This motion was called **Semantic Web**, and it relied on several concepts: + +- A special knowledge representation based on **[description logics](https://en.wikipedia.org/wiki/Description_logic)** (DL). It is similar to frame knowledge representation, because it builds a hierarchy of objects with properties, but it has formal logical semantics and inference. There is a whole family of DLs which balance between expressiveness and algorithmic complexity of inference. +- Distributed knowledge representation, where all concepts are represented by a global URI identifier, making it possible to create knowledge hierarchies that span the internet. +- A family of XML-based languages for knowledge description: RDF (Resource Description Framework), RDFS (RDF Schema), OWL (Ontology Web Language). + +A core concept in the Semantic Web is a concept of **Ontology**. It refers to a explicit specification of a problem domain using some formal knowledge representation. The simplest ontology can be just a hierarchy of objects in a problem domain, but more complex ontologies will include rules that can be used for inference. + +In the semantic web, all representations are based on triplets. Each object and each relation are uniquely identified by the URI. For example, if we want to state the fact that this AI Curriculum has been developed by Dmitry Soshnikov on Jan 1st, 2022 - here are the triplets we can use: + + + +``` +http://github.com/microsoft/ai-for-beginners http://www.example.com/terms/creation-date “Jan 13, 2007” +http://github.com/microsoft/ai-for-beginners http://purl.org/dc/elements/1.1/creator http://soshnikov.com +``` + +> ✅ Here `http://www.example.com/terms/creation-date` and `http://purl.org/dc/elements/1.1/creator` are some well-known and universally accepted URIs to express the concepts of *creator* and *creation date*. + +In a more complex case, if we want to define a list of creators, we can use some data structures defined in RDF. + + + +> Diagrams above by [Dmitry Soshnikov](http://soshnikov.com) + +The progress of building the Semantic Web was somehow slowed down by the success of search engines and natural language processing techniques, which allow extracting structured data from text. However, in some areas there are still significant efforts to maintain ontologies and knowledge bases. A few projects worth noting: + +* [WikiData](https://wikidata.org/) is a collection of machine readable knowledge bases associated with Wikipedia. Most of the data is mined from Wikipedia *InfoBoxes*, pieces of structured content inside Wikipedia pages. You can [query](https://query.wikidata.org/) wikidata in SPARQL, a special query language for Semantic Web. Here is a sample query that displays most popular eye colors among humans: + +```sparql +#defaultView:BubbleChart +SELECT ?eyeColorLabel (COUNT(?human) AS ?count) +WHERE +{ + ?human wdt:P31 wd:Q5. # human instance-of homo sapiens + ?human wdt:P1340 ?eyeColor. # human eye-color ?eyeColor + SERVICE wikibase:label { bd:serviceParam wikibase:language "en". } +} +GROUP BY ?eyeColorLabel +``` + +* [DBpedia](https://www.dbpedia.org/) is another effort similar to WikiData. + +> ✅ If you want to experiment with building your own ontologies, or opening existing ones, there is a great visual ontology editor called [Protégé](https://protege.stanford.edu/). Download it, or use it online. + + + +*Web Protégé editor open with the Romanov Family ontology. Screenshot by Dmitry Soshnikov* + +## ✍️ Exercise: A Family Ontology + +See [FamilyOntology.ipynb](FamilyOntology.ipynb) for an example of using Semantic Web techniques to reason about family relationships. We will take a family tree represented in common GEDCOM format and an ontology of family relationships and build a graph of all family relationships for given set of individuals. + +## Microsoft Concept Graph + +In most of the cases, ontologies are carefully created by hand. However, it is also possible to **mine** ontologies from unstructured data, for example, from natural language texts. + +One such attempt was done by Microsoft Research, and resulted in [Microsoft Concept Graph](https://blogs.microsoft.com/ai/microsoft-researchers-release-graph-that-helps-machines-conceptualize/?WT.mc_id=academic-57639-dmitryso). + +It is a large collection of entities grouped together using `is-a` inheritance relationship. It allows answering questions like "What is Microsoft?" - the answer being something like "a company with probability 0.87, and a brand with probability 0.75". + +The Graph is available either as REST API, or as a large downloadable text file that lists all entity pairs. + +## ✍️ Exercise: A Concept Graph + +Try the [MSConceptGraph.ipynb](MSConceptGraph.ipynb) notebook to see how we can use Microsoft Concept Graph to group news articles into several categories. + +## Conclusion + +Nowadays, AI is often considered to be a synonym for *Machine Learning* or *Neural Networks*. However, a human being also exhibits explicit reasoning, which is something currently not being handled by neural networks. In real world projects, explicit reasoning is still used to perform tasks that require explanations, or being able to modify the behavior of the system in a controlled way. + +## 🚀 Challenge + +In the Family Ontology notebook associated to this lesson, there is an opportunity to experiment with other family relations. Try to discover new connections between people in the family tree. + +## [Post-lecture quiz](https://red-field-0a6ddfd03.1.azurestaticapps.net/quiz/202) + +## Review & Self Study + +Do some research on the internet to discover areas where humans have tried to quantify and codify knowledge. Take a look at Bloom's Taxonomy, and go back in history to learn how humans tried to make sense of their world. Explore the work of Linnaeus to create a taxonomy of organisms, and observe the way Dmitri Mendeleev created a way for chemical elements to be described and grouped. What other interesting examples can you find? + +**Assignment**: [Build an Ontology](assignment.md) diff --git a/lessons/2-Symbolic/translations/assignment.tr.md b/lessons/2-Symbolic/translations/assignment.tr.md new file mode 100644 index 00000000..89664e69 --- /dev/null +++ b/lessons/2-Symbolic/translations/assignment.tr.md @@ -0,0 +1,3 @@ +# Bir Ontoloji Oluşturun + +Bir bilgi tabanı oluşturmak, bir konu hakkındaki gerçekleri temsil eden bir modeli kategorize etmekle ilgilidir. Bir konu seçin - bir kişi, bir yer veya bir nesne gibi - ve sonra o konunun bir modelini oluşturun. Bu derste açıklanan bazı teknikleri ve model kurma stratejilerini kullanın. Bir örnek, mobilyalar, ışıklar vb. ile bir oturma odasının ontolojisini oluşturmak olabilir. Oturma odası mutfaktan nasıl farklıdır? Ya banyo? Yemek odası değil de oturma odası olduğunu nereden biliyorsun? Ontolojinizi oluşturmak için [Protégé](https://protege.stanford.edu/)'i kullanın. \ No newline at end of file From f66cad1a57158670b5010d2ab7c2b601f702cf4d Mon Sep 17 00:00:00 2001 From: semercim Date: Mon, 29 Aug 2022 12:58:07 +0200 Subject: [PATCH 09/38] Translating lesson 2 to Turkish. --- lessons/2-Symbolic/translations/README.tr.md | 72 ++++++++++---------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/lessons/2-Symbolic/translations/README.tr.md b/lessons/2-Symbolic/translations/README.tr.md index a9a8d990..4ff0fac6 100644 --- a/lessons/2-Symbolic/translations/README.tr.md +++ b/lessons/2-Symbolic/translations/README.tr.md @@ -151,38 +151,40 @@ Uzman sistemler farklı araçlar kullanılarak uygulanabilir: İleri ve geri çıkarsama uzman sistemi uygulama örneği için [Animals.tr.ipynb](Animals.tr.ipynb) bölümüne bakın. -> **Not**: Bu örnek oldukça basittir ve yalnızca bir uzman sistemin nasıl göründüğü hakkında fikir verir. Böyle bir sistem oluşturmaya başladığınızda, yalnızca belirli sayıda kurala ulaştığınızda, yaklaşık 200'den fazlaysa, *akıllı* davranış fark edeceksiniz. Bir noktada, kurallar hepsini akılda tutamayacak kadar karmaşık hale gelir ve bu noktada bir sistemin neden belirli kararlar aldığını merak etmeye başlayabilirsiniz. Bununla birlikte, bilgi tabanlı sistemlerin önemli özelliği, kararlardan herhangi birinin nasıl verildiğini her zaman tam olarak *açıklayabilmenizdir. +> **Not**: Bu örnek oldukça basittir ve yalnızca bir uzman sistemin nasıl göründüğü hakkında fikir verir. Böyle bir sistem oluşturmaya başladığınızda, yalnızca belirli sayıda kurala ulaştığınızda, yaklaşık 200'den fazlaysa, *akıllı* davranış fark edeceksiniz. Bir noktada, kurallar hepsini akılda tutamayacak kadar karmaşık hale gelir ve bu noktada bir sistemin neden belirli kararlar aldığını merak etmeye başlayabilirsiniz. Bununla birlikte, bilgi tabanlı sistemlerin önemli özelliği, kararlardan herhangi birinin nasıl verildiğini her zaman tam olarak *açıklayabilmenizdir*. -## Ontologies and the Semantic Web +## Ontolojiler ve Anlamsal Web -At the end of 20th century there was an initiative to use knowledge representation to annotate Internet resources, so that it would be possible to find resources that correspond to very specific queries. This motion was called **Semantic Web**, and it relied on several concepts: +20. yüzyılın sonunda, çok özel sorgulara karşılık gelen kaynakları bulmak mümkün olacak şekilde, İnternet kaynaklarına açıklama eklemek için bilgi temsilini kullanma girişimi vardı. Bu harekete **Anlamsal Web** adı verildi ve birkaç kavrama dayanıyordu: -- A special knowledge representation based on **[description logics](https://en.wikipedia.org/wiki/Description_logic)** (DL). It is similar to frame knowledge representation, because it builds a hierarchy of objects with properties, but it has formal logical semantics and inference. There is a whole family of DLs which balance between expressiveness and algorithmic complexity of inference. -- Distributed knowledge representation, where all concepts are represented by a global URI identifier, making it possible to create knowledge hierarchies that span the internet. -- A family of XML-based languages for knowledge description: RDF (Resource Description Framework), RDFS (RDF Schema), OWL (Ontology Web Language). +- **[Tanım mantığına](https://en.wikipedia.org/wiki/Description_logic)** (TM) dayalı özel bir bilgi temsili. Çerçeve bilgi temsiline benzerdir, çünkü özelliklere sahip bir nesneler hiyerarşisi oluşturur, ancak biçimsel mantıksal anlambilimi ve çıkarsama vardır. Anlamlılığın ve çıkarsamanın algoritmik karmaşıklığı arasında denge kuran bütün bir TM ailesi vardır. +- Tüm kavramların küresel bir URI tanımlayıcısı tarafından temsil edildiği, interneti kapsayan bilgi hiyerarşileri oluşturmayı mümkün kılan dağıtılmış bilgi temsili. +- Bilgi tanımı için bir XML tabanlı dil ailesi: RDF (Kaynak Tanım Çerçevesi - Resource Description Framework), RDFS (RDF Şeması), OWL (Ontoloji Web Dili). -A core concept in the Semantic Web is a concept of **Ontology**. It refers to a explicit specification of a problem domain using some formal knowledge representation. The simplest ontology can be just a hierarchy of objects in a problem domain, but more complex ontologies will include rules that can be used for inference. +Anlamsal Web'deki temel bir kavram, **Ontoloji** kavramıdır. Bazı resmi bilgi temsillerini kullanarak bir problem alanının açık bir isterini ifade eder. En basit ontoloji, bir problem alanındaki nesnelerin sade bir hiyerarşisi olabilir, ancak daha karmaşık ontolojiler, çıkarsama için kullanılabilecek kuralları içerecektir. In the semantic web, all representations are based on triplets. Each object and each relation are uniquely identified by the URI. For example, if we want to state the fact that this AI Curriculum has been developed by Dmitry Soshnikov on Jan 1st, 2022 - here are the triplets we can use: - +Anlamsal ağda, tüm temsiller üçlülere dayanmaktadır. Her nesne ve her ilişki, URI tarafından benzersiz bir şekilde tanımlanır. Örneğin, bu YZ Müfredatının 1 Ocak 2022'de Dmitry Soshnikov tarafından geliştirildiğini belirtmek istersek - kullanabileceğimiz üçlüler böyledir: + + ``` http://github.com/microsoft/ai-for-beginners http://www.example.com/terms/creation-date “Jan 13, 2007” http://github.com/microsoft/ai-for-beginners http://purl.org/dc/elements/1.1/creator http://soshnikov.com ``` -> ✅ Here `http://www.example.com/terms/creation-date` and `http://purl.org/dc/elements/1.1/creator` are some well-known and universally accepted URIs to express the concepts of *creator* and *creation date*. +> ✅ Burada `http://www.example.com/terms/creation-date` ve `http://purl.org/dc/elements/1.1/creator` *yaratıcı* ve *oluşturma tarihi* kavramlarını ifade etmek için iyi bilinen ve evrensel olarak kabul edilen bazı URI'lerdir. -In a more complex case, if we want to define a list of creators, we can use some data structures defined in RDF. +Daha karmaşık bir durumda, bir yaratıcı listesi tanımlamak istersek, RDF'de tanımlanan bazı veri yapılarını kullanabiliriz. - + -> Diagrams above by [Dmitry Soshnikov](http://soshnikov.com) +> Diyagramların sahibi [Dmitry Soshnikov](http://soshnikov.com) -The progress of building the Semantic Web was somehow slowed down by the success of search engines and natural language processing techniques, which allow extracting structured data from text. However, in some areas there are still significant efforts to maintain ontologies and knowledge bases. A few projects worth noting: +Anlamsal Web'i oluşturmanın ilerlemesi, arama motorlarının ve metinden yapılandırılmış verilerin çıkarılmasına izin veren doğal dil işleme tekniklerinin başarısıyla bir şekilde yavaşladı. Bununla birlikte, bazı alanlarda ontolojileri ve bilgi tabanlarını sürdürmek için hala önemli çabalar vardır. Kayda değer birkaç proje: -* [WikiData](https://wikidata.org/) is a collection of machine readable knowledge bases associated with Wikipedia. Most of the data is mined from Wikipedia *InfoBoxes*, pieces of structured content inside Wikipedia pages. You can [query](https://query.wikidata.org/) wikidata in SPARQL, a special query language for Semantic Web. Here is a sample query that displays most popular eye colors among humans: +* [WikiData](https://wikidata.org/), Wikipedia ile ilişkili makine tarafından okunabilen bilgi tabanlarının bir koleksiyonudur. Verilerin çoğu, Wikipedia sayfalarındaki yapılandırılmış içerik parçaları olan Wikipedia *Bilgi Kutularından* çıkarılır. Anlamsal Web için özel bir sorgu dili olan SPARQL ile wikidatada [sorgu](https://query.wikidata.org/) yapabilirsiniz. İşte insanlar arasında en popüler göz renklerini gösteren örnek bir sorgu: ```sparql #defaultView:BubbleChart @@ -196,44 +198,44 @@ WHERE GROUP BY ?eyeColorLabel ``` -* [DBpedia](https://www.dbpedia.org/) is another effort similar to WikiData. +* [DBpedia](https://www.dbpedia.org/) WikiData'ya benzer başka bir çalışmadır. -> ✅ If you want to experiment with building your own ontologies, or opening existing ones, there is a great visual ontology editor called [Protégé](https://protege.stanford.edu/). Download it, or use it online. +> ✅ Kendi ontolojilerinizi oluşturmayı veya mevcut olanları açmayı denemek istiyorsanız, [Protégé](https://protege.stanford.edu/) adında harika bir görsel ontoloji düzenleyicisi var. İndirin veya çevrimiçi kullanın. - + -*Web Protégé editor open with the Romanov Family ontology. Screenshot by Dmitry Soshnikov* +*Romanov Ailesi ontolojisi ile açık Web Protégé editörü. Dmitry Soshnikov'un ekran görüntüsü* -## ✍️ Exercise: A Family Ontology +## ✍️ Alıştırma: Bir Aile Ontolojisi -See [FamilyOntology.ipynb](FamilyOntology.ipynb) for an example of using Semantic Web techniques to reason about family relationships. We will take a family tree represented in common GEDCOM format and an ontology of family relationships and build a graph of all family relationships for given set of individuals. +Aile ilişkileri hakkında akıl yürütmede Anlamsal Web tekniklerini kullanma örneği için [FamilyOntology.tr.ipynb](FamilyOntology.tr.ipynb) bölümüne bakın. Ortak GEDCOM formatında temsil edilen bir aile ağacını ve aile ilişkilerinin ontolojisini alacağız ve belirli bir grup birey için tüm aile ilişkilerinin bir çizgesini oluşturacağız. -## Microsoft Concept Graph +## Microsoft Kavram Çizgesi -In most of the cases, ontologies are carefully created by hand. However, it is also possible to **mine** ontologies from unstructured data, for example, from natural language texts. +Çoğu durumda, ontolojiler dikkatle elle oluşturulur. Bununla birlikte, örneğin doğal dil metinlerinden yapılandırılmamış verilerden ontolojiler **çıkarmak** da mümkündür. -One such attempt was done by Microsoft Research, and resulted in [Microsoft Concept Graph](https://blogs.microsoft.com/ai/microsoft-researchers-release-graph-that-helps-machines-conceptualize/?WT.mc_id=academic-57639-dmitryso). +Böyle bir girişim Microsoft Research tarafından yapıldı ve [Microsoft Kavram Çizgesi](https://blogs.microsoft.com/ai/microsoft-researchers-release-graph-that-helps-machines-conceptualize/?WT.mc_id=academic-57639-dmitryso) ile sonuçlandı. -It is a large collection of entities grouped together using `is-a` inheritance relationship. It allows answering questions like "What is Microsoft?" - the answer being something like "a company with probability 0.87, and a brand with probability 0.75". +It is a large collection of entities grouped together using `is-a` inheritance relationship. It allows answering questions like "What is Microsoft?" - the answer being something like "a company with probability 0.87, and a brand with probability 0.75". `is-a` (bir örneği olma) kalıtım ilişkisi kullanılarak gruplandırılmış geniş bir varlıklar topluluğudur. "Microsoft Nedir?" gibi soruların yanıtlanmasına olanak tanır - cevap, "0.87 bir şirket ve 0.75 olasılıkla bir marka" gibi bir şeydir. -The Graph is available either as REST API, or as a large downloadable text file that lists all entity pairs. +Çizge, ya REST API olarak ya da tüm varlık çiftlerini listeleyen büyük bir indirilebilir metin dosyası olarak mevcuttur. -## ✍️ Exercise: A Concept Graph +## ✍️ Alıştırma: Bir Kavram Çizgesi -Try the [MSConceptGraph.ipynb](MSConceptGraph.ipynb) notebook to see how we can use Microsoft Concept Graph to group news articles into several categories. +Haber makalelerini birkaç kategoride gruplandırmak için Microsoft Kavram Çizgesi'ni nasıl kullanabileceğimizi görmek için [MSConceptGraph.tr.ipynb](MSConceptGraph.tr.ipynb) not defterini deneyin. -## Conclusion +## Vargılar -Nowadays, AI is often considered to be a synonym for *Machine Learning* or *Neural Networks*. However, a human being also exhibits explicit reasoning, which is something currently not being handled by neural networks. In real world projects, explicit reasoning is still used to perform tasks that require explanations, or being able to modify the behavior of the system in a controlled way. +Günümüzde YZ, genellikle *Makine Öğrenmesi* veya *Sinir Ağları* ile eşanlamlı olarak kabul edilir. Bununla birlikte, bir insan aynı zamanda şu anda sinir ağları tarafından ele alınmayan açık bir akıl yürütme sergiler. Gerçek dünya projelerinde, açıklama gerektiren görevleri gerçekleştirmek veya sistemin davranışını kontrollü bir şekilde değiştirebilmek için açık akıl yürütme hala kullanılmaktadır. -## 🚀 Challenge +## 🚀 Kendini Sınama -In the Family Ontology notebook associated to this lesson, there is an opportunity to experiment with other family relations. Try to discover new connections between people in the family tree. +Bu dersle ilişkili Aile Ontolojisi defterinde, diğer aile ilişkilerini deneme fırsatı vardır. Soy ağacındaki insanlar arasında yeni bağlantılar keşfetmeye çalışın. -## [Post-lecture quiz](https://red-field-0a6ddfd03.1.azurestaticapps.net/quiz/202) +## [Ders sonrası sınavı](https://red-field-0a6ddfd03.1.azurestaticapps.net/quiz/202) -## Review & Self Study +## Gözden Geçirme ve Bireysel Çalışma -Do some research on the internet to discover areas where humans have tried to quantify and codify knowledge. Take a look at Bloom's Taxonomy, and go back in history to learn how humans tried to make sense of their world. Explore the work of Linnaeus to create a taxonomy of organisms, and observe the way Dmitri Mendeleev created a way for chemical elements to be described and grouped. What other interesting examples can you find? +İnsanların bilgiyi ölçmeye ve kodlamaya çalıştığı alanları keşfetmek için internette biraz araştırma yapın. Bloom'un Taksonomisine bir göz atın ve insanların dünyalarını nasıl anlamlandırmaya çalıştıklarını öğrenmek için tarihe bakın. Linnaeus'un bir organizma sınıflandırması yaratma çalışmalarını keşfedin ve Dmitri Mendeleev'in kimyasal elementlerin tanımlanması ve gruplandırılması için yarattığını yolu gözlemleyin. Başka hangi ilginç örnekleri bulabilirsiniz? -**Assignment**: [Build an Ontology](assignment.md) +**Ödev**: [Bir Ontoloji Oluşturun](assignment.tr.md) From f8c3007f67461254471e50603d39728b062b7292 Mon Sep 17 00:00:00 2001 From: semercim Date: Mon, 29 Aug 2022 13:00:12 +0200 Subject: [PATCH 10/38] Translating lesson 2 to Turkish. --- lessons/2-Symbolic/translations/README.tr.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lessons/2-Symbolic/translations/README.tr.md b/lessons/2-Symbolic/translations/README.tr.md index 4ff0fac6..943c169b 100644 --- a/lessons/2-Symbolic/translations/README.tr.md +++ b/lessons/2-Symbolic/translations/README.tr.md @@ -216,7 +216,7 @@ Aile ilişkileri hakkında akıl yürütmede Anlamsal Web tekniklerini kullanma Böyle bir girişim Microsoft Research tarafından yapıldı ve [Microsoft Kavram Çizgesi](https://blogs.microsoft.com/ai/microsoft-researchers-release-graph-that-helps-machines-conceptualize/?WT.mc_id=academic-57639-dmitryso) ile sonuçlandı. -It is a large collection of entities grouped together using `is-a` inheritance relationship. It allows answering questions like "What is Microsoft?" - the answer being something like "a company with probability 0.87, and a brand with probability 0.75". `is-a` (bir örneği olma) kalıtım ilişkisi kullanılarak gruplandırılmış geniş bir varlıklar topluluğudur. "Microsoft Nedir?" gibi soruların yanıtlanmasına olanak tanır - cevap, "0.87 bir şirket ve 0.75 olasılıkla bir marka" gibi bir şeydir. +It is a large collection of entities grouped together using `is-a` inheritance relationship. It allows answering questions like "What is Microsoft?" - the answer being something like "a company with probability 0.87, and a brand with probability 0.75". `is-a` (bir örneği olma) kalıtım ilişkisi kullanılarak gruplandırılmış geniş bir varlıklar topluluğudur. "Microsoft Nedir?" gibi soruların yanıtlanmasına olanak tanır - cevap, "0.87 olasılıkla bir şirket ve 0.75 olasılıkla bir marka" gibi bir şeydir. Çizge, ya REST API olarak ya da tüm varlık çiftlerini listeleyen büyük bir indirilebilir metin dosyası olarak mevcuttur. From 4b3cb5b732675b4d9828e383c7956818da841b02 Mon Sep 17 00:00:00 2001 From: semercim Date: Mon, 29 Aug 2022 13:01:19 +0200 Subject: [PATCH 11/38] Translating lesson 2 to Turkish. --- lessons/2-Symbolic/translations/README.tr.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lessons/2-Symbolic/translations/README.tr.md b/lessons/2-Symbolic/translations/README.tr.md index 943c169b..31427b0a 100644 --- a/lessons/2-Symbolic/translations/README.tr.md +++ b/lessons/2-Symbolic/translations/README.tr.md @@ -216,7 +216,7 @@ Aile ilişkileri hakkında akıl yürütmede Anlamsal Web tekniklerini kullanma Böyle bir girişim Microsoft Research tarafından yapıldı ve [Microsoft Kavram Çizgesi](https://blogs.microsoft.com/ai/microsoft-researchers-release-graph-that-helps-machines-conceptualize/?WT.mc_id=academic-57639-dmitryso) ile sonuçlandı. -It is a large collection of entities grouped together using `is-a` inheritance relationship. It allows answering questions like "What is Microsoft?" - the answer being something like "a company with probability 0.87, and a brand with probability 0.75". `is-a` (bir örneği olma) kalıtım ilişkisi kullanılarak gruplandırılmış geniş bir varlıklar topluluğudur. "Microsoft Nedir?" gibi soruların yanıtlanmasına olanak tanır - cevap, "0.87 olasılıkla bir şirket ve 0.75 olasılıkla bir marka" gibi bir şeydir. +`is-a` (bir örneği olma) kalıtım ilişkisi kullanılarak gruplandırılmış geniş bir varlıklar topluluğudur. "Microsoft Nedir?" gibi soruların yanıtlanmasına olanak tanır - cevap, "0.87 olasılıkla bir şirket ve 0.75 olasılıkla bir marka" gibi bir şeydir. Çizge, ya REST API olarak ya da tüm varlık çiftlerini listeleyen büyük bir indirilebilir metin dosyası olarak mevcuttur. From 7578b1042c23427af6bb7809648260d00449b489 Mon Sep 17 00:00:00 2001 From: semercim Date: Tue, 30 Aug 2022 22:12:46 +0200 Subject: [PATCH 12/38] Translating lesson 2 to Turkish. --- lessons/2-Symbolic/Animals.ipynb | 874 +++++++++++++++---------------- 1 file changed, 426 insertions(+), 448 deletions(-) diff --git a/lessons/2-Symbolic/Animals.ipynb b/lessons/2-Symbolic/Animals.ipynb index f511ed76..18f8edf2 100644 --- a/lessons/2-Symbolic/Animals.ipynb +++ b/lessons/2-Symbolic/Animals.ipynb @@ -1,463 +1,441 @@ { - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "collapsed": true - }, - "source": [ - "# Implementing an Animal Expert System\n", - "\n", - "An example from [AI for Beginners Curriculum](http://github.com/microsoft/ai-for-beginners).\n", - "\n", - "In this sample, we will implement a simple knowledge-based system to determine an animal based on some physical characteristics. The system can be represented by the following AND-OR tree (this is a part of the whole tree, we can easily add some more rules):\n", - "\n", - "![](images/AND-OR-Tree.png)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Our own expert systems shell with backward inference\n", - "\n", - "Let's try to define a simple language for knowledge representation based on production rules. We will use Python classes as keywords to define rules. There would be essentially 3 types of classes:\n", - "* `Ask` represents a question that needs to be asked to the user. It contains the set of possible answers.\n", - "* `If` represents a rule, and it is just a syntactic sugar to store the content of the rule\n", - "* `AND`/`OR` are classes to represent AND/OR branches of the tree. They just store the list of arguments inside. To simplify code, all functionality is defined in the parent class `Content`" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "trusted": true - }, - "outputs": [], - "source": [ - "class Ask():\n", - " def __init__(self,choices=['y','n']):\n", - " self.choices = choices\n", - " def ask(self):\n", - " if max([len(x) for x in self.choices])>1:\n", - " for i,x in enumerate(self.choices):\n", - " print(\"{0}. {1}\".format(i,x),flush=True)\n", - " x = int(input())\n", - " return self.choices[x]\n", - " else:\n", - " print(\"/\".join(self.choices),flush=True)\n", - " return input()\n", - "\n", - "class Content():\n", - " def __init__(self,x):\n", - " self.x=x\n", - " \n", - "class If(Content):\n", - " pass\n", - "\n", - "class AND(Content):\n", - " pass\n", - "\n", - "class OR(Content):\n", - " pass" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "In our system, working memory would contain the list of **facts** as **attribute-value pairs**. The knowledgebase can be defined as one big dictionary that maps actions (new facts that should be inserted into working memory) to conditions, expressed as AND-OR expressions. Also, some facts can be `Ask`-ed." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "trusted": true - }, - "outputs": [], - "source": [ - "rules = {\n", - " 'default': Ask(['y','n']),\n", - " 'color' : Ask(['red-brown','black and white','other']),\n", - " 'pattern' : Ask(['dark stripes','dark spots']),\n", - " 'mammal': If(OR(['hair','gives milk'])),\n", - " 'carnivor': If(OR([AND(['sharp teeth','claws','forward-looking eyes']),'eats meat'])),\n", - " 'ungulate': If(['mammal',OR(['has hooves','chews cud'])]),\n", - " 'bird': If(OR(['feathers',AND(['flies','lies eggs'])])),\n", - " 'animal:monkey' : If(['mammal','carnivor','color:red-brown','pattern:dark spots']),\n", - " 'animal:tiger' : If(['mammal','carnivor','color:red-brown','pattern:dark stripes']),\n", - " 'animal:giraffe' : If(['ungulate','long neck','long legs','pattern:dark spots']),\n", - " 'animal:zebra' : If(['ungulate','pattern:dark stripes']),\n", - " 'animal:ostrich' : If(['bird','long nech','color:black and white','cannot fly']),\n", - " 'animal:pinguin' : If(['bird','swims','color:black and white','cannot fly']),\n", - " 'animal:albatross' : If(['bird','flies well'])\n", - "}" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To perform the backward inference, we will define `Knowledgebase` class. It will contain:\n", - "* Working `memory` - a dictionary that maps attributes to values\n", - "* Knowledgebase `rules` in the format as defined above\n", - "\n", - "Two main methods are:\n", - "* `get` to obtain the value of an attribute, performing inference if necessary. For example, `get('color')` would get the value of a color slot (it will ask if necessary, and store the value for later usage in the working memory). If we ask `get('color:blue')`, it will ask for a color, and then return `y`/`n` value depending on the color.\n", - "* `eval` performs the actual inference, i.e. traverses AND/OR tree, evaluates sub-goals, etc." - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": { - "trusted": true - }, - "outputs": [], - "source": [ - "class KnowledgeBase():\n", - " def __init__(self,rules):\n", - " self.rules = rules\n", - " self.memory = {}\n", - " \n", - " def get(self,name):\n", - " if ':' in name:\n", - " k,v = name.split(':')\n", - " vv = self.get(k)\n", - " return 'y' if v==vv else 'n'\n", - " if name in self.memory.keys():\n", - " return self.memory[name]\n", - " for fld in self.rules.keys():\n", - " if fld==name or fld.startswith(name+\":\"):\n", - " # print(\" + proving {}\".format(fld))\n", - " value = 'y' if fld==name else fld.split(':')[1]\n", - " res = self.eval(self.rules[fld],field=name)\n", - " if res!='y' and res!='n' and value=='y':\n", - " self.memory[name] = res\n", - " return res\n", - " if res=='y':\n", - " self.memory[name] = value\n", - " return value\n", - " # field is not found, using default\n", - " res = self.eval(self.rules['default'],field=name)\n", - " self.memory[name]=res\n", - " return res\n", - " \n", - " def eval(self,expr,field=None):\n", - " # print(\" + eval {}\".format(expr))\n", - " if isinstance(expr,Ask):\n", - " print(field)\n", - " return expr.ask()\n", - " elif isinstance(expr,If):\n", - " return self.eval(expr.x)\n", - " elif isinstance(expr,AND) or isinstance(expr,list):\n", - " expr = expr.x if isinstance(expr,AND) else expr\n", - " for x in expr:\n", - " if self.eval(x)=='n':\n", - " return 'n'\n", - " return 'y'\n", - " elif isinstance(expr,OR):\n", - " for x in expr.x:\n", - " if self.eval(x)=='y':\n", - " return 'y'\n", - " return 'n'\n", - " elif isinstance(expr,str):\n", - " return self.get(expr)\n", - " else:\n", - " print(\"Unknown expr: {}\".format(expr))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's define our animal knowledgebase and perform the consultation. Note that this call will ask you questions. You can answer by typing `y`/`n` for yes-no questions, or by specifying number (0..N) for questions with longer multiple-choice answers." - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": { - "trusted": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "hair\n", - "y/n\n", - "sharp teeth\n", - "y/n\n", - "claws\n", - "y/n\n", - "eats meat\n", - "y/n\n", - "color\n", - "0. red-brown\n", - "1. black and white\n", - "2. other\n", - "pattern\n", - "0. dark stripes\n", - "1. dark spots\n" - ] - }, - { - "data": { - "text/plain": [ - "'monkey'" - ] - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "kb = KnowledgeBase(rules)\n", - "kb.get('animal')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Using PyKnow for Forward Inference\n", - "\n", - "In the next example, we will try to implement forward inference using one of the libraries for knowledge representation, [PyKnow](https://github.com/buguroo/pyknow/). **PyKnow** is a library for creating forward inference systems in Python, which is designed to be similar to classical old system [CLIPS](http://www.clipsrules.net/index.html). \n", - "\n", - "We could have also implemented forward chaining ourselves without many problems, but naive implementations are usually not very efficient. For more effective rule matching a special algorithm [Rete](https://en.wikipedia.org/wiki/Rete_algorithm) is used." - ] - }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Implementing an Animal Expert System\n", + "\n", + "An example from [AI for Beginners Curriculum](http://github.com/microsoft/ai-for-beginners).\n", + "\n", + "In this sample, we will implement a simple knowledge-based system to determine an animal based on some physical characteristics. The system can be represented by the following AND-OR tree (this is a part of the whole tree, we can easily add some more rules):\n", + "\n", + "![](images/AND-OR-Tree.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Our own expert systems shell with backward inference\n", + "\n", + "Let's try to define a simple language for knowledge representation based on production rules. We will use Python classes as keywords to define rules. There would be essentially 3 types of classes:\n", + "* `Ask` represents a question that needs to be asked to the user. It contains the set of possible answers.\n", + "* `If` represents a rule, and it is just a syntactic sugar to store the content of the rule\n", + "* `AND`/`OR` are classes to represent AND/OR branches of the tree. They just store the list of arguments inside. To simplify code, all functionality is defined in the parent class `Content`" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "class Ask():\n", + " def __init__(self,choices=['y','n']):\n", + " self.choices = choices\n", + " def ask(self):\n", + " if max([len(x) for x in self.choices])>1:\n", + " for i,x in enumerate(self.choices):\n", + " print(\"{0}. {1}\".format(i,x),flush=True)\n", + " x = int(input())\n", + " return self.choices[x]\n", + " else:\n", + " print(\"/\".join(self.choices),flush=True)\n", + " return input()\n", + "\n", + "class Content():\n", + " def __init__(self,x):\n", + " self.x=x\n", + " \n", + "class If(Content):\n", + " pass\n", + "\n", + "class AND(Content):\n", + " pass\n", + "\n", + "class OR(Content):\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In our system, working memory would contain the list of **facts** as **attribute-value pairs**. The knowledgebase can be defined as one big dictionary that maps actions (new facts that should be inserted into working memory) to conditions, expressed as AND-OR expressions. Also, some facts can be `Ask`-ed." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "rules = {\n", + " 'default': Ask(['y','n']),\n", + " 'color' : Ask(['red-brown','black and white','other']),\n", + " 'pattern' : Ask(['dark stripes','dark spots']),\n", + " 'mammal': If(OR(['hair','gives milk'])),\n", + " 'carnivor': If(OR([AND(['sharp teeth','claws','forward-looking eyes']),'eats meat'])),\n", + " 'ungulate': If(['mammal',OR(['has hooves','chews cud'])]),\n", + " 'bird': If(OR(['feathers',AND(['flies','lies eggs'])])),\n", + " 'animal:monkey' : If(['mammal','carnivor','color:red-brown','pattern:dark spots']),\n", + " 'animal:tiger' : If(['mammal','carnivor','color:red-brown','pattern:dark stripes']),\n", + " 'animal:giraffe' : If(['ungulate','long neck','long legs','pattern:dark spots']),\n", + " 'animal:zebra' : If(['ungulate','pattern:dark stripes']),\n", + " 'animal:ostrich' : If(['bird','long neck','color:black and white','cannot fly']),\n", + " 'animal:pinguin' : If(['bird','swims','color:black and white','cannot fly']),\n", + " 'animal:albatross' : If(['bird','flies well'])\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To perform the backward inference, we will define `Knowledgebase` class. It will contain:\n", + "* Working `memory` - a dictionary that maps attributes to values\n", + "* Knowledgebase `rules` in the format as defined above\n", + "\n", + "Two main methods are:\n", + "* `get` to obtain the value of an attribute, performing inference if necessary. For example, `get('color')` would get the value of a color slot (it will ask if necessary, and store the value for later usage in the working memory). If we ask `get('color:blue')`, it will ask for a color, and then return `y`/`n` value depending on the color.\n", + "* `eval` performs the actual inference, i.e. traverses AND/OR tree, evaluates sub-goals, etc." + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [], + "source": [ + "class KnowledgeBase():\n", + " def __init__(self,rules):\n", + " self.rules = rules\n", + " self.memory = {}\n", + " \n", + " def get(self,name):\n", + " if ':' in name:\n", + " k,v = name.split(':')\n", + " vv = self.get(k)\n", + " return 'y' if v==vv else 'n'\n", + " if name in self.memory.keys():\n", + " return self.memory[name]\n", + " for fld in self.rules.keys():\n", + " if fld==name or fld.startswith(name+\":\"):\n", + " # print(\" + proving {}\".format(fld))\n", + " value = 'y' if fld==name else fld.split(':')[1]\n", + " res = self.eval(self.rules[fld],field=name)\n", + " if res!='y' and res!='n' and value=='y':\n", + " self.memory[name] = res\n", + " return res\n", + " if res=='y':\n", + " self.memory[name] = value\n", + " return value\n", + " # field is not found, using default\n", + " res = self.eval(self.rules['default'],field=name)\n", + " self.memory[name]=res\n", + " return res\n", + " \n", + " def eval(self,expr,field=None):\n", + " # print(\" + eval {}\".format(expr))\n", + " if isinstance(expr,Ask):\n", + " print(field)\n", + " return expr.ask()\n", + " elif isinstance(expr,If):\n", + " return self.eval(expr.x)\n", + " elif isinstance(expr,AND) or isinstance(expr,list):\n", + " expr = expr.x if isinstance(expr,AND) else expr\n", + " for x in expr:\n", + " if self.eval(x)=='n':\n", + " return 'n'\n", + " return 'y'\n", + " elif isinstance(expr,OR):\n", + " for x in expr.x:\n", + " if self.eval(x)=='y':\n", + " return 'y'\n", + " return 'n'\n", + " elif isinstance(expr,str):\n", + " return self.get(expr)\n", + " else:\n", + " print(\"Unknown expr: {}\".format(expr))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's define our animal knowledgebase and perform the consultation. Note that this call will ask you questions. You can answer by typing `y`/`n` for yes-no questions, or by specifying number (0..N) for questions with longer multiple-choice answers." + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 36, - "metadata": { - "trusted": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Collecting git+https://github.com/buguroo/pyknow/\n", - " Cloning https://github.com/buguroo/pyknow/ to c:\\users\\dmitryso\\appdata\\local\\temp\\pip-req-build-3iv4twpl\n", - "Collecting frozendict==1.2\n", - " Using cached frozendict-1.2.tar.gz (2.6 kB)\n", - "Collecting schema==0.6.7\n", - " Using cached schema-0.6.7-py2.py3-none-any.whl (14 kB)\n", - "Building wheels for collected packages: pyknow, frozendict\n", - " Building wheel for pyknow (setup.py): started\n", - " Building wheel for pyknow (setup.py): finished with status 'done'\n", - " Created wheel for pyknow: filename=pyknow-1.7.0-py3-none-any.whl size=34580 sha256=334cc7a6eb47459f488db594e8537d7d33d2865c2dbcdd44854146c5c27608e3\n", - " Stored in directory: C:\\Users\\dmitryso\\AppData\\Local\\Temp\\pip-ephem-wheel-cache-l_g7bnq7\\wheels\\96\\36\\bd\\ee1de50bbcf2c7a323dead05584cf90db8898524cf7f57f488\n", - " Building wheel for frozendict (setup.py): started\n", - " Building wheel for frozendict (setup.py): finished with status 'done'\n", - " Created wheel for frozendict: filename=frozendict-1.2-py3-none-any.whl size=3146 sha256=71e32ca6c8ad7e0413bdc9a38f5882a36ba0509e562564a69904fcc9c8b66a9b\n", - " Stored in directory: c:\\users\\dmitryso\\appdata\\local\\pip\\cache\\wheels\\5b\\fa\\ab\\0a80360debb57b95f092356ee3a075bbbffc631b9813136599\n", - "Successfully built pyknow frozendict\n", - "Installing collected packages: schema, frozendict, pyknow\n", - "Successfully installed frozendict-1.2 pyknow-1.7.0 schema-0.6.7\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - " Running command git clone -q https://github.com/buguroo/pyknow/ 'C:\\Users\\dmitryso\\AppData\\Local\\Temp\\pip-req-build-3iv4twpl'\n" - ] - } - ], - "source": [ - "import sys\n", - "!{sys.executable} -m pip install git+https://github.com/buguroo/pyknow/" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "hair\n", + "y/n\n", + "sharp teeth\n", + "y/n\n", + "claws\n", + "y/n\n", + "eats meat\n", + "y/n\n", + "color\n", + "0. red-brown\n", + "1. black and white\n", + "2. other\n", + "pattern\n", + "0. dark stripes\n", + "1. dark spots\n" + ] }, { - "cell_type": "code", - "execution_count": 37, - "metadata": { - "trusted": true - }, - "outputs": [], - "source": [ - "from pyknow import *" + "data": { + "text/plain": [ + "'monkey'" ] - }, + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "kb = KnowledgeBase(rules)\n", + "kb.get('animal')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Using PyKnow for Forward Inference\n", + "\n", + "In the next example, we will try to implement forward inference using one of the libraries for knowledge representation, [PyKnow](https://github.com/buguroo/pyknow/). **PyKnow** is a library for creating forward inference systems in Python, which is designed to be similar to classical old system [CLIPS](http://www.clipsrules.net/index.html). \n", + "\n", + "We could have also implemented forward chaining ourselves without many problems, but naive implementations are usually not very efficient. For more effective rule matching a special algorithm [Rete](https://en.wikipedia.org/wiki/Rete_algorithm) is used." + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We will define our system as a class that subclasses `KnowledgeEngine`. Each rule is defined by a separate function with `@Rule` annotation, which specifies when the rule should fire. Inside the rule, we can add new facts using `declare` function, and adding those facts will result in some more rules being called by forward inference engine. " - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "Collecting git+https://github.com/buguroo/pyknow/\n", + " Cloning https://github.com/buguroo/pyknow/ to c:\\users\\dmitryso\\appdata\\local\\temp\\pip-req-build-3iv4twpl\n", + "Collecting frozendict==1.2\n", + " Using cached frozendict-1.2.tar.gz (2.6 kB)\n", + "Collecting schema==0.6.7\n", + " Using cached schema-0.6.7-py2.py3-none-any.whl (14 kB)\n", + "Building wheels for collected packages: pyknow, frozendict\n", + " Building wheel for pyknow (setup.py): started\n", + " Building wheel for pyknow (setup.py): finished with status 'done'\n", + " Created wheel for pyknow: filename=pyknow-1.7.0-py3-none-any.whl size=34580 sha256=334cc7a6eb47459f488db594e8537d7d33d2865c2dbcdd44854146c5c27608e3\n", + " Stored in directory: C:\\Users\\dmitryso\\AppData\\Local\\Temp\\pip-ephem-wheel-cache-l_g7bnq7\\wheels\\96\\36\\bd\\ee1de50bbcf2c7a323dead05584cf90db8898524cf7f57f488\n", + " Building wheel for frozendict (setup.py): started\n", + " Building wheel for frozendict (setup.py): finished with status 'done'\n", + " Created wheel for frozendict: filename=frozendict-1.2-py3-none-any.whl size=3146 sha256=71e32ca6c8ad7e0413bdc9a38f5882a36ba0509e562564a69904fcc9c8b66a9b\n", + " Stored in directory: c:\\users\\dmitryso\\appdata\\local\\pip\\cache\\wheels\\5b\\fa\\ab\\0a80360debb57b95f092356ee3a075bbbffc631b9813136599\n", + "Successfully built pyknow frozendict\n", + "Installing collected packages: schema, frozendict, pyknow\n", + "Successfully installed frozendict-1.2 pyknow-1.7.0 schema-0.6.7\n" + ] }, { - "cell_type": "code", - "execution_count": 39, - "metadata": { - "trusted": true - }, - "outputs": [], - "source": [ - "class Animals(KnowledgeEngine):\n", - " @Rule(OR(\n", - " AND(Fact('sharp teeth'),Fact('claws'),Fact('forward looking eyes')),\n", - " Fact('eats meat')))\n", - " def cornivor(self):\n", - " self.declare(Fact('carnivor'))\n", - " \n", - " @Rule(OR(Fact('hair'),Fact('gives milk')))\n", - " def mammal(self):\n", - " self.declare(Fact('mammal'))\n", - "\n", - " @Rule(Fact('mammal'),\n", - " OR(Fact('has hooves'),Fact('chews cud')))\n", - " def hooves(self):\n", - " self.declare('ungulate')\n", - " \n", - " @Rule(OR(Fact('feathers'),AND(Fact('flies'),Fact('lays eggs'))))\n", - " def bird(self):\n", - " self.declare('bird')\n", - " \n", - " @Rule(Fact('mammal'),Fact('carnivor'),\n", - " Fact(color='red-brown'),\n", - " Fact(pattern='dark spots'))\n", - " def monkey(self):\n", - " self.declare(Fact(animal='monkey'))\n", - "\n", - " @Rule(Fact('mammal'),Fact('carnivor'),\n", - " Fact(color='red-brown'),\n", - " Fact(pattern='dark stripes'))\n", - " def tiger(self):\n", - " self.declare(Fact(animal='tiger'))\n", - "\n", - " @Rule(Fact('ungulate'),\n", - " Fact('long neck'),\n", - " Fact('long legs'),\n", - " Fact(pattern='dark spots'))\n", - " def giraffe(self):\n", - " self.declare(Fact(animal='giraffe'))\n", - "\n", - " @Rule(Fact('ungulate'),\n", - " Fact(pattern='dark stripes'))\n", - " def zebra(self):\n", - " self.declare(Fact(animal='zebra'))\n", - "\n", - " @Rule(Fact('bird'),\n", - " Fact('long neck'),\n", - " Fact('cannot fly'),\n", - " Fact(color='black and white'))\n", - " def straus(self):\n", - " self.declare(Fact(animal='ostrich'))\n", - "\n", - " @Rule(Fact('bird'),\n", - " Fact('swims'),\n", - " Fact('cannot fly'),\n", - " Fact(color='black and white'))\n", - " def pinguin(self):\n", - " self.declare(Fact(animal='pinguin'))\n", - "\n", - " @Rule(Fact('bird'),\n", - " Fact('flies well'))\n", - " def albatros(self):\n", - " self.declare(Fact(animal='albatross'))\n", - " \n", - " @Rule(Fact(animal=MATCH.a))\n", - " def print_result(self,a):\n", - " print('Animal is {}'.format(a))\n", - " \n", - " def factz(self,l):\n", - " for x in l:\n", - " self.declare(x)" - ] - }, + "name": "stderr", + "output_type": "stream", + "text": [ + " Running command git clone -q https://github.com/buguroo/pyknow/ 'C:\\Users\\dmitryso\\AppData\\Local\\Temp\\pip-req-build-3iv4twpl'\n" + ] + } + ], + "source": [ + "import sys\n", + "!{sys.executable} -m pip install git+https://github.com/buguroo/pyknow/" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [], + "source": [ + "from pyknow import *" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will define our system as a class that subclasses `KnowledgeEngine`. Each rule is defined by a separate function with `@Rule` annotation, which specifies when the rule should fire. Inside the rule, we can add new facts using `declare` function, and adding those facts will result in some more rules being called by forward inference engine. " + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [], + "source": [ + "class Animals(KnowledgeEngine):\n", + " @Rule(OR(\n", + " AND(Fact('sharp teeth'),Fact('claws'),Fact('forward looking eyes')),\n", + " Fact('eats meat')))\n", + " def cornivor(self):\n", + " self.declare(Fact('carnivor'))\n", + " \n", + " @Rule(OR(Fact('hair'),Fact('gives milk')))\n", + " def mammal(self):\n", + " self.declare(Fact('mammal'))\n", + "\n", + " @Rule(Fact('mammal'),\n", + " OR(Fact('has hooves'),Fact('chews cud')))\n", + " def hooves(self):\n", + " self.declare('ungulate')\n", + " \n", + " @Rule(OR(Fact('feathers'),AND(Fact('flies'),Fact('lays eggs'))))\n", + " def bird(self):\n", + " self.declare('bird')\n", + " \n", + " @Rule(Fact('mammal'),Fact('carnivor'),\n", + " Fact(color='red-brown'),\n", + " Fact(pattern='dark spots'))\n", + " def monkey(self):\n", + " self.declare(Fact(animal='monkey'))\n", + "\n", + " @Rule(Fact('mammal'),Fact('carnivor'),\n", + " Fact(color='red-brown'),\n", + " Fact(pattern='dark stripes'))\n", + " def tiger(self):\n", + " self.declare(Fact(animal='tiger'))\n", + "\n", + " @Rule(Fact('ungulate'),\n", + " Fact('long neck'),\n", + " Fact('long legs'),\n", + " Fact(pattern='dark spots'))\n", + " def giraffe(self):\n", + " self.declare(Fact(animal='giraffe'))\n", + "\n", + " @Rule(Fact('ungulate'),\n", + " Fact(pattern='dark stripes'))\n", + " def zebra(self):\n", + " self.declare(Fact(animal='zebra'))\n", + "\n", + " @Rule(Fact('bird'),\n", + " Fact('long neck'),\n", + " Fact('cannot fly'),\n", + " Fact(color='black and white'))\n", + " def straus(self):\n", + " self.declare(Fact(animal='ostrich'))\n", + "\n", + " @Rule(Fact('bird'),\n", + " Fact('swims'),\n", + " Fact('cannot fly'),\n", + " Fact(color='black and white'))\n", + " def pinguin(self):\n", + " self.declare(Fact(animal='pinguin'))\n", + "\n", + " @Rule(Fact('bird'),\n", + " Fact('flies well'))\n", + " def albatros(self):\n", + " self.declare(Fact(animal='albatross'))\n", + " \n", + " @Rule(Fact(animal=MATCH.a))\n", + " def print_result(self,a):\n", + " print('Animal is {}'.format(a))\n", + " \n", + " def factz(self,l):\n", + " for x in l:\n", + " self.declare(x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Once we have defined a knowledgebase, we populate our working memory with some initial facts, and then call `run()` method to perform the inference. You can see as a result that new inferred facts are added to the working memory, including the final fact about the animal (if we set up all the initial facts correctly)." + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Once we have defined a knowledgebase, we populate our working memory with some initial facts, and then call `run()` method to perform the inference. You can see as a result that new inferred facts are added to the working memory, including the final fact about the animal (if we set up all the initial facts correctly)." - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "Animal is tiger\n" + ] }, { - "cell_type": "code", - "execution_count": 43, - "metadata": { - "trusted": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Animal is tiger\n" - ] - }, - { - "data": { - "text/plain": [ - "FactList([(0, InitialFact()),\n", - " (1, Fact(color='red-brown')),\n", - " (2, Fact(pattern='dark stripes')),\n", - " (3, Fact('sharp teeth')),\n", - " (4, Fact('claws')),\n", - " (5, Fact('forward looking eyes')),\n", - " (6, Fact('gives milk')),\n", - " (7, Fact('mammal')),\n", - " (8, Fact('carnivor')),\n", - " (9, Fact(animal='tiger'))])" - ] - }, - "execution_count": 43, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "ex1 = Animals()\n", - "ex1.reset()\n", - "ex1.factz([\n", - " Fact(color='red-brown'),\n", - " Fact(pattern='dark stripes'),\n", - " Fact('sharp teeth'),\n", - " Fact('claws'),\n", - " Fact('forward looking eyes'),\n", - " Fact('gives milk')])\n", - "ex1.run()\n", - "ex1.facts" + "data": { + "text/plain": [ + "FactList([(0, InitialFact()),\n", + " (1, Fact(color='red-brown')),\n", + " (2, Fact(pattern='dark stripes')),\n", + " (3, Fact('sharp teeth')),\n", + " (4, Fact('claws')),\n", + " (5, Fact('forward looking eyes')),\n", + " (6, Fact('gives milk')),\n", + " (7, Fact('mammal')),\n", + " (8, Fact('carnivor')),\n", + " (9, Fact(animal='tiger'))])" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3.7.4 64-bit (conda)", - "metadata": { - "interpreter": { - "hash": "86193a1ab0ba47eac1c69c1756090baa3b420b3eea7d4aafab8b85f8b312f0c5" - } - }, - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.9.5" + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" } + ], + "source": [ + "ex1 = Animals()\n", + "ex1.reset()\n", + "ex1.factz([\n", + " Fact(color='red-brown'),\n", + " Fact(pattern='dark stripes'),\n", + " Fact('sharp teeth'),\n", + " Fact('claws'),\n", + " Fact('forward looking eyes'),\n", + " Fact('gives milk')])\n", + "ex1.run()\n", + "ex1.facts" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" }, - "nbformat": 4, - "nbformat_minor": 2 + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 } From eec53d502fedab075cbc7ba9a2d7ebf6d0e8c60b Mon Sep 17 00:00:00 2001 From: semercim Date: Tue, 30 Aug 2022 22:13:17 +0200 Subject: [PATCH 13/38] Translating lesson 2 to Turkish. --- .../2-Symbolic/translations/Animals.tr.ipynb | 350 ++++++++++++++++++ .../translations/FamilyOntology.tr.ipynb | 343 +++++++++++++++++ .../translations/MSConceptGraph.tr.ipynb | 184 +++++++++ 3 files changed, 877 insertions(+) create mode 100644 lessons/2-Symbolic/translations/Animals.tr.ipynb create mode 100644 lessons/2-Symbolic/translations/FamilyOntology.tr.ipynb create mode 100644 lessons/2-Symbolic/translations/MSConceptGraph.tr.ipynb diff --git a/lessons/2-Symbolic/translations/Animals.tr.ipynb b/lessons/2-Symbolic/translations/Animals.tr.ipynb new file mode 100644 index 00000000..5d2b9862 --- /dev/null +++ b/lessons/2-Symbolic/translations/Animals.tr.ipynb @@ -0,0 +1,350 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Bir Hayvan Uzman Sisteminin Uygulanması\n", + "\n", + "[Yeni Başlayanlar için YZ Müfredatı](http://github.com/microsoft/ai-for-beginners)'ndan bir örnek.\n", + "\n", + "Bu örnekte, bazı fiziksel özelliklere dayalı olarak bir hayvanı belirlemek için basit bir bilgiye dayalı sistemi uygulayacağız. Sistem aşağıdaki VE-VEYA ağacı ile temsil edilebilir (bu, tüm ağacın bir parçasıdır, kolayca daha fazla kural ekleyebiliriz):\n", + "\n", + "![](../images/AND-OR-Tree.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Geriye dönük çıkarsamalı kendi uzman sistemlerimizin kabuğu\n", + "\n", + "Üretme kurallarına dayalı bilgi temsili için basit bir dil tanımlamaya çalışalım. Kuralları tanımlamada anahtar kelimeler olarak Python sınıflarını kullanacağız. Temel olarak 3 tür sınıf olacaktır:\n", + "* `Sor`, kullanıcıya sorulması gereken bir soruyu temsil eder. Olası cevaplar kümesini içerir.\n", + "* `If` represents a rule, and it is just a syntactic sugar to store the content of the rule\n", + "* `Eger` bir kuralı temsil eder ve sadece kuralın içeriğini saklamak için sözdizimsel bir bileşendir.\n", + "* `VE`/`VEYA`, ağacın VE/VEYA dallarını temsil eden sınıflardır. Sadece argümanların listesini içeride saklarlar. Kodu basitleştirmek için, tüm işlevler `Icerik` üst sınıfında tanımlanmıştır." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class Sor():\n", + " def __init__(self,tercihler=['e','h']):\n", + " self.tercihler = tercihler\n", + " def sor(self):\n", + " if max([len(x) for x in self.tercihler])>1:\n", + " for i,x in enumerate(self.tercihler):\n", + " print(\"{0}. {1}\".format(i,x),flush=True)\n", + " x = int(input())\n", + " return self.tercihler[x]\n", + " else:\n", + " print(\"/\".join(self.tercihler),flush=True)\n", + " return input()\n", + "\n", + "class Icerik():\n", + " def __init__(self,x):\n", + " self.x=x\n", + " \n", + "class Eger(Icerik):\n", + " pass\n", + "\n", + "class VE(Icerik):\n", + " pass\n", + "\n", + "class VEYA(Icerik):\n", + " pass" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Sistemimizde, çalışan bellek, **nitelik-değer çiftleri** olarak **olguların (gerçeklerin)** listesini içerir. Bilgi tabanı, eylemleri (çalışan belleğe eklenmesi gereken yeni gerçekleri) VE-VEYA ifadeleri olarak ifade edilen koşullara eşleyen büyük bir sözlük olarak tanımlanabilir. Ayrıca, bazı gerçekler `Sor`-ulabilir." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "kurallar = {\n", + " 'varsayilan': Sor(['e','h']),\n", + " 'renk' : Sor(['kirmizi-kahverengi','siyah ve beyaz','diger']),\n", + " 'desen' : Sor(['koyu seritler','koyu benekler']),\n", + " 'memeli': Eger(VEYA(['killi','sut verir'])),\n", + " 'etcil': Eger(VEYA([VE(['sivri disler','penceler','ileriye bakan gozler']),'et yer'])),\n", + " 'toynakli': Eger(['memeli',VEYA(['toynaklari var','gevis getirir'])]),\n", + " 'kus': Eger(VEYA(['tuylu',VE(['ucar','yumurta verir'])])),\n", + " 'hayvan:maymun' : Eger(['memeli','etcil','renk:kirmizi-kahverengi','desen:koyu benekler']),\n", + " 'hayvan:kaplan' : Eger(['memeli','etcil','renk:kirmizi-kahverengi','desen:koyu seritler']),\n", + " 'hayvan:zurafa' : Eger(['toynakli','uzun boyun','uzun bacaklar','desen:koyu benekler']),\n", + " 'hayvan:zebra' : Eger(['toynakli','desen:koyu seritler']),\n", + " 'hayvan:devekusu' : Eger(['kus','uzun boyun','renk:siyah ve beyaz','ucamaz']),\n", + " 'hayvan:penguen' : Eger(['kus','yuzer','renk:siyah ve beyaz','ucamaz']),\n", + " 'hayvan:albatros' : Eger(['kus','iyi ucar'])\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Geriye dönük çıkarsama gerçekleştirmek için `BilgiTabani` sınıfını tanımlayacağız. Şunları içerecektir:\n", + "* Çalışan `bellek` - nitelikleri değerlerle eşleştiren bir sözlük\n", + "* Yukarıda tanımlanan biçimde `kurallar` bilgi tabanı\n", + "\n", + "İki ana yöntem şunlardır:\n", + "* Bir niteliğin değerini elde etmek için `getir`, gerekirse çıkarım yapar. Örneğin, `getir('renk')` bir renk yuvasının değerini alır (gerekirse sorar ve değeri daha sonra kullanmak üzere çalışan bellekte saklar). `getir('renk:mavi')` diye sorarsak, bir renk isteyecek ve ardından renge bağlı olarak `e`/`h` değerini döndürecektir.\n", + "* `degerlendir` gerçek çıkarsamayı gerçekleştirir, yani VE/VEYA ağacında ilerler, alt hedefleri değerlendirir, vb." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class BilgiTabani():\n", + " def __init__(self,kurallar):\n", + " self.kurallar = kurallar\n", + " self.bellek = {}\n", + " \n", + " def getir(self,name):\n", + " if ':' in name:\n", + " k,v = name.split(':')\n", + " vv = self.getir(k)\n", + " return 'e' if v==vv else 'h'\n", + " if name in self.bellek.keys():\n", + " return self.bellek[name]\n", + " for fld in self.kurallar.keys():\n", + " if fld==name or fld.startswith(name+\":\"):\n", + " # print(\" + proving {}\".format(fld))\n", + " value = 'e' if fld==name else fld.split(':')[1]\n", + " res = self.degerlendir(self.kurallar[fld],field=name)\n", + " if res!='e' and res!='h' and value=='e':\n", + " self.bellek[name] = res\n", + " return res\n", + " if res=='e':\n", + " self.bellek[name] = value\n", + " return value\n", + " # field is not found, using default\n", + " res = self.degerlendir(self.kurallar['varsayilan'],field=name)\n", + " self.bellek[name]=res\n", + " return res\n", + " \n", + " def degerlendir(self,expr,field=None):\n", + " # print(\" + eval {}\".format(expr))\n", + " if isinstance(expr,Sor):\n", + " print(field)\n", + " return expr.sor()\n", + " elif isinstance(expr,Eger):\n", + " return self.degerlendir(expr.x)\n", + " elif isinstance(expr,VE) or isinstance(expr,list):\n", + " expr = expr.x if isinstance(expr,VE) else expr\n", + " for x in expr:\n", + " if self.degerlendir(x)=='h':\n", + " return 'h'\n", + " return 'e'\n", + " elif isinstance(expr,VEYA):\n", + " for x in expr.x:\n", + " if self.degerlendir(x)=='e':\n", + " return 'e'\n", + " return 'h'\n", + " elif isinstance(expr,str):\n", + " return self.getir(expr)\n", + " else:\n", + " print(\"Bilinmeyen ifade: {}\".format(expr))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Şimdi hayvan bilgi tabanımızı tanımlayalım ve incelemeyi gerçekleştirelim. Bu aramanın size sorular soracağını unutmayın. Evet-hayır soruları için `e`/`h` yazarak veya daha uzun çoktan seçmeli cevaplar için sayı (0..N) belirterek cevap verebilirsiniz." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "kb = BilgiTabani(kurallar)\n", + "kb.getir('hayvan')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## İleri Çıkarsama için PyKnow'u Kullanma\n", + "\n", + "Sonraki örnekte, bilgi temsili kütüphanelerinden biri olan [PyKnow](https://github.com/buguroo/pyknow/) kullanarak ileriye çıkarsama uygulamaya çalışacağız. **PyKnow**, klasik eski \n", + "[CLIPS](http://www.clipsrules.net/index.html) sistemine benzer şekilde tasarlanmış, Python'da ileriye çıkarsama sistemleri oluşturmaya yönelik bir kütüphanedir.\n", + "\n", + "Kendimiz ileriye zincirlemeyi pek sorun yaşamadan da uygulayabilirdik, ancak saf uygulamalar genellikle çok verimli değildir. Daha etkili kural eşleştirmesi için özel bir algoritma olan [Rete](https://en.wikipedia.org/wiki/Rete_algorithm) kullanılır." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "!{sys.executable} -m pip install git+https://github.com/buguroo/pyknow/" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from pyknow import *" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Sistemimizi `KnowledgeEngine` (BilgiMotoru) altsınıfları olan bir sınıf olarak tanımlayacağız. Her kural, kuralın ne zaman tetikleneceğini belirten `@Rule` (Kural) ek açıklamalı ayrı bir işlevle tanımlanır. Kuralın içinde, `declare` (bildirme) işlevini kullanarak yeni gerçekler ekleyebiliriz ve bu gerçekleri eklemek, ileri çıkarsama motoru tarafından daha fazla kuralın çağrılmasıyla sonuçlanacaktır." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class Hayvanlar(KnowledgeEngine):\n", + " @Rule(OR(\n", + " AND(Fact('sivri disler'),Fact('penceler'),Fact('ileriye bakan gozler')),\n", + " Fact('et yer')))\n", + " def etcil(self):\n", + " self.declare(Fact('etcil'))\n", + " \n", + " @Rule(OR(Fact('killi'),Fact('sut verir')))\n", + " def memeli(self):\n", + " self.declare(Fact('memeli'))\n", + "\n", + " @Rule(Fact('memeli'),\n", + " OR(Fact('toynaklari var'),Fact('gevis getirir')))\n", + " def toynaklar(self):\n", + " self.declare('toynakli')\n", + " \n", + " @Rule(OR(Fact('tuylu'),AND(Fact('ucar'),Fact('yumurta verir'))))\n", + " def kus(self):\n", + " self.declare('kus')\n", + " \n", + " @Rule(Fact('memeli'),Fact('etcil'),\n", + " Fact(renk='kirmizi-kahverengi'),\n", + " Fact(desen='koyu benekler'))\n", + " def maymun(self):\n", + " self.declare(Fact(hayvan='maymun'))\n", + "\n", + " @Rule(Fact('memeli'),Fact('etcil'),\n", + " Fact(renk='kirmizi-kahverengi'),\n", + " Fact(desen='koyu seritler'))\n", + " def kaplan(self):\n", + " self.declare(Fact(hayvan='kaplan'))\n", + "\n", + " @Rule(Fact('toynakli'),\n", + " Fact('uzun boyun'),\n", + " Fact('uzun bacaklar'),\n", + " Fact(desen='koyu benekler'))\n", + " def zurafa(self):\n", + " self.declare(Fact(hayvan='zurafa'))\n", + "\n", + " @Rule(Fact('toynakli'),\n", + " Fact(desen='koyu seritler'))\n", + " def zebra(self):\n", + " self.declare(Fact(hayvan='zebra'))\n", + "\n", + " @Rule(Fact('kus'),\n", + " Fact('uzun boyun'),\n", + " Fact('ucamaz'),\n", + " Fact(renk='siyah ve beyaz'))\n", + " def devekusu(self):\n", + " self.declare(Fact(hayvan='devekusu'))\n", + "\n", + " @Rule(Fact('kus'),\n", + " Fact('yuzer'),\n", + " Fact('ucamaz'),\n", + " Fact(renk='siyah ve beyaz'))\n", + " def penguen(self):\n", + " self.declare(Fact(hayvan='penguen'))\n", + "\n", + " @Rule(Fact('kus'),\n", + " Fact('iyi ucar'))\n", + " def albatros(self):\n", + " self.declare(Fact(hayvan='albatros'))\n", + " \n", + " @Rule(Fact(hayvan=MATCH.a))\n", + " def print_result(self,a):\n", + " print('Hayvan {}'.format(a))\n", + " \n", + " def factz(self,l):\n", + " for x in l:\n", + " self.declare(x)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Bir bilgi tabanı tanımladıktan sonra, çalışan belleğimizi bazı ilk gerçeklerle doldururuz ve ardından çıkarsama gerçekleştirmek için `run()` yöntemini çağırırız. Sonuç olarak, hayvanla ilgili son gerçek de dahil olmak üzere (başlangıçtaki tüm gerçekleri doğru bir şekilde kurarsak) çalışan belleğe yeni çıkarsanan gerçeklerin eklendiğini görebilirsiniz." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ex1 = Hayvanlar()\n", + "ex1.reset()\n", + "ex1.factz([\n", + " Fact(renk='kirmizi-kahverengi'),\n", + " Fact(desen='koyu seritler'),\n", + " Fact('sivri disler'),\n", + " Fact('penceler'),\n", + " Fact('ileriye bakan gozler'),\n", + " Fact('sut verir')])\n", + "ex1.run()\n", + "ex1.facts" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.12" + }, + "vscode": { + "interpreter": { + "hash": "7e1998ff7f8aa20ada591c520b972326324e5ea05489af9e422744c7c09f6dad" + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/lessons/2-Symbolic/translations/FamilyOntology.tr.ipynb b/lessons/2-Symbolic/translations/FamilyOntology.tr.ipynb new file mode 100644 index 00000000..f26360b2 --- /dev/null +++ b/lessons/2-Symbolic/translations/FamilyOntology.tr.ipynb @@ -0,0 +1,343 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Aile İlişkileri Ontolojisi\n", + "\n", + "Bu örnek, [Yeni Başlayanlar için Yapay Zeka Müfredatı](http://github.com/microsoft/ai-for-beginners)'nın bir parçasıdır ve [bu blog gönderisinden](https://habr.com/posta/270857/) esinlenilmiştir.\n", + "\n", + "Bir ailedeki insanlar arasındaki farklı ilişkileri hatırlamakta her zaman zorlanırım. Bu örnekte, aile ilişkilerini ve gerçek soy ağacını tanımlayan bir ontoloji alacağız ve daha sonra tüm akrabaları bulmak için otomatik çıkarsamayı nasıl yapabileceğimizi göstereceğiz.\n", + "\n", + "### Soy Ağacını Almak\n", + "\n", + "Örnek olarak, [Romanov Çar Ailesinin](https://en.wikipedia.org/wiki/House_of_Romanov) soy ağacını alacağız. Aile ilişkilerini tanımlamanın en yaygın biçimi [GEDCOM](https://en.wikipedia.org/wiki/GEDCOM)'dur. Romanov soy ağacını GEDCOM formatında alacağız:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!head -15 ../data/tsars.ged" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "GEDCOM dosyasını kullanmak için `python-gedcom` kütüphanesini kullanabiliriz:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "!{sys.executable} -m pip install python-gedcom" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Bu kütüphane, dosya ayrıştırmayla ilgili bazı teknik sorunları ortadan kaldırır, ancak yine de bize ağaçtaki tüm bireylere ve ailelere oldukça düşük düzeyde erişim sağlar. Dosyayı şu şekilde ayrıştırabilir ve tüm bireylerin listesini gösterebiliriz:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from gedcom.parser import Parser\n", + "from gedcom.element.individual import IndividualElement\n", + "from gedcom.element.family import FamilyElement\n", + "g = Parser()\n", + "g.parse_file('../data/tsars.ged')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "d = g.get_element_dictionary()\n", + "[ (k,v.get_name()) for k,v in d.items() if isinstance(v,IndividualElement)]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "İşte aileler hakkında bilgiyi böyle edinebiliriz. Bunun bize bir **tanımlayıcı** listesi verdiğini ve daha fazla netlik istiyorsak bunları adlara dönüştürmemiz gerektiğini unutmayın:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "d = g.get_element_dictionary()\n", + "[ (k,[x.get_value() for x in v.get_child_elements()]) for k,v in d.items() if isinstance(v,FamilyElement)]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Aile Ontolojisini Alma\n", + "\n", + "Şimdi, Semantik Web üçlüleri kümesi olarak tanımlanan [aile ontolojisine](https://raw.githubusercontent.com/blokhin/genealogical-trees/master/data/header.ttl) bir göz atalım. Bu ontoloji, `isUncleOf` (Amcadır), `isCousinOf` (Kuzendir) ve diğerleri gibi ilişkileri tanımlar. Tüm bu ilişkiler `isMotherOf` (Annedir), `isFatherOf` (Babadır), `isBrotherOf` (Erkekkardeştir) ve `isSisterOf` (Kızkardeştir) temel yüklemleri cinsinden tanımlanır. Ontolojiyi kullanarak diğer tüm ilişkileri çıkarmak için otomatik akıl yürütmeyi kullanacağız.\n", + "\n", + "Burada, `isSisterOf` (Kızkardeştir) ve `isParentOf` (Ebeveyndir) (*Teyze/Hala kişinin ebeveyninin kız kardeşidir*) bileşimi olarak tanımlanan `isAuntOf` (Teyzedir) özelliğinin örnek bir tanımı verilmiştir.\n", + "\n", + "```\n", + "fhkb:isAuntOf a owl:ObjectProperty ;\n", + " rdfs:domain fhkb:Woman ;\n", + " rdfs:range fhkb:Person ;\n", + " owl:propertyChainAxiom ( fhkb:isSisterOf fhkb:isParentOf ) .\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!head -20 ../data/onto.ttl" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Çıkarsama için Ontoloji Oluşturma\n", + "\n", + "Basit olması için, aile ontolojisinden orijinal kuralları ve GEDCOM dosyamızdan bireyler hakkındaki gerçekleri içerecek bir ontoloji dosyası oluşturacağız. GEDCOM dosyasını inceleyeceğiz ve aileler ve bireyler hakkında bilgi çıkaracağız ve bunları üçlülere dönüştüreceğiz." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!cp ../data/onto.ttl .\n", + "\n", + "gedcom_dict = g.get_element_dictionary()\n", + "individuals, marriages = {}, {}\n", + "\n", + "def term2id(el):\n", + " return \"i\" + el.get_pointer().replace('@', '').lower()\n", + "\n", + "out = open(\"onto.ttl\",\"a\")\n", + "\n", + "for k, v in gedcom_dict.items():\n", + " if isinstance(v,IndividualElement):\n", + " children, siblings = set(), set()\n", + " idx = term2id(v)\n", + "\n", + " title = v.get_name()[0] + \" \" + v.get_name()[1]\n", + " title = title.replace('\"', '').replace('[', '').replace(']', '').replace('(', '').replace(')', '').strip()\n", + "\n", + " own_families = g.get_families(v, 'FAMS')\n", + " for fam in own_families:\n", + " children |= set(term2id(i) for i in g.get_family_members(fam, \"CHIL\"))\n", + "\n", + " parent_families = g.get_families(v, 'FAMC')\n", + " if len(parent_families):\n", + " for member in g.get_family_members(parent_families[0], \"CHIL\"): # NB adoptive families i.e len(parent_families)>1 are not considered (TODO?)\n", + " if member.get_pointer() == v.get_pointer():\n", + " continue\n", + " siblings.add(term2id(member))\n", + "\n", + " if idx in individuals:\n", + " children |= individuals[idx].get('children', set())\n", + " siblings |= individuals[idx].get('siblings', set())\n", + " individuals[idx] = {'sex': v.get_gender().lower(), 'children': children, 'siblings': siblings, 'title': title}\n", + "\n", + " elif isinstance(v,FamilyElement):\n", + " wife, husb, children = None, None, set()\n", + " children = set(term2id(i) for i in g.get_family_members(v, \"CHIL\"))\n", + "\n", + " try:\n", + " wife = g.get_family_members(v, \"WIFE\")[0]\n", + " wife = term2id(wife)\n", + " if wife in individuals: individuals[wife]['children'] |= children\n", + " else: individuals[wife] = {'children': children}\n", + " except IndexError: pass\n", + " try:\n", + " husb = g.get_family_members(v, \"HUSB\")[0]\n", + " husb = term2id(husb)\n", + " if husb in individuals: individuals[husb]['children'] |= children\n", + " else: individuals[husb] = {'children': children}\n", + " except IndexError: pass\n", + "\n", + " if wife and husb: marriages[wife + husb] = (term2id(v), wife, husb)\n", + "\n", + "for idx, val in individuals.items():\n", + " added_terms = ''\n", + " if val['sex'] == 'f':\n", + " parent_predicate, sibl_predicate = \"isMotherOf\", \"isSisterOf\"\n", + " else:\n", + " parent_predicate, sibl_predicate = \"isFatherOf\", \"isBrotherOf\"\n", + " if len(val['children']):\n", + " added_terms += \" ;\\n fhkb:\" + parent_predicate + \" \" + \", \".join([\"fhkb:\" + i for i in val['children']])\n", + " if len(val['siblings']):\n", + " added_terms += \" ;\\n fhkb:\" + sibl_predicate + \" \" + \", \".join([\"fhkb:\" + i for i in val['siblings']])\n", + " out.write(\"fhkb:%s a owl:NamedIndividual, owl:Thing%s ;\\n rdfs:label \\\"%s\\\" .\\n\" % (idx, added_terms, val['title']))\n", + "\n", + "for k, v in marriages.items():\n", + " out.write(\"fhkb:%s a owl:NamedIndividual, owl:Thing ;\\n fhkb:hasFemalePartner fhkb:%s ;\\n fhkb:hasMalePartner fhkb:%s .\\n\" % v)\n", + "\n", + "out.write(\"[] a owl:AllDifferent ;\\n owl:distinctMembers (\")\n", + "for idx in individuals.keys():\n", + " out.write(\" fhkb:\" + idx)\n", + "for k, v in marriages.items():\n", + " out.write(\" fhkb:\" + v[0])\n", + "out.write(\" ) .\")\n", + "out.close()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!tail onto.ttl" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Çıkarım Yapmak \n", + "\n", + "Şimdi bu ontolojiyi çıkarsama ve sorgulama için kullanabilmek istiyoruz. [RDFLib](https://github.com/RDFLib), RDF Çizgesinin farklı formatlarda okunması, sorgulanması vb. için kütüphane kullanacağız.\n", + "\n", + "Mantıksal çıkarım için, RDF Çizgesinin **Kapanışını** oluşturmamıza, yani tüm olası kavramları ve ilişkileri ekleyip çıkarsamamıza, yardımcı olan [OWL-RL](https://github.com/RDFLib/OWL-RL) kütüphanesini kullanacağız." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Ontoloji dosyasını açalım ve kaç tane üçlü içerdiğini görelim:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import rdflib\n", + "from owlrl import DeductiveClosure, OWLRL_Extension\n", + "\n", + "g = rdflib.Graph()\n", + "g.parse(\"onto.ttl\", format=\"turtle\")\n", + "\n", + "print(\"Bununla ucluler:%d\" % len(g))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Şimdi kapanışı oluşturalım ve üçlülerin sayısının nasıl arttığını görelim:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "DeductiveClosure(OWLRL_Extension).expand(g)\n", + "print(\"Cikarsama sonrasi ucluler:%d\" % len(g))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Akrabaları Sorgulama\n", + "\n", + "Artık insanlar arasındaki farklı ilişkileri görmek için çizgeyi sorgulayabiliriz. **SPARQL** dilini `query` metodu ile birlikte kullanabiliriz. Bizim durumumuzda, soy ağacımızdaki tüm **amcaları** görelim:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "qres = g.query(\n", + " \"\"\"SELECT DISTINCT ?aname ?bname\n", + " WHERE {\n", + " ?a fhkb:isUncleOf ?b .\n", + " ?a rdfs:label ?aname .\n", + " ?b rdfs:label ?bname .\n", + " }\"\"\")\n", + "\n", + "for row in qres:\n", + " print(\"%s amcasidir %s\" % row)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Farklı diğer aile ilişkilerini denemekten çekinmeyin. Örneğin, belirli bir kişinin tüm atalarını yinelemeli tanımlayan `isAncestorOf` (Atadır) ilişkisine bakabilirsiniz.\n", + "\n", + "Son olarak, etrafı temizleyelim!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!rm onto.ttl" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.12" + }, + "vscode": { + "interpreter": { + "hash": "b0fa6594d8f4cbf19f97940f81e996739fb7646882a419484c72d19e05852a7e" + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/lessons/2-Symbolic/translations/MSConceptGraph.tr.ipynb b/lessons/2-Symbolic/translations/MSConceptGraph.tr.ipynb new file mode 100644 index 00000000..9fbf3538 --- /dev/null +++ b/lessons/2-Symbolic/translations/MSConceptGraph.tr.ipynb @@ -0,0 +1,184 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Microsoft Kavram Çizgesi\n", + "\n", + "[Microsoft Kavram Çizgesi](https://concept.research.microsoft.com/), kavramlar arasında `is-a` (bir örneğidir) ilişkileri olan, internetten çıkarılan geniş bir terimler sınıflandırmasıdır.\n", + "\n", + "Bağlam Grafiği iki biçimde mevcuttur:\n", + " * İndirmek için büyük metin dosyası\n", + " * REST API'si\n", + "\n", + "İstatistik:\n", + " * 5401933 eşsiz kavram, \n", + " * 12551613 eşsiz örnek,\n", + " * 87603947 `is-a` ilişkisi" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Web Hizmetini Kullanma\n", + "\n", + "Web hizmeti, farklı gruplara ait bir kavramın olasılığını tahmin etmek için farklı çağrılar sunar. Daha fazla bilgiyi [burada](https://concept.research.microsoft.com/Home/Api) bulabilirsiniz.\n", + "İşte aranacak örnek URL: `https://concept.research.microsoft.com/api/Concept/ScoreByProb?instance=microsoft&topK=10`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import urllib\n", + "import json\n", + "import ssl\n", + "\n", + "def http(x):\n", + " ssl._create_default_https_context = ssl._create_unverified_context\n", + " response = urllib.request.urlopen(x)\n", + " data = response.read()\n", + " return data.decode('utf-8')\n", + "\n", + "def query(x):\n", + " return json.loads(http(\"https://concept.research.microsoft.com/api/Concept/ScoreByProb?instance={}&topK=10\".format(urllib.parse.quote(x))))\n", + "\n", + "query('microsoft')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Haber başlıklarını ana kavramlarını kullanarak kategorize etmeye çalışalım. Haber başlıklarını almak için [NewsApi.org](http://newsapi.org) hizmetini kullanacağız. Hizmeti kullanmak için kendi API anahtarınızı almanız gerekir - web sitesine gidin ve ücretsiz geliştirici planına kaydolun." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "newsapi_key = ''\n", + "def get_news(country='us'):\n", + " res = json.loads(http(\"https://newsapi.org/v2/top-headlines?country={0}&apiKey={1}\".format(country,newsapi_key)))\n", + " return res['articles']\n", + "\n", + "all_titles = [x['title'] for x in get_news('us')+get_news('gb')]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "all_titles" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Her şeyden önce, haber başlıklarından isimleri çıkarabilmek istiyoruz. Bunu yapmak için bunun gibi birçok olağan DDİ görevini basitleştiren `TextBlob` kütüphanesini kullanacağız." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "!{sys.executable} -m pip install textblob\n", + "!{sys.executable} -m textblob.download_corpora\n", + "from textblob import TextBlob" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "w = {}\n", + "for x in all_titles:\n", + " for n in TextBlob(x).noun_phrases:\n", + " if n in w:\n", + " w[n].append(x)\n", + " else:\n", + " w[n]=[x]\n", + "{ x:len(w[x]) for x in w.keys()}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "İsimlerin bize geniş konu ile ilgili gruplar vermediğini görebiliriz. İsimleri kavram çizgesinden elde edilen daha genel terimlerle değiştirelim. Bu biraz zaman alacak çünkü her bir isim öbeği için REST çağrısı yapıyoruz." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "w = {}\n", + "for x in all_titles:\n", + " for noun in TextBlob(x).noun_phrases:\n", + " terms = query(noun.replace(' ','%20'))\n", + " for term in [u for u in terms.keys() if terms[u]>0.1]:\n", + " if term in w:\n", + " w[term].append(x)\n", + " else:\n", + " w[term]=[x]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "{ x:len(w[x]) for x in w.keys() if len(w[x])>3}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print('\\nECONOMY:\\n'+'\\n'.join(w['economy']))\n", + "print('\\nNATION:\\n'+'\\n'.join(w['nation']))\n", + "print('\\nPERSON:\\n'+'\\n'.join(w['person']))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} From dfb7f298095452945972da650ff0f56242888f6c Mon Sep 17 00:00:00 2001 From: semercim Date: Wed, 31 Aug 2022 08:39:46 +0200 Subject: [PATCH 14/38] Finished Turkish translation of lesson 2's quiz. --- .../src/assets/translations/tr/index.js | 4 +- .../src/assets/translations/tr/lesson-2.json | 115 ++++++++++++++++++ 2 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 etc/quiz-app/src/assets/translations/tr/lesson-2.json diff --git a/etc/quiz-app/src/assets/translations/tr/index.js b/etc/quiz-app/src/assets/translations/tr/index.js index ad1d78d5..42255a08 100644 --- a/etc/quiz-app/src/assets/translations/tr/index.js +++ b/etc/quiz-app/src/assets/translations/tr/index.js @@ -1,7 +1,9 @@ import tr1 from './lesson-1.json'; +import tr2 from './lesson-2.json'; //add items here const quiz = { - 0: tr1[0] + 0: tr1[0], + 1: tr2[0] }; export default quiz; diff --git a/etc/quiz-app/src/assets/translations/tr/lesson-2.json b/etc/quiz-app/src/assets/translations/tr/lesson-2.json new file mode 100644 index 00000000..ff4b3725 --- /dev/null +++ b/etc/quiz-app/src/assets/translations/tr/lesson-2.json @@ -0,0 +1,115 @@ +[ + { + "title": "Yeni Başlayanlar İçin YZ: Sınavlar", + "complete": "Tebrikler, sınavı tamamladınız!", + "error": "Üzgünüz, tekrar deneyin", + "quizzes": [ + { + "id": 102, + "title": "Bilgi Temsili ve Uzman Sistemler: Ön Sınav", + "quiz": [ + { + "questionText": "Akıllı sistemler oluşturmaya yönelik yukarıdan aşağıya yaklaşım şunlara dayanıyordu:", + "answerOptions": [ + { + "answerText": "bilgi arama ve okuma", + "isCorrect": false + }, + { + "answerText": "bilgi temsili ve akıl yürütme", + "isCorrect": true + }, + { + "answerText": "bilgi muhakeme ve arama", + "isCorrect": false + } + ] + }, + { + "questionText": "Bilgi ile enformasyon aynıdır:", + "answerOptions": [ + { + "answerText": "Doğru", + "isCorrect": false + }, + { + "answerText": "Yanlış", + "isCorrect": true + } + ] + }, + { + "questionText": "Bilgi şu şekilde elde edilir:", + "answerOptions": [ + { + "answerText": "etkin öğrenme süreci", + "isCorrect": true + }, + { + "answerText": "edilgen öğrenme süreci", + "isCorrect": false + }, + { + "answerText": "bunların ikisi de", + "isCorrect": false + } + ] + } + ] + }, + { + "id": 202, + "title": "Bilgi Temsili ve Uzman Sistemler: Ders Sonrası Sınavı", + "quiz": [ + { + "questionText": "Bilgi temsilinin en basit yöntemi şudur:", + "answerOptions": [ + { + "answerText": "algoritmik", + "isCorrect": true + }, + { + "answerText": "simgesel", + "isCorrect": false + }, + { + "answerText": "sinerjik", + "isCorrect": false + } + ] + }, + { + "questionText": "Senaryolar, zamanla ortaya çıkabilecek karmaşık durumları temsil edebilir.", + "answerOptions": [ + { + "answerText": "doğru", + "isCorrect": true + }, + { + "answerText": "yanlış", + "isCorrect": false + } + ] + }, + { + "questionText": "İleriye dönük çıkarsama, ilk verilerle başlar ve ardından", + "answerOptions": [ + { + "answerText": "bir akıl yürütme döngüsü yürütür", + "isCorrect": true + }, + { + "answerText": "bir hedef arar", + "isCorrect": false + }, + { + "answerText": "baştan başlar", + "isCorrect": false + } + ] + } + ] + } + ] + } +] \ No newline at end of file From f44859e1f4adc878c90ec9f0e8d2d76ba9d5ba89 Mon Sep 17 00:00:00 2001 From: semercim Date: Wed, 31 Aug 2022 22:16:10 +0200 Subject: [PATCH 15/38] Translating lesson 3 to Turkish. --- .../translations/README.tr.md | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 lessons/3-NeuralNetworks/translations/README.tr.md diff --git a/lessons/3-NeuralNetworks/translations/README.tr.md b/lessons/3-NeuralNetworks/translations/README.tr.md new file mode 100644 index 00000000..2aff2c8f --- /dev/null +++ b/lessons/3-NeuralNetworks/translations/README.tr.md @@ -0,0 +1,48 @@ +# Sinir Ağlarına Giriş + +![Bir doodle'da Sinir Ağlarına Giriş içeriğinin özeti](../../sketchnotes/ai-neuralnetworks.png) + +Giriş bölümünde tartıştığımız gibi, zekaya ulaşmanın yollarından biri bir **bilgisayar modeli** veya bir **yapay beyin** eğitmektir. 20. yüzyılın ortalarından beri, araştırmacılar farklı matematiksel modeller denediler, son yıllara kadar bu yön oldukça başarılı oldu. Beynin bu tür matematiksel modellerine **sinir ağları** denir. + +> Bazen sinir ağları, gerçek nöron ağlarından değil, modellerden bahsettiğimizi vurgulamak için *Yapay Sinir Ağları*, YSA olarak adlandırılır. + +## Makine Öğrenmesi + +Sinir Ağları, amacı sorunları çözebilen bilgisayar modellerini eğitmek için verileri kullanmak olan **Makine Öğrenmesi** adlı daha büyük bir disiplinin parçasıdır. Makine Öğrenmesi, Yapay Zekanın büyük bir bölümünü oluşturur, ancak bu müfredatta klasik MÖ'yi ele almıyoruz. + +> Klasik Makine Öğrenmesi hakkında daha fazla bilgi edinmek için ayrı **[Yeni Başlayanlar için Makine Öğrenmesi](http://github.com/microsoft/ml-for-beginners)** müfredatımızı ziyaret edin. + +Makine Öğrenmesinde, **X** örneklerinden oluşan bir veri kümemiz ve bunlara karşılık gelen **Y** çıktı değerlerine sahip olduğumuzu varsayıyoruz. Örnekler genellikle **öznitelikler** içeren N boyutlu vektörlerdir ve çıktılara **etiketler** denir. + +En yaygın iki makine öğrenmesi sorununu ele alacağız: + +* **Sınıflandırma**, bir girdi nesnesini iki veya daha fazla sınıfa ayırmamızı gerektirir. +* **Bağlanım**, girdi örneklerinin her biri için bir sayı tahmin etmemizi gerektirir. + +> Girdileri ve çıktıları tensörler olarak temsil ederken, girdi veri kümesi M×N boyutunda bir matristir; burada M, örnek sayısı ve N, öznitelik sayısıdır. Çıktı etiketleri Y, M boyutlu bir vektördür. + +Bu müfredatta sadece sinir ağı modellerine odaklanacağız. + +## Bir Sinir Modeli + +Biyolojiden, beynimizin, her biri birden fazla "girdi" (akson) ve bir çıktı (dendrit) içeren sinir hücrelerinden oluştuğunu biliyoruz. Aksonlar ve dendritler elektrik sinyallerini iletebilir ve aksonlar ve dendritler arasındaki bağlantılar farklı derecelerde iletkenlik sergileyebilir (nöromediatörler tarafından kontrol edilirler). + +![Sinir Modeli](../images/synapse-wikipedia.jpg) | ![Sinir Modeli](../images/artneuron.png) +----|---- +Gerçek Sinir *([İmge](https://en.wikipedia.org/wiki/Synapse#/media/File:SynapseSchematic_lines.svg) Wikipedia'dan)* | Yapay Sinir *(İmge sahibi Yazar)* + +Böylece, bir nöronun en basit matematiksel modeli birkaç X girdisi 1, ..., XN ve bir Y çıktısı ve bir dizi W ağırlığı içerir 1, ..., WN. Çıktı şöyle hesaplanır: + +Y = f\left(\sum_{i=1}^N X_iW_i\right) + +burada f bir doğrusal olmayan **etkinleştirme işlevi**dir. + +> Sinirin ilk modelleri, 1943'te Warren McCullock ve Walter Pitts tarafından yazılan [Sinir aktivitesinin özünde olan fikirlerin mantıksal bir hesabı](http://www.springerlink.com/content/61446605110620kg/fulltext.pdf) adlı klasik makalede tanımlanmıştır. Donald Hebb, "[Davranışın Organizasyonu: Bir Nöropsikolojik Teori](https://books.google.com/books?id=VNetYrB8EBoC)" adlı kitabında bu ağları eğitebilmenin yolunu önerdi. + +## Bu Bölümdekiler + +Bu bölümde şunları öğreneceğiz: +* [Algılayıcı](03-Perceptron/translations/README.tr.md), iki sınıflı sınıflandırma için en eski sinir ağı modellerinden biridir +* [Çok katmanlı ağlar](04-OwnFramework/translations/README.tr.md) eşleştirilmiş bir not defteri ile [kendi çerçevemizi nasıl oluştururuz](04-OwnFramework/translations/OwnFramework.tr.ipynb) +* [Sinir ağları çerçeveleri](05-Frameworks/translations/README.tr.md), şu not defterleriyle birlikte: [PyTorch](05-Frameworks/translations/IntroPyTorch.tr.ipynb) ve [Keras/Tensorflow](05-Frameworks/translations/IntroKerasTF.tr.ipynb) +* [Aşırı öğrenme](05-Frameworks/translations/Overfitting.tr.md) \ No newline at end of file From 654996c05031519adafccecb42312cdc25ab36d2 Mon Sep 17 00:00:00 2001 From: semercim Date: Sat, 24 Sep 2022 22:45:26 +0200 Subject: [PATCH 16/38] Translated lesson 3 perceptron readme file to Turkish. --- .../03-Perceptron/translations/README.tr.md | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 lessons/3-NeuralNetworks/03-Perceptron/translations/README.tr.md diff --git a/lessons/3-NeuralNetworks/03-Perceptron/translations/README.tr.md b/lessons/3-NeuralNetworks/03-Perceptron/translations/README.tr.md new file mode 100644 index 00000000..1ce3e5b7 --- /dev/null +++ b/lessons/3-NeuralNetworks/03-Perceptron/translations/README.tr.md @@ -0,0 +1,94 @@ +# Sinir Ağlarına Giriş: Algılayıcı + +## [Ders öncesi sınavı](https://red-field-0a6ddfd03.1.azurestaticapps.net/quiz/103) + +Modern bir sinir ağına benzer bir şeyi uygulamaya yönelik ilk girişimlerden biri, 1957'de Cornell Havacılık Laboratuvarı'ndan Frank Rosenblatt tarafından yapıldı. Üçgenler, kareler ve daireler gibi ilkel geometrik şekilleri tanımak için tasarlanmış "Mark-1" adlı bir donanım uygulamasıydı. + +| | | +|--------------|-----------| +|Frank Rosenblatt | Mark 1 Algılayıcısı| + +> İmgeler [Wikipedia'dan](https://en.wikipedia.org/wiki/Perceptron) + +Bir girdi imgesi 20x20'lik fotosel dizisi ile temsil edildi, bu nedenle sinir ağının 400 girdisi ve bir ikili çıktısı vardı. Basit bir ağ, **eşik mantık birimi** olarak da adlandırılan bir nöron içeriyordu. Sinir ağı ağırlıkları, eğitim aşamasında elle ayar gerektiren potansiyometreler gibi davrandı. + +> ✅ Potansiyometre, kullanıcının bir devrenin direncini ayarlamasını sağlayan bir cihazdır. + +> New York Times o dönemde algılayıcı hakkında şunları yazmıştı: *[Donanmanın] beklediği, yürüyebilecek, konuşabilecek, görebilecek, yazabilecek, kendini yeniden üretebilecek ve varlığının bilincinde olabilecek bir elektronik bilgisayarın embriyosu.* + +## Algılayıcı Modeli + +Modelimizde N tane özniteliğimiz olduğunu varsayalım, bu durumda girdi vektörü N boyutunda bir vektör olacaktır. Bir algılayıcı bir **ikili sınıflandırma** modelidir, yani iki girdi verisi sınıfını ayırt edebilir. Her x girdi vektörü için algılayıcımızın çıktısının sınıfa bağlı olarak +1 veya -1 olacağını varsayacağız. Çıktı, aşağıdaki formül kullanılarak hesaplanacaktır: + +y(x) = f(wTx) + +burada f basamak etkinleştirme fonksiyonudur. + + + + +## Algılayıcıyı Eğitme + +Bir algılayıcıyı eğitmek için değerlerin çoğunu doğru şekilde sınıflandıran, yani en küçük **hata** ile sonuçlanan bir w ağırlık vektörü bulmamız gerekir. Bu hata, **algılayıcı kriteri** tarafından aşağıdaki şekilde tanımlanır: + +E(w) = -∑wTxiti + +burada: + +* yanlış sınıflandırmaya neden olan i eğitim veri noktalarının toplamı alınır. +* xi girdi verisidir ve buna göre olumsuz ve olumlu örnekler için ti -1 veya +1'dir. + +Bu kriter w ağırlıklarının bir fonksiyonu olarak kabul edilir ve bunu en aza indirmemiz gerekir. Genellikle, bazı ilk ağırlıkları w(0) ile başladığımız ve ardından her adımda ağırlıkları aşağıdaki formüle göre güncellediğimiz **gradyan inişi** adlı bir yöntem kullanılır: + +w(t+1) = w(t) - η∇E(w) + +Here η is the so-called **learning rate**, and ∇E(w) denotes the **gradient** of E. After we calculate the gradient, we end up with + +Burada η sözde **öğrenme oranı** ve ∇E(w) E'nin **gradyanını** belirtir. Gradyanı hesapladıktan sonra, aşağıdaki işleme varırız: + +w(t+1) = w(t) + ∑ηxiti + +Python'daki algoritma şöyle görünür: + +```python +def train(positive_examples, negative_examples, num_iterations = 100, eta = 1): + + weights = [0,0,0] # Ağırlıkları ilkle (neredeyse rastgele :)) + + for i in range(num_iterations): + pos = random.choice(positive_examples) + neg = random.choice(negative_examples) + + z = np.dot(pos, weights) # algılayıcı çıktısını hesapla + if z < 0: # pozitif örnek negatif sınıflandırıldı + weights = weights + eta*weights.shape + + z = np.dot(neg, weights) + if z >= 0: # negatif örnek pozitif sınıflandırıldı + weights = weights - eta*weights.shape + + return weights +``` + +## Vargılar + +Bu derste, ikili sınıflandırma modeli olan algılayıcıyı ve ağırlık vektörü kullanarak onu nasıl eğiteceğinizi öğrendiniz. + +## 🚀 Kendini Sınama + +Kendi algılayıcınızı oluşturmaya çalışmak istiyorsanız, [Azure ML tasarımcısını (Azure ML designer)](https://docs.microsoft.com/en-us/azure/machine-learning/concept-designer?WT.mc_id=academic-57639-dmitryso) kullanan [Microsoft Learn'deki bu laboratuvarı](https://docs.microsoft.com/en-us/azure/machine-learning/component-reference/two-class-averaged-perceptron?WT.mc_id=academic-57639-dmitryso) deneyin. + +## [Ders sonrası sınavı](https://red-field-0a6ddfd03.1.azurestaticapps.net/quiz/203) + +## Gözden Geçirme ve Bireysel Çalışma + +Bir oyuncak probleminin yanı sıra gerçek hayattaki problemleri çözmek için algılayıcıyı nasıl kullanabileceğimizi görmek ve öğrenmeye devam etmek için - [Algılayıcı](./Perceptron.tr.ipynb) not defterine gidin. + +İşte ilave olarak ilginç bir [algılayıcılar makalesi](https://towardsdatascience.com/what-is-a-perceptron-basics-of-neural-networks-c4cfea20c590). + +## [Ödev](../lab/translations/README.tr.md) + +Bu dersimizde ikili sınıflandırma görevi için bir algılayıcı uyguladık ve bunu iki el yazısı rakamı arasından sınıflandırmak için kullandık. Bu laboratuvarda, rakam sınıflandırma problemini tamamen çözmeniz, yani hangi rakamın belirli bir imgeye karşılık gelme olasılığının en yüksek olduğunu belirlemeniz istenmektedir. + +* [Talimatlar](../lab/translations/README.tr.md) +* [Not Defteri](../lab/translations/PerceptronMultiClass.tr.ipynb) From 50e857c52f0f4a7e1677dbff009f560bf79cfdc3 Mon Sep 17 00:00:00 2001 From: semercim Date: Sun, 25 Sep 2022 00:07:17 +0200 Subject: [PATCH 17/38] Translated lesson 3 perceptron notebook to Turkish. --- .../03-Perceptron/Perceptron.ipynb | 15 +- .../translations/Perceptron.tr.ipynb | 1100 +++++++++++++++++ .../03-Perceptron/translations/README.tr.md | 4 +- 3 files changed, 1110 insertions(+), 9 deletions(-) create mode 100644 lessons/3-NeuralNetworks/03-Perceptron/translations/Perceptron.tr.ipynb diff --git a/lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb b/lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb index c01be7ea..de91f19e 100644 --- a/lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb +++ b/lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb @@ -213,7 +213,7 @@ " * $t_{n} \\in \\{-1, +1\\}$ for negative and positive training samples, respectively\n", " * $\\mathcal{M}$ - a set of wrongly classified examples\n", " \n", - "We will use the process of **graident descent**. Starting with some initial random weights $\\mathbf{w}^{(0)}$, we will adjust weights on each step of the training using the gradient of $E$:\n", + "We will use the process of **gradient descent**. Starting with some initial random weights $\\mathbf{w}^{(0)}$, we will adjust weights on each step of the training using the gradient of $E$:\n", "\n", "$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n", "\n", @@ -1052,11 +1052,9 @@ ], "metadata": { "celltoolbar": "Slideshow", - "interpreter": { - "hash": "16aeaa504b544176258e5caf576fc030dfd6fff62d0c15825e7863ff13e121ff" - }, "kernelspec": { - "display_name": "Python 3.8.0 64-bit (conda)", + "display_name": "Python 3.10.6 64-bit", + "language": "python", "name": "python3" }, "language_info": { @@ -1069,10 +1067,15 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.0" + "version": "3.10.6" }, "livereveal": { "start_slideshow_at": "selected" + }, + "vscode": { + "interpreter": { + "hash": "b0fa6594d8f4cbf19f97940f81e996739fb7646882a419484c72d19e05852a7e" + } } }, "nbformat": 4, diff --git a/lessons/3-NeuralNetworks/03-Perceptron/translations/Perceptron.tr.ipynb b/lessons/3-NeuralNetworks/03-Perceptron/translations/Perceptron.tr.ipynb new file mode 100644 index 00000000..698731ff --- /dev/null +++ b/lessons/3-NeuralNetworks/03-Perceptron/translations/Perceptron.tr.ipynb @@ -0,0 +1,1100 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true, + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Algılayıcı\n", + "\n", + "> Bu not defteri, [Yeni Başlayanlar İçin Yapay Zeka Müfredatı](http://github.com/microsoft/ai-for-beginners)'nın bir parçasıdır. Eksiksiz öğrenme materyallerinin tamamı için kod deposunu ziyaret edin.\n", + "\n", + "Tartıştığımız gibi, algılayıcı **ikili sınıflandırma problemini** çözmenize, yani girdi örneklerini iki sınıfa ayırmanıza izin verir - bunlara **pozitif** ve **negatif** diyebiliriz.\n", + "\n", + "İlk olarak, bazı gerekli kütüphaneleri içe aktaralım." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import pylab\n", + "from matplotlib import gridspec\n", + "from sklearn.datasets import make_classification\n", + "import numpy as np\n", + "from ipywidgets import interact, interactive, fixed\n", + "import ipywidgets as widgets\n", + "import pickle\n", + "import os\n", + "import gzip\n", + "\n", + "# yeniden üretilebilirlik için tohumu (seed) seçin - rastgele varyasyonların etkilerini keşfetmek için değiştirin\n", + "np.random.seed(1)\n", + "import random" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Basit Örnek Problem\n", + "\n", + "Başlangıç olarak, iki girdi özniteliğimiz olan bir basit örnek problem ile başlayalım. Örneğin, tıpta tümörleri boyutuna ve yaşına bağlı olarak iyi huylu ve kötü huylu olarak sınıflandırmak isteyebiliriz.\n", + "\n", + "SciKit Learn kütüphanesinden `make_classification` fonksiyonunu kullanarak rastgele bir sınıflandırma veri kümesi oluşturacağız:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Features:\n", + " [[-1.7441838 -1.3952037 ]\n", + " [ 2.5921783 -0.08124504]\n", + " [ 0.9218062 0.91789985]\n", + " [-0.8437018 -0.18738253]]\n", + "Labels:\n", + " [-1 -1 1 -1]\n" + ] + } + ], + "source": [ + "n = 50\n", + "X, Y = make_classification(n_samples = n, n_features=2,\n", + " n_redundant=0, n_informative=2, flip_y=0)\n", + "Y = Y*2-1 # ilk 0/1 değerlerini -1/1'e çevir\n", + "X = X.astype(np.float32); Y = Y.astype(np.int32) # öznitelikler - kayan virgüllü sayı, etiket - tam sayı\n", + "\n", + "# Veri kümesini eğitim ve test olarak ayırın\n", + "train_x, test_x = np.split(X, [ n*8//10])\n", + "train_labels, test_labels = np.split(Y, [n*8//10])\n", + "print(\"Features:\\n\",train_x[0:4])\n", + "print(\"Labels:\\n\",train_labels[0:4])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's also plot the dataset:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/var/folders/_l/jnklp1bj4cl95rc01tf5vx4h0000gn/T/ipykernel_48969/3457453734.py:11: UserWarning: Matplotlib is currently using module://matplotlib_inline.backend_inline, which is a non-GUI backend, so cannot show the figure.\n", + " fig.show()\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "def plot_dataset(suptitle, features, labels):\n", + " # prepare the plot\n", + " fig, ax = pylab.subplots(1, 1)\n", + " #pylab.subplots_adjust(bottom=0.2, wspace=0.4)\n", + " fig.suptitle(suptitle, fontsize = 16)\n", + " ax.set_xlabel('$x_i[0]$ -- (öznitelik 1)')\n", + " ax.set_ylabel('$x_i[1]$ -- (öznitelik 2)')\n", + "\n", + " colors = ['r' if l>0 else 'b' for l in labels]\n", + " ax.scatter(features[:, 0], features[:, 1], marker='o', c=colors, s=100, alpha = 0.5)\n", + " fig.show()\n", + "\n", + "plot_dataset('Eğitim verisi', train_x, train_labels)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Algılayıcı\n", + "\n", + "Algılayıcı bir ikili sınıflandırıcı olduğundan, her bir $x$ girdi vektörü için algılayıcımızın çıktısı, sınıfa bağlı olarak +1 veya -1 olacaktır. Çıktı aşağıdaki formül kullanılarak hesaplanacaktır.\n", + "\n", + "$$y(\\mathbf{x}) = f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x})$$\n", + "\n", + "burada $\\mathbf{w}$ bir ağırlık vektörüdür, $f$ bir basamak etkinleştirme fonksiyonudur:\n", + "$$\n", + "f(x) = \\begin{cases}\n", + " +1 & x \\geq 0 \\\\\n", + " -1 & x < 0\n", + " \\end{cases} \\\\\n", + "$$\n", + "\n", + "Bununla birlikte, genel bir doğrusal modelin de bir ek girdisi olmalıdır, yani ideal olarak $y$'yi $y=f(\\mathbf{w}^{\\mathrm{T}}\\mathbf{x})+\\mathbf{b}$ olarak hesaplamalıyız. Modelimizi basitleştirmek için, girdi özniteliklerimize her zaman 1'e eşit olan bir boyut daha ekleyerek bu ek girdi teriminden kurtulabiliriz:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[ 0.92180622 0.91789985 1. ]\n", + " [-1.06435513 1.49764717 1. ]\n", + " [ 0.32839951 2.25677919 1. ]]\n" + ] + } + ], + "source": [ + "pos_examples = np.array([ [t[0], t[1], 1] for i,t in enumerate(train_x) \n", + " if train_labels[i]>0])\n", + "neg_examples = np.array([ [t[0], t[1], 1] for i,t in enumerate(train_x) \n", + " if train_labels[i]<0])\n", + "print(pos_examples[0:3])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Eğitim Algoritması\n", + "\n", + "Algılayıcıyı eğitmek için, hatayı en aza indirecek $\\mathbf{w}$ ağırlıklarını bulmamız gerekiyor. Hata, **algılayıcı kriterleri** kullanılarak tanımlanır:\n", + "\n", + "$$E(\\mathbf{w}) = -\\sum_{n \\in \\mathcal{M}}\\mathbf{w}^{\\mathrm{T}}\\mathbf{x}_{n}t_{n}$$\n", + " \n", + " * $t_{n} \\in \\{-1, +1\\}$ for negative and positive training samples, respectively\n", + " * $\\mathcal{M}$ - a set of wrongly classified examples\n", + "\n", + "**Gradyan inişi** işlemini kullanacağız. Bazı rastgele ilk $\\mathbf{w}^{(0)}$ ağırlıkları ile başlayarak, $E$'nin gradyanını kullanarak eğitimin her adımındaki ağırlıkları ayarlayacağız:\n", + "\n", + "$$\\mathbf{w}^{\\tau + 1}=\\mathbf{w}^{\\tau} - \\eta \\nabla E(\\mathbf{w}) = \\mathbf{w}^{\\tau} + \\eta \\mathbf{x}_{n} t_{n}$$\n", + "\n", + "burada $\\eta$ **öğrenme oranı** ve $\\tau\\in\\mathbb{N}$ yineleme sayısıdır.\n", + "\n", + "Bu algoritmayı Python'da tanımlayalım:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "def train(positive_examples, negative_examples, num_iterations = 100):\n", + " num_dims = positive_examples.shape[1]\n", + " \n", + " # Ağırlıkları ilkle.\n", + " # Basitlik için 0 ile ilkletiyoruz, ancak rastgele ilkleme de iyi bir fikirdir\n", + " weights = np.zeros((num_dims,1)) \n", + " \n", + " pos_count = positive_examples.shape[0]\n", + " neg_count = negative_examples.shape[0]\n", + " \n", + " report_frequency = 10\n", + " \n", + " for i in range(num_iterations):\n", + " # Bir pozitif ve bir negatif örnek seçin\n", + " pos = random.choice(positive_examples)\n", + " neg = random.choice(negative_examples)\n", + "\n", + " z = np.dot(pos, weights) \n", + " if z < 0: # pozitif örnek negatif olarak sınıflandırıldı\n", + " weights = weights + pos.reshape(weights.shape)\n", + "\n", + " z = np.dot(neg, weights)\n", + " if z >= 0: # negatif örnek pozitif olarak sınıflandırıldı\n", + " weights = weights - neg.reshape(weights.shape)\n", + " \n", + " # Periyodik olarak, tüm örneklerde mevcut doğruluğu yazdırın\n", + " if i % report_frequency == 0: \n", + " pos_out = np.dot(positive_examples, weights)\n", + " neg_out = np.dot(negative_examples, weights) \n", + " pos_correct = (pos_out >= 0).sum() / float(pos_count)\n", + " neg_correct = (neg_out < 0).sum() / float(neg_count)\n", + " print(\"Yineleme={}, positif doğruluk={}, negatif doğruluk={}\".format(i,pos_correct,neg_correct))\n", + "\n", + " return weights" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Şimdi eğitimi veri kümemizde çalıştıralım:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Yineleme=0, positif doğruluk=0.7368421052631579, negatif doğruluk=0.8571428571428571\n", + "Yineleme=10, positif doğruluk=0.8421052631578947, negatif doğruluk=1.0\n", + "Yineleme=20, positif doğruluk=0.8421052631578947, negatif doğruluk=1.0\n", + "Yineleme=30, positif doğruluk=0.8947368421052632, negatif doğruluk=0.8571428571428571\n", + "Yineleme=40, positif doğruluk=0.8947368421052632, negatif doğruluk=0.8095238095238095\n", + "Yineleme=50, positif doğruluk=0.8421052631578947, negatif doğruluk=0.9523809523809523\n", + "Yineleme=60, positif doğruluk=0.8421052631578947, negatif doğruluk=0.9523809523809523\n", + "Yineleme=70, positif doğruluk=0.9473684210526315, negatif doğruluk=0.8095238095238095\n", + "Yineleme=80, positif doğruluk=1.0, negatif doğruluk=0.7619047619047619\n", + "Yineleme=90, positif doğruluk=0.8947368421052632, negatif doğruluk=0.9047619047619048\n", + "[[-0.30137426 5.42483654 0. ]]\n" + ] + } + ], + "source": [ + "wts = train(pos_examples,neg_examples)\n", + "print(wts.transpose())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Gördüğünüz gibi, ilk doğruluk %50 civarındadır, ancak hızla %90'a yakın daha yüksek değerlere çıkar.\n", + "\n", + "Sınıfların nasıl ayrıldığını görselleştirelim. Sınıflandırma fonksiyonumuz $\\mathbf{w}^Tx$ gibi görünüyor ve bir sınıf için 0'dan büyük, diğeri için 0'ın altında. Böylece, sınıf ayırma doğrusu $\\mathbf{w}^Tx = 0$ ile tanımlanır. Yalnızca $x_0$ ve $x_1$ boyutlarına sahip olduğumuz için, doğrunun denklemi $w_0x_0+w_1x_1+w_2 = 0$ olacaktır (ekstra bir boyut olarak $x_2=1$ tanımladığımızı unutmayın). Bu doğruyu çizelim:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "def plot_boundary(positive_examples, negative_examples, weights):\n", + " if np.isclose(weights[1], 0):\n", + " if np.isclose(weights[0], 0):\n", + " x = y = np.array([-6, 6], dtype = 'float32')\n", + " else:\n", + " y = np.array([-6, 6], dtype='float32')\n", + " x = -(weights[1] * y + weights[2])/weights[0]\n", + " else:\n", + " x = np.array([-6, 6], dtype='float32')\n", + " y = -(weights[0] * x + weights[2])/weights[1]\n", + "\n", + " pylab.xlim(-6, 6)\n", + " pylab.ylim(-6, 6) \n", + " pylab.plot(positive_examples[:,0], positive_examples[:,1], 'bo')\n", + " pylab.plot(negative_examples[:,0], negative_examples[:,1], 'ro')\n", + " pylab.plot(x, y, 'g', linewidth=2.0)\n", + " pylab.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plot_boundary(pos_examples,neg_examples,wts)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Test Veri Kümesinde Değerlendirme\n", + "\n", + "Başlangıçta, bazı verileri test veri kümesine ayırdık. Bu test veri kümesinde sınıflandırıcımızın ne kadar doğru olduğunu görelim. Bunu yapmak için ayrıca test veri kümesini ekstra bir boyutla genişletiyoruz, ağırlıklar matrisi ile çarpıyoruz ve elde edilen değerin etiketle (+1 veya -1) aynı işarette olduğundan emin oluyoruz. Daha sonra doğruluğu elde etmek için tüm boole değerlerini toplarız ve test örnekleminin uzunluğuna böleriz:" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "1.0" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def accuracy(weights, test_x, test_labels):\n", + " res = np.dot(np.c_[test_x,np.ones(len(test_x))],weights)\n", + " return (res.reshape(test_labels.shape)*test_labels>=0).sum()/float(len(test_labels))\n", + "\n", + "accuracy(wts, test_x, test_labels)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Eğitim sürecini gözlemlemek\n", + "\n", + "Eğitim sırasında doğruluğun nasıl azaldığını daha önce gördük. Eğitim sırasında ayırma doğrusunun nasıl davrandığını görmek güzel olurdu. Aşağıdaki kod, her şeyi tek bir grafikte görselleştirecektir ve kaydırıcıyı eğitim süreci boyunca \"zaman yolculuğu\"na hareket ettirebilmelisiniz." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/var/folders/_l/jnklp1bj4cl95rc01tf5vx4h0000gn/T/ipykernel_48969/1624475785.py:30: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.\n", + " return np.array(snapshots)\n" + ] + } + ], + "source": [ + "def train_graph(positive_examples, negative_examples, num_iterations = 100):\n", + " num_dims = positive_examples.shape[1]\n", + " weights = np.zeros((num_dims,1)) # ağırlıkları ilkle\n", + " \n", + " pos_count = positive_examples.shape[0]\n", + " neg_count = negative_examples.shape[0]\n", + " \n", + " report_frequency = 15;\n", + " snapshots = []\n", + " \n", + " for i in range(num_iterations):\n", + " pos = random.choice(positive_examples)\n", + " neg = random.choice(negative_examples)\n", + "\n", + " z = np.dot(pos, weights) \n", + " if z < 0:\n", + " weights = weights + pos.reshape(weights.shape)\n", + "\n", + " z = np.dot(neg, weights)\n", + " if z >= 0:\n", + " weights = weights - neg.reshape(weights.shape)\n", + " \n", + " if i % report_frequency == 0: \n", + " pos_out = np.dot(positive_examples, weights)\n", + " neg_out = np.dot(negative_examples, weights) \n", + " pos_correct = (pos_out >= 0).sum() / float(pos_count)\n", + " neg_correct = (neg_out < 0).sum() / float(neg_count)\n", + " snapshots.append((np.copy(weights),(pos_correct+neg_correct)/2.0))\n", + "\n", + " return np.array(snapshots)\n", + "\n", + "snapshots = train_graph(pos_examples,neg_examples)\n", + "\n", + "def plotit(pos_examples,neg_examples,snapshots,step):\n", + " fig = pylab.figure(figsize=(10,4))\n", + " fig.add_subplot(1, 2, 1)\n", + " plot_boundary(pos_examples, neg_examples, snapshots[step][0])\n", + " fig.add_subplot(1, 2, 2)\n", + " pylab.plot(np.arange(len(snapshots[:,1])), snapshots[:,1])\n", + " pylab.ylabel('Accuracy')\n", + " pylab.xlabel('Iteration')\n", + " pylab.plot(step, snapshots[step,1], \"bo\")\n", + " pylab.show()\n", + "def pl1(step): plotit(pos_examples,neg_examples,snapshots,step)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "e47dac57d0aa469e943218c20f3eecd6", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "interactive(children=(IntSlider(value=0, description='step', max=6), Output()), _dom_classes=('widget-interact…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interact(pl1, step=widgets.IntSlider(value=0, min=0, max=len(snapshots)-1))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Algılayıcının Sınırları\n", + "\n", + "Yukarıda gördüğünüz gibi, algılayıcı bir **doğrusal sınıflandırıcıdır**. **Doğrusal olarak ayrılabilir** iseler, yani düz bir çizgi ile ayrılabilirlerse, iki sınıf arasında iyi bir ayrım yapabilir. Aksi takdirde, algılayıcı eğitim işlemi yakınsamayacaktır.\n", + "\n", + "Bir algılayıcı tarafından çözülemeyen bir problemin en bariz örneği **XOR problemi** olarak adlandırılır. Algılayıcımızın aşağıdaki doğruluk tablosuna sahip olan XOR boole işlevini öğrenmesini istiyoruz:\n", + "\n", + "| | 0 | 1 |\n", + "|---|---|---|\n", + "| 0 | 0 | 1 | \n", + "| 1 | 1 | 0 |\n", + "\n", + "Hadi bunu deneyelim ve yapalım! Tüm pozitif ve negatif eğitim örneklerini manuel olarak dolduracağız ve ardından yukarıda tanımlanan eğitim fonksiyonumuzu çağıracağız:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/var/folders/_l/jnklp1bj4cl95rc01tf5vx4h0000gn/T/ipykernel_48969/1624475785.py:30: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.\n", + " return np.array(snapshots)\n" + ] + } + ], + "source": [ + "pos_examples_xor = np.array([[1,0,1],[0,1,1]])\n", + "neg_examples_xor = np.array([[1,1,1],[0,0,1]])\n", + "\n", + "snapshots_xor = train_graph(pos_examples_xor,neg_examples_xor,1000)\n", + "def pl2(step): plotit(pos_examples_xor,neg_examples_xor,snapshots_xor,step)" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "23f34a026a83468c9aea5f07a6d5b016", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "interactive(children=(IntSlider(value=0, description='step', max=6), Output()), _dom_classes=('widget-interact…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "interact(pl2, step=widgets.IntSlider(value=0, min=0, max=len(snapshots)-1))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true, + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "Yukarıdaki grafikten de görebileceğiniz gibi, doğruluk hiçbir zaman %75'in üzerine çıkmaz, çünkü olası tüm örnekleri doğru elde edecek şekilde düz bir çizgi çizmek imkansızdır.\n", + "\n", + "XOR problemi, algılayıcının sınırlarının klasik bir örneğidir ve 1969'da Marvin Minsky ve Seymour Papert tarafından [Algılayıcılar](https://en.wikipedia.org/wiki/Perceptrons_(book)) adlı kitaplarında belirtilmiştir. Bu gözlem, sinir ağları alanındaki araştırmayı neredeyse 10 yıllarca sınırlandırdı - ve bunu kursumuzun bir sonraki bölümünde göreceğiz - çok katmanlı algılayıcılar bu tür sorunları mükemmel bir şekilde çözme yeteneğine sahipler.\n", + "\n", + "## Karmaşık Örnek - MNIST\n", + "\n", + "Perceptron, XOR problemini çözemese de, el yazısı karakter tanıma gibi daha birçok karmaşık problemi çözebilir.\n", + "\n", + "Makine öğrenmesinde uzmanlaşırken sıklıkla kullanılan bir veri kümesine [MNIST](https://en.wikipedia.org/wiki/MNIST_database) denir. Modifiye Ulusal Standartlar ve Teknoloji Enstitüsü tarafından oluşturulmuştur ve yaklaşık 250 öğrenci ve enstitü çalışanından toplanan 60000 el yazısıyla yazılmış rakamdan bir eğitim kümesi içerir. Ayrıca farklı kişilerden toplanan 10000 rakamlık bir test veri kümesi de bulunmaktadır.\n", + "\n", + "Tüm rakamlar, 28x28 piksel boyutundaki gri tonlamalı imgelerle temsil edilir.\n", + "\n", + "> MNIST veri Kümesi, makine öğrenmesi yarışmalarına ve mücadelelerine ev sahipliği yapan bir site olan [Kaggle](https://www.kaggle.com/c/digit-recognizer) üzerinde bir eğitim yarışması olarak mevcuttur. MNIST rakamlarını nasıl sınıflandıracağınızı öğrendikten sonra, diğer katılımcılar arasında nasıl derecelendirildiğini görmek için çözümünüzü Kaggle'a gönderebilirsiniz.\n", + "\n", + "MNIST veri kğmesini yükleyerek başlıyoruz:" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "# Bu not defterini klonlanmış bir depodan çalıştırmıyorsanız, önce ikili veri kümesi dosyasını almanız gerekebilir.\n", + "# !wget https://github.com/microsoft/AI-For-Beginners/blob/main/data/mnist.pkl.gz?raw=true\n", + "# Bu durumda aşağıdaki veri kümesinin bağlantısını da düzeltin.\n", + "\n", + "with gzip.open('../../data/mnist.pkl.gz', 'rb') as mnist_pickle:\n", + " MNIST = pickle.load(mnist_pickle)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Şimdi veri kümesini çizelim:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[ 0 0 188 255 94 0 0 0 0 0 0 0 0 0 0 0 0 0\n", + " 0 0 0 0 0 0 0 0 0 0 0 191 250 253 93 0 0 0\n", + " 0 0 0 0 0 0 0 0 0 0 0 0 0 0]\n", + "1\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "print(MNIST['Train']['Features'][0][130:180])\n", + "print(MNIST['Train']['Labels'][0])\n", + "features = MNIST['Train']['Features'].astype(np.float32) / 256.0\n", + "labels = MNIST['Train']['Labels']\n", + "fig = pylab.figure(figsize=(10,5))\n", + "for i in range(10):\n", + " ax = fig.add_subplot(1,10,i+1)\n", + " pylab.imshow(features[i].reshape(28,28))\n", + "pylab.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Algılayıcı bir ikili sınıflandırıcı olduğundan, problemimizi sadece iki rakamı tanımakla sınırlayacağız. Aşağıdaki işlev, pozitif ve negatif örnek dizilerini verilen iki rakam ile dolduracaktır (ve ayrıca netlik için bu rakamların örneklerini de gösterecektir)." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "def set_mnist_pos_neg(positive_label, negative_label):\n", + " positive_indices = [i for i, j in enumerate(MNIST['Train']['Labels']) \n", + " if j == positive_label]\n", + " negative_indices = [i for i, j in enumerate(MNIST['Train']['Labels']) \n", + " if j == negative_label]\n", + "\n", + " positive_images = MNIST['Train']['Features'][positive_indices]\n", + " negative_images = MNIST['Train']['Features'][negative_indices]\n", + "\n", + " fig = pylab.figure()\n", + " ax = fig.add_subplot(1, 2, 1)\n", + " pylab.imshow(positive_images[0].reshape(28,28), cmap='gray', interpolation='nearest')\n", + " ax.set_xticks([])\n", + " ax.set_yticks([])\n", + " ax = fig.add_subplot(1, 2, 2)\n", + " pylab.imshow(negative_images[0].reshape(28,28), cmap='gray', interpolation='nearest')\n", + " ax.set_xticks([])\n", + " ax.set_yticks([])\n", + " pylab.show()\n", + " \n", + " return positive_images, negative_images" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "0 ile 1 arasında sınıflandırma yapmaya çalışarak başlayacağız:" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAWAAAACqCAYAAACTZZUqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjMuNCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8QVMy6AAAACXBIWXMAAAsTAAALEwEAmpwYAAAI8UlEQVR4nO3dS6hV1R8H8H3kKuHzopZIiIgEooYRUYN0IGoZCkqiGSIiDq5Y6ERwEBENGog5UtTIBtee+IAok3yEICImSoMiqFEiKb3z+iqse/+TKP6steUc9z33dzz38xl+WXedlZ77ddPae69aX19fAcDAGxK9AIDBSgEDBFHAAEEUMEAQBQwQRAEDBOloZHCtVnPPGk3V19dXG+jP9L2m2cq+166AAYIoYIAgChggiAIGCKKAAYIoYIAgChggiAIGCKKAAYIoYIAgChggiAIGCKKAAYIoYIAgChggiAIGCKKAAYIoYIAgChggiAIGCNLQoZzce06cOJHN582bl2Rr1qzJjt23b1+/romBM3bs2CQbOXJkduwLL7xQ15xPPPFENt+1a1eS9fT0ZMcePXo0yfr6Bt/ZqK6AAYIoYIAgChggiAIGCGITro2cPHkyyZ588sns2N7e3iQbjJsg96JRo0Yl2TPPPJMd+8477yRZR0dzfu0nTpyYZJMmTcqO7e7uTrKtW7dmx3733XeV1tXKXAEDBFHAAEEUMEAQBQwQRAEDBKk1svNdq9Vsk7eAl156KZu//PLLSTZ06NDs2P379yfZunXrsmNv3rzZwOqq6evrqw3Yh/2jVb/XnZ2d2fztt99OskWLFjV5Nc33ww8/ZPMlS5Yk2TfffJMde/Xq1X5dU38p+167AgYIooABgihggCAKGCCITbgWt3Tp0iR7//33s2OHDRuWZF9++WV27Jw5c5Ls2rVrjS2uCWzC/WfhwoXZ/MiRIwO8ktazYcOGbL5nz54BXkl9bMIBtBgFDBBEAQMEUcAAQRQwQBAvZG8RZS+ufuWVV5Isd7dDURTFr7/+mmS5x5OLojXueOA/s2fPTrItW7YErOT/bdq0KckuX76cHbt58+YkKztBuapt27Zl819++SXJDhw40JQ19AdXwABBFDBAEAUMEEQBAwTxKHKAxx9/PMnefPPN7NiZM2fWPe+qVauS7IMPPqh/YS1gsD6KfPDgwSR79tlnK897/vz5JPv888/r/vk33ngjyb766qvs2BEjRiTZ2LFjs2NzG2O534tGHTp0KMmWL19eed6qPIoM0GIUMEAQBQwQRAEDBFHAAEE8itxEq1evzubd3d1JVnY3Su6U1xMnTmTHHj16tIHVEaFWy9/kMWRItWuh3B0wRVEUP/74Y5J99tlnlT6rzI0bN+rKiqIoPv300yR77LHHsmMb+bOZNm1aki1evDg79vDhw3XP2yyugAGCKGCAIAoYIIgCBgjiUeR+MmHChCQ7fvx4dmzu8eKyv4d9+/Yl2dq1axtc3b2j3R9FnjVrVjb/4osvKs07efLkbH7p0qVK8w6kZcuWZfOq7/Mte8y/q6ur0ryN8CgyQItRwABBFDBAEAUMEEQBAwTxKPJd6OzsTLJjx44l2YwZM+qes+yU4o8++qjuOWh9U6ZMqTxHT09Pkt2+fbvyvNHOnDmTzXP/vaNHj272cgaEK2CAIAoYIIgCBgiigAGC2IS7C7nTXxs5vThn0qRJ2bxsc4570++//155jnPnziXZb7/9VnneaFeuXMnmR44cSbKVK1fWPe/TTz+dzUeOHJlk169fr3ve/uAKGCCIAgYIooABgihggCDeB3wH48ePz+a5p94eeeSRuuc9e/Zsks2dOzc79s8//6x73nbQTu8Dzj2t9e2332bHPvDAA5U+qx3eB1xm0aJFSfbxxx9XnnfcuHFJ1qzNTO8DBmgxChggiAIGCKKAAYIoYIAgHkW+g507d2bz3Mm2ubtJyt5vOn/+/CQbbHc7DAYdHemvV9W7HQaj77//PnoJTeMKGCCIAgYIooABgihggCA24f6Re+x46tSpdf987lDErVu3ZsfacBsccu/+fffdd7NjV61a1eTV0IpcAQMEUcAAQRQwQBAFDBBEAQMEGXR3QZQ9Cvree+8l2aOPPpod+8cffyTZ+vXrk+zw4cMNro520tvbm2THjx/Pjq16F8SBAweyee6x94E++bdenZ2d2by7u7vSvHv27Mnm/XFCdVWugAGCKGCAIAoYIIgCBggy6E5F7urqyua7du2qe45Tp04lWdmpxjSmnU5FzhkzZkw2P3nyZJI1ctJ2mfPnzyfZli1b6l5Ds9x///1J9vrrr2fHrl69uu55b926lWTTp0/Pjr148WLd81blVGSAFqOAAYIoYIAgChggiAIGCNLWd0E8//zzSbZ79+7s2FGjRiVZ2anGK1asSLIrV640uDpy2v0uiDKzZ89OsrLv6owZMyp91unTp7P5xo0b6/r5np6ebD5s2LAku++++7Jjc48XP/zww3V9/p0cOnQoyZYvX1553qrcBQHQYhQwQBAFDBBEAQMEaYtNuLLHOy9cuJBkU6ZMqXveZcuWZfMPP/yw7jlozGDdhMvJbfYWRVG89dZbSTZixIhmL+dfP/30UzYfPnx4kg3kuoqiKFauXJlk+/fvH9A15NiEA2gxChggiAIGCKKAAYIoYIAgbXEq8pIlS7J5I3c85IwePbrSz0MVZbv3Dz74YJJt37692cv5V+5l6s109erVJCs7WOGTTz5p9nL6lStggCAKGCCIAgYIooABgrTFJtzt27ezeW9vb5INGZL/N+fvv/9OsoceeqjawqAJ9u7dm2QLFizIjl24cGGzl9Nvbty4kc2fe+65JDt27FizlzMgXAEDBFHAAEEUMEAQBQwQRAEDBGmLF7KX+frrr5OsoyN/48drr72WZLmTW2kuL2S/O2WnD8+fPz/JnnrqqezYF198MclqtfSvo6wzcmN37NiRHfvqq68m2V9//ZUdm3sU+V7jhewALUYBAwRRwABBFDBAkLbehOPeYxOOdmQTDqDFKGCAIAoYIIgCBgiigAGCKGCAIAoYIIgCBgiigAGCKGCAIAoYIIgCBgiigAGCKGCAIAoYIIgCBgiigAGCKGCAIAoYIIgCBgiigAGCdDQ4/ueiKC42YyFQFMXkoM/1vaaZSr/XDR1LD0D/8b8gAIIoYIAgChggiAIGCKKAAYIoYIAgChggiAIGCKKAAYL8D+KUFeSspSmeAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "pos1,neg1 = set_mnist_pos_neg(1,0)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "def plotit2(snapshots_mn,step):\n", + " fig = pylab.figure(figsize=(10,4))\n", + " ax = fig.add_subplot(1, 2, 1)\n", + " pylab.imshow(snapshots_mn[step][0].reshape(28, 28), interpolation='nearest')\n", + " ax.set_xticks([])\n", + " ax.set_yticks([])\n", + " pylab.colorbar()\n", + " ax = fig.add_subplot(1, 2, 2)\n", + " ax.set_ylim([0,1])\n", + " pylab.plot(np.arange(len(snapshots_mn[:,1])), snapshots_mn[:,1])\n", + " pylab.plot(step, snapshots_mn[step,1], \"bo\")\n", + " pylab.show()\n", + "def pl3(step): plotit2(snapshots_mn,step)\n", + "def pl4(step): plotit2(snapshots_mn2,step) " + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "afbc754ef0d04c95a1af039574b46a6b", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "interactive(children=(IntSlider(value=0, description='step', max=66), Output()), _dom_classes=('widget-interac…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 21, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "snapshots_mn = train_graph(pos1,neg1,1000) \n", + "interact(pl3, step=widgets.IntSlider(value=0, min=0, max=len(snapshots_mn) - 1))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Lütfen doğruluğun çok hızlı bir şekilde neredeyse %100'e kadar çıktığına dikkat edin.\n", + "\n", + "Lütfen, kaydırıcıyı eğitimin sonuna doğru bir konuma getirin ve solda çizilen ağırlık matrisini gözlemleyin. Bu matris, algılayıcının gerçekte nasıl çalıştığını anlamanıza izin verecektir. Alanın ortasında tipik olarak 1 rakamı için mevcut olan piksellere karşılık gelen yüksek ağırlık değerlerini ve 0 rakamı bölümlerinin olduğu kenarlarda düşük negatif değerlerini görebilirsiniz. Yani, algılayıcıya sunulan rakam aslında 1 ise, orta kısmı yüksek değerlerle çarpılarak pozitif sonuç üretilecektir. Tersine, algılayıcı 0'ı gözlemlediğinde, karşılık gelen pikseller negatif sayılarla çarpılacaktır.\n", + "\n", + "> Algılayıcımıza yatay olarak hafifçe kaydırılmış bir 1 rakamı verirsek, öyleki pikselleri 0'ın dikey kısımlarının olduğu yeri doldursun, yanlış sonuç alabileceğimizi fark edebilirsiniz. MNIST veri kümemizin doğası gereği, tüm rakamlar ortalanmış ve düzgün bir şekilde konumlandırılmıştır ve algılayıcı, rakamları ayırt etmek için buna güvenir.\n", + "\n", + "Şimdi farklı rakamlar deneyelim:" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "pos2,neg2 = set_mnist_pos_neg(2,5)" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "bf6f25d14c3b4d548ac026af97f70e2a", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "interactive(children=(IntSlider(value=0, description='step', max=66), Output()), _dom_classes=('widget-interac…" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "snapshots_mn2 = train_graph(pos2,neg2,1000)\n", + "interact(pl4, step=widgets.IntSlider(value=0, min=0, max=len(snapshots_mn2) - 1))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Vargılar \n", + "\n", + "Nedense 2 ve 5 o kadar kolay ayrılamaz. Nispeten yüksek doğruluk elde etmemize rağmen (%85'in üzerinde), algılayıcının bir noktada öğrenmeyi nasıl durdurduğunu açıkça görebiliriz.\n", + "\n", + "Bunun neden olduğunu anlamak için [Temel Bileşen Analizi](https://en.wikipedia.org/wiki/Principal_component_analysis) (PCA) kullanmayı deneyebiliriz. Sınıflar arasında en iyi ayrılabilirliği elde edecek şekilde girdi veri kümesinin boyutunu azaltmak için kullanılan bir makine öğrenmesi tekniğidir.\n", + "\n", + "Bizim durumumuzda, bir girdi imgesi 784 piksele (girdi öznitelikleri) sahiptir ve parametre sayısını sadece 2'ye düşürmek için PCA'yı kullanmak istiyoruz, böylece bunları grafik üzerinde çizebiliriz. Bu iki parametre, orijinal özniteliklerin doğrusal bir birleşimi olacaktır ve bu prosedürü, sınıfları ayıran en iyi görünümü elde edene kadar orijinal 784 boyutlu uzayımızı \"döndürmek\" ve 2B uzayımıza izdüşümü gözlemlemek olarak görebiliriz." + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "from sklearn.decomposition import PCA\n", + "\n", + "def pca_analysis(positive_label, negative_label):\n", + " positive_images, negative_images = set_mnist_pos_neg(positive_label, negative_label)\n", + " M = np.append(positive_images, negative_images, 0)\n", + "\n", + " mypca = PCA(n_components=2)\n", + " mypca.fit(M)\n", + " \n", + " pos_points = mypca.transform(positive_images[:200])\n", + " neg_points = mypca.transform(negative_images[:200])\n", + "\n", + " pylab.plot(pos_points[:,0], pos_points[:,1], 'bo')\n", + " pylab.plot(neg_points[:,0], neg_points[:,1], 'ro')" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "pca_analysis(1,0)" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "scrolled": false, + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "pca_analysis(2,5)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "Gördüğünüz gibi, 0 ve 1 düz bir çizgi ile net bir şekilde ayrılabilir. Bu, orijinal 784 boyutlu uzayda rakamlara karşılık gelen noktaların da doğrusal olarak ayrılabilir olduğunu gösterir. 2 ve 5 durumunda, rakamları net bir şekilde ayıracak iyi bir izdüşüm bulamıyoruz ve bu nedenle bazı yanlış sınıflandırma durumları var.\n", + "\n", + "> Bu kursun ilerleyen bölümlerinde, Sinir Ağlarını kullanarak doğrusal olmayan sınıflandırıcıların nasıl oluşturulacağını ve rakamların düzgün şekilde hizalanmaması sorunuyla nasıl başa çıkılacağını öğreneceğiz. Çok yakında 10 farklı sınıfa ayırarak MNIST rakam sınıflandırmasında %99'un üzerinde doğruluğa ulaşacağız.\n", + "\n", + "## Ana Fikirler\n", + " * En basit sinir ağı mimarisini öğrendik - tek katmanlı algılayıcı.\n", + " * Gradyan inişine dayalı basit eğitim prosedürünü kullanarak algılayıcıyı \"elle\" uyguladık.\n", + " * Basitliğine rağmen, tek katmanlı algılayıcı, el yazısı rakam tanımanın oldukça karmaşık problemlerini çözebilir.\n", + " * Tek katmanlı algılayıcı bir doğrusal sınıflandırıcıdır ve bu nedenle lojistik bağlanım (regresyon) ile aynı sınıflandırma gücünü sağlar.\n", + " * Örneklem uzayında, algılayıcı hiperdüzlem kullanarak iki sınıf girdi verisini ayırabilir." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Katkıda Bulunanlar\n", + "\n", + "Bu defter, [Yeni Başlayanlar için Yapay Zeka Müfredatı](http://github.com/microsoft/ai-for-beginners)'nın bir parçasıdır ve [Dmitry Soshnikov](http://soshnikov.com) tarafından hazırlanmıştır. Microsoft Research Cambridge'deki Neural Network Workshop'tan ilham almıştır. Bazı kodlar ve açıklayıcı materyaller [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/)'ın, [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/)'ın ve [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/)'nın sunumlarından ve [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) deposundan alınmıştır." + ] + } + ], + "metadata": { + "celltoolbar": "Slideshow", + "kernelspec": { + "display_name": "Python 3.8.12 ('ai4beg')", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.12" + }, + "livereveal": { + "start_slideshow_at": "selected" + }, + "vscode": { + "interpreter": { + "hash": "d355c6d9fcfa2da36351d09a4957315c029537f44307b30fb3762ace87798487" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/lessons/3-NeuralNetworks/03-Perceptron/translations/README.tr.md b/lessons/3-NeuralNetworks/03-Perceptron/translations/README.tr.md index 1ce3e5b7..81b57609 100644 --- a/lessons/3-NeuralNetworks/03-Perceptron/translations/README.tr.md +++ b/lessons/3-NeuralNetworks/03-Perceptron/translations/README.tr.md @@ -42,8 +42,6 @@ Bu kriter w ağırlıklarının bir fonksiyonu olarak kabul edilir ve bunu en az w(t+1) = w(t) - η∇E(w) -Here η is the so-called **learning rate**, and ∇E(w) denotes the **gradient** of E. After we calculate the gradient, we end up with - Burada η sözde **öğrenme oranı** ve ∇E(w) E'nin **gradyanını** belirtir. Gradyanı hesapladıktan sonra, aşağıdaki işleme varırız: w(t+1) = w(t) + ∑ηxiti @@ -82,7 +80,7 @@ Kendi algılayıcınızı oluşturmaya çalışmak istiyorsanız, [Azure ML tasa ## Gözden Geçirme ve Bireysel Çalışma -Bir oyuncak probleminin yanı sıra gerçek hayattaki problemleri çözmek için algılayıcıyı nasıl kullanabileceğimizi görmek ve öğrenmeye devam etmek için - [Algılayıcı](./Perceptron.tr.ipynb) not defterine gidin. +Bir oyuncak probleminin yanı sıra gerçek hayattaki problemleri çözmek için algılayıcıyı nasıl kullanabileceğimizi görmek ve öğrenmeye devam etmek için [Algılayıcı](./Perceptron.tr.ipynb) not defterine gidin. İşte ilave olarak ilginç bir [algılayıcılar makalesi](https://towardsdatascience.com/what-is-a-perceptron-basics-of-neural-networks-c4cfea20c590). From e02f863a9227bb9b9da9ba7d7099dd6be0381213 Mon Sep 17 00:00:00 2001 From: semercim Date: Sun, 25 Sep 2022 01:09:14 +0200 Subject: [PATCH 18/38] Translated lesson 3 lab to Turkish. --- .../lab/PerceptronMultiClass.ipynb | 11 +- .../03-Perceptron/lab/README.md | 2 +- .../PerceptronMultiClass.tr.ipynb | 235 ++++++++++++++++++ .../lab/translations/README.tr.md | 21 ++ .../translations/Perceptron.tr.ipynb | 8 +- 5 files changed, 269 insertions(+), 8 deletions(-) create mode 100644 lessons/3-NeuralNetworks/03-Perceptron/lab/translations/PerceptronMultiClass.tr.ipynb create mode 100644 lessons/3-NeuralNetworks/03-Perceptron/lab/translations/README.tr.md diff --git a/lessons/3-NeuralNetworks/03-Perceptron/lab/PerceptronMultiClass.ipynb b/lessons/3-NeuralNetworks/03-Perceptron/lab/PerceptronMultiClass.ipynb index 89d11985..789da972 100644 --- a/lessons/3-NeuralNetworks/03-Perceptron/lab/PerceptronMultiClass.ipynb +++ b/lessons/3-NeuralNetworks/03-Perceptron/lab/PerceptronMultiClass.ipynb @@ -193,7 +193,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Code to create *one-vs-other* dataset for two-digit classification. You need to modify this code to create *one-vs-all* dateset." + "Code to create *one-vs-other* dataset for two-digit classification. You need to modify this code to create *one-vs-all* dataset." ] }, { @@ -239,7 +239,7 @@ "metadata": { "celltoolbar": "Slideshow", "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Python 3.10.6 64-bit", "language": "python", "name": "python3" }, @@ -253,10 +253,15 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.5" + "version": "3.10.6" }, "livereveal": { "start_slideshow_at": "selected" + }, + "vscode": { + "interpreter": { + "hash": "b0fa6594d8f4cbf19f97940f81e996739fb7646882a419484c72d19e05852a7e" + } } }, "nbformat": 4, diff --git a/lessons/3-NeuralNetworks/03-Perceptron/lab/README.md b/lessons/3-NeuralNetworks/03-Perceptron/lab/README.md index f7248b20..a4737753 100644 --- a/lessons/3-NeuralNetworks/03-Perceptron/lab/README.md +++ b/lessons/3-NeuralNetworks/03-Perceptron/lab/README.md @@ -14,6 +14,6 @@ Using the code we have developed in this lesson for binary classification of MNI > **Hint**: If we combine weights of all 10 perceptrons into one matrix, we should be able to apply all 10 perceptrons to the input digits by one matrix multiplication. Most probable digit can then be found just by applying `argmax` operation on the output. -## Stating Notebook +## Starting Notebook Start the lab by opening [PerceptronMultiClass.ipynb](PerceptronMultiClass.ipynb) diff --git a/lessons/3-NeuralNetworks/03-Perceptron/lab/translations/PerceptronMultiClass.tr.ipynb b/lessons/3-NeuralNetworks/03-Perceptron/lab/translations/PerceptronMultiClass.tr.ipynb new file mode 100644 index 00000000..73f7cf50 --- /dev/null +++ b/lessons/3-NeuralNetworks/03-Perceptron/lab/translations/PerceptronMultiClass.tr.ipynb @@ -0,0 +1,235 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true, + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "# Algılayıcı ile Çok Sınıflı Sınıflandırma\n", + "\n", + "[Yeni Başlayanlar için Yapay Zeka Müfredatı](https://github.com/microsoft/ai-for-beginners)'ndan Laboratuvar Ödevi." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "import numpy as np\n", + "import pickle\n", + "import os" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Dersten aşağıdaki algılayıcı eğitim kodunu kullanabilirsiniz:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "def train(positive_examples, negative_examples, num_iterations = 100):\n", + " num_dims = positive_examples.shape[1]\n", + " weights = np.zeros((num_dims,1)) # ağırlıkları ilkle\n", + " \n", + " pos_count = positive_examples.shape[0]\n", + " neg_count = negative_examples.shape[0]\n", + " \n", + " report_frequency = 10\n", + " \n", + " for i in range(num_iterations):\n", + " pos = random.choice(positive_examples)\n", + " neg = random.choice(negative_examples)\n", + "\n", + " z = np.dot(pos, weights) \n", + " if z < 0:\n", + " weights = weights + pos.reshape(weights.shape)\n", + "\n", + " z = np.dot(neg, weights)\n", + " if z >= 0:\n", + " weights = weights - neg.reshape(weights.shape)\n", + " \n", + " if i % report_frequency == 0: \n", + " pos_out = np.dot(positive_examples, weights)\n", + " neg_out = np.dot(negative_examples, weights) \n", + " pos_correct = (pos_out >= 0).sum() / float(pos_count)\n", + " neg_correct = (neg_out < 0).sum() / float(neg_count)\n", + " print(\"Yineleme={}, pozitif doğruluk={}, negatif doğruluk={}\".format(i,pos_correct,neg_correct))\n", + "\n", + " return weights" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "fragment" + } + }, + "outputs": [], + "source": [ + "def accuracy(weights, test_x, test_labels):\n", + " res = np.dot(np.c_[test_x,np.ones(len(test_x))],weights)\n", + " return (res.reshape(test_labels.shape)*test_labels>=0).sum()/float(len(test_labels))\n", + "\n", + "accuracy(wts, test_x, test_labels)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true, + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Veri Kümesini Okuma\n", + "\n", + "Bu kod, veri kümesini internetteki depodan indirir. AI Müfredat deposunun `/data` dizininden veri kümesini manuel olarak da kopyalayabilirsiniz." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "!rm *.pkl\n", + "!wget https://raw.githubusercontent.com/microsoft/AI-For-Beginners/main/data/mnist.pkl.gz\n", + "!gzip -d mnist.pkl.gz" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "with open('mnist.pkl', 'rb') as mnist_pickle:\n", + " MNIST = pickle.load(mnist_pickle)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "print(MNIST['Train']['Features'][0][130:180])\n", + "print(MNIST['Train']['Labels'][0])\n", + "features = MNIST['Train']['Features'].astype(np.float32) / 256.0\n", + "labels = MNIST['Train']['Labels']\n", + "fig = plt.figure(figsize=(10,5))\n", + "for i in range(10):\n", + " ax = fig.add_subplot(1,10,i+1)\n", + " plt.imshow(features[i].reshape(28,28))\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "İki rakamlı sınıflandırma için *bire karşı diğeri* veri kümesi oluşturma kodu. *Bire karşı hepsi* veri kümesi oluşturmak için bu kodu değiştirmeniz gerekir." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "def set_mnist_pos_neg(positive_label, negative_label):\n", + " positive_indices = [i for i, j in enumerate(MNIST['Train']['Labels']) \n", + " if j == positive_label]\n", + " negative_indices = [i for i, j in enumerate(MNIST['Train']['Labels']) \n", + " if j == negative_label]\n", + "\n", + " positive_images = MNIST['Train']['Features'][positive_indices]\n", + " negative_images = MNIST['Train']['Features'][negative_indices]\n", + "\n", + " return positive_images, negative_images" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Şimdi yapmanız gerekenler:\n", + "1. Tüm rakamlar için 10 *bire karşı hepsi* veri kümesi oluşturun.\n", + "1. 10 algılayıcı eğitin.\n", + "1. Rakam sınıflandırmasını gerçekleştirmek için `classify` (sınıflandırma) işlevini tanımlayın.\n", + "1. Sınıflandırmanın doğruluğunu ölçün ve *hata matrisi*ni yazdırın.\n", + "1. [İsteğe bağlı] Bir matris çarpımı kullanarak sınıflandırmayı gerçekleştiren gelişmiş `classify` işlevini oluşturun." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "celltoolbar": "Slideshow", + "kernelspec": { + "display_name": "Python 3.8.12 ('ai4beg')", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.12" + }, + "livereveal": { + "start_slideshow_at": "selected" + }, + "vscode": { + "interpreter": { + "hash": "d355c6d9fcfa2da36351d09a4957315c029537f44307b30fb3762ace87798487" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/lessons/3-NeuralNetworks/03-Perceptron/lab/translations/README.tr.md b/lessons/3-NeuralNetworks/03-Perceptron/lab/translations/README.tr.md new file mode 100644 index 00000000..72c6b90e --- /dev/null +++ b/lessons/3-NeuralNetworks/03-Perceptron/lab/translations/README.tr.md @@ -0,0 +1,21 @@ +# Algılayıcı ile Çok Sınıflı Sınıflandırma + +[Yeni Başlayanlar için Yapay Zeka Müfredatı](https://github.com/microsoft/ai-for-beginners)'ndan Laboratuvar Ödevi. + +## Görevs + +MNIST el yazısı rakamlarının ikili sınıflandırması için bu derste geliştirdiğimiz kodu kullanarak, herhangi bir rakamı tanıyabilecek çok sınıflı bir sınıflandırma oluşturun. Eğitim ve test veri kümesindeki sınıflandırma doğruluğunu hesaplayın ve hata matrisini yazdırın. + +## İpuçları + +1. Her rakam için, "bu rakam ve diğer tüm rakamlar" ikili sınıflandırıcısı için bir veri kümesi oluşturun. +1. İkili sınıflandırma için 10 farklı algılayıcı eğitin (her rakam için bir tane). +1. Bir girdi rakamını sınıflandıracak bir fonksiyon tanımlayın. + +> **Hint**: If we combine weights of all 10 perceptrons into one matrix, we should be able to apply all 10 perceptrons to the input digits by one matrix multiplication. Most probable digit can then be found just by applying `argmax` operation on the output. + +**İpucu**: Tüm 10 algılayıcının ağırlıklarını tek bir matriste birleştirirsek, 10 algılayıcının tümünü bir matris çarpımı ile girdi rakamlarına uygulayabilmeliyiz. En olası basamak, çıktıya yalnızca `argmax` işlemi uygulanarak bulunabilir. + +## Başlangıç Not Defteri + +[PerceptronMultiClass.tr.ipynb](PerceptronMultiClass.tr.ipynb) dosyasını açarak laboratuvarı başlatın. diff --git a/lessons/3-NeuralNetworks/03-Perceptron/translations/Perceptron.tr.ipynb b/lessons/3-NeuralNetworks/03-Perceptron/translations/Perceptron.tr.ipynb index 698731ff..57948cda 100644 --- a/lessons/3-NeuralNetworks/03-Perceptron/translations/Perceptron.tr.ipynb +++ b/lessons/3-NeuralNetworks/03-Perceptron/translations/Perceptron.tr.ipynb @@ -651,7 +651,7 @@ "outputs": [], "source": [ "# Bu not defterini klonlanmış bir depodan çalıştırmıyorsanız, önce ikili veri kümesi dosyasını almanız gerekebilir.\n", - "# !wget https://github.com/microsoft/AI-For-Beginners/blob/main/data/mnist.pkl.gz?raw=true\n", + "# !wget https://raw.githubusercontent.com/microsoft/AI-For-Beginners/main/data/mnist.pkl.gz\n", "# Bu durumda aşağıdaki veri kümesinin bağlantısını da düzeltin.\n", "\n", "with gzip.open('../../data/mnist.pkl.gz', 'rb') as mnist_pickle:\n", @@ -1070,7 +1070,7 @@ "metadata": { "celltoolbar": "Slideshow", "kernelspec": { - "display_name": "Python 3.8.12 ('ai4beg')", + "display_name": "Python 3.10.6 64-bit", "language": "python", "name": "python3" }, @@ -1084,14 +1084,14 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.12" + "version": "3.10.6" }, "livereveal": { "start_slideshow_at": "selected" }, "vscode": { "interpreter": { - "hash": "d355c6d9fcfa2da36351d09a4957315c029537f44307b30fb3762ace87798487" + "hash": "b0fa6594d8f4cbf19f97940f81e996739fb7646882a419484c72d19e05852a7e" } } }, From 7059027feed42ac70a4685712ea6cc631b0b36f6 Mon Sep 17 00:00:00 2001 From: semercim Date: Sun, 25 Sep 2022 21:12:50 +0200 Subject: [PATCH 19/38] Finished Turkish translation of lesson 3's quiz. --- .../src/assets/translations/tr/index.js | 4 +- .../src/assets/translations/tr/lesson-3.json | 115 ++++++++++++++++++ 2 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 etc/quiz-app/src/assets/translations/tr/lesson-3.json diff --git a/etc/quiz-app/src/assets/translations/tr/index.js b/etc/quiz-app/src/assets/translations/tr/index.js index 42255a08..a81da928 100644 --- a/etc/quiz-app/src/assets/translations/tr/index.js +++ b/etc/quiz-app/src/assets/translations/tr/index.js @@ -1,9 +1,11 @@ import tr1 from './lesson-1.json'; import tr2 from './lesson-2.json'; +import tr3 from './lesson-3.json'; //add items here const quiz = { 0: tr1[0], - 1: tr2[0] + 1: tr2[0], + 2: tr3[0] }; export default quiz; diff --git a/etc/quiz-app/src/assets/translations/tr/lesson-3.json b/etc/quiz-app/src/assets/translations/tr/lesson-3.json new file mode 100644 index 00000000..00400c91 --- /dev/null +++ b/etc/quiz-app/src/assets/translations/tr/lesson-3.json @@ -0,0 +1,115 @@ +[ + { + "title": "Yeni Başlayanlar İçin YZ: Sınavlar", + "complete": "Tebrikler, sınavı tamamladınız!", + "error": "Üzgünüz, tekrar deneyin", + "quizzes": [ + { + "id": 103, + "title": "Sinir Ağlarına Giriş - Algılayıcı: Ön Sınav", + "quiz": [ + { + "questionText": "İlk sinir ağları şuna ihtiyaç duyuyordu:", + "answerOptions": [ + { + "answerText": "elle ağırlık ayarlama", + "isCorrect": true + }, + { + "answerText": "terabaytlarca veri", + "isCorrect": false + }, + { + "answerText": "özel akıl yürütme", + "isCorrect": false + } + ] + }, + { + "questionText": "Basit bir nörona 'eşik mantık birimi' de denir", + "answerOptions": [ + { + "answerText": "doğru", + "isCorrect": true + }, + { + "answerText": "yanlış", + "isCorrect": false + } + ] + }, + { + "questionText": "Algılayıcı bir ___ türü modeldir.", + "answerOptions": [ + { + "answerText": "çok sınıflı sınıflandırma", + "isCorrect": false + }, + { + "answerText": "öbekleme", + "isCorrect": false + }, + { + "answerText": "ikili sınıflandırma", + "isCorrect": true + } + ] + } + ] + }, + { + "id": 203, + "title": "Sinir Ağlarına Giriş - Algılayıcı: Ders Sonrası Sınavı", + "quiz": [ + { + "questionText": "Bir algılayıcı eğitmek için en küçük ___ ile sonlanan ağırlık vektörünü bulun.", + "answerOptions": [ + { + "answerText": "boyut", + "isCorrect": false + }, + { + "answerText": "hata", + "isCorrect": true + }, + { + "answerText": "düğüm", + "isCorrect": false + } + ] + }, + { + "questionText": "Ağırlık işlevini en aza indirirken gradyan inişini kullanabilirsiniz.", + "answerOptions": [ + { + "answerText": "doğru", + "isCorrect": true + }, + { + "answerText": "yanlış", + "isCorrect": false + } + ] + }, + { + "questionText": "Eğitim esnasında her adımda ___ güncellenir.", + "answerOptions": [ + { + "answerText": "öğrenme oranı", + "isCorrect": false + }, + { + "answerText": "ağırlıklar", + "isCorrect": true + }, + { + "answerText": "gradyan", + "isCorrect": false + } + ] + } + ] + } + ] + } +] \ No newline at end of file From 9c63c8728710557a89f59a83b702a28966ac2e9a Mon Sep 17 00:00:00 2001 From: semercim Date: Thu, 29 Sep 2022 13:24:55 +0200 Subject: [PATCH 20/38] Update to the latest change from the main English version. --- translations/README.tr.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/translations/README.tr.md b/translations/README.tr.md index e8b66af2..103e114a 100644 --- a/translations/README.tr.md +++ b/translations/README.tr.md @@ -27,16 +27,16 @@ Bu müfredatta şunları öğreneceksiniz: Bu müfredatta neleri ele almayacağız: -* **İşte YZ** kullanımına ilişkin iş vakaları. Microsoft Öğrenme yolunundaki [İş için YZ'ye Giriş](https://docs.microsoft.com/learn/paths/introduction-ai-for-business-users/?WT.mc_id=academic-57639-dmitryso)'i veya [INSEAD](https://www.insead.edu/) ile işbirliğiyle geliştirilmiş [YZ İş Okulu](https://www.microsoft.com/ai/ai-business-school/?WT.mc_id=academic-57639-dmitryso)'nu almayı düşünün. +* **İşte YZ** kullanımına ilişkin iş vakaları. Microsoft Öğrenme yolunundaki [İş için YZ'ye Giriş](https://docs.microsoft.com/learn/paths/introduction-ai-for-business-users/?WT.mc_id=academic-77998-cacaste)'i veya [INSEAD](https://www.insead.edu/) ile işbirliğiyle geliştirilmiş [YZ İş Okulu](https://www.microsoft.com/ai/ai-business-school/?WT.mc_id=academic-77998-cacaste)'nu almayı düşünün. * **Klasik Yapay Öğrenme**, [Yeni Başlayanlar için Yapay Öğrenme Müfredatı](http://github.com/Microsoft/ML-for-Beginners)'mızda iyice açıklanmıştır. -* **[Bilişsel Hizmetler](https://azure.microsoft.com/services/cognitive-services/?WT.mc_id=academic-57639-dmitryso)** kullanılarak oluşturulmuş pratik YZ uygulamaları. Bunun gibi [görme](https://docs.microsoft.com/learn/paths/create-computer-vision-solutions-azure-cognitive-services/?WT.mc_id=academic-57639-dmitryso), [doğal dil işleme](https://docs.microsoft.com/learn/paths/explore-natural-language-processing/?WT.mc_id=academic-57639-dmitryso) ve diğerleri için Microsoft Öğrenme modülleriyle başlamanızı öneririz. -* [Azure Yapay Öğrenme](https://azure.microsoft.com/services/machine-learning/?WT.mc_id=academic-57639-dmitryso) veya [Azure Databricks](https://docs.microsoft.com/learn/paths/data-engineer-azure-databricks?WT.mc_id=academic-57639-dmitryso) gibi belli YÖ **Bulut Çerçeveleri**. [Azure Yapay Öğrenme ile yapay öğrenme çözümleri oluşturma ve çalıştırma](https://docs.microsoft.com/learn/paths/build-ai-solutions-with-azure-ml-service/?WT.mc_id=academic-57639-dmitryso) ve [Azure Databricks ile yapay öğrenme çözümleri oluşturma ve çalıştırma](https://docs.microsoft.com/learn/paths/build-operate-machine-learning-solutions-azure-databricks/?WT.mc_id=academic-57639-dmitryso) öğrenme yollarını kullanmayı düşünün. -* **Konuşkan YZ** ve **Sohbet Botları**. Ayrı bir [konuşkan YZ çözümleri yaratma](https://docs.microsoft.com/learn/paths/create-conversational-ai-solutions/?WT.mc_id=academic-57639-dmitryso) öğrenme yolu vardır, ayrıca daha fazla ayrıntı için [bu blog gönderisine](https://soshnikov.com/azure/hello-bot-conversational-ai-on-microsoft-platform/) bakın. +* **[Bilişsel Hizmetler](https://azure.microsoft.com/services/cognitive-services/?WT.mc_id=academic-77998-cacaste)** kullanılarak oluşturulmuş pratik YZ uygulamaları. Bunun gibi [görme](https://docs.microsoft.com/learn/paths/create-computer-vision-solutions-azure-cognitive-services/?WT.mc_id=academic-77998-cacaste), [doğal dil işleme](https://docs.microsoft.com/learn/paths/explore-natural-language-processing/?WT.mc_id=academic-77998-cacaste) ve diğerleri için Microsoft Öğrenme modülleriyle başlamanızı öneririz. +* [Azure Yapay Öğrenme](https://azure.microsoft.com/services/machine-learning/?WT.mc_id=academic-77998-cacaste) veya [Azure Databricks](https://docs.microsoft.com/learn/paths/data-engineer-azure-databricks?WT.mc_id=academic-77998-cacaste) gibi belli YÖ **Bulut Çerçeveleri**. [Azure Yapay Öğrenme ile yapay öğrenme çözümleri oluşturma ve çalıştırma](https://docs.microsoft.com/learn/paths/build-ai-solutions-with-azure-ml-service/?WT.mc_id=academic-77998-cacaste) ve [Azure Databricks ile yapay öğrenme çözümleri oluşturma ve çalıştırma](https://docs.microsoft.com/learn/paths/build-operate-machine-learning-solutions-azure-databricks/?WT.mc_id=academic-77998-cacaste) öğrenme yollarını kullanmayı düşünün. +* **Konuşkan YZ** ve **Sohbet Botları**. Ayrı bir [konuşkan YZ çözümleri yaratma](https://docs.microsoft.com/learn/paths/create-conversational-ai-solutions/?WT.mc_id=academic-77998-cacaste) öğrenme yolu vardır, ayrıca daha fazla ayrıntı için [bu blog gönderisine](https://soshnikov.com/azure/hello-bot-conversational-ai-on-microsoft-platform/) bakın. * Derin öğrenmenin ardındaki **Derin Matematik**. Bunun için Ian Goodfellow, Yoshua Bengio ve Aaron Courville tarafından yazılmış [Derin Öğrenme](https://www.amazon.com/Deep-Learning-Adaptive-Computation-Machine/dp/0262035618) adlı [https://www.deeplearningbook.org/](https://www.deeplearningbook.org/) adresinden de ulaşılabilir kitabı tavsiye ediyoruz. -For a gentle introduction to *AI in the Cloud* topics you may consider taking the [Get started with artificial intelligence on Azure](https://docs.microsoft.com/learn/paths/get-started-with-artificial-intelligence-on-azure/?WT.mc_id=academic-57639-dmitryso) Learning Path. +For a gentle introduction to *AI in the Cloud* topics you may consider taking the [Get started with artificial intelligence on Azure](https://docs.microsoft.com/learn/paths/get-started-with-artificial-intelligence-on-azure/?WT.mc_id=academic-77998-cacaste) Learning Path. -*Bulutta Yapay Zeka* konularına nazik bir giriş için [Azure'de yapay zekayı kullanmaya başlama](https://docs.microsoft.com/learn/paths/get-started-with-artificial-intelligence-on-azure/?WT.mc_id=academic-57639-dmitryso) öğrenme yolunu almayı düşünebilirsiniz. +*Bulutta Yapay Zeka* konularına nazik bir giriş için [Azure'de yapay zekayı kullanmaya başlama](https://docs.microsoft.com/learn/paths/get-started-with-artificial-intelligence-on-azure/?WT.mc_id=academic-77998-cacaste) öğrenme yolunu almayı düşünebilirsiniz. --- # İçerik @@ -61,11 +61,11 @@ For a gentle introduction to *AI in the Cloud* topics you may consider taking th Keras/TensorFlow Lab IVBilgisayarla Görme - YZ Temelleri: Bilgisayarla Görmeyi Keşfedin + YZ Temelleri: Bilgisayarla Görmeyi Keşfedin Bilgisayarla Görmede Microsoft Öğrenme Modülü - PyTorch - TensorFlow + PyTorch + TensorFlow 6Bilgisayarla Görmeye Giriş. OpenCVMetinDefterLab 7Evrişimli Sinir Ağları
CNN MimarileriMetin
MetinPyTorchTensorFlowLab @@ -75,11 +75,11 @@ For a gentle introduction to *AI in the Cloud* topics you may consider taking th 11Nesne TespitiMetinPyTorchTensorFlowLab 12Anlamsal Bölünme. U-NetMetinPyTorchTensorFlow VDoğal Dil İşleme - YZ Temelleri: Doğal Dil İşlemeyi Keşfedin + YZ Temelleri: Doğal Dil İşlemeyi Keşfedin Doğal Dil Üstüne Microsoft Öğrenme Modülü - PyTorch - TensorFlow + PyTorch + TensorFlow 13Metin Temsili. Bow/TF-IDFMetinPyTorchTensorFlow 14Anlamsal kelime gömmeleri. Word2Vec and GloVeMetinPyTorchTensorFlow @@ -94,7 +94,7 @@ For a gentle introduction to *AI in the Cloud* topics you may consider taking th 22Derin Pekiştirmeli ÖğrenmeMetinTensorFlowLab 23Çok Etmenli SistemlerMetin VIIYZ Etiği -24YZ Etiği ve Sorumlu YZMetinMicrosoft Öğrenme Modülü: Sorumlu YZ İlkeleri +24YZ Etiği ve Sorumlu YZMetinMicrosoft Öğrenme Modülü: Sorumlu YZ İlkeleri Ekstralar X1Çok Modlu Ağlar, CLIP and VQGANMetinDefter @@ -122,7 +122,7 @@ Ancak, dersi kendi kendine çalışma projesi olarak almak istiyorsanız, tüm d - "Yüksek sesle öğrenmek" için [tartışma panosunu](https://github.com/microsoft/AI-For-Beginners/discussions) ziyaret edin. - Diğer öğrencilerle [Gitter](https://gitter.im/Microsoft/ai-for-beginners)'da veya [Telegram kanalı](http://t.me/ai_for_beginners)nda konuşun. -> Daha fazla çalışma için bu [Microsoft Öğrenme](https://docs.microsoft.com/en-us/users/dmitrysoshnikov-9132/collections/31zgizg2p418yo/?WT.mc_id=academic-57639-dmitryso) modüllerini ve öğrenme yollarını takip etmenizi öneririz. +> Daha fazla çalışma için bu [Microsoft Öğrenme](https://docs.microsoft.com/en-us/users/dmitrysoshnikov-9132/collections/31zgizg2p418yo/?WT.mc_id=academic-77998-cacaste) modüllerini ve öğrenme yollarını takip etmenizi öneririz. **Eğitimciler**, bu müfredatın nasıl kullanılacağına ilişkin [bazı öneriler ekledik](/etc/for-teachers.md). From 5b6d08589e235855247320c27d2f0c1ed4afbd03 Mon Sep 17 00:00:00 2001 From: semercim Date: Thu, 29 Sep 2022 13:41:55 +0200 Subject: [PATCH 21/38] Update to the latest change from the main English version. --- lessons/2-Symbolic/translations/README.tr.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lessons/2-Symbolic/translations/README.tr.md b/lessons/2-Symbolic/translations/README.tr.md index 31427b0a..12ccb35c 100644 --- a/lessons/2-Symbolic/translations/README.tr.md +++ b/lessons/2-Symbolic/translations/README.tr.md @@ -214,7 +214,7 @@ Aile ilişkileri hakkında akıl yürütmede Anlamsal Web tekniklerini kullanma Çoğu durumda, ontolojiler dikkatle elle oluşturulur. Bununla birlikte, örneğin doğal dil metinlerinden yapılandırılmamış verilerden ontolojiler **çıkarmak** da mümkündür. -Böyle bir girişim Microsoft Research tarafından yapıldı ve [Microsoft Kavram Çizgesi](https://blogs.microsoft.com/ai/microsoft-researchers-release-graph-that-helps-machines-conceptualize/?WT.mc_id=academic-57639-dmitryso) ile sonuçlandı. +Böyle bir girişim Microsoft Research tarafından yapıldı ve [Microsoft Kavram Çizgesi](https://blogs.microsoft.com/ai/microsoft-researchers-release-graph-that-helps-machines-conceptualize/?WT.mc_id=academic-77998-cacaste) ile sonuçlandı. `is-a` (bir örneği olma) kalıtım ilişkisi kullanılarak gruplandırılmış geniş bir varlıklar topluluğudur. "Microsoft Nedir?" gibi soruların yanıtlanmasına olanak tanır - cevap, "0.87 olasılıkla bir şirket ve 0.75 olasılıkla bir marka" gibi bir şeydir. From fa548eeb320de651dacd3ff3b0e42c53e267ed89 Mon Sep 17 00:00:00 2001 From: semercim Date: Thu, 29 Sep 2022 13:42:26 +0200 Subject: [PATCH 22/38] Update to the latest change from the main English version. --- lessons/2-Symbolic/translations/README.tr.md | 2 +- .../3-NeuralNetworks/03-Perceptron/translations/README.tr.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lessons/2-Symbolic/translations/README.tr.md b/lessons/2-Symbolic/translations/README.tr.md index 31427b0a..12ccb35c 100644 --- a/lessons/2-Symbolic/translations/README.tr.md +++ b/lessons/2-Symbolic/translations/README.tr.md @@ -214,7 +214,7 @@ Aile ilişkileri hakkında akıl yürütmede Anlamsal Web tekniklerini kullanma Çoğu durumda, ontolojiler dikkatle elle oluşturulur. Bununla birlikte, örneğin doğal dil metinlerinden yapılandırılmamış verilerden ontolojiler **çıkarmak** da mümkündür. -Böyle bir girişim Microsoft Research tarafından yapıldı ve [Microsoft Kavram Çizgesi](https://blogs.microsoft.com/ai/microsoft-researchers-release-graph-that-helps-machines-conceptualize/?WT.mc_id=academic-57639-dmitryso) ile sonuçlandı. +Böyle bir girişim Microsoft Research tarafından yapıldı ve [Microsoft Kavram Çizgesi](https://blogs.microsoft.com/ai/microsoft-researchers-release-graph-that-helps-machines-conceptualize/?WT.mc_id=academic-77998-cacaste) ile sonuçlandı. `is-a` (bir örneği olma) kalıtım ilişkisi kullanılarak gruplandırılmış geniş bir varlıklar topluluğudur. "Microsoft Nedir?" gibi soruların yanıtlanmasına olanak tanır - cevap, "0.87 olasılıkla bir şirket ve 0.75 olasılıkla bir marka" gibi bir şeydir. diff --git a/lessons/3-NeuralNetworks/03-Perceptron/translations/README.tr.md b/lessons/3-NeuralNetworks/03-Perceptron/translations/README.tr.md index 81b57609..52854986 100644 --- a/lessons/3-NeuralNetworks/03-Perceptron/translations/README.tr.md +++ b/lessons/3-NeuralNetworks/03-Perceptron/translations/README.tr.md @@ -74,7 +74,7 @@ Bu derste, ikili sınıflandırma modeli olan algılayıcıyı ve ağırlık vek ## 🚀 Kendini Sınama -Kendi algılayıcınızı oluşturmaya çalışmak istiyorsanız, [Azure ML tasarımcısını (Azure ML designer)](https://docs.microsoft.com/en-us/azure/machine-learning/concept-designer?WT.mc_id=academic-57639-dmitryso) kullanan [Microsoft Learn'deki bu laboratuvarı](https://docs.microsoft.com/en-us/azure/machine-learning/component-reference/two-class-averaged-perceptron?WT.mc_id=academic-57639-dmitryso) deneyin. +Kendi algılayıcınızı oluşturmaya çalışmak istiyorsanız, [Azure ML tasarımcısını (Azure ML designer)](https://docs.microsoft.com/en-us/azure/machine-learning/concept-designer?WT.mc_id=academic-77998-cacaste) kullanan [Microsoft Learn'deki bu laboratuvarı](https://docs.microsoft.com/en-us/azure/machine-learning/component-reference/two-class-averaged-perceptron?WT.mc_id=academic-77998-cacaste) deneyin. ## [Ders sonrası sınavı](https://red-field-0a6ddfd03.1.azurestaticapps.net/quiz/203) From 47d1053216ae3a0761b8608d0a091c14f8d4716e Mon Sep 17 00:00:00 2001 From: semercim Date: Fri, 30 Sep 2022 21:55:11 +0200 Subject: [PATCH 23/38] Translating lesson 4 to Turkish. --- .../04-OwnFramework/translations/README.tr.md | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 lessons/3-NeuralNetworks/04-OwnFramework/translations/README.tr.md diff --git a/lessons/3-NeuralNetworks/04-OwnFramework/translations/README.tr.md b/lessons/3-NeuralNetworks/04-OwnFramework/translations/README.tr.md new file mode 100644 index 00000000..256da0f5 --- /dev/null +++ b/lessons/3-NeuralNetworks/04-OwnFramework/translations/README.tr.md @@ -0,0 +1,86 @@ +# Sinir Ağlarına Giriş. Çok Katmanlı Algılayıcı + +Önceki bölümde, en basit sinir ağı modelini öğrendiniz - tek katmanlı algılayıcı, doğrusal iki sınıflı sınıflandırma modeli. + +Bu bölümde, bu modeli daha esnek bir çerçeveye genişleterek şunları yapmayı sağlayacağız: + +* İki sınıfa ek olarak **çok sınıflı sınıflandırma** gerçekleştirme +* Sınıflandırmaya ek olarak **regresyon (bağlanım) problemlerini** çözme +* Doğrusal olarak ayrılamayan sınıfları ayırma. + +Python'da farklı sinir ağı mimarileri oluşturmamıza izin verecek kendi modüler çerçevemizi de geliştireceğiz. + +## [Ders öncesi sınavı](https://red-field-0a6ddfd03.1.azurestaticapps.net/quiz/104) + +## Makine Öğrenmesinin Formülleştirilmesi + +Makine Öğrenmesi problemini formülleştirerek başlayalım. **Y** etiketli bir **X** eğitim veri kümemiz olduğunu ve en doğru tahminleri yapacak bir *f* modeli oluşturmamız gerektiğini varsayalım. Tahminlerin kalitesi **Kayıp işlevi** ℒ ile ölçülür. Aşağıdaki kayıp fonksiyonları sıklıkla kullanılır: + +* Bağlanım problemi için, bir sayıyı tahmin etmemiz gerektiğinde, **mutlak hata** ∑i|f(x(i))-y(i)| veya **kare hatası** ∑i(f(x(i))-y(i ))2 kullanabiliriz. +* Sınıflandırma için **0-1 kaybı** (esas olarak modelin **doğruluğu** ile aynıdır) veya **lojistik kayıp** kullanırız. + +Tek katmanlı algılayıcı için *f* işlevi, *f(x)=wx+b* doğrusal işlevi olarak tanımlanmıştır (burada *w* ağırlık matrisidir, *x* girdi özniteliklerinin vektörüdür ve *b* ek girdi vektörüdür). Farklı sinir ağı mimarileri için bu işlev daha karmaşık bir biçim alabilir. + +> Sınıflandırma vakasında, genellikle ağ çıktısı olarak karşılık gelen sınıfların olasılıklarının alınması arzu edilir. Rastgele sayıları olasılıklara dönüştürmek için (örneğin çıktıyı normalleştirmek için), genellikle **softmaks** işlevi σ'yı kullanırız ve *f* işlevi *f(x)=σ(wx+b)* olur. + +Yukarıdaki *f* tanımında *w* ve *b*, θ=⟨*w,b*⟩ **parametreler**i olarak adlandırılır. Veri kümesi ⟨**X**,**Y**⟩ verildiğinde, θ parametrelerinin bir fonksiyonu olarak tüm veri kümesindeki genel bir hatayı hesaplayabiliriz. + +> ✅ **Sinir ağı eğitiminin amacı, θ parametrelerini değiştirerek hatayı en aza indirmektir.** + +## Gradyan İnişi Eniyilemesi + +**Gradyan iniş**i adı verilen iyi bilinen bir işlev eniyileme yöntemi vardır. Buradaki fikir, parametrelere göre kayıp fonksiyonunun bir türevini (çok boyutlu durumda **gradyan** olarak adlandırılır) hesaplayabilmemiz ve parametreleri, hatanın azalacağı şekilde değiştirebilmemizdir. Bu, aşağıdaki gibi formüle dökülebilir: + +* Parametreleri bazı rastgele değerlerle ilklet w(0), b(0) +* Aşağıdaki adımı birçok kez tekrarlayın: + - w(i+1) = w(i)-η∂ℒ/∂w + - b(i+1) = b(i)-η∂ℒ/∂b + +Eğitim esnasında, eniyileme adımlarının tüm veri kümesi dikkate alınarak hesaplanması gerekir (kaybın tüm eğitim örneklerinin toplamı olarak hesaplandığını unutmayın). Bununla birlikte, gerçek hayatta **minigruplar** olarak adlandırılan veri kümesinin küçük kısımlarını alır ve bir veri alt kümesine dayalı olarak gradyanları hesaplarız. Alt küme her seferinde rastgele alındığından, bu yönteme **rasgele gradyan inişi** (SGD - RGİ) denir. + +## Çok Katmanlı Algılayıcılar ve Geri Yayma + +Tek katmanlı ağ, yukarıda gördüğümüz gibi, doğrusal olarak ayrılabilir sınıfları sınıflandırma yeteneğine sahiptir. Daha zengin bir model oluşturmak için ağın birkaç katmanını birleştirebiliriz. Matematiksel olarak bu, *f* fonksiyonunun daha karmaşık bir forma sahip olacağı ve birkaç adımda hesaplanacağı anlamına gelir: +* z1=w1x+b1 +* z2=w2α(z1)+b2 +* f = σ(z2) + +Burada, α bir **doğrusal olmayan etkinleştirme işlevidir**, σ bir softmaks işlevidir ve θ=<*w1,b1,w2,b2*> parametreleridir. + +Gradyan inişi algoritması aynı kalacaktır, ancak gradyanları hesaplamak daha zor olacaktır. Zincir türev alma kuralı göz önüne alındığında, türevleri şu şekilde hesaplayabiliriz: + +* ∂ℒ/∂w2 = (∂ℒ/∂σ)(∂σ/∂z2)(∂z2/∂w2) +* ∂ℒ/∂w1 = (∂ℒ/∂σ)(∂σ/∂z2)(∂z2/∂α)(∂α/∂z1)(∂z1/∂w1) + +> ✅ Parametrelere göre kayıp fonksiyonunun türevlerini hesaplamak için zincir türev alma kuralı kullanılır. + +Tüm bu ifadelerin en soldaki kısmının aynı olduğuna ve dolayısıyla kayıp fonksiyonundan başlayarak ve hesaplama çizgesi boyunca "geriye" doğru giden türevleri etkin bir şekilde hesaplayabileceğimize dikkat edin. Bu nedenle çok katmanlı bir algılayıcıyı eğitme yöntemine **geri yayma** veya 'geriyay' denir. + +compute graph + +> TODO: imge alıntısı + +> ✅ Geriyay'ı not defteri örneğimizde çok daha ayrıntılı olarak ele alacağız. + +## Vargılar + +Bu dersimizde kendi sinir ağı kütüphanemizi oluşturduk ve onu basit bir iki boyutlu sınıflandırma görevi için kullandık. + +## 🚀 Kendini Sınama + +Ekteki not defterinde, çok katmanlı algılayıcıları oluşturmak ve eğitmek için kendi çerçevenizi uygulayacaksınız. Modern sinir ağlarının nasıl çalıştığını ayrıntılı olarak görebileceksiniz. + +[OwnFramework (KendiCerveceniz)](OwnFramework.tr.ipynb) not defterine gidin ve üzerinde çalışın. + +## [Ders sonrası sınavı](https://red-field-0a6ddfd03.1.azurestaticapps.net/quiz/204) + +## Gözden Geçirme ve Bireysel Çalışma + +Geri yayma, YZ ve makine öğrenmesinde kullanılan yaygın bir algoritmadır ve [daha ayrıntılı olarak](https://wikipedia.org/wiki/Backpropagation) incelemeye değerdir. + +## [Ödev](../lab/translations/README.tr.md) + +Bu laboratuvarda, MNIST el yazısı rakam sınıflandırmasını çözmek için bu derste oluşturduğunuz çerçeveyi kullanmanız istenmektedir. + +* [Talimatlar](../lab/translations/README.tr.md) +* [Not Defteri](../lab/translations/MyFW_MNIST.tr.ipynb) From 43153a10aba8f288e65554f20fa6afb268a58140 Mon Sep 17 00:00:00 2001 From: semercim Date: Sat, 1 Oct 2022 21:50:01 +0200 Subject: [PATCH 24/38] Translating lesson 4 to Turkish. --- .../2-Symbolic/translations/Animals.tr.ipynb | 2 +- .../translations/FamilyOntology.tr.ipynb | 2 +- .../translations/MSConceptGraph.tr.ipynb | 2 +- .../03-Perceptron/Perceptron.ipynb | 9 +- .../lab/PerceptronMultiClass.ipynb | 8 +- .../PerceptronMultiClass.tr.ipynb | 23 +- .../translations/Perceptron.tr.ipynb | 410 +- .../04-OwnFramework/OwnFramework.ipynb | 5865 ++++++++++++++++- .../translations/OwnFramework.tr.ipynb | 1101 ++++ .../04-OwnFramework/translations/README.tr.md | 2 +- 10 files changed, 7036 insertions(+), 388 deletions(-) create mode 100644 lessons/3-NeuralNetworks/04-OwnFramework/translations/OwnFramework.tr.ipynb diff --git a/lessons/2-Symbolic/translations/Animals.tr.ipynb b/lessons/2-Symbolic/translations/Animals.tr.ipynb index 5d2b9862..f2aa9d82 100644 --- a/lessons/2-Symbolic/translations/Animals.tr.ipynb +++ b/lessons/2-Symbolic/translations/Animals.tr.ipynb @@ -337,7 +337,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.12" + "version": "3.8.13" }, "vscode": { "interpreter": { diff --git a/lessons/2-Symbolic/translations/FamilyOntology.tr.ipynb b/lessons/2-Symbolic/translations/FamilyOntology.tr.ipynb index f26360b2..a9ed7062 100644 --- a/lessons/2-Symbolic/translations/FamilyOntology.tr.ipynb +++ b/lessons/2-Symbolic/translations/FamilyOntology.tr.ipynb @@ -330,7 +330,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.12" + "version": "3.8.13" }, "vscode": { "interpreter": { diff --git a/lessons/2-Symbolic/translations/MSConceptGraph.tr.ipynb b/lessons/2-Symbolic/translations/MSConceptGraph.tr.ipynb index 9fbf3538..367f7f68 100644 --- a/lessons/2-Symbolic/translations/MSConceptGraph.tr.ipynb +++ b/lessons/2-Symbolic/translations/MSConceptGraph.tr.ipynb @@ -176,7 +176,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.12" + "version": "3.8.13" } }, "nbformat": 4, diff --git a/lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb b/lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb index de91f19e..90e439a1 100644 --- a/lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb +++ b/lessons/3-NeuralNetworks/03-Perceptron/Perceptron.ipynb @@ -3,7 +3,6 @@ { "cell_type": "markdown", "metadata": { - "collapsed": true, "slideshow": { "slide_type": "slide" } @@ -599,7 +598,6 @@ { "cell_type": "markdown", "metadata": { - "collapsed": true, "slideshow": { "slide_type": "slide" } @@ -986,7 +984,6 @@ "cell_type": "code", "execution_count": 26, "metadata": { - "scrolled": false, "slideshow": { "slide_type": "slide" } @@ -1053,7 +1050,7 @@ "metadata": { "celltoolbar": "Slideshow", "kernelspec": { - "display_name": "Python 3.10.6 64-bit", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -1067,7 +1064,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.6" + "version": "3.8.13" }, "livereveal": { "start_slideshow_at": "selected" @@ -1079,5 +1076,5 @@ } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } diff --git a/lessons/3-NeuralNetworks/03-Perceptron/lab/PerceptronMultiClass.ipynb b/lessons/3-NeuralNetworks/03-Perceptron/lab/PerceptronMultiClass.ipynb index 789da972..b57f44d3 100644 --- a/lessons/3-NeuralNetworks/03-Perceptron/lab/PerceptronMultiClass.ipynb +++ b/lessons/3-NeuralNetworks/03-Perceptron/lab/PerceptronMultiClass.ipynb @@ -3,7 +3,6 @@ { "cell_type": "markdown", "metadata": { - "collapsed": true, "slideshow": { "slide_type": "slide" } @@ -109,7 +108,6 @@ { "cell_type": "markdown", "metadata": { - "collapsed": true, "slideshow": { "slide_type": "slide" } @@ -239,7 +237,7 @@ "metadata": { "celltoolbar": "Slideshow", "kernelspec": { - "display_name": "Python 3.10.6 64-bit", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -253,7 +251,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.6" + "version": "3.8.13" }, "livereveal": { "start_slideshow_at": "selected" @@ -265,5 +263,5 @@ } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } diff --git a/lessons/3-NeuralNetworks/03-Perceptron/lab/translations/PerceptronMultiClass.tr.ipynb b/lessons/3-NeuralNetworks/03-Perceptron/lab/translations/PerceptronMultiClass.tr.ipynb index 73f7cf50..b8c7336c 100644 --- a/lessons/3-NeuralNetworks/03-Perceptron/lab/translations/PerceptronMultiClass.tr.ipynb +++ b/lessons/3-NeuralNetworks/03-Perceptron/lab/translations/PerceptronMultiClass.tr.ipynb @@ -3,7 +3,6 @@ { "cell_type": "markdown", "metadata": { - "collapsed": true, "slideshow": { "slide_type": "slide" } @@ -98,7 +97,6 @@ { "cell_type": "markdown", "metadata": { - "collapsed": true, "slideshow": { "slide_type": "slide" } @@ -131,7 +129,15 @@ "outputs": [], "source": [ "with open('mnist.pkl', 'rb') as mnist_pickle:\n", - " MNIST = pickle.load(mnist_pickle)" + " train_set, validation_set, test_set = pickle.load(mnist_pickle, encoding='bytes')\n", + "\n", + "MNIST = {}\n", + "MNIST['Train'] = {}\n", + "MNIST['Validation'] = {}\n", + "MNIST['Test'] = {} \n", + "MNIST['Train']['Features'], MNIST['Train']['Labels'] = train_set[0], train_set[1]\n", + "MNIST['Validation']['Features'], MNIST['Validation']['Labels'] = validation_set[0], validation_set[1]\n", + "MNIST['Test']['Features'], MNIST['Test']['Labels'] = test_set[0], test_set[1]" ] }, { @@ -195,17 +201,12 @@ "1. Sınıflandırmanın doğruluğunu ölçün ve *hata matrisi*ni yazdırın.\n", "1. [İsteğe bağlı] Bir matris çarpımı kullanarak sınıflandırmayı gerçekleştiren gelişmiş `classify` işlevini oluşturun." ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [] } ], "metadata": { "celltoolbar": "Slideshow", "kernelspec": { - "display_name": "Python 3.8.12 ('ai4beg')", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -219,7 +220,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.12" + "version": "3.8.13" }, "livereveal": { "start_slideshow_at": "selected" @@ -231,5 +232,5 @@ } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } diff --git a/lessons/3-NeuralNetworks/03-Perceptron/translations/Perceptron.tr.ipynb b/lessons/3-NeuralNetworks/03-Perceptron/translations/Perceptron.tr.ipynb index 57948cda..2d261a12 100644 --- a/lessons/3-NeuralNetworks/03-Perceptron/translations/Perceptron.tr.ipynb +++ b/lessons/3-NeuralNetworks/03-Perceptron/translations/Perceptron.tr.ipynb @@ -3,7 +3,6 @@ { "cell_type": "markdown", "metadata": { - "collapsed": true, "slideshow": { "slide_type": "slide" } @@ -20,7 +19,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -56,27 +55,13 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Features:\n", - " [[-1.7441838 -1.3952037 ]\n", - " [ 2.5921783 -0.08124504]\n", - " [ 0.9218062 0.91789985]\n", - " [-0.8437018 -0.18738253]]\n", - "Labels:\n", - " [-1 -1 1 -1]\n" - ] - } - ], + "outputs": [], "source": [ "n = 50\n", "X, Y = make_classification(n_samples = n, n_features=2,\n", @@ -100,34 +85,13 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": { "slideshow": { "slide_type": "skip" } }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/var/folders/_l/jnklp1bj4cl95rc01tf5vx4h0000gn/T/ipykernel_48969/3457453734.py:11: UserWarning: Matplotlib is currently using module://matplotlib_inline.backend_inline, which is a non-GUI backend, so cannot show the figure.\n", - " fig.show()\n" - ] - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "def plot_dataset(suptitle, features, labels):\n", " # prepare the plot\n", @@ -171,23 +135,13 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[[ 0.92180622 0.91789985 1. ]\n", - " [-1.06435513 1.49764717 1. ]\n", - " [ 0.32839951 2.25677919 1. ]]\n" - ] - } - ], + "outputs": [], "source": [ "pos_examples = np.array([ [t[0], t[1], 1] for i,t in enumerate(train_x) \n", " if train_labels[i]>0])\n", @@ -224,7 +178,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": { "slideshow": { "slide_type": "skip" @@ -277,31 +231,13 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Yineleme=0, positif doğruluk=0.7368421052631579, negatif doğruluk=0.8571428571428571\n", - "Yineleme=10, positif doğruluk=0.8421052631578947, negatif doğruluk=1.0\n", - "Yineleme=20, positif doğruluk=0.8421052631578947, negatif doğruluk=1.0\n", - "Yineleme=30, positif doğruluk=0.8947368421052632, negatif doğruluk=0.8571428571428571\n", - "Yineleme=40, positif doğruluk=0.8947368421052632, negatif doğruluk=0.8095238095238095\n", - "Yineleme=50, positif doğruluk=0.8421052631578947, negatif doğruluk=0.9523809523809523\n", - "Yineleme=60, positif doğruluk=0.8421052631578947, negatif doğruluk=0.9523809523809523\n", - "Yineleme=70, positif doğruluk=0.9473684210526315, negatif doğruluk=0.8095238095238095\n", - "Yineleme=80, positif doğruluk=1.0, negatif doğruluk=0.7619047619047619\n", - "Yineleme=90, positif doğruluk=0.8947368421052632, negatif doğruluk=0.9047619047619048\n", - "[[-0.30137426 5.42483654 0. ]]\n" - ] - } - ], + "outputs": [], "source": [ "wts = train(pos_examples,neg_examples)\n", "print(wts.transpose())" @@ -318,7 +254,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": { "slideshow": { "slide_type": "skip" @@ -347,26 +283,13 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "plot_boundary(pos_examples,neg_examples,wts)" ] @@ -386,24 +309,13 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" } }, - "outputs": [ - { - "data": { - "text/plain": [ - "1.0" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "def accuracy(weights, test_x, test_labels):\n", " res = np.dot(np.c_[test_x,np.ones(len(test_x))],weights)\n", @@ -427,22 +339,13 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": { "slideshow": { "slide_type": "skip" } }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/var/folders/_l/jnklp1bj4cl95rc01tf5vx4h0000gn/T/ipykernel_48969/1624475785.py:30: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.\n", - " return np.array(snapshots)\n" - ] - } - ], + "outputs": [], "source": [ "def train_graph(positive_examples, negative_examples, num_iterations = 100):\n", " num_dims = positive_examples.shape[1]\n", @@ -492,38 +395,13 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "e47dac57d0aa469e943218c20f3eecd6", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "interactive(children=(IntSlider(value=0, description='step', max=6), Output()), _dom_classes=('widget-interact…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "interact(pl1, step=widgets.IntSlider(value=0, min=0, max=len(snapshots)-1))" ] @@ -540,7 +418,7 @@ "\n", "Yukarıda gördüğünüz gibi, algılayıcı bir **doğrusal sınıflandırıcıdır**. **Doğrusal olarak ayrılabilir** iseler, yani düz bir çizgi ile ayrılabilirlerse, iki sınıf arasında iyi bir ayrım yapabilir. Aksi takdirde, algılayıcı eğitim işlemi yakınsamayacaktır.\n", "\n", - "Bir algılayıcı tarafından çözülemeyen bir problemin en bariz örneği **XOR problemi** olarak adlandırılır. Algılayıcımızın aşağıdaki doğruluk tablosuna sahip olan XOR boole işlevini öğrenmesini istiyoruz:\n", + "Bir algılayıcı tarafından çözülemeyen bir problemin en bariz örneği **XOR (Dışlayıcı Veya) problemi** olarak adlandırılır. Algılayıcımızın aşağıdaki doğruluk tablosuna sahip olan XOR boole işlevini öğrenmesini istiyoruz:\n", "\n", "| | 0 | 1 |\n", "|---|---|---|\n", @@ -552,22 +430,13 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/var/folders/_l/jnklp1bj4cl95rc01tf5vx4h0000gn/T/ipykernel_48969/1624475785.py:30: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.\n", - " return np.array(snapshots)\n" - ] - } - ], + "outputs": [], "source": [ "pos_examples_xor = np.array([[1,0,1],[0,1,1]])\n", "neg_examples_xor = np.array([[1,1,1],[0,0,1]])\n", @@ -578,38 +447,13 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "23f34a026a83468c9aea5f07a6d5b016", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "interactive(children=(IntSlider(value=0, description='step', max=6), Output()), _dom_classes=('widget-interact…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "interact(pl2, step=widgets.IntSlider(value=0, min=0, max=len(snapshots)-1))" ] @@ -617,7 +461,6 @@ { "cell_type": "markdown", "metadata": { - "collapsed": true, "slideshow": { "slide_type": "slide" } @@ -637,12 +480,12 @@ "\n", "> MNIST veri Kümesi, makine öğrenmesi yarışmalarına ve mücadelelerine ev sahipliği yapan bir site olan [Kaggle](https://www.kaggle.com/c/digit-recognizer) üzerinde bir eğitim yarışması olarak mevcuttur. MNIST rakamlarını nasıl sınıflandıracağınızı öğrendikten sonra, diğer katılımcılar arasında nasıl derecelendirildiğini görmek için çözümünüzü Kaggle'a gönderebilirsiniz.\n", "\n", - "MNIST veri kğmesini yükleyerek başlıyoruz:" + "MNIST veri kümesini yükleyerek başlıyoruz:" ] }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" @@ -653,9 +496,24 @@ "# Bu not defterini klonlanmış bir depodan çalıştırmıyorsanız, önce ikili veri kümesi dosyasını almanız gerekebilir.\n", "# !wget https://raw.githubusercontent.com/microsoft/AI-For-Beginners/main/data/mnist.pkl.gz\n", "# Bu durumda aşağıdaki veri kümesinin bağlantısını da düzeltin.\n", + "MNIST = {}\n", "\n", - "with gzip.open('../../data/mnist.pkl.gz', 'rb') as mnist_pickle:\n", - " MNIST = pickle.load(mnist_pickle)" + "with gzip.open('../../../../data/mnist.pkl.gz', 'rb') as mnist_pickle:\n", + " train_set, validation_set, test_set = pickle.load(mnist_pickle, encoding='bytes')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "MNIST['Train'] = {}\n", + "MNIST['Validation'] = {}\n", + "MNIST['Test'] = {} \n", + "MNIST['Train']['Features'], MNIST['Train']['Labels'] = train_set[0], train_set[1]\n", + "MNIST['Validation']['Features'], MNIST['Validation']['Labels'] = validation_set[0], validation_set[1]\n", + "MNIST['Test']['Features'], MNIST['Test']['Labels'] = test_set[0], test_set[1]" ] }, { @@ -667,36 +525,13 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[ 0 0 188 255 94 0 0 0 0 0 0 0 0 0 0 0 0 0\n", - " 0 0 0 0 0 0 0 0 0 0 0 191 250 253 93 0 0 0\n", - " 0 0 0 0 0 0 0 0 0 0 0 0 0 0]\n", - "1\n" - ] - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "print(MNIST['Train']['Features'][0][130:180])\n", "print(MNIST['Train']['Labels'][0])\n", @@ -718,7 +553,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" @@ -758,31 +593,20 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "pos1,neg1 = set_mnist_pos_neg(1,0)" ] }, { "cell_type": "code", - "execution_count": 20, + "execution_count": null, "metadata": { "slideshow": { "slide_type": "skip" @@ -808,38 +632,13 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "afbc754ef0d04c95a1af039574b46a6b", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "interactive(children=(IntSlider(value=0, description='step', max=66), Output()), _dom_classes=('widget-interac…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 21, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "snapshots_mn = train_graph(pos1,neg1,1000) \n", "interact(pl3, step=widgets.IntSlider(value=0, min=0, max=len(snapshots_mn) - 1))" @@ -860,62 +659,26 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "pos2,neg2 = set_mnist_pos_neg(2,5)" ] }, { "cell_type": "code", - "execution_count": 23, + "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "bf6f25d14c3b4d548ac026af97f70e2a", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "interactive(children=(IntSlider(value=0, description='step', max=66), Output()), _dom_classes=('widget-interac…" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "snapshots_mn2 = train_graph(pos2,neg2,1000)\n", "interact(pl4, step=widgets.IntSlider(value=0, min=0, max=len(snapshots_mn2) - 1))" @@ -940,7 +703,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": null, "metadata": { "slideshow": { "slide_type": "fragment" @@ -966,73 +729,26 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": null, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "pca_analysis(1,0)" ] }, { "cell_type": "code", - "execution_count": 26, + "execution_count": null, "metadata": { - "scrolled": false, "slideshow": { "slide_type": "slide" } }, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "pca_analysis(2,5)" ] @@ -1070,7 +786,7 @@ "metadata": { "celltoolbar": "Slideshow", "kernelspec": { - "display_name": "Python 3.10.6 64-bit", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -1084,7 +800,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.6" + "version": "3.8.13" }, "livereveal": { "start_slideshow_at": "selected" @@ -1096,5 +812,5 @@ } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } diff --git a/lessons/3-NeuralNetworks/04-OwnFramework/OwnFramework.ipynb b/lessons/3-NeuralNetworks/04-OwnFramework/OwnFramework.ipynb index 35b62448..ed9e5339 100644 --- a/lessons/3-NeuralNetworks/04-OwnFramework/OwnFramework.ipynb +++ b/lessons/3-NeuralNetworks/04-OwnFramework/OwnFramework.ipynb @@ -13,7 +13,7 @@ "\n", "> This notebook is a part of [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners). Visit the repository for complete set of learning materials.\n", "\n", - "In this notebook, we will gradually build our own neural framework capable of solving multi-class classification tasks as well as regression with multi-layered preceptrons.\n", + "In this notebook, we will gradually build our own neural framework capable of solving multi-class classification tasks as well as regression with multi-layered perceptrons.\n", "\n", "First, let's import some required libraries." ] @@ -55,7 +55,6 @@ "cell_type": "code", "execution_count": 15, "metadata": { - "scrolled": false, "slideshow": { "slide_type": "slide" } @@ -77,7 +76,6 @@ "cell_type": "code", "execution_count": 16, "metadata": { - "scrolled": false, "slideshow": { "slide_type": "skip" } @@ -101,7 +99,6 @@ "cell_type": "code", "execution_count": 17, "metadata": { - "scrolled": false, "slideshow": { "slide_type": "slide" } @@ -109,7 +106,980 @@ "outputs": [ { "data": { - "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n rubberband_canvas.addEventListener(\n 'dblclick',\n on_mouse_event_closure('dblclick')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n var img = evt.data;\n if (img.type !== 'image/png') {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n img.type = 'image/png';\n }\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n img\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.key === this._key) {\n return;\n } else {\n this._key = event.key;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.key !== 'Control') {\n value += 'ctrl+';\n }\n else if (event.altKey && event.key !== 'Alt') {\n value += 'alt+';\n }\n else if (event.shiftKey && event.key !== 'Shift') {\n value += 'shift+';\n }\n\n value += 'k' + event.key;\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.binaryType = comm.kernel.ws.binaryType;\n ws.readyState = comm.kernel.ws.readyState;\n function updateReadyState(_event) {\n if (comm.kernel.ws) {\n ws.readyState = comm.kernel.ws.readyState;\n } else {\n ws.readyState = 3; // Closed state.\n }\n }\n comm.kernel.ws.addEventListener('open', updateReadyState);\n comm.kernel.ws.addEventListener('close', updateReadyState);\n comm.kernel.ws.addEventListener('error', updateReadyState);\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n var data = msg['content']['data'];\n if (data['blob'] !== undefined) {\n data = {\n data: new Blob(msg['buffers'], { type: data['blob'] }),\n };\n }\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(data);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "/* global mpl */\n", + "window.mpl = {};\n", + "\n", + "mpl.get_websocket_type = function () {\n", + " if (typeof WebSocket !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof MozWebSocket !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert(\n", + " 'Your browser does not have WebSocket support. ' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.'\n", + " );\n", + " }\n", + "};\n", + "\n", + "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = this.ws.binaryType !== undefined;\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById('mpl-warnings');\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent =\n", + " 'This browser does not support binary websocket messages. ' +\n", + " 'Performance may be slow.';\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = document.createElement('div');\n", + " this.root.setAttribute('style', 'display: inline-block');\n", + " this._root_extra_style(this.root);\n", + "\n", + " parent_element.appendChild(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message('supports_binary', { value: fig.supports_binary });\n", + " fig.send_message('send_image_mode', {});\n", + " if (fig.ratio !== 1) {\n", + " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", + " }\n", + " fig.send_message('refresh', {});\n", + " };\n", + "\n", + " this.imageObj.onload = function () {\n", + " if (fig.image_mode === 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function () {\n", + " fig.ws.close();\n", + " };\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "};\n", + "\n", + "mpl.figure.prototype._init_header = function () {\n", + " var titlebar = document.createElement('div');\n", + " titlebar.classList =\n", + " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", + " var titletext = document.createElement('div');\n", + " titletext.classList = 'ui-dialog-title';\n", + " titletext.setAttribute(\n", + " 'style',\n", + " 'width: 100%; text-align: center; padding: 3px;'\n", + " );\n", + " titlebar.appendChild(titletext);\n", + " this.root.appendChild(titlebar);\n", + " this.header = titletext;\n", + "};\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", + "\n", + "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", + "\n", + "mpl.figure.prototype._init_canvas = function () {\n", + " var fig = this;\n", + "\n", + " var canvas_div = (this.canvas_div = document.createElement('div'));\n", + " canvas_div.setAttribute(\n", + " 'style',\n", + " 'border: 1px solid #ddd;' +\n", + " 'box-sizing: content-box;' +\n", + " 'clear: both;' +\n", + " 'min-height: 1px;' +\n", + " 'min-width: 1px;' +\n", + " 'outline: 0;' +\n", + " 'overflow: hidden;' +\n", + " 'position: relative;' +\n", + " 'resize: both;'\n", + " );\n", + "\n", + " function on_keyboard_event_closure(name) {\n", + " return function (event) {\n", + " return fig.key_event(event, name);\n", + " };\n", + " }\n", + "\n", + " canvas_div.addEventListener(\n", + " 'keydown',\n", + " on_keyboard_event_closure('key_press')\n", + " );\n", + " canvas_div.addEventListener(\n", + " 'keyup',\n", + " on_keyboard_event_closure('key_release')\n", + " );\n", + "\n", + " this._canvas_extra_style(canvas_div);\n", + " this.root.appendChild(canvas_div);\n", + "\n", + " var canvas = (this.canvas = document.createElement('canvas'));\n", + " canvas.classList.add('mpl-canvas');\n", + " canvas.setAttribute('style', 'box-sizing: content-box;');\n", + "\n", + " this.context = canvas.getContext('2d');\n", + "\n", + " var backingStore =\n", + " this.context.backingStorePixelRatio ||\n", + " this.context.webkitBackingStorePixelRatio ||\n", + " this.context.mozBackingStorePixelRatio ||\n", + " this.context.msBackingStorePixelRatio ||\n", + " this.context.oBackingStorePixelRatio ||\n", + " this.context.backingStorePixelRatio ||\n", + " 1;\n", + "\n", + " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", + "\n", + " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", + " 'canvas'\n", + " ));\n", + " rubberband_canvas.setAttribute(\n", + " 'style',\n", + " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", + " );\n", + "\n", + " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", + " if (this.ResizeObserver === undefined) {\n", + " if (window.ResizeObserver !== undefined) {\n", + " this.ResizeObserver = window.ResizeObserver;\n", + " } else {\n", + " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", + " this.ResizeObserver = obs.ResizeObserver;\n", + " }\n", + " }\n", + "\n", + " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", + " var nentries = entries.length;\n", + " for (var i = 0; i < nentries; i++) {\n", + " var entry = entries[i];\n", + " var width, height;\n", + " if (entry.contentBoxSize) {\n", + " if (entry.contentBoxSize instanceof Array) {\n", + " // Chrome 84 implements new version of spec.\n", + " width = entry.contentBoxSize[0].inlineSize;\n", + " height = entry.contentBoxSize[0].blockSize;\n", + " } else {\n", + " // Firefox implements old version of spec.\n", + " width = entry.contentBoxSize.inlineSize;\n", + " height = entry.contentBoxSize.blockSize;\n", + " }\n", + " } else {\n", + " // Chrome <84 implements even older version of spec.\n", + " width = entry.contentRect.width;\n", + " height = entry.contentRect.height;\n", + " }\n", + "\n", + " // Keep the size of the canvas and rubber band canvas in sync with\n", + " // the canvas container.\n", + " if (entry.devicePixelContentBoxSize) {\n", + " // Chrome 84 implements new version of spec.\n", + " canvas.setAttribute(\n", + " 'width',\n", + " entry.devicePixelContentBoxSize[0].inlineSize\n", + " );\n", + " canvas.setAttribute(\n", + " 'height',\n", + " entry.devicePixelContentBoxSize[0].blockSize\n", + " );\n", + " } else {\n", + " canvas.setAttribute('width', width * fig.ratio);\n", + " canvas.setAttribute('height', height * fig.ratio);\n", + " }\n", + " canvas.setAttribute(\n", + " 'style',\n", + " 'width: ' + width + 'px; height: ' + height + 'px;'\n", + " );\n", + "\n", + " rubberband_canvas.setAttribute('width', width);\n", + " rubberband_canvas.setAttribute('height', height);\n", + "\n", + " // And update the size in Python. We ignore the initial 0/0 size\n", + " // that occurs as the element is placed into the DOM, which should\n", + " // otherwise not happen due to the minimum size styling.\n", + " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", + " fig.request_resize(width, height);\n", + " }\n", + " }\n", + " });\n", + " this.resizeObserverInstance.observe(canvas_div);\n", + "\n", + " function on_mouse_event_closure(name) {\n", + " return function (event) {\n", + " return fig.mouse_event(event, name);\n", + " };\n", + " }\n", + "\n", + " rubberband_canvas.addEventListener(\n", + " 'mousedown',\n", + " on_mouse_event_closure('button_press')\n", + " );\n", + " rubberband_canvas.addEventListener(\n", + " 'mouseup',\n", + " on_mouse_event_closure('button_release')\n", + " );\n", + " rubberband_canvas.addEventListener(\n", + " 'dblclick',\n", + " on_mouse_event_closure('dblclick')\n", + " );\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband_canvas.addEventListener(\n", + " 'mousemove',\n", + " on_mouse_event_closure('motion_notify')\n", + " );\n", + "\n", + " rubberband_canvas.addEventListener(\n", + " 'mouseenter',\n", + " on_mouse_event_closure('figure_enter')\n", + " );\n", + " rubberband_canvas.addEventListener(\n", + " 'mouseleave',\n", + " on_mouse_event_closure('figure_leave')\n", + " );\n", + "\n", + " canvas_div.addEventListener('wheel', function (event) {\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " on_mouse_event_closure('scroll')(event);\n", + " });\n", + "\n", + " canvas_div.appendChild(canvas);\n", + " canvas_div.appendChild(rubberband_canvas);\n", + "\n", + " this.rubberband_context = rubberband_canvas.getContext('2d');\n", + " this.rubberband_context.strokeStyle = '#000000';\n", + "\n", + " this._resize_canvas = function (width, height, forward) {\n", + " if (forward) {\n", + " canvas_div.style.width = width + 'px';\n", + " canvas_div.style.height = height + 'px';\n", + " }\n", + " };\n", + "\n", + " // Disable right mouse context menu.\n", + " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", + " event.preventDefault();\n", + " return false;\n", + " });\n", + "\n", + " function set_focus() {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "};\n", + "\n", + "mpl.figure.prototype._init_toolbar = function () {\n", + " var fig = this;\n", + "\n", + " var toolbar = document.createElement('div');\n", + " toolbar.classList = 'mpl-toolbar';\n", + " this.root.appendChild(toolbar);\n", + "\n", + " function on_click_closure(name) {\n", + " return function (_event) {\n", + " return fig.toolbar_button_onclick(name);\n", + " };\n", + " }\n", + "\n", + " function on_mouseover_closure(tooltip) {\n", + " return function (event) {\n", + " if (!event.currentTarget.disabled) {\n", + " return fig.toolbar_button_onmouseover(tooltip);\n", + " }\n", + " };\n", + " }\n", + "\n", + " fig.buttons = {};\n", + " var buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'mpl-button-group';\n", + " for (var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " /* Instead of a spacer, we start a new button group. */\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + " buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'mpl-button-group';\n", + " continue;\n", + " }\n", + "\n", + " var button = (fig.buttons[name] = document.createElement('button'));\n", + " button.classList = 'mpl-widget';\n", + " button.setAttribute('role', 'button');\n", + " button.setAttribute('aria-disabled', 'false');\n", + " button.addEventListener('click', on_click_closure(method_name));\n", + " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", + "\n", + " var icon_img = document.createElement('img');\n", + " icon_img.src = '_images/' + image + '.png';\n", + " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", + " icon_img.alt = tooltip;\n", + " button.appendChild(icon_img);\n", + "\n", + " buttonGroup.appendChild(button);\n", + " }\n", + "\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + "\n", + " var fmt_picker = document.createElement('select');\n", + " fmt_picker.classList = 'mpl-widget';\n", + " toolbar.appendChild(fmt_picker);\n", + " this.format_dropdown = fmt_picker;\n", + "\n", + " for (var ind in mpl.extensions) {\n", + " var fmt = mpl.extensions[ind];\n", + " var option = document.createElement('option');\n", + " option.selected = fmt === mpl.default_extension;\n", + " option.innerHTML = fmt;\n", + " fmt_picker.appendChild(option);\n", + " }\n", + "\n", + " var status_bar = document.createElement('span');\n", + " status_bar.classList = 'mpl-message';\n", + " toolbar.appendChild(status_bar);\n", + " this.message = status_bar;\n", + "};\n", + "\n", + "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", + " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", + " // which will in turn request a refresh of the image.\n", + " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", + "};\n", + "\n", + "mpl.figure.prototype.send_message = function (type, properties) {\n", + " properties['type'] = type;\n", + " properties['figure_id'] = this.id;\n", + " this.ws.send(JSON.stringify(properties));\n", + "};\n", + "\n", + "mpl.figure.prototype.send_draw_message = function () {\n", + " if (!this.waiting) {\n", + " this.waiting = true;\n", + " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", + " var format_dropdown = fig.format_dropdown;\n", + " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", + " fig.ondownload(fig, format);\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", + " var size = msg['size'];\n", + " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", + " fig._resize_canvas(size[0], size[1], msg['forward']);\n", + " fig.send_message('refresh', {});\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", + " var x0 = msg['x0'] / fig.ratio;\n", + " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", + " var x1 = msg['x1'] / fig.ratio;\n", + " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", + " x0 = Math.floor(x0) + 0.5;\n", + " y0 = Math.floor(y0) + 0.5;\n", + " x1 = Math.floor(x1) + 0.5;\n", + " y1 = Math.floor(y1) + 0.5;\n", + " var min_x = Math.min(x0, x1);\n", + " var min_y = Math.min(y0, y1);\n", + " var width = Math.abs(x1 - x0);\n", + " var height = Math.abs(y1 - y0);\n", + "\n", + " fig.rubberband_context.clearRect(\n", + " 0,\n", + " 0,\n", + " fig.canvas.width / fig.ratio,\n", + " fig.canvas.height / fig.ratio\n", + " );\n", + "\n", + " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", + " // Updates the figure title.\n", + " fig.header.textContent = msg['label'];\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", + " var cursor = msg['cursor'];\n", + " switch (cursor) {\n", + " case 0:\n", + " cursor = 'pointer';\n", + " break;\n", + " case 1:\n", + " cursor = 'default';\n", + " break;\n", + " case 2:\n", + " cursor = 'crosshair';\n", + " break;\n", + " case 3:\n", + " cursor = 'move';\n", + " break;\n", + " }\n", + " fig.rubberband_canvas.style.cursor = cursor;\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_message = function (fig, msg) {\n", + " fig.message.textContent = msg['message'];\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", + " // Request the server to send over a new figure.\n", + " fig.send_draw_message();\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", + " fig.image_mode = msg['mode'];\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", + " for (var key in msg) {\n", + " if (!(key in fig.buttons)) {\n", + " continue;\n", + " }\n", + " fig.buttons[key].disabled = !msg[key];\n", + " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", + " if (msg['mode'] === 'PAN') {\n", + " fig.buttons['Pan'].classList.add('active');\n", + " fig.buttons['Zoom'].classList.remove('active');\n", + " } else if (msg['mode'] === 'ZOOM') {\n", + " fig.buttons['Pan'].classList.remove('active');\n", + " fig.buttons['Zoom'].classList.add('active');\n", + " } else {\n", + " fig.buttons['Pan'].classList.remove('active');\n", + " fig.buttons['Zoom'].classList.remove('active');\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.updated_canvas_event = function () {\n", + " // Called whenever the canvas gets updated.\n", + " this.send_message('ack', {});\n", + "};\n", + "\n", + "// A function to construct a web socket function for onmessage handling.\n", + "// Called in the figure constructor.\n", + "mpl.figure.prototype._make_on_message_function = function (fig) {\n", + " return function socket_on_message(evt) {\n", + " if (evt.data instanceof Blob) {\n", + " var img = evt.data;\n", + " if (img.type !== 'image/png') {\n", + " /* FIXME: We get \"Resource interpreted as Image but\n", + " * transferred with MIME type text/plain:\" errors on\n", + " * Chrome. But how to set the MIME type? It doesn't seem\n", + " * to be part of the websocket stream */\n", + " img.type = 'image/png';\n", + " }\n", + "\n", + " /* Free the memory for the previous frames */\n", + " if (fig.imageObj.src) {\n", + " (window.URL || window.webkitURL).revokeObjectURL(\n", + " fig.imageObj.src\n", + " );\n", + " }\n", + "\n", + " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", + " img\n", + " );\n", + " fig.updated_canvas_event();\n", + " fig.waiting = false;\n", + " return;\n", + " } else if (\n", + " typeof evt.data === 'string' &&\n", + " evt.data.slice(0, 21) === 'data:image/png;base64'\n", + " ) {\n", + " fig.imageObj.src = evt.data;\n", + " fig.updated_canvas_event();\n", + " fig.waiting = false;\n", + " return;\n", + " }\n", + "\n", + " var msg = JSON.parse(evt.data);\n", + " var msg_type = msg['type'];\n", + "\n", + " // Call the \"handle_{type}\" callback, which takes\n", + " // the figure and JSON message as its only arguments.\n", + " try {\n", + " var callback = fig['handle_' + msg_type];\n", + " } catch (e) {\n", + " console.log(\n", + " \"No handler for the '\" + msg_type + \"' message type: \",\n", + " msg\n", + " );\n", + " return;\n", + " }\n", + "\n", + " if (callback) {\n", + " try {\n", + " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", + " callback(fig, msg);\n", + " } catch (e) {\n", + " console.log(\n", + " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", + " e,\n", + " e.stack,\n", + " msg\n", + " );\n", + " }\n", + " }\n", + " };\n", + "};\n", + "\n", + "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", + "mpl.findpos = function (e) {\n", + " //this section is from http://www.quirksmode.org/js/events_properties.html\n", + " var targ;\n", + " if (!e) {\n", + " e = window.event;\n", + " }\n", + " if (e.target) {\n", + " targ = e.target;\n", + " } else if (e.srcElement) {\n", + " targ = e.srcElement;\n", + " }\n", + " if (targ.nodeType === 3) {\n", + " // defeat Safari bug\n", + " targ = targ.parentNode;\n", + " }\n", + "\n", + " // pageX,Y are the mouse positions relative to the document\n", + " var boundingRect = targ.getBoundingClientRect();\n", + " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", + " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", + "\n", + " return { x: x, y: y };\n", + "};\n", + "\n", + "/*\n", + " * return a copy of an object with only non-object keys\n", + " * we need this to avoid circular references\n", + " * http://stackoverflow.com/a/24161582/3208463\n", + " */\n", + "function simpleKeys(original) {\n", + " return Object.keys(original).reduce(function (obj, key) {\n", + " if (typeof original[key] !== 'object') {\n", + " obj[key] = original[key];\n", + " }\n", + " return obj;\n", + " }, {});\n", + "}\n", + "\n", + "mpl.figure.prototype.mouse_event = function (event, name) {\n", + " var canvas_pos = mpl.findpos(event);\n", + "\n", + " if (name === 'button_press') {\n", + " this.canvas.focus();\n", + " this.canvas_div.focus();\n", + " }\n", + "\n", + " var x = canvas_pos.x * this.ratio;\n", + " var y = canvas_pos.y * this.ratio;\n", + "\n", + " this.send_message(name, {\n", + " x: x,\n", + " y: y,\n", + " button: event.button,\n", + " step: event.step,\n", + " guiEvent: simpleKeys(event),\n", + " });\n", + "\n", + " /* This prevents the web browser from automatically changing to\n", + " * the text insertion cursor when the button is pressed. We want\n", + " * to control all of the cursor setting manually through the\n", + " * 'cursor' event from matplotlib */\n", + " event.preventDefault();\n", + " return false;\n", + "};\n", + "\n", + "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", + " // Handle any extra behaviour associated with a key event\n", + "};\n", + "\n", + "mpl.figure.prototype.key_event = function (event, name) {\n", + " // Prevent repeat events\n", + " if (name === 'key_press') {\n", + " if (event.key === this._key) {\n", + " return;\n", + " } else {\n", + " this._key = event.key;\n", + " }\n", + " }\n", + " if (name === 'key_release') {\n", + " this._key = null;\n", + " }\n", + "\n", + " var value = '';\n", + " if (event.ctrlKey && event.key !== 'Control') {\n", + " value += 'ctrl+';\n", + " }\n", + " else if (event.altKey && event.key !== 'Alt') {\n", + " value += 'alt+';\n", + " }\n", + " else if (event.shiftKey && event.key !== 'Shift') {\n", + " value += 'shift+';\n", + " }\n", + "\n", + " value += 'k' + event.key;\n", + "\n", + " this._key_event_extra(event, name);\n", + "\n", + " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", + " return false;\n", + "};\n", + "\n", + "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", + " if (name === 'download') {\n", + " this.handle_save(this, null);\n", + " } else {\n", + " this.send_message('toolbar_button', { name: name });\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", + " this.message.textContent = tooltip;\n", + "};\n", + "\n", + "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", + "// prettier-ignore\n", + "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", + "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", + "\n", + "mpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", + "\n", + "mpl.default_extension = \"png\";/* global mpl */\n", + "\n", + "var comm_websocket_adapter = function (comm) {\n", + " // Create a \"websocket\"-like object which calls the given IPython comm\n", + " // object with the appropriate methods. Currently this is a non binary\n", + " // socket, so there is still some room for performance tuning.\n", + " var ws = {};\n", + "\n", + " ws.binaryType = comm.kernel.ws.binaryType;\n", + " ws.readyState = comm.kernel.ws.readyState;\n", + " function updateReadyState(_event) {\n", + " if (comm.kernel.ws) {\n", + " ws.readyState = comm.kernel.ws.readyState;\n", + " } else {\n", + " ws.readyState = 3; // Closed state.\n", + " }\n", + " }\n", + " comm.kernel.ws.addEventListener('open', updateReadyState);\n", + " comm.kernel.ws.addEventListener('close', updateReadyState);\n", + " comm.kernel.ws.addEventListener('error', updateReadyState);\n", + "\n", + " ws.close = function () {\n", + " comm.close();\n", + " };\n", + " ws.send = function (m) {\n", + " //console.log('sending', m);\n", + " comm.send(m);\n", + " };\n", + " // Register the callback with on_msg.\n", + " comm.on_msg(function (msg) {\n", + " //console.log('receiving', msg['content']['data'], msg);\n", + " var data = msg['content']['data'];\n", + " if (data['blob'] !== undefined) {\n", + " data = {\n", + " data: new Blob(msg['buffers'], { type: data['blob'] }),\n", + " };\n", + " }\n", + " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", + " ws.onmessage(data);\n", + " });\n", + " return ws;\n", + "};\n", + "\n", + "mpl.mpl_figure_comm = function (comm, msg) {\n", + " // This is the function which gets called when the mpl process\n", + " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", + "\n", + " var id = msg.content.data.id;\n", + " // Get hold of the div created by the display call when the Comm\n", + " // socket was opened in Python.\n", + " var element = document.getElementById(id);\n", + " var ws_proxy = comm_websocket_adapter(comm);\n", + "\n", + " function ondownload(figure, _format) {\n", + " window.open(figure.canvas.toDataURL());\n", + " }\n", + "\n", + " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", + "\n", + " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", + " // web socket which is closed, not our websocket->open comm proxy.\n", + " ws_proxy.onopen();\n", + "\n", + " fig.parent_element = element;\n", + " fig.cell_info = mpl.find_output_cell(\"
\");\n", + " if (!fig.cell_info) {\n", + " console.error('Failed to find cell for figure', id, fig);\n", + " return;\n", + " }\n", + " fig.cell_info[0].output_area.element.on(\n", + " 'cleared',\n", + " { fig: fig },\n", + " fig._remove_fig_handler\n", + " );\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_close = function (fig, msg) {\n", + " var width = fig.canvas.width / fig.ratio;\n", + " fig.cell_info[0].output_area.element.off(\n", + " 'cleared',\n", + " fig._remove_fig_handler\n", + " );\n", + " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", + "\n", + " // Update the output cell to use the data from the current canvas.\n", + " fig.push_to_output();\n", + " var dataURL = fig.canvas.toDataURL();\n", + " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", + " // the notebook keyboard shortcuts fail.\n", + " IPython.keyboard_manager.enable();\n", + " fig.parent_element.innerHTML =\n", + " '';\n", + " fig.close_ws(fig, msg);\n", + "};\n", + "\n", + "mpl.figure.prototype.close_ws = function (fig, msg) {\n", + " fig.send_message('closing', msg);\n", + " // fig.ws.close()\n", + "};\n", + "\n", + "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", + " // Turn the data on the canvas into data in the output cell.\n", + " var width = this.canvas.width / this.ratio;\n", + " var dataURL = this.canvas.toDataURL();\n", + " this.cell_info[1]['text/html'] =\n", + " '';\n", + "};\n", + "\n", + "mpl.figure.prototype.updated_canvas_event = function () {\n", + " // Tell IPython that the notebook contents must change.\n", + " IPython.notebook.set_dirty(true);\n", + " this.send_message('ack', {});\n", + " var fig = this;\n", + " // Wait a second, then push the new image to the DOM so\n", + " // that it is saved nicely (might be nice to debounce this).\n", + " setTimeout(function () {\n", + " fig.push_to_output();\n", + " }, 1000);\n", + "};\n", + "\n", + "mpl.figure.prototype._init_toolbar = function () {\n", + " var fig = this;\n", + "\n", + " var toolbar = document.createElement('div');\n", + " toolbar.classList = 'btn-toolbar';\n", + " this.root.appendChild(toolbar);\n", + "\n", + " function on_click_closure(name) {\n", + " return function (_event) {\n", + " return fig.toolbar_button_onclick(name);\n", + " };\n", + " }\n", + "\n", + " function on_mouseover_closure(tooltip) {\n", + " return function (event) {\n", + " if (!event.currentTarget.disabled) {\n", + " return fig.toolbar_button_onmouseover(tooltip);\n", + " }\n", + " };\n", + " }\n", + "\n", + " fig.buttons = {};\n", + " var buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'btn-group';\n", + " var button;\n", + " for (var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " /* Instead of a spacer, we start a new button group. */\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + " buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'btn-group';\n", + " continue;\n", + " }\n", + "\n", + " button = fig.buttons[name] = document.createElement('button');\n", + " button.classList = 'btn btn-default';\n", + " button.href = '#';\n", + " button.title = name;\n", + " button.innerHTML = '';\n", + " button.addEventListener('click', on_click_closure(method_name));\n", + " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", + " buttonGroup.appendChild(button);\n", + " }\n", + "\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + "\n", + " // Add the status bar.\n", + " var status_bar = document.createElement('span');\n", + " status_bar.classList = 'mpl-message pull-right';\n", + " toolbar.appendChild(status_bar);\n", + " this.message = status_bar;\n", + "\n", + " // Add the close button to the window.\n", + " var buttongrp = document.createElement('div');\n", + " buttongrp.classList = 'btn-group inline pull-right';\n", + " button = document.createElement('button');\n", + " button.classList = 'btn btn-mini btn-primary';\n", + " button.href = '#';\n", + " button.title = 'Stop Interaction';\n", + " button.innerHTML = '';\n", + " button.addEventListener('click', function (_evt) {\n", + " fig.handle_close(fig, {});\n", + " });\n", + " button.addEventListener(\n", + " 'mouseover',\n", + " on_mouseover_closure('Stop Interaction')\n", + " );\n", + " buttongrp.appendChild(button);\n", + " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", + " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", + "};\n", + "\n", + "mpl.figure.prototype._remove_fig_handler = function (event) {\n", + " var fig = event.data.fig;\n", + " if (event.target !== this) {\n", + " // Ignore bubbled events from children.\n", + " return;\n", + " }\n", + " fig.close_ws(fig, {});\n", + "};\n", + "\n", + "mpl.figure.prototype._root_extra_style = function (el) {\n", + " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", + "};\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function (el) {\n", + " // this is important to make the div 'focusable\n", + " el.setAttribute('tabindex', 0);\n", + " // reach out to IPython and tell the keyboard manager to turn it's self\n", + " // off when our div gets focus\n", + "\n", + " // location in version 3\n", + " if (IPython.notebook.keyboard_manager) {\n", + " IPython.notebook.keyboard_manager.register_events(el);\n", + " } else {\n", + " // location in version 2\n", + " IPython.keyboard_manager.register_events(el);\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", + " var manager = IPython.notebook.keyboard_manager;\n", + " if (!manager) {\n", + " manager = IPython.keyboard_manager;\n", + " }\n", + "\n", + " // Check for shift+enter\n", + " if (event.shiftKey && event.which === 13) {\n", + " this.canvas_div.blur();\n", + " // select the cell after this one\n", + " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", + " IPython.notebook.select(index + 1);\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", + " fig.ondownload(fig, null);\n", + "};\n", + "\n", + "mpl.find_output_cell = function (html_output) {\n", + " // Return the cell and output element which can be found *uniquely* in the notebook.\n", + " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", + " // IPython event is triggered only after the cells have been serialised, which for\n", + " // our purposes (turning an active figure into a static one), is too late.\n", + " var cells = IPython.notebook.get_cells();\n", + " var ncells = cells.length;\n", + " for (var i = 0; i < ncells; i++) {\n", + " var cell = cells[i];\n", + " if (cell.cell_type === 'code') {\n", + " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", + " var data = cell.output_area.outputs[j];\n", + " if (data.data) {\n", + " // IPython >= 3 moved mimebundle to data attribute of output\n", + " data = data.data;\n", + " }\n", + " if (data['text/html'] === html_output) {\n", + " return [cell, data, j];\n", + " }\n", + " }\n", + " }\n", + " }\n", + "};\n", + "\n", + "// Register the function which deals with the matplotlib target/channel.\n", + "// The kernel may be null if the page has been refreshed.\n", + "if (IPython.notebook.kernel !== null) {\n", + " IPython.notebook.kernel.comm_manager.register_target(\n", + " 'matplotlib',\n", + " mpl.mpl_figure_comm\n", + " );\n", + "}\n" + ], "text/plain": [ "" ] @@ -226,7 +1196,980 @@ "outputs": [ { "data": { - "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n rubberband_canvas.addEventListener(\n 'dblclick',\n on_mouse_event_closure('dblclick')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n var img = evt.data;\n if (img.type !== 'image/png') {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n img.type = 'image/png';\n }\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n img\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.key === this._key) {\n return;\n } else {\n this._key = event.key;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.key !== 'Control') {\n value += 'ctrl+';\n }\n else if (event.altKey && event.key !== 'Alt') {\n value += 'alt+';\n }\n else if (event.shiftKey && event.key !== 'Shift') {\n value += 'shift+';\n }\n\n value += 'k' + event.key;\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.binaryType = comm.kernel.ws.binaryType;\n ws.readyState = comm.kernel.ws.readyState;\n function updateReadyState(_event) {\n if (comm.kernel.ws) {\n ws.readyState = comm.kernel.ws.readyState;\n } else {\n ws.readyState = 3; // Closed state.\n }\n }\n comm.kernel.ws.addEventListener('open', updateReadyState);\n comm.kernel.ws.addEventListener('close', updateReadyState);\n comm.kernel.ws.addEventListener('error', updateReadyState);\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n var data = msg['content']['data'];\n if (data['blob'] !== undefined) {\n data = {\n data: new Blob(msg['buffers'], { type: data['blob'] }),\n };\n }\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(data);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "/* global mpl */\n", + "window.mpl = {};\n", + "\n", + "mpl.get_websocket_type = function () {\n", + " if (typeof WebSocket !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof MozWebSocket !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert(\n", + " 'Your browser does not have WebSocket support. ' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.'\n", + " );\n", + " }\n", + "};\n", + "\n", + "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = this.ws.binaryType !== undefined;\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById('mpl-warnings');\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent =\n", + " 'This browser does not support binary websocket messages. ' +\n", + " 'Performance may be slow.';\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = document.createElement('div');\n", + " this.root.setAttribute('style', 'display: inline-block');\n", + " this._root_extra_style(this.root);\n", + "\n", + " parent_element.appendChild(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message('supports_binary', { value: fig.supports_binary });\n", + " fig.send_message('send_image_mode', {});\n", + " if (fig.ratio !== 1) {\n", + " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", + " }\n", + " fig.send_message('refresh', {});\n", + " };\n", + "\n", + " this.imageObj.onload = function () {\n", + " if (fig.image_mode === 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function () {\n", + " fig.ws.close();\n", + " };\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "};\n", + "\n", + "mpl.figure.prototype._init_header = function () {\n", + " var titlebar = document.createElement('div');\n", + " titlebar.classList =\n", + " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", + " var titletext = document.createElement('div');\n", + " titletext.classList = 'ui-dialog-title';\n", + " titletext.setAttribute(\n", + " 'style',\n", + " 'width: 100%; text-align: center; padding: 3px;'\n", + " );\n", + " titlebar.appendChild(titletext);\n", + " this.root.appendChild(titlebar);\n", + " this.header = titletext;\n", + "};\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", + "\n", + "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", + "\n", + "mpl.figure.prototype._init_canvas = function () {\n", + " var fig = this;\n", + "\n", + " var canvas_div = (this.canvas_div = document.createElement('div'));\n", + " canvas_div.setAttribute(\n", + " 'style',\n", + " 'border: 1px solid #ddd;' +\n", + " 'box-sizing: content-box;' +\n", + " 'clear: both;' +\n", + " 'min-height: 1px;' +\n", + " 'min-width: 1px;' +\n", + " 'outline: 0;' +\n", + " 'overflow: hidden;' +\n", + " 'position: relative;' +\n", + " 'resize: both;'\n", + " );\n", + "\n", + " function on_keyboard_event_closure(name) {\n", + " return function (event) {\n", + " return fig.key_event(event, name);\n", + " };\n", + " }\n", + "\n", + " canvas_div.addEventListener(\n", + " 'keydown',\n", + " on_keyboard_event_closure('key_press')\n", + " );\n", + " canvas_div.addEventListener(\n", + " 'keyup',\n", + " on_keyboard_event_closure('key_release')\n", + " );\n", + "\n", + " this._canvas_extra_style(canvas_div);\n", + " this.root.appendChild(canvas_div);\n", + "\n", + " var canvas = (this.canvas = document.createElement('canvas'));\n", + " canvas.classList.add('mpl-canvas');\n", + " canvas.setAttribute('style', 'box-sizing: content-box;');\n", + "\n", + " this.context = canvas.getContext('2d');\n", + "\n", + " var backingStore =\n", + " this.context.backingStorePixelRatio ||\n", + " this.context.webkitBackingStorePixelRatio ||\n", + " this.context.mozBackingStorePixelRatio ||\n", + " this.context.msBackingStorePixelRatio ||\n", + " this.context.oBackingStorePixelRatio ||\n", + " this.context.backingStorePixelRatio ||\n", + " 1;\n", + "\n", + " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", + "\n", + " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", + " 'canvas'\n", + " ));\n", + " rubberband_canvas.setAttribute(\n", + " 'style',\n", + " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", + " );\n", + "\n", + " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", + " if (this.ResizeObserver === undefined) {\n", + " if (window.ResizeObserver !== undefined) {\n", + " this.ResizeObserver = window.ResizeObserver;\n", + " } else {\n", + " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", + " this.ResizeObserver = obs.ResizeObserver;\n", + " }\n", + " }\n", + "\n", + " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", + " var nentries = entries.length;\n", + " for (var i = 0; i < nentries; i++) {\n", + " var entry = entries[i];\n", + " var width, height;\n", + " if (entry.contentBoxSize) {\n", + " if (entry.contentBoxSize instanceof Array) {\n", + " // Chrome 84 implements new version of spec.\n", + " width = entry.contentBoxSize[0].inlineSize;\n", + " height = entry.contentBoxSize[0].blockSize;\n", + " } else {\n", + " // Firefox implements old version of spec.\n", + " width = entry.contentBoxSize.inlineSize;\n", + " height = entry.contentBoxSize.blockSize;\n", + " }\n", + " } else {\n", + " // Chrome <84 implements even older version of spec.\n", + " width = entry.contentRect.width;\n", + " height = entry.contentRect.height;\n", + " }\n", + "\n", + " // Keep the size of the canvas and rubber band canvas in sync with\n", + " // the canvas container.\n", + " if (entry.devicePixelContentBoxSize) {\n", + " // Chrome 84 implements new version of spec.\n", + " canvas.setAttribute(\n", + " 'width',\n", + " entry.devicePixelContentBoxSize[0].inlineSize\n", + " );\n", + " canvas.setAttribute(\n", + " 'height',\n", + " entry.devicePixelContentBoxSize[0].blockSize\n", + " );\n", + " } else {\n", + " canvas.setAttribute('width', width * fig.ratio);\n", + " canvas.setAttribute('height', height * fig.ratio);\n", + " }\n", + " canvas.setAttribute(\n", + " 'style',\n", + " 'width: ' + width + 'px; height: ' + height + 'px;'\n", + " );\n", + "\n", + " rubberband_canvas.setAttribute('width', width);\n", + " rubberband_canvas.setAttribute('height', height);\n", + "\n", + " // And update the size in Python. We ignore the initial 0/0 size\n", + " // that occurs as the element is placed into the DOM, which should\n", + " // otherwise not happen due to the minimum size styling.\n", + " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", + " fig.request_resize(width, height);\n", + " }\n", + " }\n", + " });\n", + " this.resizeObserverInstance.observe(canvas_div);\n", + "\n", + " function on_mouse_event_closure(name) {\n", + " return function (event) {\n", + " return fig.mouse_event(event, name);\n", + " };\n", + " }\n", + "\n", + " rubberband_canvas.addEventListener(\n", + " 'mousedown',\n", + " on_mouse_event_closure('button_press')\n", + " );\n", + " rubberband_canvas.addEventListener(\n", + " 'mouseup',\n", + " on_mouse_event_closure('button_release')\n", + " );\n", + " rubberband_canvas.addEventListener(\n", + " 'dblclick',\n", + " on_mouse_event_closure('dblclick')\n", + " );\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband_canvas.addEventListener(\n", + " 'mousemove',\n", + " on_mouse_event_closure('motion_notify')\n", + " );\n", + "\n", + " rubberband_canvas.addEventListener(\n", + " 'mouseenter',\n", + " on_mouse_event_closure('figure_enter')\n", + " );\n", + " rubberband_canvas.addEventListener(\n", + " 'mouseleave',\n", + " on_mouse_event_closure('figure_leave')\n", + " );\n", + "\n", + " canvas_div.addEventListener('wheel', function (event) {\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " on_mouse_event_closure('scroll')(event);\n", + " });\n", + "\n", + " canvas_div.appendChild(canvas);\n", + " canvas_div.appendChild(rubberband_canvas);\n", + "\n", + " this.rubberband_context = rubberband_canvas.getContext('2d');\n", + " this.rubberband_context.strokeStyle = '#000000';\n", + "\n", + " this._resize_canvas = function (width, height, forward) {\n", + " if (forward) {\n", + " canvas_div.style.width = width + 'px';\n", + " canvas_div.style.height = height + 'px';\n", + " }\n", + " };\n", + "\n", + " // Disable right mouse context menu.\n", + " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", + " event.preventDefault();\n", + " return false;\n", + " });\n", + "\n", + " function set_focus() {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "};\n", + "\n", + "mpl.figure.prototype._init_toolbar = function () {\n", + " var fig = this;\n", + "\n", + " var toolbar = document.createElement('div');\n", + " toolbar.classList = 'mpl-toolbar';\n", + " this.root.appendChild(toolbar);\n", + "\n", + " function on_click_closure(name) {\n", + " return function (_event) {\n", + " return fig.toolbar_button_onclick(name);\n", + " };\n", + " }\n", + "\n", + " function on_mouseover_closure(tooltip) {\n", + " return function (event) {\n", + " if (!event.currentTarget.disabled) {\n", + " return fig.toolbar_button_onmouseover(tooltip);\n", + " }\n", + " };\n", + " }\n", + "\n", + " fig.buttons = {};\n", + " var buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'mpl-button-group';\n", + " for (var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " /* Instead of a spacer, we start a new button group. */\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + " buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'mpl-button-group';\n", + " continue;\n", + " }\n", + "\n", + " var button = (fig.buttons[name] = document.createElement('button'));\n", + " button.classList = 'mpl-widget';\n", + " button.setAttribute('role', 'button');\n", + " button.setAttribute('aria-disabled', 'false');\n", + " button.addEventListener('click', on_click_closure(method_name));\n", + " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", + "\n", + " var icon_img = document.createElement('img');\n", + " icon_img.src = '_images/' + image + '.png';\n", + " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", + " icon_img.alt = tooltip;\n", + " button.appendChild(icon_img);\n", + "\n", + " buttonGroup.appendChild(button);\n", + " }\n", + "\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + "\n", + " var fmt_picker = document.createElement('select');\n", + " fmt_picker.classList = 'mpl-widget';\n", + " toolbar.appendChild(fmt_picker);\n", + " this.format_dropdown = fmt_picker;\n", + "\n", + " for (var ind in mpl.extensions) {\n", + " var fmt = mpl.extensions[ind];\n", + " var option = document.createElement('option');\n", + " option.selected = fmt === mpl.default_extension;\n", + " option.innerHTML = fmt;\n", + " fmt_picker.appendChild(option);\n", + " }\n", + "\n", + " var status_bar = document.createElement('span');\n", + " status_bar.classList = 'mpl-message';\n", + " toolbar.appendChild(status_bar);\n", + " this.message = status_bar;\n", + "};\n", + "\n", + "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", + " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", + " // which will in turn request a refresh of the image.\n", + " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", + "};\n", + "\n", + "mpl.figure.prototype.send_message = function (type, properties) {\n", + " properties['type'] = type;\n", + " properties['figure_id'] = this.id;\n", + " this.ws.send(JSON.stringify(properties));\n", + "};\n", + "\n", + "mpl.figure.prototype.send_draw_message = function () {\n", + " if (!this.waiting) {\n", + " this.waiting = true;\n", + " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", + " var format_dropdown = fig.format_dropdown;\n", + " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", + " fig.ondownload(fig, format);\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", + " var size = msg['size'];\n", + " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", + " fig._resize_canvas(size[0], size[1], msg['forward']);\n", + " fig.send_message('refresh', {});\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", + " var x0 = msg['x0'] / fig.ratio;\n", + " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", + " var x1 = msg['x1'] / fig.ratio;\n", + " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", + " x0 = Math.floor(x0) + 0.5;\n", + " y0 = Math.floor(y0) + 0.5;\n", + " x1 = Math.floor(x1) + 0.5;\n", + " y1 = Math.floor(y1) + 0.5;\n", + " var min_x = Math.min(x0, x1);\n", + " var min_y = Math.min(y0, y1);\n", + " var width = Math.abs(x1 - x0);\n", + " var height = Math.abs(y1 - y0);\n", + "\n", + " fig.rubberband_context.clearRect(\n", + " 0,\n", + " 0,\n", + " fig.canvas.width / fig.ratio,\n", + " fig.canvas.height / fig.ratio\n", + " );\n", + "\n", + " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", + " // Updates the figure title.\n", + " fig.header.textContent = msg['label'];\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", + " var cursor = msg['cursor'];\n", + " switch (cursor) {\n", + " case 0:\n", + " cursor = 'pointer';\n", + " break;\n", + " case 1:\n", + " cursor = 'default';\n", + " break;\n", + " case 2:\n", + " cursor = 'crosshair';\n", + " break;\n", + " case 3:\n", + " cursor = 'move';\n", + " break;\n", + " }\n", + " fig.rubberband_canvas.style.cursor = cursor;\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_message = function (fig, msg) {\n", + " fig.message.textContent = msg['message'];\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", + " // Request the server to send over a new figure.\n", + " fig.send_draw_message();\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", + " fig.image_mode = msg['mode'];\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", + " for (var key in msg) {\n", + " if (!(key in fig.buttons)) {\n", + " continue;\n", + " }\n", + " fig.buttons[key].disabled = !msg[key];\n", + " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", + " if (msg['mode'] === 'PAN') {\n", + " fig.buttons['Pan'].classList.add('active');\n", + " fig.buttons['Zoom'].classList.remove('active');\n", + " } else if (msg['mode'] === 'ZOOM') {\n", + " fig.buttons['Pan'].classList.remove('active');\n", + " fig.buttons['Zoom'].classList.add('active');\n", + " } else {\n", + " fig.buttons['Pan'].classList.remove('active');\n", + " fig.buttons['Zoom'].classList.remove('active');\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.updated_canvas_event = function () {\n", + " // Called whenever the canvas gets updated.\n", + " this.send_message('ack', {});\n", + "};\n", + "\n", + "// A function to construct a web socket function for onmessage handling.\n", + "// Called in the figure constructor.\n", + "mpl.figure.prototype._make_on_message_function = function (fig) {\n", + " return function socket_on_message(evt) {\n", + " if (evt.data instanceof Blob) {\n", + " var img = evt.data;\n", + " if (img.type !== 'image/png') {\n", + " /* FIXME: We get \"Resource interpreted as Image but\n", + " * transferred with MIME type text/plain:\" errors on\n", + " * Chrome. But how to set the MIME type? It doesn't seem\n", + " * to be part of the websocket stream */\n", + " img.type = 'image/png';\n", + " }\n", + "\n", + " /* Free the memory for the previous frames */\n", + " if (fig.imageObj.src) {\n", + " (window.URL || window.webkitURL).revokeObjectURL(\n", + " fig.imageObj.src\n", + " );\n", + " }\n", + "\n", + " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", + " img\n", + " );\n", + " fig.updated_canvas_event();\n", + " fig.waiting = false;\n", + " return;\n", + " } else if (\n", + " typeof evt.data === 'string' &&\n", + " evt.data.slice(0, 21) === 'data:image/png;base64'\n", + " ) {\n", + " fig.imageObj.src = evt.data;\n", + " fig.updated_canvas_event();\n", + " fig.waiting = false;\n", + " return;\n", + " }\n", + "\n", + " var msg = JSON.parse(evt.data);\n", + " var msg_type = msg['type'];\n", + "\n", + " // Call the \"handle_{type}\" callback, which takes\n", + " // the figure and JSON message as its only arguments.\n", + " try {\n", + " var callback = fig['handle_' + msg_type];\n", + " } catch (e) {\n", + " console.log(\n", + " \"No handler for the '\" + msg_type + \"' message type: \",\n", + " msg\n", + " );\n", + " return;\n", + " }\n", + "\n", + " if (callback) {\n", + " try {\n", + " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", + " callback(fig, msg);\n", + " } catch (e) {\n", + " console.log(\n", + " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", + " e,\n", + " e.stack,\n", + " msg\n", + " );\n", + " }\n", + " }\n", + " };\n", + "};\n", + "\n", + "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", + "mpl.findpos = function (e) {\n", + " //this section is from http://www.quirksmode.org/js/events_properties.html\n", + " var targ;\n", + " if (!e) {\n", + " e = window.event;\n", + " }\n", + " if (e.target) {\n", + " targ = e.target;\n", + " } else if (e.srcElement) {\n", + " targ = e.srcElement;\n", + " }\n", + " if (targ.nodeType === 3) {\n", + " // defeat Safari bug\n", + " targ = targ.parentNode;\n", + " }\n", + "\n", + " // pageX,Y are the mouse positions relative to the document\n", + " var boundingRect = targ.getBoundingClientRect();\n", + " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", + " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", + "\n", + " return { x: x, y: y };\n", + "};\n", + "\n", + "/*\n", + " * return a copy of an object with only non-object keys\n", + " * we need this to avoid circular references\n", + " * http://stackoverflow.com/a/24161582/3208463\n", + " */\n", + "function simpleKeys(original) {\n", + " return Object.keys(original).reduce(function (obj, key) {\n", + " if (typeof original[key] !== 'object') {\n", + " obj[key] = original[key];\n", + " }\n", + " return obj;\n", + " }, {});\n", + "}\n", + "\n", + "mpl.figure.prototype.mouse_event = function (event, name) {\n", + " var canvas_pos = mpl.findpos(event);\n", + "\n", + " if (name === 'button_press') {\n", + " this.canvas.focus();\n", + " this.canvas_div.focus();\n", + " }\n", + "\n", + " var x = canvas_pos.x * this.ratio;\n", + " var y = canvas_pos.y * this.ratio;\n", + "\n", + " this.send_message(name, {\n", + " x: x,\n", + " y: y,\n", + " button: event.button,\n", + " step: event.step,\n", + " guiEvent: simpleKeys(event),\n", + " });\n", + "\n", + " /* This prevents the web browser from automatically changing to\n", + " * the text insertion cursor when the button is pressed. We want\n", + " * to control all of the cursor setting manually through the\n", + " * 'cursor' event from matplotlib */\n", + " event.preventDefault();\n", + " return false;\n", + "};\n", + "\n", + "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", + " // Handle any extra behaviour associated with a key event\n", + "};\n", + "\n", + "mpl.figure.prototype.key_event = function (event, name) {\n", + " // Prevent repeat events\n", + " if (name === 'key_press') {\n", + " if (event.key === this._key) {\n", + " return;\n", + " } else {\n", + " this._key = event.key;\n", + " }\n", + " }\n", + " if (name === 'key_release') {\n", + " this._key = null;\n", + " }\n", + "\n", + " var value = '';\n", + " if (event.ctrlKey && event.key !== 'Control') {\n", + " value += 'ctrl+';\n", + " }\n", + " else if (event.altKey && event.key !== 'Alt') {\n", + " value += 'alt+';\n", + " }\n", + " else if (event.shiftKey && event.key !== 'Shift') {\n", + " value += 'shift+';\n", + " }\n", + "\n", + " value += 'k' + event.key;\n", + "\n", + " this._key_event_extra(event, name);\n", + "\n", + " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", + " return false;\n", + "};\n", + "\n", + "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", + " if (name === 'download') {\n", + " this.handle_save(this, null);\n", + " } else {\n", + " this.send_message('toolbar_button', { name: name });\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", + " this.message.textContent = tooltip;\n", + "};\n", + "\n", + "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", + "// prettier-ignore\n", + "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", + "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", + "\n", + "mpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", + "\n", + "mpl.default_extension = \"png\";/* global mpl */\n", + "\n", + "var comm_websocket_adapter = function (comm) {\n", + " // Create a \"websocket\"-like object which calls the given IPython comm\n", + " // object with the appropriate methods. Currently this is a non binary\n", + " // socket, so there is still some room for performance tuning.\n", + " var ws = {};\n", + "\n", + " ws.binaryType = comm.kernel.ws.binaryType;\n", + " ws.readyState = comm.kernel.ws.readyState;\n", + " function updateReadyState(_event) {\n", + " if (comm.kernel.ws) {\n", + " ws.readyState = comm.kernel.ws.readyState;\n", + " } else {\n", + " ws.readyState = 3; // Closed state.\n", + " }\n", + " }\n", + " comm.kernel.ws.addEventListener('open', updateReadyState);\n", + " comm.kernel.ws.addEventListener('close', updateReadyState);\n", + " comm.kernel.ws.addEventListener('error', updateReadyState);\n", + "\n", + " ws.close = function () {\n", + " comm.close();\n", + " };\n", + " ws.send = function (m) {\n", + " //console.log('sending', m);\n", + " comm.send(m);\n", + " };\n", + " // Register the callback with on_msg.\n", + " comm.on_msg(function (msg) {\n", + " //console.log('receiving', msg['content']['data'], msg);\n", + " var data = msg['content']['data'];\n", + " if (data['blob'] !== undefined) {\n", + " data = {\n", + " data: new Blob(msg['buffers'], { type: data['blob'] }),\n", + " };\n", + " }\n", + " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", + " ws.onmessage(data);\n", + " });\n", + " return ws;\n", + "};\n", + "\n", + "mpl.mpl_figure_comm = function (comm, msg) {\n", + " // This is the function which gets called when the mpl process\n", + " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", + "\n", + " var id = msg.content.data.id;\n", + " // Get hold of the div created by the display call when the Comm\n", + " // socket was opened in Python.\n", + " var element = document.getElementById(id);\n", + " var ws_proxy = comm_websocket_adapter(comm);\n", + "\n", + " function ondownload(figure, _format) {\n", + " window.open(figure.canvas.toDataURL());\n", + " }\n", + "\n", + " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", + "\n", + " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", + " // web socket which is closed, not our websocket->open comm proxy.\n", + " ws_proxy.onopen();\n", + "\n", + " fig.parent_element = element;\n", + " fig.cell_info = mpl.find_output_cell(\"
\");\n", + " if (!fig.cell_info) {\n", + " console.error('Failed to find cell for figure', id, fig);\n", + " return;\n", + " }\n", + " fig.cell_info[0].output_area.element.on(\n", + " 'cleared',\n", + " { fig: fig },\n", + " fig._remove_fig_handler\n", + " );\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_close = function (fig, msg) {\n", + " var width = fig.canvas.width / fig.ratio;\n", + " fig.cell_info[0].output_area.element.off(\n", + " 'cleared',\n", + " fig._remove_fig_handler\n", + " );\n", + " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", + "\n", + " // Update the output cell to use the data from the current canvas.\n", + " fig.push_to_output();\n", + " var dataURL = fig.canvas.toDataURL();\n", + " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", + " // the notebook keyboard shortcuts fail.\n", + " IPython.keyboard_manager.enable();\n", + " fig.parent_element.innerHTML =\n", + " '';\n", + " fig.close_ws(fig, msg);\n", + "};\n", + "\n", + "mpl.figure.prototype.close_ws = function (fig, msg) {\n", + " fig.send_message('closing', msg);\n", + " // fig.ws.close()\n", + "};\n", + "\n", + "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", + " // Turn the data on the canvas into data in the output cell.\n", + " var width = this.canvas.width / this.ratio;\n", + " var dataURL = this.canvas.toDataURL();\n", + " this.cell_info[1]['text/html'] =\n", + " '';\n", + "};\n", + "\n", + "mpl.figure.prototype.updated_canvas_event = function () {\n", + " // Tell IPython that the notebook contents must change.\n", + " IPython.notebook.set_dirty(true);\n", + " this.send_message('ack', {});\n", + " var fig = this;\n", + " // Wait a second, then push the new image to the DOM so\n", + " // that it is saved nicely (might be nice to debounce this).\n", + " setTimeout(function () {\n", + " fig.push_to_output();\n", + " }, 1000);\n", + "};\n", + "\n", + "mpl.figure.prototype._init_toolbar = function () {\n", + " var fig = this;\n", + "\n", + " var toolbar = document.createElement('div');\n", + " toolbar.classList = 'btn-toolbar';\n", + " this.root.appendChild(toolbar);\n", + "\n", + " function on_click_closure(name) {\n", + " return function (_event) {\n", + " return fig.toolbar_button_onclick(name);\n", + " };\n", + " }\n", + "\n", + " function on_mouseover_closure(tooltip) {\n", + " return function (event) {\n", + " if (!event.currentTarget.disabled) {\n", + " return fig.toolbar_button_onmouseover(tooltip);\n", + " }\n", + " };\n", + " }\n", + "\n", + " fig.buttons = {};\n", + " var buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'btn-group';\n", + " var button;\n", + " for (var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " /* Instead of a spacer, we start a new button group. */\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + " buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'btn-group';\n", + " continue;\n", + " }\n", + "\n", + " button = fig.buttons[name] = document.createElement('button');\n", + " button.classList = 'btn btn-default';\n", + " button.href = '#';\n", + " button.title = name;\n", + " button.innerHTML = '';\n", + " button.addEventListener('click', on_click_closure(method_name));\n", + " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", + " buttonGroup.appendChild(button);\n", + " }\n", + "\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + "\n", + " // Add the status bar.\n", + " var status_bar = document.createElement('span');\n", + " status_bar.classList = 'mpl-message pull-right';\n", + " toolbar.appendChild(status_bar);\n", + " this.message = status_bar;\n", + "\n", + " // Add the close button to the window.\n", + " var buttongrp = document.createElement('div');\n", + " buttongrp.classList = 'btn-group inline pull-right';\n", + " button = document.createElement('button');\n", + " button.classList = 'btn btn-mini btn-primary';\n", + " button.href = '#';\n", + " button.title = 'Stop Interaction';\n", + " button.innerHTML = '';\n", + " button.addEventListener('click', function (_evt) {\n", + " fig.handle_close(fig, {});\n", + " });\n", + " button.addEventListener(\n", + " 'mouseover',\n", + " on_mouseover_closure('Stop Interaction')\n", + " );\n", + " buttongrp.appendChild(button);\n", + " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", + " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", + "};\n", + "\n", + "mpl.figure.prototype._remove_fig_handler = function (event) {\n", + " var fig = event.data.fig;\n", + " if (event.target !== this) {\n", + " // Ignore bubbled events from children.\n", + " return;\n", + " }\n", + " fig.close_ws(fig, {});\n", + "};\n", + "\n", + "mpl.figure.prototype._root_extra_style = function (el) {\n", + " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", + "};\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function (el) {\n", + " // this is important to make the div 'focusable\n", + " el.setAttribute('tabindex', 0);\n", + " // reach out to IPython and tell the keyboard manager to turn it's self\n", + " // off when our div gets focus\n", + "\n", + " // location in version 3\n", + " if (IPython.notebook.keyboard_manager) {\n", + " IPython.notebook.keyboard_manager.register_events(el);\n", + " } else {\n", + " // location in version 2\n", + " IPython.keyboard_manager.register_events(el);\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", + " var manager = IPython.notebook.keyboard_manager;\n", + " if (!manager) {\n", + " manager = IPython.keyboard_manager;\n", + " }\n", + "\n", + " // Check for shift+enter\n", + " if (event.shiftKey && event.which === 13) {\n", + " this.canvas_div.blur();\n", + " // select the cell after this one\n", + " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", + " IPython.notebook.select(index + 1);\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", + " fig.ondownload(fig, null);\n", + "};\n", + "\n", + "mpl.find_output_cell = function (html_output) {\n", + " // Return the cell and output element which can be found *uniquely* in the notebook.\n", + " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", + " // IPython event is triggered only after the cells have been serialised, which for\n", + " // our purposes (turning an active figure into a static one), is too late.\n", + " var cells = IPython.notebook.get_cells();\n", + " var ncells = cells.length;\n", + " for (var i = 0; i < ncells; i++) {\n", + " var cell = cells[i];\n", + " if (cell.cell_type === 'code') {\n", + " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", + " var data = cell.output_area.outputs[j];\n", + " if (data.data) {\n", + " // IPython >= 3 moved mimebundle to data attribute of output\n", + " data = data.data;\n", + " }\n", + " if (data['text/html'] === html_output) {\n", + " return [cell, data, j];\n", + " }\n", + " }\n", + " }\n", + " }\n", + "};\n", + "\n", + "// Register the function which deals with the matplotlib target/channel.\n", + "// The kernel may be null if the page has been refreshed.\n", + "if (IPython.notebook.kernel !== null) {\n", + " IPython.notebook.kernel.comm_manager.register_target(\n", + " 'matplotlib',\n", + " mpl.mpl_figure_comm\n", + " );\n", + "}\n" + ], "text/plain": [ "" ] @@ -323,7 +2266,980 @@ }, { "data": { - "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n rubberband_canvas.addEventListener(\n 'dblclick',\n on_mouse_event_closure('dblclick')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n var img = evt.data;\n if (img.type !== 'image/png') {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n img.type = 'image/png';\n }\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n img\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.key === this._key) {\n return;\n } else {\n this._key = event.key;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.key !== 'Control') {\n value += 'ctrl+';\n }\n else if (event.altKey && event.key !== 'Alt') {\n value += 'alt+';\n }\n else if (event.shiftKey && event.key !== 'Shift') {\n value += 'shift+';\n }\n\n value += 'k' + event.key;\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.binaryType = comm.kernel.ws.binaryType;\n ws.readyState = comm.kernel.ws.readyState;\n function updateReadyState(_event) {\n if (comm.kernel.ws) {\n ws.readyState = comm.kernel.ws.readyState;\n } else {\n ws.readyState = 3; // Closed state.\n }\n }\n comm.kernel.ws.addEventListener('open', updateReadyState);\n comm.kernel.ws.addEventListener('close', updateReadyState);\n comm.kernel.ws.addEventListener('error', updateReadyState);\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n var data = msg['content']['data'];\n if (data['blob'] !== undefined) {\n data = {\n data: new Blob(msg['buffers'], { type: data['blob'] }),\n };\n }\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(data);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "/* global mpl */\n", + "window.mpl = {};\n", + "\n", + "mpl.get_websocket_type = function () {\n", + " if (typeof WebSocket !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof MozWebSocket !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert(\n", + " 'Your browser does not have WebSocket support. ' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.'\n", + " );\n", + " }\n", + "};\n", + "\n", + "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = this.ws.binaryType !== undefined;\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById('mpl-warnings');\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent =\n", + " 'This browser does not support binary websocket messages. ' +\n", + " 'Performance may be slow.';\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = document.createElement('div');\n", + " this.root.setAttribute('style', 'display: inline-block');\n", + " this._root_extra_style(this.root);\n", + "\n", + " parent_element.appendChild(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message('supports_binary', { value: fig.supports_binary });\n", + " fig.send_message('send_image_mode', {});\n", + " if (fig.ratio !== 1) {\n", + " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", + " }\n", + " fig.send_message('refresh', {});\n", + " };\n", + "\n", + " this.imageObj.onload = function () {\n", + " if (fig.image_mode === 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function () {\n", + " fig.ws.close();\n", + " };\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "};\n", + "\n", + "mpl.figure.prototype._init_header = function () {\n", + " var titlebar = document.createElement('div');\n", + " titlebar.classList =\n", + " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", + " var titletext = document.createElement('div');\n", + " titletext.classList = 'ui-dialog-title';\n", + " titletext.setAttribute(\n", + " 'style',\n", + " 'width: 100%; text-align: center; padding: 3px;'\n", + " );\n", + " titlebar.appendChild(titletext);\n", + " this.root.appendChild(titlebar);\n", + " this.header = titletext;\n", + "};\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", + "\n", + "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", + "\n", + "mpl.figure.prototype._init_canvas = function () {\n", + " var fig = this;\n", + "\n", + " var canvas_div = (this.canvas_div = document.createElement('div'));\n", + " canvas_div.setAttribute(\n", + " 'style',\n", + " 'border: 1px solid #ddd;' +\n", + " 'box-sizing: content-box;' +\n", + " 'clear: both;' +\n", + " 'min-height: 1px;' +\n", + " 'min-width: 1px;' +\n", + " 'outline: 0;' +\n", + " 'overflow: hidden;' +\n", + " 'position: relative;' +\n", + " 'resize: both;'\n", + " );\n", + "\n", + " function on_keyboard_event_closure(name) {\n", + " return function (event) {\n", + " return fig.key_event(event, name);\n", + " };\n", + " }\n", + "\n", + " canvas_div.addEventListener(\n", + " 'keydown',\n", + " on_keyboard_event_closure('key_press')\n", + " );\n", + " canvas_div.addEventListener(\n", + " 'keyup',\n", + " on_keyboard_event_closure('key_release')\n", + " );\n", + "\n", + " this._canvas_extra_style(canvas_div);\n", + " this.root.appendChild(canvas_div);\n", + "\n", + " var canvas = (this.canvas = document.createElement('canvas'));\n", + " canvas.classList.add('mpl-canvas');\n", + " canvas.setAttribute('style', 'box-sizing: content-box;');\n", + "\n", + " this.context = canvas.getContext('2d');\n", + "\n", + " var backingStore =\n", + " this.context.backingStorePixelRatio ||\n", + " this.context.webkitBackingStorePixelRatio ||\n", + " this.context.mozBackingStorePixelRatio ||\n", + " this.context.msBackingStorePixelRatio ||\n", + " this.context.oBackingStorePixelRatio ||\n", + " this.context.backingStorePixelRatio ||\n", + " 1;\n", + "\n", + " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", + "\n", + " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", + " 'canvas'\n", + " ));\n", + " rubberband_canvas.setAttribute(\n", + " 'style',\n", + " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", + " );\n", + "\n", + " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", + " if (this.ResizeObserver === undefined) {\n", + " if (window.ResizeObserver !== undefined) {\n", + " this.ResizeObserver = window.ResizeObserver;\n", + " } else {\n", + " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", + " this.ResizeObserver = obs.ResizeObserver;\n", + " }\n", + " }\n", + "\n", + " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", + " var nentries = entries.length;\n", + " for (var i = 0; i < nentries; i++) {\n", + " var entry = entries[i];\n", + " var width, height;\n", + " if (entry.contentBoxSize) {\n", + " if (entry.contentBoxSize instanceof Array) {\n", + " // Chrome 84 implements new version of spec.\n", + " width = entry.contentBoxSize[0].inlineSize;\n", + " height = entry.contentBoxSize[0].blockSize;\n", + " } else {\n", + " // Firefox implements old version of spec.\n", + " width = entry.contentBoxSize.inlineSize;\n", + " height = entry.contentBoxSize.blockSize;\n", + " }\n", + " } else {\n", + " // Chrome <84 implements even older version of spec.\n", + " width = entry.contentRect.width;\n", + " height = entry.contentRect.height;\n", + " }\n", + "\n", + " // Keep the size of the canvas and rubber band canvas in sync with\n", + " // the canvas container.\n", + " if (entry.devicePixelContentBoxSize) {\n", + " // Chrome 84 implements new version of spec.\n", + " canvas.setAttribute(\n", + " 'width',\n", + " entry.devicePixelContentBoxSize[0].inlineSize\n", + " );\n", + " canvas.setAttribute(\n", + " 'height',\n", + " entry.devicePixelContentBoxSize[0].blockSize\n", + " );\n", + " } else {\n", + " canvas.setAttribute('width', width * fig.ratio);\n", + " canvas.setAttribute('height', height * fig.ratio);\n", + " }\n", + " canvas.setAttribute(\n", + " 'style',\n", + " 'width: ' + width + 'px; height: ' + height + 'px;'\n", + " );\n", + "\n", + " rubberband_canvas.setAttribute('width', width);\n", + " rubberband_canvas.setAttribute('height', height);\n", + "\n", + " // And update the size in Python. We ignore the initial 0/0 size\n", + " // that occurs as the element is placed into the DOM, which should\n", + " // otherwise not happen due to the minimum size styling.\n", + " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", + " fig.request_resize(width, height);\n", + " }\n", + " }\n", + " });\n", + " this.resizeObserverInstance.observe(canvas_div);\n", + "\n", + " function on_mouse_event_closure(name) {\n", + " return function (event) {\n", + " return fig.mouse_event(event, name);\n", + " };\n", + " }\n", + "\n", + " rubberband_canvas.addEventListener(\n", + " 'mousedown',\n", + " on_mouse_event_closure('button_press')\n", + " );\n", + " rubberband_canvas.addEventListener(\n", + " 'mouseup',\n", + " on_mouse_event_closure('button_release')\n", + " );\n", + " rubberband_canvas.addEventListener(\n", + " 'dblclick',\n", + " on_mouse_event_closure('dblclick')\n", + " );\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband_canvas.addEventListener(\n", + " 'mousemove',\n", + " on_mouse_event_closure('motion_notify')\n", + " );\n", + "\n", + " rubberband_canvas.addEventListener(\n", + " 'mouseenter',\n", + " on_mouse_event_closure('figure_enter')\n", + " );\n", + " rubberband_canvas.addEventListener(\n", + " 'mouseleave',\n", + " on_mouse_event_closure('figure_leave')\n", + " );\n", + "\n", + " canvas_div.addEventListener('wheel', function (event) {\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " on_mouse_event_closure('scroll')(event);\n", + " });\n", + "\n", + " canvas_div.appendChild(canvas);\n", + " canvas_div.appendChild(rubberband_canvas);\n", + "\n", + " this.rubberband_context = rubberband_canvas.getContext('2d');\n", + " this.rubberband_context.strokeStyle = '#000000';\n", + "\n", + " this._resize_canvas = function (width, height, forward) {\n", + " if (forward) {\n", + " canvas_div.style.width = width + 'px';\n", + " canvas_div.style.height = height + 'px';\n", + " }\n", + " };\n", + "\n", + " // Disable right mouse context menu.\n", + " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", + " event.preventDefault();\n", + " return false;\n", + " });\n", + "\n", + " function set_focus() {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "};\n", + "\n", + "mpl.figure.prototype._init_toolbar = function () {\n", + " var fig = this;\n", + "\n", + " var toolbar = document.createElement('div');\n", + " toolbar.classList = 'mpl-toolbar';\n", + " this.root.appendChild(toolbar);\n", + "\n", + " function on_click_closure(name) {\n", + " return function (_event) {\n", + " return fig.toolbar_button_onclick(name);\n", + " };\n", + " }\n", + "\n", + " function on_mouseover_closure(tooltip) {\n", + " return function (event) {\n", + " if (!event.currentTarget.disabled) {\n", + " return fig.toolbar_button_onmouseover(tooltip);\n", + " }\n", + " };\n", + " }\n", + "\n", + " fig.buttons = {};\n", + " var buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'mpl-button-group';\n", + " for (var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " /* Instead of a spacer, we start a new button group. */\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + " buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'mpl-button-group';\n", + " continue;\n", + " }\n", + "\n", + " var button = (fig.buttons[name] = document.createElement('button'));\n", + " button.classList = 'mpl-widget';\n", + " button.setAttribute('role', 'button');\n", + " button.setAttribute('aria-disabled', 'false');\n", + " button.addEventListener('click', on_click_closure(method_name));\n", + " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", + "\n", + " var icon_img = document.createElement('img');\n", + " icon_img.src = '_images/' + image + '.png';\n", + " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", + " icon_img.alt = tooltip;\n", + " button.appendChild(icon_img);\n", + "\n", + " buttonGroup.appendChild(button);\n", + " }\n", + "\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + "\n", + " var fmt_picker = document.createElement('select');\n", + " fmt_picker.classList = 'mpl-widget';\n", + " toolbar.appendChild(fmt_picker);\n", + " this.format_dropdown = fmt_picker;\n", + "\n", + " for (var ind in mpl.extensions) {\n", + " var fmt = mpl.extensions[ind];\n", + " var option = document.createElement('option');\n", + " option.selected = fmt === mpl.default_extension;\n", + " option.innerHTML = fmt;\n", + " fmt_picker.appendChild(option);\n", + " }\n", + "\n", + " var status_bar = document.createElement('span');\n", + " status_bar.classList = 'mpl-message';\n", + " toolbar.appendChild(status_bar);\n", + " this.message = status_bar;\n", + "};\n", + "\n", + "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", + " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", + " // which will in turn request a refresh of the image.\n", + " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", + "};\n", + "\n", + "mpl.figure.prototype.send_message = function (type, properties) {\n", + " properties['type'] = type;\n", + " properties['figure_id'] = this.id;\n", + " this.ws.send(JSON.stringify(properties));\n", + "};\n", + "\n", + "mpl.figure.prototype.send_draw_message = function () {\n", + " if (!this.waiting) {\n", + " this.waiting = true;\n", + " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", + " var format_dropdown = fig.format_dropdown;\n", + " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", + " fig.ondownload(fig, format);\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", + " var size = msg['size'];\n", + " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", + " fig._resize_canvas(size[0], size[1], msg['forward']);\n", + " fig.send_message('refresh', {});\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", + " var x0 = msg['x0'] / fig.ratio;\n", + " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", + " var x1 = msg['x1'] / fig.ratio;\n", + " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", + " x0 = Math.floor(x0) + 0.5;\n", + " y0 = Math.floor(y0) + 0.5;\n", + " x1 = Math.floor(x1) + 0.5;\n", + " y1 = Math.floor(y1) + 0.5;\n", + " var min_x = Math.min(x0, x1);\n", + " var min_y = Math.min(y0, y1);\n", + " var width = Math.abs(x1 - x0);\n", + " var height = Math.abs(y1 - y0);\n", + "\n", + " fig.rubberband_context.clearRect(\n", + " 0,\n", + " 0,\n", + " fig.canvas.width / fig.ratio,\n", + " fig.canvas.height / fig.ratio\n", + " );\n", + "\n", + " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", + " // Updates the figure title.\n", + " fig.header.textContent = msg['label'];\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", + " var cursor = msg['cursor'];\n", + " switch (cursor) {\n", + " case 0:\n", + " cursor = 'pointer';\n", + " break;\n", + " case 1:\n", + " cursor = 'default';\n", + " break;\n", + " case 2:\n", + " cursor = 'crosshair';\n", + " break;\n", + " case 3:\n", + " cursor = 'move';\n", + " break;\n", + " }\n", + " fig.rubberband_canvas.style.cursor = cursor;\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_message = function (fig, msg) {\n", + " fig.message.textContent = msg['message'];\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", + " // Request the server to send over a new figure.\n", + " fig.send_draw_message();\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", + " fig.image_mode = msg['mode'];\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", + " for (var key in msg) {\n", + " if (!(key in fig.buttons)) {\n", + " continue;\n", + " }\n", + " fig.buttons[key].disabled = !msg[key];\n", + " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", + " if (msg['mode'] === 'PAN') {\n", + " fig.buttons['Pan'].classList.add('active');\n", + " fig.buttons['Zoom'].classList.remove('active');\n", + " } else if (msg['mode'] === 'ZOOM') {\n", + " fig.buttons['Pan'].classList.remove('active');\n", + " fig.buttons['Zoom'].classList.add('active');\n", + " } else {\n", + " fig.buttons['Pan'].classList.remove('active');\n", + " fig.buttons['Zoom'].classList.remove('active');\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.updated_canvas_event = function () {\n", + " // Called whenever the canvas gets updated.\n", + " this.send_message('ack', {});\n", + "};\n", + "\n", + "// A function to construct a web socket function for onmessage handling.\n", + "// Called in the figure constructor.\n", + "mpl.figure.prototype._make_on_message_function = function (fig) {\n", + " return function socket_on_message(evt) {\n", + " if (evt.data instanceof Blob) {\n", + " var img = evt.data;\n", + " if (img.type !== 'image/png') {\n", + " /* FIXME: We get \"Resource interpreted as Image but\n", + " * transferred with MIME type text/plain:\" errors on\n", + " * Chrome. But how to set the MIME type? It doesn't seem\n", + " * to be part of the websocket stream */\n", + " img.type = 'image/png';\n", + " }\n", + "\n", + " /* Free the memory for the previous frames */\n", + " if (fig.imageObj.src) {\n", + " (window.URL || window.webkitURL).revokeObjectURL(\n", + " fig.imageObj.src\n", + " );\n", + " }\n", + "\n", + " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", + " img\n", + " );\n", + " fig.updated_canvas_event();\n", + " fig.waiting = false;\n", + " return;\n", + " } else if (\n", + " typeof evt.data === 'string' &&\n", + " evt.data.slice(0, 21) === 'data:image/png;base64'\n", + " ) {\n", + " fig.imageObj.src = evt.data;\n", + " fig.updated_canvas_event();\n", + " fig.waiting = false;\n", + " return;\n", + " }\n", + "\n", + " var msg = JSON.parse(evt.data);\n", + " var msg_type = msg['type'];\n", + "\n", + " // Call the \"handle_{type}\" callback, which takes\n", + " // the figure and JSON message as its only arguments.\n", + " try {\n", + " var callback = fig['handle_' + msg_type];\n", + " } catch (e) {\n", + " console.log(\n", + " \"No handler for the '\" + msg_type + \"' message type: \",\n", + " msg\n", + " );\n", + " return;\n", + " }\n", + "\n", + " if (callback) {\n", + " try {\n", + " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", + " callback(fig, msg);\n", + " } catch (e) {\n", + " console.log(\n", + " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", + " e,\n", + " e.stack,\n", + " msg\n", + " );\n", + " }\n", + " }\n", + " };\n", + "};\n", + "\n", + "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", + "mpl.findpos = function (e) {\n", + " //this section is from http://www.quirksmode.org/js/events_properties.html\n", + " var targ;\n", + " if (!e) {\n", + " e = window.event;\n", + " }\n", + " if (e.target) {\n", + " targ = e.target;\n", + " } else if (e.srcElement) {\n", + " targ = e.srcElement;\n", + " }\n", + " if (targ.nodeType === 3) {\n", + " // defeat Safari bug\n", + " targ = targ.parentNode;\n", + " }\n", + "\n", + " // pageX,Y are the mouse positions relative to the document\n", + " var boundingRect = targ.getBoundingClientRect();\n", + " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", + " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", + "\n", + " return { x: x, y: y };\n", + "};\n", + "\n", + "/*\n", + " * return a copy of an object with only non-object keys\n", + " * we need this to avoid circular references\n", + " * http://stackoverflow.com/a/24161582/3208463\n", + " */\n", + "function simpleKeys(original) {\n", + " return Object.keys(original).reduce(function (obj, key) {\n", + " if (typeof original[key] !== 'object') {\n", + " obj[key] = original[key];\n", + " }\n", + " return obj;\n", + " }, {});\n", + "}\n", + "\n", + "mpl.figure.prototype.mouse_event = function (event, name) {\n", + " var canvas_pos = mpl.findpos(event);\n", + "\n", + " if (name === 'button_press') {\n", + " this.canvas.focus();\n", + " this.canvas_div.focus();\n", + " }\n", + "\n", + " var x = canvas_pos.x * this.ratio;\n", + " var y = canvas_pos.y * this.ratio;\n", + "\n", + " this.send_message(name, {\n", + " x: x,\n", + " y: y,\n", + " button: event.button,\n", + " step: event.step,\n", + " guiEvent: simpleKeys(event),\n", + " });\n", + "\n", + " /* This prevents the web browser from automatically changing to\n", + " * the text insertion cursor when the button is pressed. We want\n", + " * to control all of the cursor setting manually through the\n", + " * 'cursor' event from matplotlib */\n", + " event.preventDefault();\n", + " return false;\n", + "};\n", + "\n", + "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", + " // Handle any extra behaviour associated with a key event\n", + "};\n", + "\n", + "mpl.figure.prototype.key_event = function (event, name) {\n", + " // Prevent repeat events\n", + " if (name === 'key_press') {\n", + " if (event.key === this._key) {\n", + " return;\n", + " } else {\n", + " this._key = event.key;\n", + " }\n", + " }\n", + " if (name === 'key_release') {\n", + " this._key = null;\n", + " }\n", + "\n", + " var value = '';\n", + " if (event.ctrlKey && event.key !== 'Control') {\n", + " value += 'ctrl+';\n", + " }\n", + " else if (event.altKey && event.key !== 'Alt') {\n", + " value += 'alt+';\n", + " }\n", + " else if (event.shiftKey && event.key !== 'Shift') {\n", + " value += 'shift+';\n", + " }\n", + "\n", + " value += 'k' + event.key;\n", + "\n", + " this._key_event_extra(event, name);\n", + "\n", + " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", + " return false;\n", + "};\n", + "\n", + "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", + " if (name === 'download') {\n", + " this.handle_save(this, null);\n", + " } else {\n", + " this.send_message('toolbar_button', { name: name });\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", + " this.message.textContent = tooltip;\n", + "};\n", + "\n", + "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", + "// prettier-ignore\n", + "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", + "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", + "\n", + "mpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", + "\n", + "mpl.default_extension = \"png\";/* global mpl */\n", + "\n", + "var comm_websocket_adapter = function (comm) {\n", + " // Create a \"websocket\"-like object which calls the given IPython comm\n", + " // object with the appropriate methods. Currently this is a non binary\n", + " // socket, so there is still some room for performance tuning.\n", + " var ws = {};\n", + "\n", + " ws.binaryType = comm.kernel.ws.binaryType;\n", + " ws.readyState = comm.kernel.ws.readyState;\n", + " function updateReadyState(_event) {\n", + " if (comm.kernel.ws) {\n", + " ws.readyState = comm.kernel.ws.readyState;\n", + " } else {\n", + " ws.readyState = 3; // Closed state.\n", + " }\n", + " }\n", + " comm.kernel.ws.addEventListener('open', updateReadyState);\n", + " comm.kernel.ws.addEventListener('close', updateReadyState);\n", + " comm.kernel.ws.addEventListener('error', updateReadyState);\n", + "\n", + " ws.close = function () {\n", + " comm.close();\n", + " };\n", + " ws.send = function (m) {\n", + " //console.log('sending', m);\n", + " comm.send(m);\n", + " };\n", + " // Register the callback with on_msg.\n", + " comm.on_msg(function (msg) {\n", + " //console.log('receiving', msg['content']['data'], msg);\n", + " var data = msg['content']['data'];\n", + " if (data['blob'] !== undefined) {\n", + " data = {\n", + " data: new Blob(msg['buffers'], { type: data['blob'] }),\n", + " };\n", + " }\n", + " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", + " ws.onmessage(data);\n", + " });\n", + " return ws;\n", + "};\n", + "\n", + "mpl.mpl_figure_comm = function (comm, msg) {\n", + " // This is the function which gets called when the mpl process\n", + " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", + "\n", + " var id = msg.content.data.id;\n", + " // Get hold of the div created by the display call when the Comm\n", + " // socket was opened in Python.\n", + " var element = document.getElementById(id);\n", + " var ws_proxy = comm_websocket_adapter(comm);\n", + "\n", + " function ondownload(figure, _format) {\n", + " window.open(figure.canvas.toDataURL());\n", + " }\n", + "\n", + " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", + "\n", + " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", + " // web socket which is closed, not our websocket->open comm proxy.\n", + " ws_proxy.onopen();\n", + "\n", + " fig.parent_element = element;\n", + " fig.cell_info = mpl.find_output_cell(\"
\");\n", + " if (!fig.cell_info) {\n", + " console.error('Failed to find cell for figure', id, fig);\n", + " return;\n", + " }\n", + " fig.cell_info[0].output_area.element.on(\n", + " 'cleared',\n", + " { fig: fig },\n", + " fig._remove_fig_handler\n", + " );\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_close = function (fig, msg) {\n", + " var width = fig.canvas.width / fig.ratio;\n", + " fig.cell_info[0].output_area.element.off(\n", + " 'cleared',\n", + " fig._remove_fig_handler\n", + " );\n", + " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", + "\n", + " // Update the output cell to use the data from the current canvas.\n", + " fig.push_to_output();\n", + " var dataURL = fig.canvas.toDataURL();\n", + " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", + " // the notebook keyboard shortcuts fail.\n", + " IPython.keyboard_manager.enable();\n", + " fig.parent_element.innerHTML =\n", + " '';\n", + " fig.close_ws(fig, msg);\n", + "};\n", + "\n", + "mpl.figure.prototype.close_ws = function (fig, msg) {\n", + " fig.send_message('closing', msg);\n", + " // fig.ws.close()\n", + "};\n", + "\n", + "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", + " // Turn the data on the canvas into data in the output cell.\n", + " var width = this.canvas.width / this.ratio;\n", + " var dataURL = this.canvas.toDataURL();\n", + " this.cell_info[1]['text/html'] =\n", + " '';\n", + "};\n", + "\n", + "mpl.figure.prototype.updated_canvas_event = function () {\n", + " // Tell IPython that the notebook contents must change.\n", + " IPython.notebook.set_dirty(true);\n", + " this.send_message('ack', {});\n", + " var fig = this;\n", + " // Wait a second, then push the new image to the DOM so\n", + " // that it is saved nicely (might be nice to debounce this).\n", + " setTimeout(function () {\n", + " fig.push_to_output();\n", + " }, 1000);\n", + "};\n", + "\n", + "mpl.figure.prototype._init_toolbar = function () {\n", + " var fig = this;\n", + "\n", + " var toolbar = document.createElement('div');\n", + " toolbar.classList = 'btn-toolbar';\n", + " this.root.appendChild(toolbar);\n", + "\n", + " function on_click_closure(name) {\n", + " return function (_event) {\n", + " return fig.toolbar_button_onclick(name);\n", + " };\n", + " }\n", + "\n", + " function on_mouseover_closure(tooltip) {\n", + " return function (event) {\n", + " if (!event.currentTarget.disabled) {\n", + " return fig.toolbar_button_onmouseover(tooltip);\n", + " }\n", + " };\n", + " }\n", + "\n", + " fig.buttons = {};\n", + " var buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'btn-group';\n", + " var button;\n", + " for (var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " /* Instead of a spacer, we start a new button group. */\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + " buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'btn-group';\n", + " continue;\n", + " }\n", + "\n", + " button = fig.buttons[name] = document.createElement('button');\n", + " button.classList = 'btn btn-default';\n", + " button.href = '#';\n", + " button.title = name;\n", + " button.innerHTML = '';\n", + " button.addEventListener('click', on_click_closure(method_name));\n", + " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", + " buttonGroup.appendChild(button);\n", + " }\n", + "\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + "\n", + " // Add the status bar.\n", + " var status_bar = document.createElement('span');\n", + " status_bar.classList = 'mpl-message pull-right';\n", + " toolbar.appendChild(status_bar);\n", + " this.message = status_bar;\n", + "\n", + " // Add the close button to the window.\n", + " var buttongrp = document.createElement('div');\n", + " buttongrp.classList = 'btn-group inline pull-right';\n", + " button = document.createElement('button');\n", + " button.classList = 'btn btn-mini btn-primary';\n", + " button.href = '#';\n", + " button.title = 'Stop Interaction';\n", + " button.innerHTML = '';\n", + " button.addEventListener('click', function (_evt) {\n", + " fig.handle_close(fig, {});\n", + " });\n", + " button.addEventListener(\n", + " 'mouseover',\n", + " on_mouseover_closure('Stop Interaction')\n", + " );\n", + " buttongrp.appendChild(button);\n", + " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", + " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", + "};\n", + "\n", + "mpl.figure.prototype._remove_fig_handler = function (event) {\n", + " var fig = event.data.fig;\n", + " if (event.target !== this) {\n", + " // Ignore bubbled events from children.\n", + " return;\n", + " }\n", + " fig.close_ws(fig, {});\n", + "};\n", + "\n", + "mpl.figure.prototype._root_extra_style = function (el) {\n", + " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", + "};\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function (el) {\n", + " // this is important to make the div 'focusable\n", + " el.setAttribute('tabindex', 0);\n", + " // reach out to IPython and tell the keyboard manager to turn it's self\n", + " // off when our div gets focus\n", + "\n", + " // location in version 3\n", + " if (IPython.notebook.keyboard_manager) {\n", + " IPython.notebook.keyboard_manager.register_events(el);\n", + " } else {\n", + " // location in version 2\n", + " IPython.keyboard_manager.register_events(el);\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", + " var manager = IPython.notebook.keyboard_manager;\n", + " if (!manager) {\n", + " manager = IPython.keyboard_manager;\n", + " }\n", + "\n", + " // Check for shift+enter\n", + " if (event.shiftKey && event.which === 13) {\n", + " this.canvas_div.blur();\n", + " // select the cell after this one\n", + " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", + " IPython.notebook.select(index + 1);\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", + " fig.ondownload(fig, null);\n", + "};\n", + "\n", + "mpl.find_output_cell = function (html_output) {\n", + " // Return the cell and output element which can be found *uniquely* in the notebook.\n", + " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", + " // IPython event is triggered only after the cells have been serialised, which for\n", + " // our purposes (turning an active figure into a static one), is too late.\n", + " var cells = IPython.notebook.get_cells();\n", + " var ncells = cells.length;\n", + " for (var i = 0; i < ncells; i++) {\n", + " var cell = cells[i];\n", + " if (cell.cell_type === 'code') {\n", + " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", + " var data = cell.output_area.outputs[j];\n", + " if (data.data) {\n", + " // IPython >= 3 moved mimebundle to data attribute of output\n", + " data = data.data;\n", + " }\n", + " if (data['text/html'] === html_output) {\n", + " return [cell, data, j];\n", + " }\n", + " }\n", + " }\n", + " }\n", + "};\n", + "\n", + "// Register the function which deals with the matplotlib target/channel.\n", + "// The kernel may be null if the page has been refreshed.\n", + "if (IPython.notebook.kernel !== null) {\n", + " IPython.notebook.kernel.comm_manager.register_target(\n", + " 'matplotlib',\n", + " mpl.mpl_figure_comm\n", + " );\n", + "}\n" + ], "text/plain": [ "" ] @@ -543,7 +3459,980 @@ "outputs": [ { "data": { - "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n rubberband_canvas.addEventListener(\n 'dblclick',\n on_mouse_event_closure('dblclick')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n var img = evt.data;\n if (img.type !== 'image/png') {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n img.type = 'image/png';\n }\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n img\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.key === this._key) {\n return;\n } else {\n this._key = event.key;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.key !== 'Control') {\n value += 'ctrl+';\n }\n else if (event.altKey && event.key !== 'Alt') {\n value += 'alt+';\n }\n else if (event.shiftKey && event.key !== 'Shift') {\n value += 'shift+';\n }\n\n value += 'k' + event.key;\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.binaryType = comm.kernel.ws.binaryType;\n ws.readyState = comm.kernel.ws.readyState;\n function updateReadyState(_event) {\n if (comm.kernel.ws) {\n ws.readyState = comm.kernel.ws.readyState;\n } else {\n ws.readyState = 3; // Closed state.\n }\n }\n comm.kernel.ws.addEventListener('open', updateReadyState);\n comm.kernel.ws.addEventListener('close', updateReadyState);\n comm.kernel.ws.addEventListener('error', updateReadyState);\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n var data = msg['content']['data'];\n if (data['blob'] !== undefined) {\n data = {\n data: new Blob(msg['buffers'], { type: data['blob'] }),\n };\n }\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(data);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "/* global mpl */\n", + "window.mpl = {};\n", + "\n", + "mpl.get_websocket_type = function () {\n", + " if (typeof WebSocket !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof MozWebSocket !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert(\n", + " 'Your browser does not have WebSocket support. ' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.'\n", + " );\n", + " }\n", + "};\n", + "\n", + "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = this.ws.binaryType !== undefined;\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById('mpl-warnings');\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent =\n", + " 'This browser does not support binary websocket messages. ' +\n", + " 'Performance may be slow.';\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = document.createElement('div');\n", + " this.root.setAttribute('style', 'display: inline-block');\n", + " this._root_extra_style(this.root);\n", + "\n", + " parent_element.appendChild(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message('supports_binary', { value: fig.supports_binary });\n", + " fig.send_message('send_image_mode', {});\n", + " if (fig.ratio !== 1) {\n", + " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", + " }\n", + " fig.send_message('refresh', {});\n", + " };\n", + "\n", + " this.imageObj.onload = function () {\n", + " if (fig.image_mode === 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function () {\n", + " fig.ws.close();\n", + " };\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "};\n", + "\n", + "mpl.figure.prototype._init_header = function () {\n", + " var titlebar = document.createElement('div');\n", + " titlebar.classList =\n", + " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", + " var titletext = document.createElement('div');\n", + " titletext.classList = 'ui-dialog-title';\n", + " titletext.setAttribute(\n", + " 'style',\n", + " 'width: 100%; text-align: center; padding: 3px;'\n", + " );\n", + " titlebar.appendChild(titletext);\n", + " this.root.appendChild(titlebar);\n", + " this.header = titletext;\n", + "};\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", + "\n", + "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", + "\n", + "mpl.figure.prototype._init_canvas = function () {\n", + " var fig = this;\n", + "\n", + " var canvas_div = (this.canvas_div = document.createElement('div'));\n", + " canvas_div.setAttribute(\n", + " 'style',\n", + " 'border: 1px solid #ddd;' +\n", + " 'box-sizing: content-box;' +\n", + " 'clear: both;' +\n", + " 'min-height: 1px;' +\n", + " 'min-width: 1px;' +\n", + " 'outline: 0;' +\n", + " 'overflow: hidden;' +\n", + " 'position: relative;' +\n", + " 'resize: both;'\n", + " );\n", + "\n", + " function on_keyboard_event_closure(name) {\n", + " return function (event) {\n", + " return fig.key_event(event, name);\n", + " };\n", + " }\n", + "\n", + " canvas_div.addEventListener(\n", + " 'keydown',\n", + " on_keyboard_event_closure('key_press')\n", + " );\n", + " canvas_div.addEventListener(\n", + " 'keyup',\n", + " on_keyboard_event_closure('key_release')\n", + " );\n", + "\n", + " this._canvas_extra_style(canvas_div);\n", + " this.root.appendChild(canvas_div);\n", + "\n", + " var canvas = (this.canvas = document.createElement('canvas'));\n", + " canvas.classList.add('mpl-canvas');\n", + " canvas.setAttribute('style', 'box-sizing: content-box;');\n", + "\n", + " this.context = canvas.getContext('2d');\n", + "\n", + " var backingStore =\n", + " this.context.backingStorePixelRatio ||\n", + " this.context.webkitBackingStorePixelRatio ||\n", + " this.context.mozBackingStorePixelRatio ||\n", + " this.context.msBackingStorePixelRatio ||\n", + " this.context.oBackingStorePixelRatio ||\n", + " this.context.backingStorePixelRatio ||\n", + " 1;\n", + "\n", + " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", + "\n", + " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", + " 'canvas'\n", + " ));\n", + " rubberband_canvas.setAttribute(\n", + " 'style',\n", + " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", + " );\n", + "\n", + " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", + " if (this.ResizeObserver === undefined) {\n", + " if (window.ResizeObserver !== undefined) {\n", + " this.ResizeObserver = window.ResizeObserver;\n", + " } else {\n", + " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", + " this.ResizeObserver = obs.ResizeObserver;\n", + " }\n", + " }\n", + "\n", + " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", + " var nentries = entries.length;\n", + " for (var i = 0; i < nentries; i++) {\n", + " var entry = entries[i];\n", + " var width, height;\n", + " if (entry.contentBoxSize) {\n", + " if (entry.contentBoxSize instanceof Array) {\n", + " // Chrome 84 implements new version of spec.\n", + " width = entry.contentBoxSize[0].inlineSize;\n", + " height = entry.contentBoxSize[0].blockSize;\n", + " } else {\n", + " // Firefox implements old version of spec.\n", + " width = entry.contentBoxSize.inlineSize;\n", + " height = entry.contentBoxSize.blockSize;\n", + " }\n", + " } else {\n", + " // Chrome <84 implements even older version of spec.\n", + " width = entry.contentRect.width;\n", + " height = entry.contentRect.height;\n", + " }\n", + "\n", + " // Keep the size of the canvas and rubber band canvas in sync with\n", + " // the canvas container.\n", + " if (entry.devicePixelContentBoxSize) {\n", + " // Chrome 84 implements new version of spec.\n", + " canvas.setAttribute(\n", + " 'width',\n", + " entry.devicePixelContentBoxSize[0].inlineSize\n", + " );\n", + " canvas.setAttribute(\n", + " 'height',\n", + " entry.devicePixelContentBoxSize[0].blockSize\n", + " );\n", + " } else {\n", + " canvas.setAttribute('width', width * fig.ratio);\n", + " canvas.setAttribute('height', height * fig.ratio);\n", + " }\n", + " canvas.setAttribute(\n", + " 'style',\n", + " 'width: ' + width + 'px; height: ' + height + 'px;'\n", + " );\n", + "\n", + " rubberband_canvas.setAttribute('width', width);\n", + " rubberband_canvas.setAttribute('height', height);\n", + "\n", + " // And update the size in Python. We ignore the initial 0/0 size\n", + " // that occurs as the element is placed into the DOM, which should\n", + " // otherwise not happen due to the minimum size styling.\n", + " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", + " fig.request_resize(width, height);\n", + " }\n", + " }\n", + " });\n", + " this.resizeObserverInstance.observe(canvas_div);\n", + "\n", + " function on_mouse_event_closure(name) {\n", + " return function (event) {\n", + " return fig.mouse_event(event, name);\n", + " };\n", + " }\n", + "\n", + " rubberband_canvas.addEventListener(\n", + " 'mousedown',\n", + " on_mouse_event_closure('button_press')\n", + " );\n", + " rubberband_canvas.addEventListener(\n", + " 'mouseup',\n", + " on_mouse_event_closure('button_release')\n", + " );\n", + " rubberband_canvas.addEventListener(\n", + " 'dblclick',\n", + " on_mouse_event_closure('dblclick')\n", + " );\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband_canvas.addEventListener(\n", + " 'mousemove',\n", + " on_mouse_event_closure('motion_notify')\n", + " );\n", + "\n", + " rubberband_canvas.addEventListener(\n", + " 'mouseenter',\n", + " on_mouse_event_closure('figure_enter')\n", + " );\n", + " rubberband_canvas.addEventListener(\n", + " 'mouseleave',\n", + " on_mouse_event_closure('figure_leave')\n", + " );\n", + "\n", + " canvas_div.addEventListener('wheel', function (event) {\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " on_mouse_event_closure('scroll')(event);\n", + " });\n", + "\n", + " canvas_div.appendChild(canvas);\n", + " canvas_div.appendChild(rubberband_canvas);\n", + "\n", + " this.rubberband_context = rubberband_canvas.getContext('2d');\n", + " this.rubberband_context.strokeStyle = '#000000';\n", + "\n", + " this._resize_canvas = function (width, height, forward) {\n", + " if (forward) {\n", + " canvas_div.style.width = width + 'px';\n", + " canvas_div.style.height = height + 'px';\n", + " }\n", + " };\n", + "\n", + " // Disable right mouse context menu.\n", + " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", + " event.preventDefault();\n", + " return false;\n", + " });\n", + "\n", + " function set_focus() {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "};\n", + "\n", + "mpl.figure.prototype._init_toolbar = function () {\n", + " var fig = this;\n", + "\n", + " var toolbar = document.createElement('div');\n", + " toolbar.classList = 'mpl-toolbar';\n", + " this.root.appendChild(toolbar);\n", + "\n", + " function on_click_closure(name) {\n", + " return function (_event) {\n", + " return fig.toolbar_button_onclick(name);\n", + " };\n", + " }\n", + "\n", + " function on_mouseover_closure(tooltip) {\n", + " return function (event) {\n", + " if (!event.currentTarget.disabled) {\n", + " return fig.toolbar_button_onmouseover(tooltip);\n", + " }\n", + " };\n", + " }\n", + "\n", + " fig.buttons = {};\n", + " var buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'mpl-button-group';\n", + " for (var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " /* Instead of a spacer, we start a new button group. */\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + " buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'mpl-button-group';\n", + " continue;\n", + " }\n", + "\n", + " var button = (fig.buttons[name] = document.createElement('button'));\n", + " button.classList = 'mpl-widget';\n", + " button.setAttribute('role', 'button');\n", + " button.setAttribute('aria-disabled', 'false');\n", + " button.addEventListener('click', on_click_closure(method_name));\n", + " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", + "\n", + " var icon_img = document.createElement('img');\n", + " icon_img.src = '_images/' + image + '.png';\n", + " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", + " icon_img.alt = tooltip;\n", + " button.appendChild(icon_img);\n", + "\n", + " buttonGroup.appendChild(button);\n", + " }\n", + "\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + "\n", + " var fmt_picker = document.createElement('select');\n", + " fmt_picker.classList = 'mpl-widget';\n", + " toolbar.appendChild(fmt_picker);\n", + " this.format_dropdown = fmt_picker;\n", + "\n", + " for (var ind in mpl.extensions) {\n", + " var fmt = mpl.extensions[ind];\n", + " var option = document.createElement('option');\n", + " option.selected = fmt === mpl.default_extension;\n", + " option.innerHTML = fmt;\n", + " fmt_picker.appendChild(option);\n", + " }\n", + "\n", + " var status_bar = document.createElement('span');\n", + " status_bar.classList = 'mpl-message';\n", + " toolbar.appendChild(status_bar);\n", + " this.message = status_bar;\n", + "};\n", + "\n", + "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", + " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", + " // which will in turn request a refresh of the image.\n", + " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", + "};\n", + "\n", + "mpl.figure.prototype.send_message = function (type, properties) {\n", + " properties['type'] = type;\n", + " properties['figure_id'] = this.id;\n", + " this.ws.send(JSON.stringify(properties));\n", + "};\n", + "\n", + "mpl.figure.prototype.send_draw_message = function () {\n", + " if (!this.waiting) {\n", + " this.waiting = true;\n", + " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", + " var format_dropdown = fig.format_dropdown;\n", + " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", + " fig.ondownload(fig, format);\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", + " var size = msg['size'];\n", + " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", + " fig._resize_canvas(size[0], size[1], msg['forward']);\n", + " fig.send_message('refresh', {});\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", + " var x0 = msg['x0'] / fig.ratio;\n", + " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", + " var x1 = msg['x1'] / fig.ratio;\n", + " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", + " x0 = Math.floor(x0) + 0.5;\n", + " y0 = Math.floor(y0) + 0.5;\n", + " x1 = Math.floor(x1) + 0.5;\n", + " y1 = Math.floor(y1) + 0.5;\n", + " var min_x = Math.min(x0, x1);\n", + " var min_y = Math.min(y0, y1);\n", + " var width = Math.abs(x1 - x0);\n", + " var height = Math.abs(y1 - y0);\n", + "\n", + " fig.rubberband_context.clearRect(\n", + " 0,\n", + " 0,\n", + " fig.canvas.width / fig.ratio,\n", + " fig.canvas.height / fig.ratio\n", + " );\n", + "\n", + " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", + " // Updates the figure title.\n", + " fig.header.textContent = msg['label'];\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", + " var cursor = msg['cursor'];\n", + " switch (cursor) {\n", + " case 0:\n", + " cursor = 'pointer';\n", + " break;\n", + " case 1:\n", + " cursor = 'default';\n", + " break;\n", + " case 2:\n", + " cursor = 'crosshair';\n", + " break;\n", + " case 3:\n", + " cursor = 'move';\n", + " break;\n", + " }\n", + " fig.rubberband_canvas.style.cursor = cursor;\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_message = function (fig, msg) {\n", + " fig.message.textContent = msg['message'];\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", + " // Request the server to send over a new figure.\n", + " fig.send_draw_message();\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", + " fig.image_mode = msg['mode'];\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", + " for (var key in msg) {\n", + " if (!(key in fig.buttons)) {\n", + " continue;\n", + " }\n", + " fig.buttons[key].disabled = !msg[key];\n", + " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", + " if (msg['mode'] === 'PAN') {\n", + " fig.buttons['Pan'].classList.add('active');\n", + " fig.buttons['Zoom'].classList.remove('active');\n", + " } else if (msg['mode'] === 'ZOOM') {\n", + " fig.buttons['Pan'].classList.remove('active');\n", + " fig.buttons['Zoom'].classList.add('active');\n", + " } else {\n", + " fig.buttons['Pan'].classList.remove('active');\n", + " fig.buttons['Zoom'].classList.remove('active');\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.updated_canvas_event = function () {\n", + " // Called whenever the canvas gets updated.\n", + " this.send_message('ack', {});\n", + "};\n", + "\n", + "// A function to construct a web socket function for onmessage handling.\n", + "// Called in the figure constructor.\n", + "mpl.figure.prototype._make_on_message_function = function (fig) {\n", + " return function socket_on_message(evt) {\n", + " if (evt.data instanceof Blob) {\n", + " var img = evt.data;\n", + " if (img.type !== 'image/png') {\n", + " /* FIXME: We get \"Resource interpreted as Image but\n", + " * transferred with MIME type text/plain:\" errors on\n", + " * Chrome. But how to set the MIME type? It doesn't seem\n", + " * to be part of the websocket stream */\n", + " img.type = 'image/png';\n", + " }\n", + "\n", + " /* Free the memory for the previous frames */\n", + " if (fig.imageObj.src) {\n", + " (window.URL || window.webkitURL).revokeObjectURL(\n", + " fig.imageObj.src\n", + " );\n", + " }\n", + "\n", + " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", + " img\n", + " );\n", + " fig.updated_canvas_event();\n", + " fig.waiting = false;\n", + " return;\n", + " } else if (\n", + " typeof evt.data === 'string' &&\n", + " evt.data.slice(0, 21) === 'data:image/png;base64'\n", + " ) {\n", + " fig.imageObj.src = evt.data;\n", + " fig.updated_canvas_event();\n", + " fig.waiting = false;\n", + " return;\n", + " }\n", + "\n", + " var msg = JSON.parse(evt.data);\n", + " var msg_type = msg['type'];\n", + "\n", + " // Call the \"handle_{type}\" callback, which takes\n", + " // the figure and JSON message as its only arguments.\n", + " try {\n", + " var callback = fig['handle_' + msg_type];\n", + " } catch (e) {\n", + " console.log(\n", + " \"No handler for the '\" + msg_type + \"' message type: \",\n", + " msg\n", + " );\n", + " return;\n", + " }\n", + "\n", + " if (callback) {\n", + " try {\n", + " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", + " callback(fig, msg);\n", + " } catch (e) {\n", + " console.log(\n", + " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", + " e,\n", + " e.stack,\n", + " msg\n", + " );\n", + " }\n", + " }\n", + " };\n", + "};\n", + "\n", + "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", + "mpl.findpos = function (e) {\n", + " //this section is from http://www.quirksmode.org/js/events_properties.html\n", + " var targ;\n", + " if (!e) {\n", + " e = window.event;\n", + " }\n", + " if (e.target) {\n", + " targ = e.target;\n", + " } else if (e.srcElement) {\n", + " targ = e.srcElement;\n", + " }\n", + " if (targ.nodeType === 3) {\n", + " // defeat Safari bug\n", + " targ = targ.parentNode;\n", + " }\n", + "\n", + " // pageX,Y are the mouse positions relative to the document\n", + " var boundingRect = targ.getBoundingClientRect();\n", + " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", + " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", + "\n", + " return { x: x, y: y };\n", + "};\n", + "\n", + "/*\n", + " * return a copy of an object with only non-object keys\n", + " * we need this to avoid circular references\n", + " * http://stackoverflow.com/a/24161582/3208463\n", + " */\n", + "function simpleKeys(original) {\n", + " return Object.keys(original).reduce(function (obj, key) {\n", + " if (typeof original[key] !== 'object') {\n", + " obj[key] = original[key];\n", + " }\n", + " return obj;\n", + " }, {});\n", + "}\n", + "\n", + "mpl.figure.prototype.mouse_event = function (event, name) {\n", + " var canvas_pos = mpl.findpos(event);\n", + "\n", + " if (name === 'button_press') {\n", + " this.canvas.focus();\n", + " this.canvas_div.focus();\n", + " }\n", + "\n", + " var x = canvas_pos.x * this.ratio;\n", + " var y = canvas_pos.y * this.ratio;\n", + "\n", + " this.send_message(name, {\n", + " x: x,\n", + " y: y,\n", + " button: event.button,\n", + " step: event.step,\n", + " guiEvent: simpleKeys(event),\n", + " });\n", + "\n", + " /* This prevents the web browser from automatically changing to\n", + " * the text insertion cursor when the button is pressed. We want\n", + " * to control all of the cursor setting manually through the\n", + " * 'cursor' event from matplotlib */\n", + " event.preventDefault();\n", + " return false;\n", + "};\n", + "\n", + "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", + " // Handle any extra behaviour associated with a key event\n", + "};\n", + "\n", + "mpl.figure.prototype.key_event = function (event, name) {\n", + " // Prevent repeat events\n", + " if (name === 'key_press') {\n", + " if (event.key === this._key) {\n", + " return;\n", + " } else {\n", + " this._key = event.key;\n", + " }\n", + " }\n", + " if (name === 'key_release') {\n", + " this._key = null;\n", + " }\n", + "\n", + " var value = '';\n", + " if (event.ctrlKey && event.key !== 'Control') {\n", + " value += 'ctrl+';\n", + " }\n", + " else if (event.altKey && event.key !== 'Alt') {\n", + " value += 'alt+';\n", + " }\n", + " else if (event.shiftKey && event.key !== 'Shift') {\n", + " value += 'shift+';\n", + " }\n", + "\n", + " value += 'k' + event.key;\n", + "\n", + " this._key_event_extra(event, name);\n", + "\n", + " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", + " return false;\n", + "};\n", + "\n", + "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", + " if (name === 'download') {\n", + " this.handle_save(this, null);\n", + " } else {\n", + " this.send_message('toolbar_button', { name: name });\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", + " this.message.textContent = tooltip;\n", + "};\n", + "\n", + "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", + "// prettier-ignore\n", + "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", + "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", + "\n", + "mpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", + "\n", + "mpl.default_extension = \"png\";/* global mpl */\n", + "\n", + "var comm_websocket_adapter = function (comm) {\n", + " // Create a \"websocket\"-like object which calls the given IPython comm\n", + " // object with the appropriate methods. Currently this is a non binary\n", + " // socket, so there is still some room for performance tuning.\n", + " var ws = {};\n", + "\n", + " ws.binaryType = comm.kernel.ws.binaryType;\n", + " ws.readyState = comm.kernel.ws.readyState;\n", + " function updateReadyState(_event) {\n", + " if (comm.kernel.ws) {\n", + " ws.readyState = comm.kernel.ws.readyState;\n", + " } else {\n", + " ws.readyState = 3; // Closed state.\n", + " }\n", + " }\n", + " comm.kernel.ws.addEventListener('open', updateReadyState);\n", + " comm.kernel.ws.addEventListener('close', updateReadyState);\n", + " comm.kernel.ws.addEventListener('error', updateReadyState);\n", + "\n", + " ws.close = function () {\n", + " comm.close();\n", + " };\n", + " ws.send = function (m) {\n", + " //console.log('sending', m);\n", + " comm.send(m);\n", + " };\n", + " // Register the callback with on_msg.\n", + " comm.on_msg(function (msg) {\n", + " //console.log('receiving', msg['content']['data'], msg);\n", + " var data = msg['content']['data'];\n", + " if (data['blob'] !== undefined) {\n", + " data = {\n", + " data: new Blob(msg['buffers'], { type: data['blob'] }),\n", + " };\n", + " }\n", + " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", + " ws.onmessage(data);\n", + " });\n", + " return ws;\n", + "};\n", + "\n", + "mpl.mpl_figure_comm = function (comm, msg) {\n", + " // This is the function which gets called when the mpl process\n", + " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", + "\n", + " var id = msg.content.data.id;\n", + " // Get hold of the div created by the display call when the Comm\n", + " // socket was opened in Python.\n", + " var element = document.getElementById(id);\n", + " var ws_proxy = comm_websocket_adapter(comm);\n", + "\n", + " function ondownload(figure, _format) {\n", + " window.open(figure.canvas.toDataURL());\n", + " }\n", + "\n", + " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", + "\n", + " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", + " // web socket which is closed, not our websocket->open comm proxy.\n", + " ws_proxy.onopen();\n", + "\n", + " fig.parent_element = element;\n", + " fig.cell_info = mpl.find_output_cell(\"
\");\n", + " if (!fig.cell_info) {\n", + " console.error('Failed to find cell for figure', id, fig);\n", + " return;\n", + " }\n", + " fig.cell_info[0].output_area.element.on(\n", + " 'cleared',\n", + " { fig: fig },\n", + " fig._remove_fig_handler\n", + " );\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_close = function (fig, msg) {\n", + " var width = fig.canvas.width / fig.ratio;\n", + " fig.cell_info[0].output_area.element.off(\n", + " 'cleared',\n", + " fig._remove_fig_handler\n", + " );\n", + " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", + "\n", + " // Update the output cell to use the data from the current canvas.\n", + " fig.push_to_output();\n", + " var dataURL = fig.canvas.toDataURL();\n", + " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", + " // the notebook keyboard shortcuts fail.\n", + " IPython.keyboard_manager.enable();\n", + " fig.parent_element.innerHTML =\n", + " '';\n", + " fig.close_ws(fig, msg);\n", + "};\n", + "\n", + "mpl.figure.prototype.close_ws = function (fig, msg) {\n", + " fig.send_message('closing', msg);\n", + " // fig.ws.close()\n", + "};\n", + "\n", + "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", + " // Turn the data on the canvas into data in the output cell.\n", + " var width = this.canvas.width / this.ratio;\n", + " var dataURL = this.canvas.toDataURL();\n", + " this.cell_info[1]['text/html'] =\n", + " '';\n", + "};\n", + "\n", + "mpl.figure.prototype.updated_canvas_event = function () {\n", + " // Tell IPython that the notebook contents must change.\n", + " IPython.notebook.set_dirty(true);\n", + " this.send_message('ack', {});\n", + " var fig = this;\n", + " // Wait a second, then push the new image to the DOM so\n", + " // that it is saved nicely (might be nice to debounce this).\n", + " setTimeout(function () {\n", + " fig.push_to_output();\n", + " }, 1000);\n", + "};\n", + "\n", + "mpl.figure.prototype._init_toolbar = function () {\n", + " var fig = this;\n", + "\n", + " var toolbar = document.createElement('div');\n", + " toolbar.classList = 'btn-toolbar';\n", + " this.root.appendChild(toolbar);\n", + "\n", + " function on_click_closure(name) {\n", + " return function (_event) {\n", + " return fig.toolbar_button_onclick(name);\n", + " };\n", + " }\n", + "\n", + " function on_mouseover_closure(tooltip) {\n", + " return function (event) {\n", + " if (!event.currentTarget.disabled) {\n", + " return fig.toolbar_button_onmouseover(tooltip);\n", + " }\n", + " };\n", + " }\n", + "\n", + " fig.buttons = {};\n", + " var buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'btn-group';\n", + " var button;\n", + " for (var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " /* Instead of a spacer, we start a new button group. */\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + " buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'btn-group';\n", + " continue;\n", + " }\n", + "\n", + " button = fig.buttons[name] = document.createElement('button');\n", + " button.classList = 'btn btn-default';\n", + " button.href = '#';\n", + " button.title = name;\n", + " button.innerHTML = '';\n", + " button.addEventListener('click', on_click_closure(method_name));\n", + " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", + " buttonGroup.appendChild(button);\n", + " }\n", + "\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + "\n", + " // Add the status bar.\n", + " var status_bar = document.createElement('span');\n", + " status_bar.classList = 'mpl-message pull-right';\n", + " toolbar.appendChild(status_bar);\n", + " this.message = status_bar;\n", + "\n", + " // Add the close button to the window.\n", + " var buttongrp = document.createElement('div');\n", + " buttongrp.classList = 'btn-group inline pull-right';\n", + " button = document.createElement('button');\n", + " button.classList = 'btn btn-mini btn-primary';\n", + " button.href = '#';\n", + " button.title = 'Stop Interaction';\n", + " button.innerHTML = '';\n", + " button.addEventListener('click', function (_evt) {\n", + " fig.handle_close(fig, {});\n", + " });\n", + " button.addEventListener(\n", + " 'mouseover',\n", + " on_mouseover_closure('Stop Interaction')\n", + " );\n", + " buttongrp.appendChild(button);\n", + " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", + " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", + "};\n", + "\n", + "mpl.figure.prototype._remove_fig_handler = function (event) {\n", + " var fig = event.data.fig;\n", + " if (event.target !== this) {\n", + " // Ignore bubbled events from children.\n", + " return;\n", + " }\n", + " fig.close_ws(fig, {});\n", + "};\n", + "\n", + "mpl.figure.prototype._root_extra_style = function (el) {\n", + " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", + "};\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function (el) {\n", + " // this is important to make the div 'focusable\n", + " el.setAttribute('tabindex', 0);\n", + " // reach out to IPython and tell the keyboard manager to turn it's self\n", + " // off when our div gets focus\n", + "\n", + " // location in version 3\n", + " if (IPython.notebook.keyboard_manager) {\n", + " IPython.notebook.keyboard_manager.register_events(el);\n", + " } else {\n", + " // location in version 2\n", + " IPython.keyboard_manager.register_events(el);\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", + " var manager = IPython.notebook.keyboard_manager;\n", + " if (!manager) {\n", + " manager = IPython.keyboard_manager;\n", + " }\n", + "\n", + " // Check for shift+enter\n", + " if (event.shiftKey && event.which === 13) {\n", + " this.canvas_div.blur();\n", + " // select the cell after this one\n", + " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", + " IPython.notebook.select(index + 1);\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", + " fig.ondownload(fig, null);\n", + "};\n", + "\n", + "mpl.find_output_cell = function (html_output) {\n", + " // Return the cell and output element which can be found *uniquely* in the notebook.\n", + " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", + " // IPython event is triggered only after the cells have been serialised, which for\n", + " // our purposes (turning an active figure into a static one), is too late.\n", + " var cells = IPython.notebook.get_cells();\n", + " var ncells = cells.length;\n", + " for (var i = 0; i < ncells; i++) {\n", + " var cell = cells[i];\n", + " if (cell.cell_type === 'code') {\n", + " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", + " var data = cell.output_area.outputs[j];\n", + " if (data.data) {\n", + " // IPython >= 3 moved mimebundle to data attribute of output\n", + " data = data.data;\n", + " }\n", + " if (data['text/html'] === html_output) {\n", + " return [cell, data, j];\n", + " }\n", + " }\n", + " }\n", + " }\n", + "};\n", + "\n", + "// Register the function which deals with the matplotlib target/channel.\n", + "// The kernel may be null if the page has been refreshed.\n", + "if (IPython.notebook.kernel !== null) {\n", + " IPython.notebook.kernel.comm_manager.register_target(\n", + " 'matplotlib',\n", + " mpl.mpl_figure_comm\n", + " );\n", + "}\n" + ], "text/plain": [ "" ] @@ -708,7 +4597,7 @@ "source": [ "To compute $\\partial\\mathcal{L}/\\partial W$ we can use the **chaining rule** for computing derivatives of a composite function, as you can see in the formulae above. It corresponds to the following idea:\n", "\n", - "* Suppose under given input we have obtanes loss $\\Delta\\mathcal{L}$\n", + "* Suppose under given input we have obtained loss $\\Delta\\mathcal{L}$\n", "* To minimize it, we would have to adjust softmax output $p$ by value $\\Delta p = (\\partial\\mathcal{L}/\\partial p)\\Delta\\mathcal{L}$ \n", "* This corresponds to the changes to node $z$ by $\\Delta z = (\\partial\\mathcal{p}/\\partial z)\\Delta p$\n", "* To minimize this error, we need to adjust parameters accordingly: $\\Delta W = (\\partial\\mathcal{z}/\\partial W)\\Delta z$ (and the same for $b$)\n", @@ -1103,7 +4992,980 @@ "outputs": [ { "data": { - "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n rubberband_canvas.addEventListener(\n 'dblclick',\n on_mouse_event_closure('dblclick')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n var img = evt.data;\n if (img.type !== 'image/png') {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n img.type = 'image/png';\n }\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n img\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.key === this._key) {\n return;\n } else {\n this._key = event.key;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.key !== 'Control') {\n value += 'ctrl+';\n }\n else if (event.altKey && event.key !== 'Alt') {\n value += 'alt+';\n }\n else if (event.shiftKey && event.key !== 'Shift') {\n value += 'shift+';\n }\n\n value += 'k' + event.key;\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.binaryType = comm.kernel.ws.binaryType;\n ws.readyState = comm.kernel.ws.readyState;\n function updateReadyState(_event) {\n if (comm.kernel.ws) {\n ws.readyState = comm.kernel.ws.readyState;\n } else {\n ws.readyState = 3; // Closed state.\n }\n }\n comm.kernel.ws.addEventListener('open', updateReadyState);\n comm.kernel.ws.addEventListener('close', updateReadyState);\n comm.kernel.ws.addEventListener('error', updateReadyState);\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n var data = msg['content']['data'];\n if (data['blob'] !== undefined) {\n data = {\n data: new Blob(msg['buffers'], { type: data['blob'] }),\n };\n }\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(data);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "/* global mpl */\n", + "window.mpl = {};\n", + "\n", + "mpl.get_websocket_type = function () {\n", + " if (typeof WebSocket !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof MozWebSocket !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert(\n", + " 'Your browser does not have WebSocket support. ' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.'\n", + " );\n", + " }\n", + "};\n", + "\n", + "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = this.ws.binaryType !== undefined;\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById('mpl-warnings');\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent =\n", + " 'This browser does not support binary websocket messages. ' +\n", + " 'Performance may be slow.';\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = document.createElement('div');\n", + " this.root.setAttribute('style', 'display: inline-block');\n", + " this._root_extra_style(this.root);\n", + "\n", + " parent_element.appendChild(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message('supports_binary', { value: fig.supports_binary });\n", + " fig.send_message('send_image_mode', {});\n", + " if (fig.ratio !== 1) {\n", + " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", + " }\n", + " fig.send_message('refresh', {});\n", + " };\n", + "\n", + " this.imageObj.onload = function () {\n", + " if (fig.image_mode === 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function () {\n", + " fig.ws.close();\n", + " };\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "};\n", + "\n", + "mpl.figure.prototype._init_header = function () {\n", + " var titlebar = document.createElement('div');\n", + " titlebar.classList =\n", + " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", + " var titletext = document.createElement('div');\n", + " titletext.classList = 'ui-dialog-title';\n", + " titletext.setAttribute(\n", + " 'style',\n", + " 'width: 100%; text-align: center; padding: 3px;'\n", + " );\n", + " titlebar.appendChild(titletext);\n", + " this.root.appendChild(titlebar);\n", + " this.header = titletext;\n", + "};\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", + "\n", + "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", + "\n", + "mpl.figure.prototype._init_canvas = function () {\n", + " var fig = this;\n", + "\n", + " var canvas_div = (this.canvas_div = document.createElement('div'));\n", + " canvas_div.setAttribute(\n", + " 'style',\n", + " 'border: 1px solid #ddd;' +\n", + " 'box-sizing: content-box;' +\n", + " 'clear: both;' +\n", + " 'min-height: 1px;' +\n", + " 'min-width: 1px;' +\n", + " 'outline: 0;' +\n", + " 'overflow: hidden;' +\n", + " 'position: relative;' +\n", + " 'resize: both;'\n", + " );\n", + "\n", + " function on_keyboard_event_closure(name) {\n", + " return function (event) {\n", + " return fig.key_event(event, name);\n", + " };\n", + " }\n", + "\n", + " canvas_div.addEventListener(\n", + " 'keydown',\n", + " on_keyboard_event_closure('key_press')\n", + " );\n", + " canvas_div.addEventListener(\n", + " 'keyup',\n", + " on_keyboard_event_closure('key_release')\n", + " );\n", + "\n", + " this._canvas_extra_style(canvas_div);\n", + " this.root.appendChild(canvas_div);\n", + "\n", + " var canvas = (this.canvas = document.createElement('canvas'));\n", + " canvas.classList.add('mpl-canvas');\n", + " canvas.setAttribute('style', 'box-sizing: content-box;');\n", + "\n", + " this.context = canvas.getContext('2d');\n", + "\n", + " var backingStore =\n", + " this.context.backingStorePixelRatio ||\n", + " this.context.webkitBackingStorePixelRatio ||\n", + " this.context.mozBackingStorePixelRatio ||\n", + " this.context.msBackingStorePixelRatio ||\n", + " this.context.oBackingStorePixelRatio ||\n", + " this.context.backingStorePixelRatio ||\n", + " 1;\n", + "\n", + " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", + "\n", + " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", + " 'canvas'\n", + " ));\n", + " rubberband_canvas.setAttribute(\n", + " 'style',\n", + " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", + " );\n", + "\n", + " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", + " if (this.ResizeObserver === undefined) {\n", + " if (window.ResizeObserver !== undefined) {\n", + " this.ResizeObserver = window.ResizeObserver;\n", + " } else {\n", + " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", + " this.ResizeObserver = obs.ResizeObserver;\n", + " }\n", + " }\n", + "\n", + " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", + " var nentries = entries.length;\n", + " for (var i = 0; i < nentries; i++) {\n", + " var entry = entries[i];\n", + " var width, height;\n", + " if (entry.contentBoxSize) {\n", + " if (entry.contentBoxSize instanceof Array) {\n", + " // Chrome 84 implements new version of spec.\n", + " width = entry.contentBoxSize[0].inlineSize;\n", + " height = entry.contentBoxSize[0].blockSize;\n", + " } else {\n", + " // Firefox implements old version of spec.\n", + " width = entry.contentBoxSize.inlineSize;\n", + " height = entry.contentBoxSize.blockSize;\n", + " }\n", + " } else {\n", + " // Chrome <84 implements even older version of spec.\n", + " width = entry.contentRect.width;\n", + " height = entry.contentRect.height;\n", + " }\n", + "\n", + " // Keep the size of the canvas and rubber band canvas in sync with\n", + " // the canvas container.\n", + " if (entry.devicePixelContentBoxSize) {\n", + " // Chrome 84 implements new version of spec.\n", + " canvas.setAttribute(\n", + " 'width',\n", + " entry.devicePixelContentBoxSize[0].inlineSize\n", + " );\n", + " canvas.setAttribute(\n", + " 'height',\n", + " entry.devicePixelContentBoxSize[0].blockSize\n", + " );\n", + " } else {\n", + " canvas.setAttribute('width', width * fig.ratio);\n", + " canvas.setAttribute('height', height * fig.ratio);\n", + " }\n", + " canvas.setAttribute(\n", + " 'style',\n", + " 'width: ' + width + 'px; height: ' + height + 'px;'\n", + " );\n", + "\n", + " rubberband_canvas.setAttribute('width', width);\n", + " rubberband_canvas.setAttribute('height', height);\n", + "\n", + " // And update the size in Python. We ignore the initial 0/0 size\n", + " // that occurs as the element is placed into the DOM, which should\n", + " // otherwise not happen due to the minimum size styling.\n", + " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", + " fig.request_resize(width, height);\n", + " }\n", + " }\n", + " });\n", + " this.resizeObserverInstance.observe(canvas_div);\n", + "\n", + " function on_mouse_event_closure(name) {\n", + " return function (event) {\n", + " return fig.mouse_event(event, name);\n", + " };\n", + " }\n", + "\n", + " rubberband_canvas.addEventListener(\n", + " 'mousedown',\n", + " on_mouse_event_closure('button_press')\n", + " );\n", + " rubberband_canvas.addEventListener(\n", + " 'mouseup',\n", + " on_mouse_event_closure('button_release')\n", + " );\n", + " rubberband_canvas.addEventListener(\n", + " 'dblclick',\n", + " on_mouse_event_closure('dblclick')\n", + " );\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband_canvas.addEventListener(\n", + " 'mousemove',\n", + " on_mouse_event_closure('motion_notify')\n", + " );\n", + "\n", + " rubberband_canvas.addEventListener(\n", + " 'mouseenter',\n", + " on_mouse_event_closure('figure_enter')\n", + " );\n", + " rubberband_canvas.addEventListener(\n", + " 'mouseleave',\n", + " on_mouse_event_closure('figure_leave')\n", + " );\n", + "\n", + " canvas_div.addEventListener('wheel', function (event) {\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " on_mouse_event_closure('scroll')(event);\n", + " });\n", + "\n", + " canvas_div.appendChild(canvas);\n", + " canvas_div.appendChild(rubberband_canvas);\n", + "\n", + " this.rubberband_context = rubberband_canvas.getContext('2d');\n", + " this.rubberband_context.strokeStyle = '#000000';\n", + "\n", + " this._resize_canvas = function (width, height, forward) {\n", + " if (forward) {\n", + " canvas_div.style.width = width + 'px';\n", + " canvas_div.style.height = height + 'px';\n", + " }\n", + " };\n", + "\n", + " // Disable right mouse context menu.\n", + " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", + " event.preventDefault();\n", + " return false;\n", + " });\n", + "\n", + " function set_focus() {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "};\n", + "\n", + "mpl.figure.prototype._init_toolbar = function () {\n", + " var fig = this;\n", + "\n", + " var toolbar = document.createElement('div');\n", + " toolbar.classList = 'mpl-toolbar';\n", + " this.root.appendChild(toolbar);\n", + "\n", + " function on_click_closure(name) {\n", + " return function (_event) {\n", + " return fig.toolbar_button_onclick(name);\n", + " };\n", + " }\n", + "\n", + " function on_mouseover_closure(tooltip) {\n", + " return function (event) {\n", + " if (!event.currentTarget.disabled) {\n", + " return fig.toolbar_button_onmouseover(tooltip);\n", + " }\n", + " };\n", + " }\n", + "\n", + " fig.buttons = {};\n", + " var buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'mpl-button-group';\n", + " for (var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " /* Instead of a spacer, we start a new button group. */\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + " buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'mpl-button-group';\n", + " continue;\n", + " }\n", + "\n", + " var button = (fig.buttons[name] = document.createElement('button'));\n", + " button.classList = 'mpl-widget';\n", + " button.setAttribute('role', 'button');\n", + " button.setAttribute('aria-disabled', 'false');\n", + " button.addEventListener('click', on_click_closure(method_name));\n", + " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", + "\n", + " var icon_img = document.createElement('img');\n", + " icon_img.src = '_images/' + image + '.png';\n", + " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", + " icon_img.alt = tooltip;\n", + " button.appendChild(icon_img);\n", + "\n", + " buttonGroup.appendChild(button);\n", + " }\n", + "\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + "\n", + " var fmt_picker = document.createElement('select');\n", + " fmt_picker.classList = 'mpl-widget';\n", + " toolbar.appendChild(fmt_picker);\n", + " this.format_dropdown = fmt_picker;\n", + "\n", + " for (var ind in mpl.extensions) {\n", + " var fmt = mpl.extensions[ind];\n", + " var option = document.createElement('option');\n", + " option.selected = fmt === mpl.default_extension;\n", + " option.innerHTML = fmt;\n", + " fmt_picker.appendChild(option);\n", + " }\n", + "\n", + " var status_bar = document.createElement('span');\n", + " status_bar.classList = 'mpl-message';\n", + " toolbar.appendChild(status_bar);\n", + " this.message = status_bar;\n", + "};\n", + "\n", + "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", + " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", + " // which will in turn request a refresh of the image.\n", + " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", + "};\n", + "\n", + "mpl.figure.prototype.send_message = function (type, properties) {\n", + " properties['type'] = type;\n", + " properties['figure_id'] = this.id;\n", + " this.ws.send(JSON.stringify(properties));\n", + "};\n", + "\n", + "mpl.figure.prototype.send_draw_message = function () {\n", + " if (!this.waiting) {\n", + " this.waiting = true;\n", + " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", + " var format_dropdown = fig.format_dropdown;\n", + " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", + " fig.ondownload(fig, format);\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", + " var size = msg['size'];\n", + " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", + " fig._resize_canvas(size[0], size[1], msg['forward']);\n", + " fig.send_message('refresh', {});\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", + " var x0 = msg['x0'] / fig.ratio;\n", + " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", + " var x1 = msg['x1'] / fig.ratio;\n", + " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", + " x0 = Math.floor(x0) + 0.5;\n", + " y0 = Math.floor(y0) + 0.5;\n", + " x1 = Math.floor(x1) + 0.5;\n", + " y1 = Math.floor(y1) + 0.5;\n", + " var min_x = Math.min(x0, x1);\n", + " var min_y = Math.min(y0, y1);\n", + " var width = Math.abs(x1 - x0);\n", + " var height = Math.abs(y1 - y0);\n", + "\n", + " fig.rubberband_context.clearRect(\n", + " 0,\n", + " 0,\n", + " fig.canvas.width / fig.ratio,\n", + " fig.canvas.height / fig.ratio\n", + " );\n", + "\n", + " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", + " // Updates the figure title.\n", + " fig.header.textContent = msg['label'];\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", + " var cursor = msg['cursor'];\n", + " switch (cursor) {\n", + " case 0:\n", + " cursor = 'pointer';\n", + " break;\n", + " case 1:\n", + " cursor = 'default';\n", + " break;\n", + " case 2:\n", + " cursor = 'crosshair';\n", + " break;\n", + " case 3:\n", + " cursor = 'move';\n", + " break;\n", + " }\n", + " fig.rubberband_canvas.style.cursor = cursor;\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_message = function (fig, msg) {\n", + " fig.message.textContent = msg['message'];\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", + " // Request the server to send over a new figure.\n", + " fig.send_draw_message();\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", + " fig.image_mode = msg['mode'];\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", + " for (var key in msg) {\n", + " if (!(key in fig.buttons)) {\n", + " continue;\n", + " }\n", + " fig.buttons[key].disabled = !msg[key];\n", + " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", + " if (msg['mode'] === 'PAN') {\n", + " fig.buttons['Pan'].classList.add('active');\n", + " fig.buttons['Zoom'].classList.remove('active');\n", + " } else if (msg['mode'] === 'ZOOM') {\n", + " fig.buttons['Pan'].classList.remove('active');\n", + " fig.buttons['Zoom'].classList.add('active');\n", + " } else {\n", + " fig.buttons['Pan'].classList.remove('active');\n", + " fig.buttons['Zoom'].classList.remove('active');\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.updated_canvas_event = function () {\n", + " // Called whenever the canvas gets updated.\n", + " this.send_message('ack', {});\n", + "};\n", + "\n", + "// A function to construct a web socket function for onmessage handling.\n", + "// Called in the figure constructor.\n", + "mpl.figure.prototype._make_on_message_function = function (fig) {\n", + " return function socket_on_message(evt) {\n", + " if (evt.data instanceof Blob) {\n", + " var img = evt.data;\n", + " if (img.type !== 'image/png') {\n", + " /* FIXME: We get \"Resource interpreted as Image but\n", + " * transferred with MIME type text/plain:\" errors on\n", + " * Chrome. But how to set the MIME type? It doesn't seem\n", + " * to be part of the websocket stream */\n", + " img.type = 'image/png';\n", + " }\n", + "\n", + " /* Free the memory for the previous frames */\n", + " if (fig.imageObj.src) {\n", + " (window.URL || window.webkitURL).revokeObjectURL(\n", + " fig.imageObj.src\n", + " );\n", + " }\n", + "\n", + " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", + " img\n", + " );\n", + " fig.updated_canvas_event();\n", + " fig.waiting = false;\n", + " return;\n", + " } else if (\n", + " typeof evt.data === 'string' &&\n", + " evt.data.slice(0, 21) === 'data:image/png;base64'\n", + " ) {\n", + " fig.imageObj.src = evt.data;\n", + " fig.updated_canvas_event();\n", + " fig.waiting = false;\n", + " return;\n", + " }\n", + "\n", + " var msg = JSON.parse(evt.data);\n", + " var msg_type = msg['type'];\n", + "\n", + " // Call the \"handle_{type}\" callback, which takes\n", + " // the figure and JSON message as its only arguments.\n", + " try {\n", + " var callback = fig['handle_' + msg_type];\n", + " } catch (e) {\n", + " console.log(\n", + " \"No handler for the '\" + msg_type + \"' message type: \",\n", + " msg\n", + " );\n", + " return;\n", + " }\n", + "\n", + " if (callback) {\n", + " try {\n", + " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", + " callback(fig, msg);\n", + " } catch (e) {\n", + " console.log(\n", + " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", + " e,\n", + " e.stack,\n", + " msg\n", + " );\n", + " }\n", + " }\n", + " };\n", + "};\n", + "\n", + "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", + "mpl.findpos = function (e) {\n", + " //this section is from http://www.quirksmode.org/js/events_properties.html\n", + " var targ;\n", + " if (!e) {\n", + " e = window.event;\n", + " }\n", + " if (e.target) {\n", + " targ = e.target;\n", + " } else if (e.srcElement) {\n", + " targ = e.srcElement;\n", + " }\n", + " if (targ.nodeType === 3) {\n", + " // defeat Safari bug\n", + " targ = targ.parentNode;\n", + " }\n", + "\n", + " // pageX,Y are the mouse positions relative to the document\n", + " var boundingRect = targ.getBoundingClientRect();\n", + " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", + " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", + "\n", + " return { x: x, y: y };\n", + "};\n", + "\n", + "/*\n", + " * return a copy of an object with only non-object keys\n", + " * we need this to avoid circular references\n", + " * http://stackoverflow.com/a/24161582/3208463\n", + " */\n", + "function simpleKeys(original) {\n", + " return Object.keys(original).reduce(function (obj, key) {\n", + " if (typeof original[key] !== 'object') {\n", + " obj[key] = original[key];\n", + " }\n", + " return obj;\n", + " }, {});\n", + "}\n", + "\n", + "mpl.figure.prototype.mouse_event = function (event, name) {\n", + " var canvas_pos = mpl.findpos(event);\n", + "\n", + " if (name === 'button_press') {\n", + " this.canvas.focus();\n", + " this.canvas_div.focus();\n", + " }\n", + "\n", + " var x = canvas_pos.x * this.ratio;\n", + " var y = canvas_pos.y * this.ratio;\n", + "\n", + " this.send_message(name, {\n", + " x: x,\n", + " y: y,\n", + " button: event.button,\n", + " step: event.step,\n", + " guiEvent: simpleKeys(event),\n", + " });\n", + "\n", + " /* This prevents the web browser from automatically changing to\n", + " * the text insertion cursor when the button is pressed. We want\n", + " * to control all of the cursor setting manually through the\n", + " * 'cursor' event from matplotlib */\n", + " event.preventDefault();\n", + " return false;\n", + "};\n", + "\n", + "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", + " // Handle any extra behaviour associated with a key event\n", + "};\n", + "\n", + "mpl.figure.prototype.key_event = function (event, name) {\n", + " // Prevent repeat events\n", + " if (name === 'key_press') {\n", + " if (event.key === this._key) {\n", + " return;\n", + " } else {\n", + " this._key = event.key;\n", + " }\n", + " }\n", + " if (name === 'key_release') {\n", + " this._key = null;\n", + " }\n", + "\n", + " var value = '';\n", + " if (event.ctrlKey && event.key !== 'Control') {\n", + " value += 'ctrl+';\n", + " }\n", + " else if (event.altKey && event.key !== 'Alt') {\n", + " value += 'alt+';\n", + " }\n", + " else if (event.shiftKey && event.key !== 'Shift') {\n", + " value += 'shift+';\n", + " }\n", + "\n", + " value += 'k' + event.key;\n", + "\n", + " this._key_event_extra(event, name);\n", + "\n", + " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", + " return false;\n", + "};\n", + "\n", + "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", + " if (name === 'download') {\n", + " this.handle_save(this, null);\n", + " } else {\n", + " this.send_message('toolbar_button', { name: name });\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", + " this.message.textContent = tooltip;\n", + "};\n", + "\n", + "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", + "// prettier-ignore\n", + "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", + "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", + "\n", + "mpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", + "\n", + "mpl.default_extension = \"png\";/* global mpl */\n", + "\n", + "var comm_websocket_adapter = function (comm) {\n", + " // Create a \"websocket\"-like object which calls the given IPython comm\n", + " // object with the appropriate methods. Currently this is a non binary\n", + " // socket, so there is still some room for performance tuning.\n", + " var ws = {};\n", + "\n", + " ws.binaryType = comm.kernel.ws.binaryType;\n", + " ws.readyState = comm.kernel.ws.readyState;\n", + " function updateReadyState(_event) {\n", + " if (comm.kernel.ws) {\n", + " ws.readyState = comm.kernel.ws.readyState;\n", + " } else {\n", + " ws.readyState = 3; // Closed state.\n", + " }\n", + " }\n", + " comm.kernel.ws.addEventListener('open', updateReadyState);\n", + " comm.kernel.ws.addEventListener('close', updateReadyState);\n", + " comm.kernel.ws.addEventListener('error', updateReadyState);\n", + "\n", + " ws.close = function () {\n", + " comm.close();\n", + " };\n", + " ws.send = function (m) {\n", + " //console.log('sending', m);\n", + " comm.send(m);\n", + " };\n", + " // Register the callback with on_msg.\n", + " comm.on_msg(function (msg) {\n", + " //console.log('receiving', msg['content']['data'], msg);\n", + " var data = msg['content']['data'];\n", + " if (data['blob'] !== undefined) {\n", + " data = {\n", + " data: new Blob(msg['buffers'], { type: data['blob'] }),\n", + " };\n", + " }\n", + " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", + " ws.onmessage(data);\n", + " });\n", + " return ws;\n", + "};\n", + "\n", + "mpl.mpl_figure_comm = function (comm, msg) {\n", + " // This is the function which gets called when the mpl process\n", + " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", + "\n", + " var id = msg.content.data.id;\n", + " // Get hold of the div created by the display call when the Comm\n", + " // socket was opened in Python.\n", + " var element = document.getElementById(id);\n", + " var ws_proxy = comm_websocket_adapter(comm);\n", + "\n", + " function ondownload(figure, _format) {\n", + " window.open(figure.canvas.toDataURL());\n", + " }\n", + "\n", + " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", + "\n", + " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", + " // web socket which is closed, not our websocket->open comm proxy.\n", + " ws_proxy.onopen();\n", + "\n", + " fig.parent_element = element;\n", + " fig.cell_info = mpl.find_output_cell(\"
\");\n", + " if (!fig.cell_info) {\n", + " console.error('Failed to find cell for figure', id, fig);\n", + " return;\n", + " }\n", + " fig.cell_info[0].output_area.element.on(\n", + " 'cleared',\n", + " { fig: fig },\n", + " fig._remove_fig_handler\n", + " );\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_close = function (fig, msg) {\n", + " var width = fig.canvas.width / fig.ratio;\n", + " fig.cell_info[0].output_area.element.off(\n", + " 'cleared',\n", + " fig._remove_fig_handler\n", + " );\n", + " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", + "\n", + " // Update the output cell to use the data from the current canvas.\n", + " fig.push_to_output();\n", + " var dataURL = fig.canvas.toDataURL();\n", + " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", + " // the notebook keyboard shortcuts fail.\n", + " IPython.keyboard_manager.enable();\n", + " fig.parent_element.innerHTML =\n", + " '';\n", + " fig.close_ws(fig, msg);\n", + "};\n", + "\n", + "mpl.figure.prototype.close_ws = function (fig, msg) {\n", + " fig.send_message('closing', msg);\n", + " // fig.ws.close()\n", + "};\n", + "\n", + "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", + " // Turn the data on the canvas into data in the output cell.\n", + " var width = this.canvas.width / this.ratio;\n", + " var dataURL = this.canvas.toDataURL();\n", + " this.cell_info[1]['text/html'] =\n", + " '';\n", + "};\n", + "\n", + "mpl.figure.prototype.updated_canvas_event = function () {\n", + " // Tell IPython that the notebook contents must change.\n", + " IPython.notebook.set_dirty(true);\n", + " this.send_message('ack', {});\n", + " var fig = this;\n", + " // Wait a second, then push the new image to the DOM so\n", + " // that it is saved nicely (might be nice to debounce this).\n", + " setTimeout(function () {\n", + " fig.push_to_output();\n", + " }, 1000);\n", + "};\n", + "\n", + "mpl.figure.prototype._init_toolbar = function () {\n", + " var fig = this;\n", + "\n", + " var toolbar = document.createElement('div');\n", + " toolbar.classList = 'btn-toolbar';\n", + " this.root.appendChild(toolbar);\n", + "\n", + " function on_click_closure(name) {\n", + " return function (_event) {\n", + " return fig.toolbar_button_onclick(name);\n", + " };\n", + " }\n", + "\n", + " function on_mouseover_closure(tooltip) {\n", + " return function (event) {\n", + " if (!event.currentTarget.disabled) {\n", + " return fig.toolbar_button_onmouseover(tooltip);\n", + " }\n", + " };\n", + " }\n", + "\n", + " fig.buttons = {};\n", + " var buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'btn-group';\n", + " var button;\n", + " for (var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " /* Instead of a spacer, we start a new button group. */\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + " buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'btn-group';\n", + " continue;\n", + " }\n", + "\n", + " button = fig.buttons[name] = document.createElement('button');\n", + " button.classList = 'btn btn-default';\n", + " button.href = '#';\n", + " button.title = name;\n", + " button.innerHTML = '';\n", + " button.addEventListener('click', on_click_closure(method_name));\n", + " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", + " buttonGroup.appendChild(button);\n", + " }\n", + "\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + "\n", + " // Add the status bar.\n", + " var status_bar = document.createElement('span');\n", + " status_bar.classList = 'mpl-message pull-right';\n", + " toolbar.appendChild(status_bar);\n", + " this.message = status_bar;\n", + "\n", + " // Add the close button to the window.\n", + " var buttongrp = document.createElement('div');\n", + " buttongrp.classList = 'btn-group inline pull-right';\n", + " button = document.createElement('button');\n", + " button.classList = 'btn btn-mini btn-primary';\n", + " button.href = '#';\n", + " button.title = 'Stop Interaction';\n", + " button.innerHTML = '';\n", + " button.addEventListener('click', function (_evt) {\n", + " fig.handle_close(fig, {});\n", + " });\n", + " button.addEventListener(\n", + " 'mouseover',\n", + " on_mouseover_closure('Stop Interaction')\n", + " );\n", + " buttongrp.appendChild(button);\n", + " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", + " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", + "};\n", + "\n", + "mpl.figure.prototype._remove_fig_handler = function (event) {\n", + " var fig = event.data.fig;\n", + " if (event.target !== this) {\n", + " // Ignore bubbled events from children.\n", + " return;\n", + " }\n", + " fig.close_ws(fig, {});\n", + "};\n", + "\n", + "mpl.figure.prototype._root_extra_style = function (el) {\n", + " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", + "};\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function (el) {\n", + " // this is important to make the div 'focusable\n", + " el.setAttribute('tabindex', 0);\n", + " // reach out to IPython and tell the keyboard manager to turn it's self\n", + " // off when our div gets focus\n", + "\n", + " // location in version 3\n", + " if (IPython.notebook.keyboard_manager) {\n", + " IPython.notebook.keyboard_manager.register_events(el);\n", + " } else {\n", + " // location in version 2\n", + " IPython.keyboard_manager.register_events(el);\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", + " var manager = IPython.notebook.keyboard_manager;\n", + " if (!manager) {\n", + " manager = IPython.keyboard_manager;\n", + " }\n", + "\n", + " // Check for shift+enter\n", + " if (event.shiftKey && event.which === 13) {\n", + " this.canvas_div.blur();\n", + " // select the cell after this one\n", + " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", + " IPython.notebook.select(index + 1);\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", + " fig.ondownload(fig, null);\n", + "};\n", + "\n", + "mpl.find_output_cell = function (html_output) {\n", + " // Return the cell and output element which can be found *uniquely* in the notebook.\n", + " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", + " // IPython event is triggered only after the cells have been serialised, which for\n", + " // our purposes (turning an active figure into a static one), is too late.\n", + " var cells = IPython.notebook.get_cells();\n", + " var ncells = cells.length;\n", + " for (var i = 0; i < ncells; i++) {\n", + " var cell = cells[i];\n", + " if (cell.cell_type === 'code') {\n", + " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", + " var data = cell.output_area.outputs[j];\n", + " if (data.data) {\n", + " // IPython >= 3 moved mimebundle to data attribute of output\n", + " data = data.data;\n", + " }\n", + " if (data['text/html'] === html_output) {\n", + " return [cell, data, j];\n", + " }\n", + " }\n", + " }\n", + " }\n", + "};\n", + "\n", + "// Register the function which deals with the matplotlib target/channel.\n", + "// The kernel may be null if the page has been refreshed.\n", + "if (IPython.notebook.kernel !== null) {\n", + " IPython.notebook.kernel.comm_manager.register_target(\n", + " 'matplotlib',\n", + " mpl.mpl_figure_comm\n", + " );\n", + "}\n" + ], "text/plain": [ "" ] @@ -1212,7 +6074,6 @@ "cell_type": "code", "execution_count": 40, "metadata": { - "scrolled": false, "slideshow": { "slide_type": "slide" } @@ -1220,7 +6081,980 @@ "outputs": [ { "data": { - "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n rubberband_canvas.addEventListener(\n 'dblclick',\n on_mouse_event_closure('dblclick')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n var img = evt.data;\n if (img.type !== 'image/png') {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n img.type = 'image/png';\n }\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n img\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.key === this._key) {\n return;\n } else {\n this._key = event.key;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.key !== 'Control') {\n value += 'ctrl+';\n }\n else if (event.altKey && event.key !== 'Alt') {\n value += 'alt+';\n }\n else if (event.shiftKey && event.key !== 'Shift') {\n value += 'shift+';\n }\n\n value += 'k' + event.key;\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.binaryType = comm.kernel.ws.binaryType;\n ws.readyState = comm.kernel.ws.readyState;\n function updateReadyState(_event) {\n if (comm.kernel.ws) {\n ws.readyState = comm.kernel.ws.readyState;\n } else {\n ws.readyState = 3; // Closed state.\n }\n }\n comm.kernel.ws.addEventListener('open', updateReadyState);\n comm.kernel.ws.addEventListener('close', updateReadyState);\n comm.kernel.ws.addEventListener('error', updateReadyState);\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n var data = msg['content']['data'];\n if (data['blob'] !== undefined) {\n data = {\n data: new Blob(msg['buffers'], { type: data['blob'] }),\n };\n }\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(data);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "/* global mpl */\n", + "window.mpl = {};\n", + "\n", + "mpl.get_websocket_type = function () {\n", + " if (typeof WebSocket !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof MozWebSocket !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert(\n", + " 'Your browser does not have WebSocket support. ' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.'\n", + " );\n", + " }\n", + "};\n", + "\n", + "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = this.ws.binaryType !== undefined;\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById('mpl-warnings');\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent =\n", + " 'This browser does not support binary websocket messages. ' +\n", + " 'Performance may be slow.';\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = document.createElement('div');\n", + " this.root.setAttribute('style', 'display: inline-block');\n", + " this._root_extra_style(this.root);\n", + "\n", + " parent_element.appendChild(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message('supports_binary', { value: fig.supports_binary });\n", + " fig.send_message('send_image_mode', {});\n", + " if (fig.ratio !== 1) {\n", + " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", + " }\n", + " fig.send_message('refresh', {});\n", + " };\n", + "\n", + " this.imageObj.onload = function () {\n", + " if (fig.image_mode === 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function () {\n", + " fig.ws.close();\n", + " };\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "};\n", + "\n", + "mpl.figure.prototype._init_header = function () {\n", + " var titlebar = document.createElement('div');\n", + " titlebar.classList =\n", + " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", + " var titletext = document.createElement('div');\n", + " titletext.classList = 'ui-dialog-title';\n", + " titletext.setAttribute(\n", + " 'style',\n", + " 'width: 100%; text-align: center; padding: 3px;'\n", + " );\n", + " titlebar.appendChild(titletext);\n", + " this.root.appendChild(titlebar);\n", + " this.header = titletext;\n", + "};\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", + "\n", + "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", + "\n", + "mpl.figure.prototype._init_canvas = function () {\n", + " var fig = this;\n", + "\n", + " var canvas_div = (this.canvas_div = document.createElement('div'));\n", + " canvas_div.setAttribute(\n", + " 'style',\n", + " 'border: 1px solid #ddd;' +\n", + " 'box-sizing: content-box;' +\n", + " 'clear: both;' +\n", + " 'min-height: 1px;' +\n", + " 'min-width: 1px;' +\n", + " 'outline: 0;' +\n", + " 'overflow: hidden;' +\n", + " 'position: relative;' +\n", + " 'resize: both;'\n", + " );\n", + "\n", + " function on_keyboard_event_closure(name) {\n", + " return function (event) {\n", + " return fig.key_event(event, name);\n", + " };\n", + " }\n", + "\n", + " canvas_div.addEventListener(\n", + " 'keydown',\n", + " on_keyboard_event_closure('key_press')\n", + " );\n", + " canvas_div.addEventListener(\n", + " 'keyup',\n", + " on_keyboard_event_closure('key_release')\n", + " );\n", + "\n", + " this._canvas_extra_style(canvas_div);\n", + " this.root.appendChild(canvas_div);\n", + "\n", + " var canvas = (this.canvas = document.createElement('canvas'));\n", + " canvas.classList.add('mpl-canvas');\n", + " canvas.setAttribute('style', 'box-sizing: content-box;');\n", + "\n", + " this.context = canvas.getContext('2d');\n", + "\n", + " var backingStore =\n", + " this.context.backingStorePixelRatio ||\n", + " this.context.webkitBackingStorePixelRatio ||\n", + " this.context.mozBackingStorePixelRatio ||\n", + " this.context.msBackingStorePixelRatio ||\n", + " this.context.oBackingStorePixelRatio ||\n", + " this.context.backingStorePixelRatio ||\n", + " 1;\n", + "\n", + " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", + "\n", + " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", + " 'canvas'\n", + " ));\n", + " rubberband_canvas.setAttribute(\n", + " 'style',\n", + " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", + " );\n", + "\n", + " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", + " if (this.ResizeObserver === undefined) {\n", + " if (window.ResizeObserver !== undefined) {\n", + " this.ResizeObserver = window.ResizeObserver;\n", + " } else {\n", + " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", + " this.ResizeObserver = obs.ResizeObserver;\n", + " }\n", + " }\n", + "\n", + " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", + " var nentries = entries.length;\n", + " for (var i = 0; i < nentries; i++) {\n", + " var entry = entries[i];\n", + " var width, height;\n", + " if (entry.contentBoxSize) {\n", + " if (entry.contentBoxSize instanceof Array) {\n", + " // Chrome 84 implements new version of spec.\n", + " width = entry.contentBoxSize[0].inlineSize;\n", + " height = entry.contentBoxSize[0].blockSize;\n", + " } else {\n", + " // Firefox implements old version of spec.\n", + " width = entry.contentBoxSize.inlineSize;\n", + " height = entry.contentBoxSize.blockSize;\n", + " }\n", + " } else {\n", + " // Chrome <84 implements even older version of spec.\n", + " width = entry.contentRect.width;\n", + " height = entry.contentRect.height;\n", + " }\n", + "\n", + " // Keep the size of the canvas and rubber band canvas in sync with\n", + " // the canvas container.\n", + " if (entry.devicePixelContentBoxSize) {\n", + " // Chrome 84 implements new version of spec.\n", + " canvas.setAttribute(\n", + " 'width',\n", + " entry.devicePixelContentBoxSize[0].inlineSize\n", + " );\n", + " canvas.setAttribute(\n", + " 'height',\n", + " entry.devicePixelContentBoxSize[0].blockSize\n", + " );\n", + " } else {\n", + " canvas.setAttribute('width', width * fig.ratio);\n", + " canvas.setAttribute('height', height * fig.ratio);\n", + " }\n", + " canvas.setAttribute(\n", + " 'style',\n", + " 'width: ' + width + 'px; height: ' + height + 'px;'\n", + " );\n", + "\n", + " rubberband_canvas.setAttribute('width', width);\n", + " rubberband_canvas.setAttribute('height', height);\n", + "\n", + " // And update the size in Python. We ignore the initial 0/0 size\n", + " // that occurs as the element is placed into the DOM, which should\n", + " // otherwise not happen due to the minimum size styling.\n", + " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", + " fig.request_resize(width, height);\n", + " }\n", + " }\n", + " });\n", + " this.resizeObserverInstance.observe(canvas_div);\n", + "\n", + " function on_mouse_event_closure(name) {\n", + " return function (event) {\n", + " return fig.mouse_event(event, name);\n", + " };\n", + " }\n", + "\n", + " rubberband_canvas.addEventListener(\n", + " 'mousedown',\n", + " on_mouse_event_closure('button_press')\n", + " );\n", + " rubberband_canvas.addEventListener(\n", + " 'mouseup',\n", + " on_mouse_event_closure('button_release')\n", + " );\n", + " rubberband_canvas.addEventListener(\n", + " 'dblclick',\n", + " on_mouse_event_closure('dblclick')\n", + " );\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband_canvas.addEventListener(\n", + " 'mousemove',\n", + " on_mouse_event_closure('motion_notify')\n", + " );\n", + "\n", + " rubberband_canvas.addEventListener(\n", + " 'mouseenter',\n", + " on_mouse_event_closure('figure_enter')\n", + " );\n", + " rubberband_canvas.addEventListener(\n", + " 'mouseleave',\n", + " on_mouse_event_closure('figure_leave')\n", + " );\n", + "\n", + " canvas_div.addEventListener('wheel', function (event) {\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " on_mouse_event_closure('scroll')(event);\n", + " });\n", + "\n", + " canvas_div.appendChild(canvas);\n", + " canvas_div.appendChild(rubberband_canvas);\n", + "\n", + " this.rubberband_context = rubberband_canvas.getContext('2d');\n", + " this.rubberband_context.strokeStyle = '#000000';\n", + "\n", + " this._resize_canvas = function (width, height, forward) {\n", + " if (forward) {\n", + " canvas_div.style.width = width + 'px';\n", + " canvas_div.style.height = height + 'px';\n", + " }\n", + " };\n", + "\n", + " // Disable right mouse context menu.\n", + " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", + " event.preventDefault();\n", + " return false;\n", + " });\n", + "\n", + " function set_focus() {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "};\n", + "\n", + "mpl.figure.prototype._init_toolbar = function () {\n", + " var fig = this;\n", + "\n", + " var toolbar = document.createElement('div');\n", + " toolbar.classList = 'mpl-toolbar';\n", + " this.root.appendChild(toolbar);\n", + "\n", + " function on_click_closure(name) {\n", + " return function (_event) {\n", + " return fig.toolbar_button_onclick(name);\n", + " };\n", + " }\n", + "\n", + " function on_mouseover_closure(tooltip) {\n", + " return function (event) {\n", + " if (!event.currentTarget.disabled) {\n", + " return fig.toolbar_button_onmouseover(tooltip);\n", + " }\n", + " };\n", + " }\n", + "\n", + " fig.buttons = {};\n", + " var buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'mpl-button-group';\n", + " for (var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " /* Instead of a spacer, we start a new button group. */\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + " buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'mpl-button-group';\n", + " continue;\n", + " }\n", + "\n", + " var button = (fig.buttons[name] = document.createElement('button'));\n", + " button.classList = 'mpl-widget';\n", + " button.setAttribute('role', 'button');\n", + " button.setAttribute('aria-disabled', 'false');\n", + " button.addEventListener('click', on_click_closure(method_name));\n", + " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", + "\n", + " var icon_img = document.createElement('img');\n", + " icon_img.src = '_images/' + image + '.png';\n", + " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", + " icon_img.alt = tooltip;\n", + " button.appendChild(icon_img);\n", + "\n", + " buttonGroup.appendChild(button);\n", + " }\n", + "\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + "\n", + " var fmt_picker = document.createElement('select');\n", + " fmt_picker.classList = 'mpl-widget';\n", + " toolbar.appendChild(fmt_picker);\n", + " this.format_dropdown = fmt_picker;\n", + "\n", + " for (var ind in mpl.extensions) {\n", + " var fmt = mpl.extensions[ind];\n", + " var option = document.createElement('option');\n", + " option.selected = fmt === mpl.default_extension;\n", + " option.innerHTML = fmt;\n", + " fmt_picker.appendChild(option);\n", + " }\n", + "\n", + " var status_bar = document.createElement('span');\n", + " status_bar.classList = 'mpl-message';\n", + " toolbar.appendChild(status_bar);\n", + " this.message = status_bar;\n", + "};\n", + "\n", + "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", + " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", + " // which will in turn request a refresh of the image.\n", + " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", + "};\n", + "\n", + "mpl.figure.prototype.send_message = function (type, properties) {\n", + " properties['type'] = type;\n", + " properties['figure_id'] = this.id;\n", + " this.ws.send(JSON.stringify(properties));\n", + "};\n", + "\n", + "mpl.figure.prototype.send_draw_message = function () {\n", + " if (!this.waiting) {\n", + " this.waiting = true;\n", + " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", + " var format_dropdown = fig.format_dropdown;\n", + " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", + " fig.ondownload(fig, format);\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", + " var size = msg['size'];\n", + " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", + " fig._resize_canvas(size[0], size[1], msg['forward']);\n", + " fig.send_message('refresh', {});\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", + " var x0 = msg['x0'] / fig.ratio;\n", + " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", + " var x1 = msg['x1'] / fig.ratio;\n", + " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", + " x0 = Math.floor(x0) + 0.5;\n", + " y0 = Math.floor(y0) + 0.5;\n", + " x1 = Math.floor(x1) + 0.5;\n", + " y1 = Math.floor(y1) + 0.5;\n", + " var min_x = Math.min(x0, x1);\n", + " var min_y = Math.min(y0, y1);\n", + " var width = Math.abs(x1 - x0);\n", + " var height = Math.abs(y1 - y0);\n", + "\n", + " fig.rubberband_context.clearRect(\n", + " 0,\n", + " 0,\n", + " fig.canvas.width / fig.ratio,\n", + " fig.canvas.height / fig.ratio\n", + " );\n", + "\n", + " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", + " // Updates the figure title.\n", + " fig.header.textContent = msg['label'];\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", + " var cursor = msg['cursor'];\n", + " switch (cursor) {\n", + " case 0:\n", + " cursor = 'pointer';\n", + " break;\n", + " case 1:\n", + " cursor = 'default';\n", + " break;\n", + " case 2:\n", + " cursor = 'crosshair';\n", + " break;\n", + " case 3:\n", + " cursor = 'move';\n", + " break;\n", + " }\n", + " fig.rubberband_canvas.style.cursor = cursor;\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_message = function (fig, msg) {\n", + " fig.message.textContent = msg['message'];\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", + " // Request the server to send over a new figure.\n", + " fig.send_draw_message();\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", + " fig.image_mode = msg['mode'];\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", + " for (var key in msg) {\n", + " if (!(key in fig.buttons)) {\n", + " continue;\n", + " }\n", + " fig.buttons[key].disabled = !msg[key];\n", + " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", + " if (msg['mode'] === 'PAN') {\n", + " fig.buttons['Pan'].classList.add('active');\n", + " fig.buttons['Zoom'].classList.remove('active');\n", + " } else if (msg['mode'] === 'ZOOM') {\n", + " fig.buttons['Pan'].classList.remove('active');\n", + " fig.buttons['Zoom'].classList.add('active');\n", + " } else {\n", + " fig.buttons['Pan'].classList.remove('active');\n", + " fig.buttons['Zoom'].classList.remove('active');\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.updated_canvas_event = function () {\n", + " // Called whenever the canvas gets updated.\n", + " this.send_message('ack', {});\n", + "};\n", + "\n", + "// A function to construct a web socket function for onmessage handling.\n", + "// Called in the figure constructor.\n", + "mpl.figure.prototype._make_on_message_function = function (fig) {\n", + " return function socket_on_message(evt) {\n", + " if (evt.data instanceof Blob) {\n", + " var img = evt.data;\n", + " if (img.type !== 'image/png') {\n", + " /* FIXME: We get \"Resource interpreted as Image but\n", + " * transferred with MIME type text/plain:\" errors on\n", + " * Chrome. But how to set the MIME type? It doesn't seem\n", + " * to be part of the websocket stream */\n", + " img.type = 'image/png';\n", + " }\n", + "\n", + " /* Free the memory for the previous frames */\n", + " if (fig.imageObj.src) {\n", + " (window.URL || window.webkitURL).revokeObjectURL(\n", + " fig.imageObj.src\n", + " );\n", + " }\n", + "\n", + " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", + " img\n", + " );\n", + " fig.updated_canvas_event();\n", + " fig.waiting = false;\n", + " return;\n", + " } else if (\n", + " typeof evt.data === 'string' &&\n", + " evt.data.slice(0, 21) === 'data:image/png;base64'\n", + " ) {\n", + " fig.imageObj.src = evt.data;\n", + " fig.updated_canvas_event();\n", + " fig.waiting = false;\n", + " return;\n", + " }\n", + "\n", + " var msg = JSON.parse(evt.data);\n", + " var msg_type = msg['type'];\n", + "\n", + " // Call the \"handle_{type}\" callback, which takes\n", + " // the figure and JSON message as its only arguments.\n", + " try {\n", + " var callback = fig['handle_' + msg_type];\n", + " } catch (e) {\n", + " console.log(\n", + " \"No handler for the '\" + msg_type + \"' message type: \",\n", + " msg\n", + " );\n", + " return;\n", + " }\n", + "\n", + " if (callback) {\n", + " try {\n", + " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", + " callback(fig, msg);\n", + " } catch (e) {\n", + " console.log(\n", + " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", + " e,\n", + " e.stack,\n", + " msg\n", + " );\n", + " }\n", + " }\n", + " };\n", + "};\n", + "\n", + "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", + "mpl.findpos = function (e) {\n", + " //this section is from http://www.quirksmode.org/js/events_properties.html\n", + " var targ;\n", + " if (!e) {\n", + " e = window.event;\n", + " }\n", + " if (e.target) {\n", + " targ = e.target;\n", + " } else if (e.srcElement) {\n", + " targ = e.srcElement;\n", + " }\n", + " if (targ.nodeType === 3) {\n", + " // defeat Safari bug\n", + " targ = targ.parentNode;\n", + " }\n", + "\n", + " // pageX,Y are the mouse positions relative to the document\n", + " var boundingRect = targ.getBoundingClientRect();\n", + " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", + " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", + "\n", + " return { x: x, y: y };\n", + "};\n", + "\n", + "/*\n", + " * return a copy of an object with only non-object keys\n", + " * we need this to avoid circular references\n", + " * http://stackoverflow.com/a/24161582/3208463\n", + " */\n", + "function simpleKeys(original) {\n", + " return Object.keys(original).reduce(function (obj, key) {\n", + " if (typeof original[key] !== 'object') {\n", + " obj[key] = original[key];\n", + " }\n", + " return obj;\n", + " }, {});\n", + "}\n", + "\n", + "mpl.figure.prototype.mouse_event = function (event, name) {\n", + " var canvas_pos = mpl.findpos(event);\n", + "\n", + " if (name === 'button_press') {\n", + " this.canvas.focus();\n", + " this.canvas_div.focus();\n", + " }\n", + "\n", + " var x = canvas_pos.x * this.ratio;\n", + " var y = canvas_pos.y * this.ratio;\n", + "\n", + " this.send_message(name, {\n", + " x: x,\n", + " y: y,\n", + " button: event.button,\n", + " step: event.step,\n", + " guiEvent: simpleKeys(event),\n", + " });\n", + "\n", + " /* This prevents the web browser from automatically changing to\n", + " * the text insertion cursor when the button is pressed. We want\n", + " * to control all of the cursor setting manually through the\n", + " * 'cursor' event from matplotlib */\n", + " event.preventDefault();\n", + " return false;\n", + "};\n", + "\n", + "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", + " // Handle any extra behaviour associated with a key event\n", + "};\n", + "\n", + "mpl.figure.prototype.key_event = function (event, name) {\n", + " // Prevent repeat events\n", + " if (name === 'key_press') {\n", + " if (event.key === this._key) {\n", + " return;\n", + " } else {\n", + " this._key = event.key;\n", + " }\n", + " }\n", + " if (name === 'key_release') {\n", + " this._key = null;\n", + " }\n", + "\n", + " var value = '';\n", + " if (event.ctrlKey && event.key !== 'Control') {\n", + " value += 'ctrl+';\n", + " }\n", + " else if (event.altKey && event.key !== 'Alt') {\n", + " value += 'alt+';\n", + " }\n", + " else if (event.shiftKey && event.key !== 'Shift') {\n", + " value += 'shift+';\n", + " }\n", + "\n", + " value += 'k' + event.key;\n", + "\n", + " this._key_event_extra(event, name);\n", + "\n", + " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", + " return false;\n", + "};\n", + "\n", + "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", + " if (name === 'download') {\n", + " this.handle_save(this, null);\n", + " } else {\n", + " this.send_message('toolbar_button', { name: name });\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", + " this.message.textContent = tooltip;\n", + "};\n", + "\n", + "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", + "// prettier-ignore\n", + "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", + "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", + "\n", + "mpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", + "\n", + "mpl.default_extension = \"png\";/* global mpl */\n", + "\n", + "var comm_websocket_adapter = function (comm) {\n", + " // Create a \"websocket\"-like object which calls the given IPython comm\n", + " // object with the appropriate methods. Currently this is a non binary\n", + " // socket, so there is still some room for performance tuning.\n", + " var ws = {};\n", + "\n", + " ws.binaryType = comm.kernel.ws.binaryType;\n", + " ws.readyState = comm.kernel.ws.readyState;\n", + " function updateReadyState(_event) {\n", + " if (comm.kernel.ws) {\n", + " ws.readyState = comm.kernel.ws.readyState;\n", + " } else {\n", + " ws.readyState = 3; // Closed state.\n", + " }\n", + " }\n", + " comm.kernel.ws.addEventListener('open', updateReadyState);\n", + " comm.kernel.ws.addEventListener('close', updateReadyState);\n", + " comm.kernel.ws.addEventListener('error', updateReadyState);\n", + "\n", + " ws.close = function () {\n", + " comm.close();\n", + " };\n", + " ws.send = function (m) {\n", + " //console.log('sending', m);\n", + " comm.send(m);\n", + " };\n", + " // Register the callback with on_msg.\n", + " comm.on_msg(function (msg) {\n", + " //console.log('receiving', msg['content']['data'], msg);\n", + " var data = msg['content']['data'];\n", + " if (data['blob'] !== undefined) {\n", + " data = {\n", + " data: new Blob(msg['buffers'], { type: data['blob'] }),\n", + " };\n", + " }\n", + " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", + " ws.onmessage(data);\n", + " });\n", + " return ws;\n", + "};\n", + "\n", + "mpl.mpl_figure_comm = function (comm, msg) {\n", + " // This is the function which gets called when the mpl process\n", + " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", + "\n", + " var id = msg.content.data.id;\n", + " // Get hold of the div created by the display call when the Comm\n", + " // socket was opened in Python.\n", + " var element = document.getElementById(id);\n", + " var ws_proxy = comm_websocket_adapter(comm);\n", + "\n", + " function ondownload(figure, _format) {\n", + " window.open(figure.canvas.toDataURL());\n", + " }\n", + "\n", + " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", + "\n", + " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", + " // web socket which is closed, not our websocket->open comm proxy.\n", + " ws_proxy.onopen();\n", + "\n", + " fig.parent_element = element;\n", + " fig.cell_info = mpl.find_output_cell(\"
\");\n", + " if (!fig.cell_info) {\n", + " console.error('Failed to find cell for figure', id, fig);\n", + " return;\n", + " }\n", + " fig.cell_info[0].output_area.element.on(\n", + " 'cleared',\n", + " { fig: fig },\n", + " fig._remove_fig_handler\n", + " );\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_close = function (fig, msg) {\n", + " var width = fig.canvas.width / fig.ratio;\n", + " fig.cell_info[0].output_area.element.off(\n", + " 'cleared',\n", + " fig._remove_fig_handler\n", + " );\n", + " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", + "\n", + " // Update the output cell to use the data from the current canvas.\n", + " fig.push_to_output();\n", + " var dataURL = fig.canvas.toDataURL();\n", + " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", + " // the notebook keyboard shortcuts fail.\n", + " IPython.keyboard_manager.enable();\n", + " fig.parent_element.innerHTML =\n", + " '';\n", + " fig.close_ws(fig, msg);\n", + "};\n", + "\n", + "mpl.figure.prototype.close_ws = function (fig, msg) {\n", + " fig.send_message('closing', msg);\n", + " // fig.ws.close()\n", + "};\n", + "\n", + "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", + " // Turn the data on the canvas into data in the output cell.\n", + " var width = this.canvas.width / this.ratio;\n", + " var dataURL = this.canvas.toDataURL();\n", + " this.cell_info[1]['text/html'] =\n", + " '';\n", + "};\n", + "\n", + "mpl.figure.prototype.updated_canvas_event = function () {\n", + " // Tell IPython that the notebook contents must change.\n", + " IPython.notebook.set_dirty(true);\n", + " this.send_message('ack', {});\n", + " var fig = this;\n", + " // Wait a second, then push the new image to the DOM so\n", + " // that it is saved nicely (might be nice to debounce this).\n", + " setTimeout(function () {\n", + " fig.push_to_output();\n", + " }, 1000);\n", + "};\n", + "\n", + "mpl.figure.prototype._init_toolbar = function () {\n", + " var fig = this;\n", + "\n", + " var toolbar = document.createElement('div');\n", + " toolbar.classList = 'btn-toolbar';\n", + " this.root.appendChild(toolbar);\n", + "\n", + " function on_click_closure(name) {\n", + " return function (_event) {\n", + " return fig.toolbar_button_onclick(name);\n", + " };\n", + " }\n", + "\n", + " function on_mouseover_closure(tooltip) {\n", + " return function (event) {\n", + " if (!event.currentTarget.disabled) {\n", + " return fig.toolbar_button_onmouseover(tooltip);\n", + " }\n", + " };\n", + " }\n", + "\n", + " fig.buttons = {};\n", + " var buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'btn-group';\n", + " var button;\n", + " for (var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " /* Instead of a spacer, we start a new button group. */\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + " buttonGroup = document.createElement('div');\n", + " buttonGroup.classList = 'btn-group';\n", + " continue;\n", + " }\n", + "\n", + " button = fig.buttons[name] = document.createElement('button');\n", + " button.classList = 'btn btn-default';\n", + " button.href = '#';\n", + " button.title = name;\n", + " button.innerHTML = '';\n", + " button.addEventListener('click', on_click_closure(method_name));\n", + " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", + " buttonGroup.appendChild(button);\n", + " }\n", + "\n", + " if (buttonGroup.hasChildNodes()) {\n", + " toolbar.appendChild(buttonGroup);\n", + " }\n", + "\n", + " // Add the status bar.\n", + " var status_bar = document.createElement('span');\n", + " status_bar.classList = 'mpl-message pull-right';\n", + " toolbar.appendChild(status_bar);\n", + " this.message = status_bar;\n", + "\n", + " // Add the close button to the window.\n", + " var buttongrp = document.createElement('div');\n", + " buttongrp.classList = 'btn-group inline pull-right';\n", + " button = document.createElement('button');\n", + " button.classList = 'btn btn-mini btn-primary';\n", + " button.href = '#';\n", + " button.title = 'Stop Interaction';\n", + " button.innerHTML = '';\n", + " button.addEventListener('click', function (_evt) {\n", + " fig.handle_close(fig, {});\n", + " });\n", + " button.addEventListener(\n", + " 'mouseover',\n", + " on_mouseover_closure('Stop Interaction')\n", + " );\n", + " buttongrp.appendChild(button);\n", + " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", + " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", + "};\n", + "\n", + "mpl.figure.prototype._remove_fig_handler = function (event) {\n", + " var fig = event.data.fig;\n", + " if (event.target !== this) {\n", + " // Ignore bubbled events from children.\n", + " return;\n", + " }\n", + " fig.close_ws(fig, {});\n", + "};\n", + "\n", + "mpl.figure.prototype._root_extra_style = function (el) {\n", + " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", + "};\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function (el) {\n", + " // this is important to make the div 'focusable\n", + " el.setAttribute('tabindex', 0);\n", + " // reach out to IPython and tell the keyboard manager to turn it's self\n", + " // off when our div gets focus\n", + "\n", + " // location in version 3\n", + " if (IPython.notebook.keyboard_manager) {\n", + " IPython.notebook.keyboard_manager.register_events(el);\n", + " } else {\n", + " // location in version 2\n", + " IPython.keyboard_manager.register_events(el);\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", + " var manager = IPython.notebook.keyboard_manager;\n", + " if (!manager) {\n", + " manager = IPython.keyboard_manager;\n", + " }\n", + "\n", + " // Check for shift+enter\n", + " if (event.shiftKey && event.which === 13) {\n", + " this.canvas_div.blur();\n", + " // select the cell after this one\n", + " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", + " IPython.notebook.select(index + 1);\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", + " fig.ondownload(fig, null);\n", + "};\n", + "\n", + "mpl.find_output_cell = function (html_output) {\n", + " // Return the cell and output element which can be found *uniquely* in the notebook.\n", + " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", + " // IPython event is triggered only after the cells have been serialised, which for\n", + " // our purposes (turning an active figure into a static one), is too late.\n", + " var cells = IPython.notebook.get_cells();\n", + " var ncells = cells.length;\n", + " for (var i = 0; i < ncells; i++) {\n", + " var cell = cells[i];\n", + " if (cell.cell_type === 'code') {\n", + " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", + " var data = cell.output_area.outputs[j];\n", + " if (data.data) {\n", + " // IPython >= 3 moved mimebundle to data attribute of output\n", + " data = data.data;\n", + " }\n", + " if (data['text/html'] === html_output) {\n", + " return [cell, data, j];\n", + " }\n", + " }\n", + " }\n", + " }\n", + "};\n", + "\n", + "// Register the function which deals with the matplotlib target/channel.\n", + "// The kernel may be null if the page has been refreshed.\n", + "if (IPython.notebook.kernel !== null) {\n", + " IPython.notebook.kernel.comm_manager.register_target(\n", + " 'matplotlib',\n", + " mpl.mpl_figure_comm\n", + " );\n", + "}\n" + ], "text/plain": [ "" ] @@ -1310,7 +7144,8 @@ "hash": "86193a1ab0ba47eac1c69c1756090baa3b420b3eea7d4aafab8b85f8b312f0c5" }, "kernelspec": { - "display_name": "Python 3.9.5 64-bit ('base': conda)", + "display_name": "Python 3 (ipykernel)", + "language": "python", "name": "python3" }, "language_info": { @@ -1323,12 +7158,12 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.5" + "version": "3.8.13" }, "livereveal": { "start_slideshow_at": "selected" } }, "nbformat": 4, - "nbformat_minor": 1 + "nbformat_minor": 4 } diff --git a/lessons/3-NeuralNetworks/04-OwnFramework/translations/OwnFramework.tr.ipynb b/lessons/3-NeuralNetworks/04-OwnFramework/translations/OwnFramework.tr.ipynb new file mode 100644 index 00000000..47e21c04 --- /dev/null +++ b/lessons/3-NeuralNetworks/04-OwnFramework/translations/OwnFramework.tr.ipynb @@ -0,0 +1,1101 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Çok Katmanlı Algılayıcılar\n", + "## Kendi Sinirsel Çerçevemizi Oluşturmak\n", + "\n", + "> Bu not defteri, [Yeni Başlayanlar için YZ Müfredatı](http://github.com/microsoft/ai-for-beginners)'nın bir parçasıdır. Eksiksiz öğrenme materyalleri kümesi için kaynak deposunu ziyaret edin.\n", + "\n", + "Bu defterde, çok-katmanlı algılayıcılarla çok-sınıflı sınıflandırma görevlerini ve bağlanımı çözebilen kendi sinirsel çerçevemizi yavaş yavaş inşa edeceğiz.\n", + "\n", + "İlk olarak, bazı gerekli kütüphaneleri içe aktaralım." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "%matplotlib nbagg\n", + "import matplotlib.pyplot as plt \n", + "from matplotlib import gridspec\n", + "from sklearn.datasets import make_classification\n", + "import numpy as np\n", + "# tekrarlanabilirlik için tohumu (seed) seçin - rastgele değişğmlerin etkilerini keşfetmek için değiştirin\n", + "np.random.seed(0)\n", + "import random" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Numune Veri Kümesi\n", + "\n", + "Daha önce olduğu gibi, iki parametreli basit bir örnek veri kümesi ile başlayacağız." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "n = 100\n", + "X, Y = make_classification(n_samples = n, n_features=2,\n", + " n_redundant=0, n_informative=2, flip_y=0.2)\n", + "X = X.astype(np.float32)\n", + "Y = Y.astype(np.int32)\n", + "\n", + "# Eğitim ve test veri kümesine bölün\n", + "train_x, test_x = np.split(X, [n*8//10])\n", + "train_labels, test_labels = np.split(Y, [n*8//10])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "def plot_dataset(suptitle, features, labels):\n", + " # görseli hazırla\n", + " fig, ax = plt.subplots(1, 1)\n", + " #pylab.subplots_adjust(bottom=0.2, wspace=0.4)\n", + " fig.suptitle(suptitle, fontsize = 16)\n", + " ax.set_xlabel('$x_i[0]$ -- (öznitelik 1)')\n", + " ax.set_ylabel('$x_i[1]$ -- (öznitelik 2)')\n", + "\n", + " colors = ['r' if l else 'b' for l in labels]\n", + " ax.scatter(features[:, 0], features[:, 1], marker='o', c=colors, s=100, alpha = 0.5)\n", + " fig.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "%matplotlib inline\n", + "plot_dataset('Eğitim verilerinin dağıtık grafiği', train_x, train_labels)\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(train_x[:5])\n", + "print(train_labels[:5])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Makine Öğrenmesi Problemi\n", + "\n", + "Diyelim ki $\\langle X,Y\\rangle$ veri setimiz var, burada $X$ bir dizi öznitelik ve $Y$ karşılık gelen etiketlerdir. Bağlanım problemi için $y_i\\in\\mathbb{R}$ ve sınıflandırma için $y_i\\in\\{0,\\dots,n\\}$ sınıf numarası ile temsil edilir.\n", + "\n", + "Herhangi bir makine öğrenmesi modeli, $f_\\theta(x)$ işleviyle temsil edilebilir, burada $\\theta$ bir **parametre** kümesidir. Amacımız, modelimizin veri kümesine en iyi şekilde uyduğu $\\theta$ parametrelerini bulmaktır. Kriterler **kayıp işlevi** $\\mathcal{L}$ tarafından tanımlanır ve en uygun değeri bulmamız gerekir\n", + "\n", + "$$\n", + "\\theta = \\mathrm{argmin}_\\theta \\mathcal{L}(f_\\theta(X),Y)\n", + "$$" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "Kayıp işlevi çözülen probleme bağlıdır.\n", + "\n", + "### Bağlanım için kayıp işlevleri\n", + "\n", + "Bağlanım için genellikle **mutlak hata** $\\mathcal{L}_{mutlak}(\\theta) = \\sum_{i=1}^n |y_i - f_{\\theta}(x_i)|$, veya **ortalama kare hatası** $\\mathcal{L}_{sq}(\\theta) = \\sum_{i=1}^n (y_i - f_{\\theta}(x_i))^2$ kullanırız." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "# çeşitli kayıp fonksiyonlarını çizmek için yardımcı fonksiyon\n", + "def plot_loss_functions(suptitle, functions, ylabels, xlabel):\n", + " fig, ax = plt.subplots(1,len(functions), figsize=(9, 3))\n", + " plt.subplots_adjust(bottom=0.2, wspace=0.4)\n", + " fig.suptitle(suptitle)\n", + " for i, fun in enumerate(functions):\n", + " ax[i].set_xlabel(xlabel)\n", + " if len(ylabels) > i:\n", + " ax[i].set_ylabel(ylabels[i])\n", + " ax[i].plot(x, fun)\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "x = np.linspace(-2, 2, 101)\n", + "plot_loss_functions(\n", + " suptitle = 'Bağlanım için ortak kayıp fonksiyonları',\n", + " functions = [np.abs(x), np.power(x, 2)],\n", + " ylabels = ['$\\mathcal{L}_{abs}}$ (mutlak kayıp)',\n", + " '$\\mathcal{L}_{sq}$ (kare kayıp)'],\n", + " xlabel = '$y - f(x_i)$')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "### Sınıflandırma için kayıp fonksiyonları\n", + "\n", + "Bir an için ikili sınıflandırmayı ele alalım. Bu durumda 0 ve 1 olarak numaralandırılmış iki sınıfımız var. $f_\\theta(x_i)\\in [0,1]$ ağının çıktısı esasen sınıf 1'in seçilme olasılığını tanımlar.\n", + "\n", + "**0-1 kaybı**\n", + "\n", + "0-1 kaybı, modelin doğruluğunu hesaplamakla aynıdır - doğru sınıflandırmaların sayısını hesaplarız:\n", + "\n", + "$$\\mathcal{L}_{0-1} = \\sum_{i=1}^n l_i \\quad l_i = \\begin{cases}\n", + " 0 & (f(x_i)<0.5 \\land y_i=0) \\lor (f(x_i)<0.5 \\land y_i=1) \\\\\n", + " 1 & \\mathrm{ diğer~türlü}\n", + " \\end{cases} \\\\\n", + "$$\n", + "\n", + "Ancak doğruluğun kendisi, doğru sınıflandırmadan ne kadar uzak olduğumuzu göstermez. Doğru sınıfı birazcık kaçırmış olabiliriz ve bu, bir bakımdan önemli ölçüde kaçırmaktan \"daha iyi\" (bir anlamda ağırlıkları çok daha az düzeltmemiz gerekiyor). Bu nedenle, genellikle bunu dikkate alan lojistik kayıp kullanılır.\n", + "\n", + "**Logistik Kayıp**\n", + "\n", + "$$\\mathcal{L}_{log} = \\sum_{i=1}^n -y\\log(f_{\\theta}(x_i)) - (1-y)\\log(1-f_\\theta(x_i))$$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "x = np.linspace(0,1,100)\n", + "def zero_one(d):\n", + " if d < 0.5:\n", + " return 0\n", + " return 1\n", + "zero_one_v = np.vectorize(zero_one)\n", + "\n", + "def logistic_loss(fx):\n", + " # assumes y == 1\n", + " return -np.log(fx)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "plot_loss_functions(suptitle = 'Sınıflandırma için ortak kayıp fonksiyonları (sınıf=1)',\n", + " functions = [zero_one_v(x), logistic_loss(x)],\n", + " ylabels = ['$\\mathcal{L}_{0-1}}$ (0-1 kaybı)',\n", + " '$\\mathcal{L}_{log}$ (logistic kayıp)'],\n", + " xlabel = '$p$')\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Lojistik kaybı anlamak için, beklenen çıktının iki durumunu göz önünde bulundurun:\n", + "* Çıktının 1 ($y=1$) olmasını beklersek, kayıp $-log f_\\theta(x_i)$ olur. Kayıp 0'dır, ağ 1 olasılıkla 1'i tahmin eder ve 1 olasılığı küçüldüğünde büyür.\n", + "* Çıktının 0 ($y=0$) olmasını beklersek, kayıp $-log(1-f_\\theta(x_i))$ olur. Burada, $1-f_\\theta(x_i)$, ağ tarafından tahmin edilen 0 olasılığıdır ve logaritmik kaybın anlamı, önceki durumda açıklananla aynıdır." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Sinir Ağı Mimarisi\n", + "\n", + "İkili sınıflandırma problemi için bir veri kümesi oluşturduk. Ancak, bunu en baştan çok sınıflı sınıflandırma olarak düşünelim, böylece kodumuzu kolayca çok sınıflı sınıflandırmaya çevirebiliriz. Bu durumda, tek katmanlı algılayıcımız aşağıdaki mimariye sahip olacaktır:\n", + "\n", + "\n", + "\n", + "Ağın iki çıktısı iki sınıfa karşılık gelir ve iki çıktı arasında en yüksek değere sahip sınıf doğru çözüme karşılık gelir.\n", + "\n", + "Model şöyle tanımlanır:\n", + "$$\n", + "f_\\theta(x) = W\\times x + b\n", + "$$\n", + "burada $$\\theta = \\langle W,b\\rangle$$ parametrelerdir.\n", + "\n", + "Bu doğrusal katmanı, hesaplamayı gerçekleştiren `forward` (ileri) işlevi olan bir Python sınıfı olarak tanımlayacağız. $x$ girdi değerini alır ve katmanın çıktısını üretir. `W` ve `b` parametreleri katman sınıfı içinde depolanır ve yaratıldığında sırasıyla rastgele değerler ve sıfırlarla ilklenir." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class Linear:\n", + " def __init__(self,nin,nout):\n", + " self.W = np.random.normal(0, 1.0/np.sqrt(nin), (nout, nin))\n", + " self.b = np.zeros((1,nout))\n", + " \n", + " def forward(self, x):\n", + " return np.dot(x, self.W.T) + self.b\n", + " \n", + "net = Linear(2,2)\n", + "net.forward(train_x[0:5])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "Çoğu durumda, tek bir girdi değeri üzerinde değil, girdi değerlerinin vektörü üzerinde çalışmak daha verimlidir. Numpy işlemlerini kullandığımız için, ağımıza bir girdi değerleri vektörü geçirebiliriz ve bu bize çıktı değerlerinin vektörünü verecektir.\n", + "\n", + "## Softmaks: Çıktıları Olasılıklara Dönüştürme\n", + "\n", + "Gördüğünüz gibi, çıktılarımız olasılık değil - herhangi bir değer alabilirler. Bunları olasılıklara dönüştürmek için tüm sınıflardaki değerleri normalleştirmemiz gerekir. Bu, **softmaks** işlevi kullanılarak yapılır: $$\\sigma(\\mathbf{z}_c) = \\frac{e^{z_c}}{\\sum_{j} e^{z_j}}, \\quad\\mathrm {öyleki}\\quad c\\in 1 .. |C|$$\n", + "\n", + "\n", + "\n", + "> Ağın çıktısı $\\sigma(\\mathbf{z})$, $C$ sınıflar kümesinde olasılık dağılımı olarak yorumlanabilir: $q = \\sigma(\\mathbf{z}_c) = \\hat{p} (c | x)$\n", + "\n", + "`Softmax` (Softmaks) katmanını, `forward` (ileri) işlevli bir sınıfla aynı şekilde tanımlayacağız:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class Softmax:\n", + " def forward(self,z):\n", + " zmax = z.max(axis=1,keepdims=True)\n", + " expz = np.exp(z-zmax)\n", + " Z = expz.sum(axis=1,keepdims=True)\n", + " return expz / Z\n", + "\n", + "softmax = Softmax()\n", + "softmax.forward(net.forward(train_x[0:10]))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "Artık çıktılar olarak olasılıklar aldığımızı görebilirsiniz, yani her çıktı vektörünün toplamı tam olarak 1'dir.\n", + "\n", + "2'den fazla sınıfımız olması durumunda, softmaks bunların hepsinde olasılıkları normalleştirir. İşte MNIST rakam sınıflandırması yapan bir ağ mimarisi diyagramı:\n", + "\n", + "![MNIST Classifier](../images/Cross-Entropy-Loss.PNG)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Çapraz Entropi Kaybı\n", + "\n", + "Sınıflandırmadaki bir kayıp fonksiyonu, tipik olarak, **çapraz entropi kaybı** olarak genelleştirilebilen bir lojistik fonksiyondur. Çapraz entropi kaybı, iki rastgele olasılık dağılımı arasındaki benzerliği hesaplayabilen bir fonksiyondur. Bununla ilgili daha ayrıntılı tartışmayı [Wikipedia](https://en.wikipedia.org/wiki/Cross_entropy)'da bulabilirsiniz.\n", + "\n", + "Bizim durumumuzda, ilk dağılım ağımızın olasılıksal çıktısıdır ve ikincisi **bire bir** dağılım olarak adlandırılır, bu da belirli bir $c$ sınıfının 1'e karşılık gelen olasılığa sahip olduğunu belirtir (geri kalan her şey 0'dır). Böyle bir durumda çapraz entropi kaybı $-\\log p_c$ olarak hesaplanabilir, burada $c$ beklenen sınıftır ve $p_c$, sinir ağımız tarafından verilen bu sınıfa karşılık gelen olasılıktır.\n", + "\n", + "> Beklenen sınıf için ağ 1 olasılığını döndürürse, çapraz entropi kaybı 0 olur. Gerçek sınıfın olasılığı 0'a ne kadar yakınsa, çapraz entropi kaybı o kadar yüksek olur (ve sonsuza kadar gidebilir!)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "def plot_cross_ent():\n", + " p = np.linspace(0.01, 0.99, 101) # tahmin edilen olasılık p(y|x)\n", + " cross_ent_v = np.vectorize(cross_ent)\n", + " f3, ax = plt.subplots(1,1, figsize=(8, 3))\n", + " l1, = plt.plot(p, cross_ent_v(p, 1), 'r--')\n", + " l2, = plt.plot(p, cross_ent_v(p, 0), 'r-')\n", + " plt.legend([l1, l2], ['$y = 1$', '$y = 0$'], loc = 'upper center', ncol = 2)\n", + " plt.xlabel('$\\hat{p}(y|x)$', size=18)\n", + " plt.ylabel('$\\mathcal{L}_{CE}$', size=18)\n", + " plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true, + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "def cross_ent(prediction, ground_truth):\n", + " t = 1 if ground_truth > 0.5 else 0\n", + " return -t * np.log(prediction) - (1 - t) * np.log(1 - prediction)\n", + "plot_cross_ent()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Çapraz entropi kaybı yine ayrı bir katman olarak tanımlanacak, ancak `forward` (ileri) işlevi iki girdi değerine sahip olacaktır: Ağın önceki katmanlarının çıktısı `p` ve beklenen sınıf `y`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class CrossEntropyLoss:\n", + " def forward(self,p,y):\n", + " self.p = p\n", + " self.y = y\n", + " p_of_y = p[np.arange(len(y)), y]\n", + " log_prob = np.log(p_of_y)\n", + " return -log_prob.mean() # tüm girdi örnekleri üzerinden ortalama\n", + "\n", + "cross_ent_loss = CrossEntropyLoss()\n", + "p = softmax.forward(net.forward(train_x[0:10]))\n", + "cross_ent_loss.forward(p,train_labels[0:10])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "> **ÖNEMLİ**: Kayıp işlevi, ağımızın ne kadar iyi (veya kötü) performans gösterdiğini gösteren bir sayı döndürür. Veri kümesinin tamamı veya veri kümesinin bir kısmı (minigrup) için bize bir sayı döndürmelidir. Bu nedenle, girdi vektörünün her bir bileşeni için çapraz entropi kaybını hesapladıktan sonra, tüm bileşenlerin ortalamasını almamız (veya toplamamız) gerekir - bu, `.mean()` çağrısıyla yapılır.\n", + "\n", + "## Hesaplamalı Çizge\n", + "\n", + "\n", + "\n", + "Bu ana kadar ağın farklı katmanları için farklı sınıflar tanımladık. Bu katmanların bileşimi **hesaplamalı çizge** olarak gösterilebilir. Şimdi, belirli bir eğitim veri kümesi (veya bunun bir parçası) için kaybı aşağıdaki şekilde hesaplayabiliriz:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "z = net.forward(train_x[0:10])\n", + "p = softmax.forward(z)\n", + "loss = cross_ent_loss.forward(p,train_labels[0:10])\n", + "print(loss)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Kaybı En Aza İndirme Problemi ve Ağ Eğitimi\n", + "\n", + "Ağı $f_\\theta$ olarak tanımladıktan ve $\\mathcal{L}(Y,f_\\theta(X))$ kayıp fonksiyonu verildikten sonra, sabit eğitim veri kümemiz altında $\\mathcal{L}$'yi $\\theta$'nın bir fonksiyonu olarak düşünebiliriz. : $\\mathcal{L}(\\theta) = \\mathcal{L}(Y,f_\\theta(X))$\n", + "\n", + "Bu durumda, ağ eğitimi $\\theta$ bağımsız değişkeni altında $\\mathcal{L}$ en aza indirme (minimizasyon) problemi olacaktır:\n", + "$$\n", + "\\theta = \\mathrm{argmin}_{\\theta} \\mathcal{L}(Y,f_\\theta(X))\n", + "$$\n", + "\n", + "**Gradyan inişi** adı verilen iyi bilinen bir işlev eniyileme (optimizasyon) yöntemi vardır. Buradaki fikir, parametrelere göre kayıp fonksiyonunun bir türevini (çok boyutlu durumda **gradyan** olarak adlandırılır) hesaplayabilmemiz ve parametreleri, hatanın azalacağı şekilde değiştirebilmemizdir.\n", + "\n", + "Gradyan inişi şu şekilde çalışır:\n", + " * Parametreleri, $w^{(0)}$ ve $b^{(0)}$, bazı rasgele değerlerle ilkletin.\n", + " * Aşağıdaki adımı birçok kez tekrarlayın:\n", + "\n", + " $$\\begin{align}\n", + " W^{(i+1)}&=W^{(i)}-\\eta\\frac{\\partial\\mathcal{L}}{\\partial W}\\\\\n", + " b^{(i+1)}&=b^{(i)}-\\eta\\frac{\\partial\\mathcal{L}}{\\partial b}\n", + " \\end{align}\n", + " $$\n", + "\n", + "Eğitim esnasında eniyileme adımlarının tüm veri kümesi dikkate alınarak hesaplanması gerekir (kaybın tüm eğitim örnekleri üzerinden bir toplam/ortalama olarak hesaplandığını unutmayın). Bununla birlikte, gerçek hayatta **minigruplar** olarak adlandırılan veri kümesinin küçük kısımlarını alır ve bir veri alt kümesine dayalı olarak gradyanları hesaplarız. Alt küme her seferinde rastgele alındığından, bu yönteme **rasgele gradyan inişi** (SGD - RGİ) denir." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Geriye Yayma\n", + "\n", + "\n", + "\n", + "$$\\def\\L{\\mathcal{L}}\\def\\zz#1#2{\\frac{\\partial#1}{\\partial#2}}\n", + "\\begin{align}\n", + "\\zz{\\L}{W} =& \\zz{\\L}{p}\\zz{p}{z}\\zz{z}{W}\\cr\n", + "\\zz{\\L}{b} =& \\zz{\\L}{p}\\zz{p}{z}\\zz{z}{b}\n", + "\\end{align}\n", + "$$" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "$\\partial\\mathcal{L}/\\partial W$'ı hesaplamak için, yukarıdaki formüllerde görebileceğiniz gibi, bileşik bir fonksiyonun türevlerini hesaplamak için **zincirleme kuralını** kullanabiliriz. Aşağıdaki fikre karşılık gelir:\n", + "\n", + "* Verilen girdinin altında $\\Delta\\mathcal{L}$ kaybını elde ettiğimizi varsayalım.\n", + "* Bunu en aza indirmek için, softmaks çıktısı $p$'yı $\\Delta p = (\\partial\\mathcal{L}/\\partial p)\\Delta\\mathcal{L}$ değerine göre ayarlamamız gerekir.\n", + "* Bu, $z$ düğümünde $\\Delta z = (\\partial\\mathcal{p}/\\partial z)\\Delta p$ tarafından yapılan değişikliklere karşılık gelir.\n", + "* Bu hatayı en aza indirmek için parametreleri buna göre ayarlamamız gerekiyor: $\\Delta W = (\\partial\\mathcal{z}/\\partial W)\\Delta z$ (ve $b$ için aynı)\n", + "\n", + "\n", + "\n", + "Bu işlem, kayıp hatasını ağın çıktısından parametrelerine geri dağıtmaya başlar. Bu nedenle işlem **geri yayma** olarak adlandırılır.\n", + "\n", + "Ağ eğitiminin bir geçişi iki bölümden oluşur:\n", + "* Belirli bir girdi minigrubu için kayıp fonksiyonunun değerini hesapladığımızda **ileriye geçiş** \n", + "* Bu hatayı hesaplamalı çizge aracılığıyla model parametrelerine geri dağıtarak en aza indirmeye çalıştığımızda **geriye geçiş**" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Geri Yaymanın Uygulanması\n", + "\n", + "* Geriye geçiş sırasında türevi hesaplayacak ve hatayı yayacak olan düğümlerimizin her birine `backward` (geri) fonksiyonunu ekleyelim.\n", + "* Ayrıca yukarıda açıklanan prosedüre göre parametre güncellemelerini de uygulamamız gerekiyor.\n", + "\n", + "Her katman için türevleri elle hesaplamamız gerekir, örneğin doğrusal katman $z = x\\times W+b$ için:\n", + "$$\\begin{align}\n", + "\\frac{\\partial z}{\\partial W} &= x \\\\\n", + "\\frac{\\partial z}{\\partial b} &= 1 \\\\\n", + "\\end{align}$$\n", + "\n", + "Katmanın çıktısındaki $\\Delta z$ hatasını telafi etmemiz gerekirse, ağırlıkları buna göre güncellememiz gerekir:\n", + "$$\\begin{align}\n", + "\\Delta x &= \\Delta z \\times W \\\\\n", + "\\Delta W &= \\frac{\\partial z}{\\partial W} \\Delta z = \\Delta z \\times x \\\\\n", + "\\Delta b &= \\frac{\\partial z}{\\partial b} \\Delta z = \\Delta z \\\\\n", + "\\end{align}$$\n", + "\n", + "**ÖNEMLİ:** Hesaplamalar her eğitim örneği için bağımsız olarak değil, bir bütün **minigrup** için yapılır. Gerekli parametre güncellemeleri $\\Delta W$ ve $\\Delta b$ tüm minigrupta hesaplanır ve ilgili vektörlerin $x\\in\\mathbb{R}^{\\mathrm{minigrup}\\, \\times\\, \\mathrm{sınıfsayısı}}$ boyutları vardır." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class Linear:\n", + " def __init__(self,nin,nout):\n", + " self.W = np.random.normal(0, 1.0/np.sqrt(nin), (nout, nin))\n", + " self.b = np.zeros((1,nout))\n", + " self.dW = np.zeros_like(self.W)\n", + " self.db = np.zeros_like(self.b)\n", + " \n", + " def forward(self, x):\n", + " self.x=x\n", + " return np.dot(x, self.W.T) + self.b\n", + " \n", + " def backward(self, dz):\n", + " dx = np.dot(dz, self.W)\n", + " dW = np.dot(dz.T, self.x)\n", + " db = dz.sum(axis=0)\n", + " self.dW = dW\n", + " self.db = db\n", + " return dx\n", + " \n", + " def update(self,lr):\n", + " self.W -= lr*self.dW\n", + " self.b -= lr*self.db" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Aynı şekilde, katmanlarımızın geri kalanı için `backward` (geri) işlevi tanımlayabiliriz:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class Softmax:\n", + " def forward(self,z):\n", + " self.z = z\n", + " zmax = z.max(axis=1,keepdims=True)\n", + " expz = np.exp(z-zmax)\n", + " Z = expz.sum(axis=1,keepdims=True)\n", + " return expz / Z\n", + " def backward(self,dp):\n", + " p = self.forward(self.z)\n", + " pdp = p * dp\n", + " return pdp - p * pdp.sum(axis=1, keepdims=True)\n", + " \n", + "class CrossEntropyLoss:\n", + " def forward(self,p,y):\n", + " self.p = p\n", + " self.y = y\n", + " p_of_y = p[np.arange(len(y)), y]\n", + " log_prob = np.log(p_of_y)\n", + " return -log_prob.mean()\n", + " def backward(self,loss):\n", + " dlog_softmax = np.zeros_like(self.p)\n", + " dlog_softmax[np.arange(len(self.y)), self.y] -= 1.0/len(self.y)\n", + " return dlog_softmax / self.p" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Training the Model\n", + "\n", + "Now we are ready to write the **training loop**, which will go through our dataset, and perform the optimization minibatch by minibatch.One complete pass through the dataset is often called **an epoch**:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "lin = Linear(2,2)\n", + "softmax = Softmax()\n", + "cross_ent_loss = CrossEntropyLoss()\n", + "\n", + "learning_rate = 0.1\n", + "\n", + "pred = np.argmax(lin.forward(train_x),axis=1)\n", + "acc = (pred==train_labels).mean()\n", + "print(\"Initial accuracy: \",acc)\n", + "\n", + "batch_size=4\n", + "for i in range(0,len(train_x),batch_size):\n", + " xb = train_x[i:i+batch_size]\n", + " yb = train_labels[i:i+batch_size]\n", + " \n", + " # forward pass\n", + " z = lin.forward(xb)\n", + " p = softmax.forward(z)\n", + " loss = cross_ent_loss.forward(p,yb)\n", + " \n", + " # backward pass\n", + " dp = cross_ent_loss.backward(loss)\n", + " dz = softmax.backward(dp)\n", + " dx = lin.backward(dz)\n", + " lin.update(learning_rate)\n", + " \n", + "pred = np.argmax(lin.forward(train_x),axis=1)\n", + "acc = (pred==train_labels).mean()\n", + "print(\"Final accuracy: \",acc)\n", + " " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Nice to see how we can increase accuracy of the model from about 50% to around 80% in one epoch.\n", + "\n", + "## Network Class\n", + "\n", + "Since in many cases neural network is just a composition of layers, we can build a class that will allow us to stack layers together and make forward and backward passes through them without explicitly programming that logic. We will store the list of layers inside the `Net` class, and use `add()` function to add new layers:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "scrolled": true, + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "class Net:\n", + " def __init__(self):\n", + " self.layers = []\n", + " \n", + " def add(self,l):\n", + " self.layers.append(l)\n", + " \n", + " def forward(self,x):\n", + " for l in self.layers:\n", + " x = l.forward(x)\n", + " return x\n", + " \n", + " def backward(self,z):\n", + " for l in self.layers[::-1]:\n", + " z = l.backward(z)\n", + " return z\n", + " \n", + " def update(self,lr):\n", + " for l in self.layers:\n", + " if 'update' in l.__dir__():\n", + " l.update(lr)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "With this `Net` class our model definition and training becomes more neat:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "net = Net()\n", + "net.add(Linear(2,2))\n", + "net.add(Softmax())\n", + "loss = CrossEntropyLoss()\n", + "\n", + "def get_loss_acc(x,y,loss=CrossEntropyLoss()):\n", + " p = net.forward(x)\n", + " l = loss.forward(p,y)\n", + " pred = np.argmax(p,axis=1)\n", + " acc = (pred==y).mean()\n", + " return l,acc\n", + "\n", + "print(\"Initial loss={}, accuracy={}: \".format(*get_loss_acc(train_x,train_labels)))\n", + "\n", + "def train_epoch(net, train_x, train_labels, loss=CrossEntropyLoss(), batch_size=4, lr=0.1):\n", + " for i in range(0,len(train_x),batch_size):\n", + " xb = train_x[i:i+batch_size]\n", + " yb = train_labels[i:i+batch_size]\n", + "\n", + " p = net.forward(xb)\n", + " l = loss.forward(p,yb)\n", + " dp = loss.backward(l)\n", + " dx = net.backward(dp)\n", + " net.update(lr)\n", + " \n", + "train_epoch(net,train_x,train_labels)\n", + " \n", + "print(\"Final loss={}, accuracy={}: \".format(*get_loss_acc(train_x,train_labels)))\n", + "print(\"Test loss={}, accuracy={}: \".format(*get_loss_acc(test_x,test_labels)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plotting the Training Process\n", + "\n", + "It would be nice to see visually how the network is being trained! We will define a `train_and_plot` function for that. To visualize the state of the network we will use level map, i.e. we will represent different values of the network output using different colors.\n", + "\n", + "> Do not worry if you do not understand some of the plotting code below - it is more important to understand the underlying neural network concepts." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "def train_and_plot(n_epoch, net, loss=CrossEntropyLoss(), batch_size=4, lr=0.1):\n", + " fig, ax = plt.subplots(2, 1)\n", + " ax[0].set_xlim(0, n_epoch + 1)\n", + " ax[0].set_ylim(0,1)\n", + "\n", + " train_acc = np.empty((n_epoch, 3))\n", + " train_acc[:] = np.NAN\n", + " valid_acc = np.empty((n_epoch, 3))\n", + " valid_acc[:] = np.NAN\n", + "\n", + " for epoch in range(1, n_epoch + 1):\n", + "\n", + " train_epoch(net,train_x,train_labels,loss,batch_size,lr)\n", + " tloss, taccuracy = get_loss_acc(train_x,train_labels,loss)\n", + " train_acc[epoch-1, :] = [epoch, tloss, taccuracy]\n", + " vloss, vaccuracy = get_loss_acc(test_x,test_labels,loss)\n", + " valid_acc[epoch-1, :] = [epoch, vloss, vaccuracy]\n", + " \n", + " ax[0].set_ylim(0, max(max(train_acc[:, 2]), max(valid_acc[:, 2])) * 1.1)\n", + "\n", + " plot_training_progress(train_acc[:, 0], (train_acc[:, 2],\n", + " valid_acc[:, 2]), fig, ax[0])\n", + " plot_decision_boundary(net, fig, ax[1])\n", + " fig.canvas.draw()\n", + " fig.canvas.flush_events()\n", + "\n", + " return train_acc, valid_acc" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "import matplotlib.cm as cm\n", + "\n", + "def plot_decision_boundary(net, fig, ax):\n", + " draw_colorbar = True\n", + " # remove previous plot\n", + " while ax.collections:\n", + " ax.collections.pop()\n", + " draw_colorbar = False\n", + "\n", + " # generate countour grid\n", + " x_min, x_max = train_x[:, 0].min() - 1, train_x[:, 0].max() + 1\n", + " y_min, y_max = train_x[:, 1].min() - 1, train_x[:, 1].max() + 1\n", + " xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),\n", + " np.arange(y_min, y_max, 0.1))\n", + " grid_points = np.c_[xx.ravel().astype('float32'), yy.ravel().astype('float32')]\n", + " n_classes = max(train_labels)+1\n", + " while train_x.shape[1] > grid_points.shape[1]:\n", + " # pad dimensions (plot only the first two)\n", + " grid_points = np.c_[grid_points,\n", + " np.empty(len(xx.ravel())).astype('float32')]\n", + " grid_points[:, -1].fill(train_x[:, grid_points.shape[1]-1].mean())\n", + "\n", + " # evaluate predictions\n", + " prediction = np.array(net.forward(grid_points))\n", + " # for two classes: prediction difference\n", + " if (n_classes == 2):\n", + " Z = np.array([0.5+(p[0]-p[1])/2.0 for p in prediction]).reshape(xx.shape)\n", + " else:\n", + " Z = np.array([p.argsort()[-1]/float(n_classes-1) for p in prediction]).reshape(xx.shape)\n", + " \n", + " # draw contour\n", + " levels = np.linspace(0, 1, 40)\n", + " cs = ax.contourf(xx, yy, Z, alpha=0.4, levels = levels)\n", + " if draw_colorbar:\n", + " fig.colorbar(cs, ax=ax, ticks = [0, 0.5, 1])\n", + " c_map = [cm.jet(x) for x in np.linspace(0.0, 1.0, n_classes) ]\n", + " colors = [c_map[l] for l in train_labels]\n", + " ax.scatter(train_x[:, 0], train_x[:, 1], marker='o', c=colors, s=60, alpha = 0.5)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "outputs": [], + "source": [ + "def plot_training_progress(x, y_data, fig, ax):\n", + " styles = ['k--', 'g-']\n", + " # remove previous plot\n", + " while ax.lines:\n", + " ax.lines.pop()\n", + " # draw updated lines\n", + " for i in range(len(y_data)):\n", + " ax.plot(x, y_data[i], styles[i])\n", + " ax.legend(ax.lines, ['training accuracy', 'validation accuracy'],\n", + " loc='upper center', ncol = 2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "%matplotlib nbagg \n", + "net = Net()\n", + "net.add(Linear(2,2))\n", + "net.add(Softmax())\n", + "\n", + "res = train_and_plot(30,net,lr=0.005)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "After running the cell above you should be able to see interactively how the boundary between classes change during training. Note that we have chosen very small learning rate so that we can see how the process happens.\n", + "\n", + "## Multi-Layered Models\n", + "\n", + "The network above has been constructed from several layers, but we still had only one `Linear` layer, which does the actual classification. What happens if we decide to add several such layers?\n", + "\n", + "Surprisingly, our code will work! Very important thing to note, however, is that in between linear layers we need to have a non-linear **activation function**, such as `tanh`. Without such non-linearity, several linear layers would have the same expressive power as just one layers - because composition of linear functions is also linear!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "class Tanh:\n", + " def forward(self,x):\n", + " y = np.tanh(x)\n", + " self.y = y\n", + " return y\n", + " def backward(self,dy):\n", + " return (1.0-self.y**2)*dy" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " Adding several layers make sense, because unlike one-layer network, multi-layered model will be able to accuratley classify sets that are not linearly separable. I.e., a model with several layers will be **reacher**.\n", + "\n", + "> It can be demonstrated that with sufficient number of neurons a two-layered model is capable to classifying any convex set of data points, and three-layered network can classify virtually any set.\n", + "\n", + "Mathematically, multi-layered perceptron would be represented by a more complex function $f_\\theta$ that can be computed in several steps:\n", + "* $z_1 = W_1\\times x+b_1$\n", + "* $z_2 = W_2\\times\\alpha(z_1)+b_2$\n", + "* $f = \\sigma(z_2)$\n", + "\n", + "Here, $\\alpha$ is a **non-linear activation function**, $\\sigma$ is a softmax function, and $\\theta=\\langle W_1,b_1,W_2,b_2\\rangle$ are parameters.\n", + "\n", + "The gradient descent algorithm would remain the same, but it would be more difficult to calculate gradients. Given the\n", + " chain differentiation rule, we can calculate derivatives as:\n", + "\n", + "$$\\begin{align}\n", + "\\frac{\\partial\\mathcal{L}}{\\partial W_2} &= \\color{red}{\\frac{\\partial\\mathcal{L}}{\\partial\\sigma}\\frac{\\partial\\sigma}{\\partial z_2}}\\color{black}{\\frac{\\partial z_2}{\\partial W_2}} \\\\\n", + "\\frac{\\partial\\mathcal{L}}{\\partial W_1} &= \\color{red}{\\frac{\\partial\\mathcal{L}}{\\partial\\sigma}\\frac{\\partial\\sigma}{\\partial z_2}}\\color{black}{\\frac{\\partial z_2}{\\partial\\alpha}\\frac{\\partial\\alpha}{\\partial z_1}\\frac{\\partial z_1}{\\partial W_1}}\n", + "\\end{align}\n", + "$$\n", + "\n", + "Note that the beginning of all those expressions is still the same, and thus we can continue back propagation beyond one linear layers to adjust further weights up the computational graph.\n", + "\n", + "Let's now experiment with two-layered network:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "net = Net()\n", + "net.add(Linear(2,10))\n", + "net.add(Tanh())\n", + "net.add(Linear(10,2))\n", + "net.add(Softmax())\n", + "loss = CrossEntropyLoss()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "outputs": [], + "source": [ + "res = train_and_plot(30,net,lr=0.01)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Why Not Always Use Multi-Layered Model?\n", + "\n", + "We have seen that multi-layered model is more *powerful* and *expressive*, than one-layered one. You may be wondering why don't we always use many-layered model. The answer to this question is **overfitting**.\n", + "\n", + "We will deal with this term more in a later sections, but the idea is the following: **the more powerful the model is, the better it can approximate training data, and the more data it needs to properly generalize** for the new data it has not seen before.\n", + "\n", + "**A linear model:**\n", + "* We are likely to get high training loss - so-called **underfitting**, when the model does not have enough power to correctly separate all data. \n", + "* Valiadation loss and training loss are more or less the same. The model is likely to generalize well to test data.\n", + "\n", + "**Complex multi-layered model**\n", + "* Low training loss - the model can approximate training data well, because it has enough expressive power.\n", + "* Validation loss can be much higher than training loss and can start to increase during training - this is because the model \"memorizes\" training points, and loses the \"overall picture\"\n", + "\n", + "![Overfitting](images/overfit.png)\n", + "\n", + "> On this picture, `x` stands for training data, `o` - validation data. Left - linear model (one-layer), it approximates the nature of the data pretty well. Right - overfitted model, the model perfectly well approximates training data, but stops making sense with any other data (validation error is very high)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "## Takeaways\n", + "\n", + "* Simple models (fewer layers, fewer neurons) with low number of parameters (\"low capacity\") are less likely to overfit\n", + "* More complex models (more layers, more neurons on each layer, high capacity) are likely to overfit. We need to monitor validation error to make sure it does not start to rise with further training\n", + "* More complex models need more data to train on.\n", + "* You can solve overfitting problem by either:\n", + " - simplifying your model\n", + " - increasing the amount of training data\n", + "* **Bias-variance trade-off** is a term that shows that you need to get the compromise\n", + " - between power of the model and amount of data,\n", + " - between overfittig and underfitting\n", + "* There is not single recipe on how many layers of parameters you need - the best way is to experiment" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Credits\n", + "\n", + "This notebook is a part of [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners), and has been prepared by [Dmitry Soshnikov](http://soshnikov.com). It is inspired by Neural Network Workshop at Microsoft Research Cambridge. Some code and illustrative materials are taken from presentations by [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) and [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/), and from [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) repository." + ] + } + ], + "metadata": { + "celltoolbar": "Slideshow", + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + }, + "livereveal": { + "start_slideshow_at": "selected" + }, + "vscode": { + "interpreter": { + "hash": "d355c6d9fcfa2da36351d09a4957315c029537f44307b30fb3762ace87798487" + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/lessons/3-NeuralNetworks/04-OwnFramework/translations/README.tr.md b/lessons/3-NeuralNetworks/04-OwnFramework/translations/README.tr.md index 256da0f5..16dc7acf 100644 --- a/lessons/3-NeuralNetworks/04-OwnFramework/translations/README.tr.md +++ b/lessons/3-NeuralNetworks/04-OwnFramework/translations/README.tr.md @@ -14,7 +14,7 @@ Python'da farklı sinir ağı mimarileri oluşturmamıza izin verecek kendi mod ## Makine Öğrenmesinin Formülleştirilmesi -Makine Öğrenmesi problemini formülleştirerek başlayalım. **Y** etiketli bir **X** eğitim veri kümemiz olduğunu ve en doğru tahminleri yapacak bir *f* modeli oluşturmamız gerektiğini varsayalım. Tahminlerin kalitesi **Kayıp işlevi** ℒ ile ölçülür. Aşağıdaki kayıp fonksiyonları sıklıkla kullanılır: +Makine Öğrenmesi problemini formülleştirerek başlayalım. **Y** etiketli bir **X** eğitim veri kümemiz olduğunu ve en doğru tahminleri yapacak bir *f* modeli oluşturmamız gerektiğini varsayalım. Tahminlerin kalitesi **kayıp işlevi** ℒ ile ölçülür. Aşağıdaki kayıp fonksiyonları sıklıkla kullanılır: * Bağlanım problemi için, bir sayıyı tahmin etmemiz gerektiğinde, **mutlak hata** ∑i|f(x(i))-y(i)| veya **kare hatası** ∑i(f(x(i))-y(i ))2 kullanabiliriz. * Sınıflandırma için **0-1 kaybı** (esas olarak modelin **doğruluğu** ile aynıdır) veya **lojistik kayıp** kullanırız. From 80dd6c2b864f25f3c30c69f9e609bb2fe45798c4 Mon Sep 17 00:00:00 2001 From: semercim Date: Sun, 2 Oct 2022 22:28:26 +0200 Subject: [PATCH 25/38] Translated lesson 4 to Turkish. --- .../src/assets/translations/tr/index.js | 4 +- .../src/assets/translations/tr/lesson-4.json | 115 ++++++ .../PerceptronMultiClass.tr.ipynb | 2 +- .../translations/Perceptron.tr.ipynb | 2 +- .../04-OwnFramework/OwnFramework.ipynb | 2 +- .../lab/translations/MyFW_MNIST.tr.ipynb | 168 ++++++++ .../lab/translations/README.tr.md | 20 + .../translations/OwnFramework.tr.ipynb | 368 +++++++++++++----- 8 files changed, 577 insertions(+), 104 deletions(-) create mode 100644 etc/quiz-app/src/assets/translations/tr/lesson-4.json create mode 100644 lessons/3-NeuralNetworks/04-OwnFramework/lab/translations/MyFW_MNIST.tr.ipynb create mode 100644 lessons/3-NeuralNetworks/04-OwnFramework/lab/translations/README.tr.md diff --git a/etc/quiz-app/src/assets/translations/tr/index.js b/etc/quiz-app/src/assets/translations/tr/index.js index a81da928..0bea43ce 100644 --- a/etc/quiz-app/src/assets/translations/tr/index.js +++ b/etc/quiz-app/src/assets/translations/tr/index.js @@ -1,11 +1,13 @@ import tr1 from './lesson-1.json'; import tr2 from './lesson-2.json'; import tr3 from './lesson-3.json'; +import tr4 from './lesson-4.json'; //add items here const quiz = { 0: tr1[0], 1: tr2[0], - 2: tr3[0] + 2: tr3[0], + 3: tr4[0] }; export default quiz; diff --git a/etc/quiz-app/src/assets/translations/tr/lesson-4.json b/etc/quiz-app/src/assets/translations/tr/lesson-4.json new file mode 100644 index 00000000..16aa8be0 --- /dev/null +++ b/etc/quiz-app/src/assets/translations/tr/lesson-4.json @@ -0,0 +1,115 @@ +[ + { + "title": "Yeni Başlayanlar İçin YZ: Sınavlar", + "complete": "Tebrikler, sınavı tamamladınız!", + "error": "Üzgünüz, tekrar deneyin", + "quizzes": [ + { + "id": 104, + "title": "Sinir Ağları: Ön Sınav", + "quiz": [ + { + "questionText": "Tahminin kalitesi kayıp fonksiyonu ile ölçülür", + "answerOptions": [ + { + "answerText": "Doğru", + "isCorrect": true + }, + { + "answerText": "Yanlış", + "isCorrect": false + } + ] + }, + { + "questionText": "Tek katmanlı ağ ____ sınıflandırma yeteneğine sahiptir", + "answerOptions": [ + { + "answerText": "doğrusal olarak birleştirilmiş sınıfları", + "isCorrect": false + }, + { + "answerText": "doğrusal olarak ayrılabilir sınıfları", + "isCorrect": true + }, + { + "answerText": "sınıfların tek katmanlarını", + "isCorrect": false + } + ] + }, + { + "questionText": "Çok katmanlı algılayıcıyı eğitme yöntemine ____ denir.", + "answerOptions": [ + { + "answerText": "geri yayma", + "isCorrect": true + }, + { + "answerText": "çoklu yayma", + "isCorrect": false + }, + { + "answerText": "ön yayma", + "isCorrect": false + } + ] + } + ] + }, + { + "id": 204, + "title": "Sinir Aşları: Ders Sonrası Sınavı", + "quiz": [ + { + "questionText": "Bağlanım kaybı fonksiyonları için ____ kullanıyoruz", + "answerOptions": [ + { + "answerText": "mutlak hata", + "isCorrect": false + }, + { + "answerText": "ortalama kare hata", + "isCorrect": false + }, + { + "answerText": "yukarıdakilerin hepsi", + "isCorrect": true + } + ] + }, + { + "questionText": "Biri hariç hepsi bir tür sınıflandırma kaybı fonksiyonudur", + "answerOptions": [ + { + "answerText": "0-1 kaybı", + "isCorrect": false + }, + { + "answerText": "ikili kayıp", + "isCorrect": true + }, + { + "answerText": "lojistik kayıp", + "isCorrect": false + } + ] + }, + { + "questionText": "Çapraz entropi kaybı, iki rastgele olasılık dağılımı arasındaki benzerliği hesaplayabilen bir fonksiyondur.", + "answerOptions": [ + { + "answerText": "Doğru", + "isCorrect": true + }, + { + "answerText": "Yanlış", + "isCorrect": false + } + ] + } + ] + } + ] + } +] \ No newline at end of file diff --git a/lessons/3-NeuralNetworks/03-Perceptron/lab/translations/PerceptronMultiClass.tr.ipynb b/lessons/3-NeuralNetworks/03-Perceptron/lab/translations/PerceptronMultiClass.tr.ipynb index b8c7336c..4a0771de 100644 --- a/lessons/3-NeuralNetworks/03-Perceptron/lab/translations/PerceptronMultiClass.tr.ipynb +++ b/lessons/3-NeuralNetworks/03-Perceptron/lab/translations/PerceptronMultiClass.tr.ipynb @@ -220,7 +220,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.13" + "version": "3.8.12" }, "livereveal": { "start_slideshow_at": "selected" diff --git a/lessons/3-NeuralNetworks/03-Perceptron/translations/Perceptron.tr.ipynb b/lessons/3-NeuralNetworks/03-Perceptron/translations/Perceptron.tr.ipynb index 2d261a12..a81c0e5f 100644 --- a/lessons/3-NeuralNetworks/03-Perceptron/translations/Perceptron.tr.ipynb +++ b/lessons/3-NeuralNetworks/03-Perceptron/translations/Perceptron.tr.ipynb @@ -800,7 +800,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.13" + "version": "3.10.6" }, "livereveal": { "start_slideshow_at": "selected" diff --git a/lessons/3-NeuralNetworks/04-OwnFramework/OwnFramework.ipynb b/lessons/3-NeuralNetworks/04-OwnFramework/OwnFramework.ipynb index ed9e5339..babe2ebd 100644 --- a/lessons/3-NeuralNetworks/04-OwnFramework/OwnFramework.ipynb +++ b/lessons/3-NeuralNetworks/04-OwnFramework/OwnFramework.ipynb @@ -6031,7 +6031,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " Adding several layers make sense, because unlike one-layer network, multi-layered model will be able to accuratley classify sets that are not linearly separable. I.e., a model with several layers will be **reacher**.\n", + " Adding several layers make sense, because unlike one-layer network, multi-layered model will be able to accurately classify sets that are not linearly separable. I.e., a model with several layers will be **reacher**.\n", "\n", "> It can be demonstrated that with sufficient number of neurons a two-layered model is capable to classifying any convex set of data points, and three-layered network can classify virtually any set.\n", "\n", diff --git a/lessons/3-NeuralNetworks/04-OwnFramework/lab/translations/MyFW_MNIST.tr.ipynb b/lessons/3-NeuralNetworks/04-OwnFramework/lab/translations/MyFW_MNIST.tr.ipynb new file mode 100644 index 00000000..c116870e --- /dev/null +++ b/lessons/3-NeuralNetworks/04-OwnFramework/lab/translations/MyFW_MNIST.tr.ipynb @@ -0,0 +1,168 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Kendi Çerçevemiz ile MNIST Rakam Sınıflandırması\n", + "\n", + "Lab Assignment from [AI for Beginners Curriculum](https://github.com/microsoft/ai-for-beginners).\n", + "\n", + "[Yeni Başlayanlar için YZ Müfredatı](https://github.com/microsoft/ai-for-beginners)'ndan Laboratuvar Ödevi.\n", + "\n", + "### Veri Kümesini Okuma\n", + "\n", + "Bu kod, veri kümesini internetteki depodan indirir. YZ Müfredat deposunun `/data` dizininden veri kümesini elle de kopyalayabilirsiniz." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + " % Total % Received % Xferd Average Speed Time Time Time Current\n", + " Dload Upload Total Spent Left Speed\n", + "\n", + " 0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0\n", + "100 9.9M 100 9.9M 0 0 9.9M 0 0:00:01 --:--:-- 0:00:01 15.8M\n" + ] + } + ], + "source": [ + "!rm *.pkl\n", + "!wget https://raw.githubusercontent.com/microsoft/AI-For-Beginners/main/data/mnist.pkl.gz\n", + "!gzip -d mnist.pkl.gz" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import pickle\n", + "with open('mnist.pkl', 'rb') as mnist_pickle:\n", + " train_set, validation_set, test_set = pickle.load(mnist_pickle, encoding='bytes')\n", + "\n", + "MNIST = {}\n", + "MNIST['Train'] = {}\n", + "MNIST['Validation'] = {}\n", + "MNIST['Test'] = {} \n", + "MNIST['Train']['Features'], MNIST['Train']['Labels'] = train_set[0], train_set[1]\n", + "MNIST['Validation']['Features'], MNIST['Validation']['Labels'] = validation_set[0], validation_set[1]\n", + "MNIST['Test']['Features'], MNIST['Test']['Labels'] = test_set[0], test_set[1]" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "labels = MNIST['Train']['Labels']\n", + "data = MNIST['Train']['Features']" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Sahip olduğumuz verilerin şeklinin ne olduğunu görelim:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(50000, 784)" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "data.shape" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Verileri Bölme\n", + "\n", + "Verileri eğitim ve test veri kümesi arasında bölmek için Scikit Learn'ü kullanacağız:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Eğitim örnekleri: 40000, test örnekleri: 10000\n" + ] + } + ], + "source": [ + "from sklearn.model_selection import train_test_split\n", + "\n", + "features_train, features_test, labels_train, labels_test = train_test_split(data,labels,test_size=0.2)\n", + "\n", + "print(f\"Eğitim örnekleri: {len(features_train)}, test örnekleri: {len(features_test)}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Talimatlar\n", + "\n", + "1. Dersten çerçeve kodunu alın ve bu not defterine veya (hatta daha iyisi) ayrı bir Python modülüne yapıştırın.\n", + "1. Eğitim sırasında eğitim ve geçerleme doğruluğunu gözlemleyerek tek katmanlı algılayıcıyı tanımlayın ve eğitin.\n", + "1. Aşırı öğrenme olup olmadığını anlamaya çalışın ve doğruluğu artırmak için katman parametrelerini ayarlayın.\n", + "1. 2 ve 3 katmanlı algılayıcılar için önceki adımları tekrarlayın. Katmanlar arasında farklı etkinleştirme işlevleri denemeyi deneyin.\n", + "1. Aşağıdaki soruları yanıtlamaya çalışın:\n", + " - Katmanlar arası etkinleştirme işlevi ağ performansını etkiler mi?\n", + " - Bu görev için 2 veya 3 katmanlı ağa ihtiyacımız var mı?\n", + " - Ağı eğitirken herhangi bir sorun yaşadınız mı? Özellikle katman sayısı arttıkça.\n", + " - Eğitim sırasında ağın ağırlıkları nasıl davranıyor? İlişkiyi anlamak için dönem sayısına karşı ağırlıkların maksimum mutlak değerini çizebilirsiniz." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/lessons/3-NeuralNetworks/04-OwnFramework/lab/translations/README.tr.md b/lessons/3-NeuralNetworks/04-OwnFramework/lab/translations/README.tr.md new file mode 100644 index 00000000..b886e745 --- /dev/null +++ b/lessons/3-NeuralNetworks/04-OwnFramework/lab/translations/README.tr.md @@ -0,0 +1,20 @@ +# Kendi Çerçevemizle MNIST Sınıflandırmasısı + +[Yeni Başlayanlar için YZ Müfredatı](https://github.com/microsoft/ai-for-beginners)'ndan Laboratuvar Ödevi. + +## Görev + +1, 2 ve 3 katmanlı algılayıcı kullanarak MNIST el yazısı rakam sınıflandırma problemini çözün. Derste geliştirdiğimiz sinir ağı çerçevesini kullanın. + +## Not Defterini Başlatmak + +[MyFW_MNIST.tr.ipynb](MyFW_MNIST.tr.ipynb) dosyasını açarak laboratuvarı başlatın. + +## Sorular + +Bu laboratuvarın sonucu olarak aşağıdaki soruları yanıtlamaya çalışın: + +- Katmanlar arası etkinleştirme işlevi ağ performansını etkiler mi? +- Bu görev için 2 veya 3 katmanlı ağa ihtiyacımız var mı? +- Ağı eğitirken herhangi bir sorun yaşadınız mı? Özellikle katman sayısı arttıkça. +- Eğitim sırasında ağın ağırlıkları nasıl davranıyor? İlişkiyi anlamak için dönem sayısına karşı ağırlıkların maksimum mutlak değerini çizebilirsiniz. \ No newline at end of file diff --git a/lessons/3-NeuralNetworks/04-OwnFramework/translations/OwnFramework.tr.ipynb b/lessons/3-NeuralNetworks/04-OwnFramework/translations/OwnFramework.tr.ipynb index 47e21c04..c51f0bd2 100644 --- a/lessons/3-NeuralNetworks/04-OwnFramework/translations/OwnFramework.tr.ipynb +++ b/lessons/3-NeuralNetworks/04-OwnFramework/translations/OwnFramework.tr.ipynb @@ -20,7 +20,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": { "slideshow": { "slide_type": "skip" @@ -53,7 +53,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": { "slideshow": { "slide_type": "slide" @@ -74,7 +74,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": { "slideshow": { "slide_type": "skip" @@ -97,13 +97,32 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/var/folders/_l/jnklp1bj4cl95rc01tf5vx4h0000gn/T/ipykernel_23744/2900170536.py:11: UserWarning: Matplotlib is currently using module://matplotlib_inline.backend_inline, which is a non-GUI backend, so cannot show the figure.\n", + " fig.show()\n" + ] + }, + { + "data": { + "image/png": "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wBEaOXbsGLZt29bhrXVvkuHDhyM9PR033ngjfHx8sG/fPvj5+eGFF17Av//9b1RXVwPoukrCQlBQENavX4958+bBaDTip59+wubNm51+ivSIESMa82uAttVTrXnqqaewbds2/PKXv0RAQAD279+P06dPIz4+Hrfffju+/vprXHrppbY2GwBHZGRmZuIPf/gDhgwZglOnTuHAgQMwGAyYO3cuXnrppcaxEj2J2NhY7Nq1C3fddRfCw8ORmZkJVVXx5z//GZ999lmHV+p///vf8eyzz2LQoEHIz8/HmTNncNlll2HLli2YO3duh+932WWX4aeffsKVV14Jk8mEAwcOIDo6Gu+//z7uueceANp/RwBL5r/88kvMmDEDpaWl2Lp1KzZv3qxr7lRrUlJS8MMPPyAqKgrPP/88HnroIU3bBQUFIS0tDb/73e8QHx+PI0eOoLy8HA8++CA2btzY6K3V8/ksjBkzBmlpabj88sthNptx5MgRREZG4t///rdNegd5enriyy+/xF/+8hf0798fR48exdmzZ7F48WLs2rWrMWTWnc8iWB9FvVj/pSC0Q3FxMcLDw9G7d2+UlpY62hxBcFl+/vlnjBkzBiNGjMC+ffscbY7VGTZsGDIyMrB3716MHDnS0eZcFAsWLMCXX36Jzz77DAsXLnS0OT0e8eAINmHVqlUA2q9uEARBO2+++SYAaB5u6Urs3r0bGRkZ6N27t6ZBt87MuXPnsH79enh4eGDixImONkeACBzhIjh48CBeffXVFlVUqqrinXfewaOPPgoAuOuuuxxlniC4DBs3bsSaNWtaJBjX19fjmWeewcsvvwyDwYA77rjDgRZeHP/7v//bpmR7165duP766wEAt99++0UlG9uTv/zlL41djS1kZWVhwYIFMBqNuPrqqxEdHe0g64TmSIhK6DabNm3CrFmz4OHhgcTERISFheHkyZMoLi4GACxfvhwrV650sJWC4PysXr0at912G7y8vJCcnIygoCAcPXq0sTrxqaeeajEOxNWw5CxFR0cjISEBBQUFOHPmDABg7Nix2LhxY4vmk85MUlISzpw5g/DwcCQlJaGsrKxR8PTt2xdpaWmNBRaCYxGBI3SbgoIC/POf/8T69esbG/sFBQVh1KhRuOOOO3DDDTc42kRBcAlOnDiBZ599Fhs3bkRubi4qKioQGhqKCRMm4L77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55872iSn4cSJE3j++edx1113OdoUwQEUFRXBZDIhKiqqxf1RUVHIz893kFWCM6OqKlasWIGpU6ciNTXV0eY4lIMHD6JXr17w8fHBXXfdhc8++wxDhgxxtFk2QQSOnXjsscegKEqnt/T09MbnP/TQQ9i7dy/Wr18PDw8P3HLLLXC3aKLefQIAubm5mDt3LhYtWoRly5Y5yHLb0Z190lNRFKXF36qqtrlPEADgvvvuw4EDB/D+++872hSHM3DgQOzbtw87duzA3XffjSVLliAzM9PRZtkET0cb0FO47777cOONN3b6nKSkpMb/h4eHIzw8HAMGDMDgwYORkJCAHTt2uJUrUe8+yc3NxaxZszBp0iS8+uqrNrbOMejdJz2R8PBweHh4tPHWFBQUtPHqCML999+PL774AmlpaYiPj3e0OQ7H29sbKSkpAICxY8di9+7deO655/DKK6842DLrIwLHTlgES3eweG6MRqM1TXI4evbJuXPnMGvWLIwZMwarVq2CweCezseLOU56Ct7e3hgzZgw2bNiAa665pvH+DRs24Oqrr3agZYIzoaoq7r//fnz22WfYtGkTkpOTHW2SU6KqqtutLRZE4DgZu3btwq5duzB16lSEhITg5MmTePTRR9GvXz+38t7oITc3FzNnzkSfPn3w9NNPo7CwsPGx6OhoB1rmWLKzs1FSUoLs7GyYTCbs27cPAJCSkoJevXo51jgbs2LFCixevBhjx45t9OhlZ2f36LysyspKHD9+vPHvU6dOYd++fQgNDUWfPn0caJljuPfee/Hee+/h888/R2BgYKPHLzg4GH5+fg62zjH87//+L+bNm4eEhARUVFRgzZo12LRpE9atW+do02yDKjgVBw4cUGfNmqWGhoaqPj4+alJSknrXXXepZ8+edbRpDmPVqlUqgHZvPZklS5a0u082btzoaNPswosvvqgmJiaq3t7e6ujRo9XNmzc72iSHsnHjxnaPhyVLljjaNIfQ0Tlj1apVjjbNYdx+++2Nv5mIiAj10ksvVdevX+9os2yG9MERBEEQBMHtcM9EBkEQBEEQejQicARBEARBcDtE4AiCIAiC4HaIwBEEQRAEwe0QgSMIgiAIgtshAkcQBEEQBLdDBI4gCIIgCG6HCBxBEARBENwOETiCIAiCILgdInAEQRAEQXA7ROAIQg9n5syZUBQFiqI0DuzU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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "%matplotlib inline\n", "plot_dataset('Eğitim verilerinin dağıtık grafiği', train_x, train_labels)\n", @@ -112,9 +131,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[ 1.3382818 -0.98613256]\n", + " [ 0.5128146 0.43299454]\n", + " [-0.4473693 -0.2680512 ]\n", + " [-0.9865851 -0.28692 ]\n", + " [-1.0693829 0.41718036]]\n", + "[1 1 0 0 0]\n" + ] + } + ], "source": [ "print(train_x[:5])\n", "print(train_labels[:5])" @@ -156,7 +188,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": { "slideshow": { "slide_type": "skip" @@ -179,13 +211,24 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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ehV7e/snPv+6det49dVXeeONN/j2228xNjbOm8/QokULli9fTrly5YiLi2PHjh1kZmZiZWX12HE8PT3p2bMnixcvZsKECRgbG+f9bP78+bi7u9O7d28AgoOD6dChA3Xr1mXZsmWYm5uzcOFCevTowerVqxk4cGC+Yxf177eg5yKAU6dOce7cOSZNmoSXlxfW1tbPPLYQohA0Qogyb8WKFRrgsS9zc3PNwoULn/nYnJwcTVZWlmbKlCkaR0dHjVqt1mg0Gs3Zs2c1gOaDDz7It//q1as1gGbo0KF52/bu3asBNHv37n3q82RnZ2vu3bunsba21sydO/ex7CNGjMi3//Tp0zWAJiEhIW9bq1atNK1atcr7/urVqxpA4+/vr8nJycnbPmfOHA2g6dmzZ75jjhkzRgNoUlJSnvmaTJ48WfPv0+OVK1c0xsbGmldeeeWZjxs6dKimSpUq+bYBGldXV01qamretsTERI2RkZFm2rRpzzzexIkTNYDm6NGj+ba/8847GpVKpYmMjNRoNP+8Dj4+PprMzMx8+x4/flwDaFasWPHM59Jonv8eHT9+XLNr1y6NnZ2dpl+/fpoHDx4895hFeaxardZkZWVpgoODNYDm9OnTeT+bPHmyxszMTHP9+vW8bWvXrtUAmuDg4LxtT3svLC0tNYmJifl+5xo1amh8fX2f+7tUqVJF061bt3zbCvse1alTR5OdnZ2337FjxzSAZvXq1fmyW1tbazQajearr77SGBsba77++ut8x//11181gCY0NPSZmQHN5MmT875/9Le6adOmvG1xcXEaExMTzeeff563rUmTJhoXFxfN3bt387ZlZ2dr/Pz8NB4eHnnnieL8/f7X085FGk3ua29sbJz3ev5blSpV8p2PhBCFJ0OGhNAjP/30E8ePH+f48eP88ccfDB06lJEjRzJ//vx8++3Zs4f27dtjb2+PsbExpqamfPrpp9y6dStvSE1wcDAAAwYMyPfYfv36YWLy/JuL9+7d44MPPsDX1xcTExNMTEywsbEhLS2Nc+fOPbZ/z549831ft25dgAJdge/atStGRv+czmrWrAmQd0X8v9tjYmKee8x/27VrFzk5OYwcObJQj3ukTZs22Nra5n3v6uqKi4vLc3+3PXv2UKtWLRo1apRv+2uvvYZGo3ns6mvPnj0fGx72LIV9j3788Ue6du3KsGHD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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "x = np.linspace(-2, 2, 101)\n", "plot_loss_functions(\n", @@ -227,7 +270,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ @@ -245,13 +288,32 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/var/folders/_l/jnklp1bj4cl95rc01tf5vx4h0000gn/T/ipykernel_23744/331859503.py:10: RuntimeWarning: divide by zero encountered in log\n", + " return -np.log(fx)\n" + ] + }, + { + "data": { + "image/png": "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GTNmYNiwYWofs1evXtixYwdyc3MxdOhQRERE4MUXX1R78K22zJw5E9OmTcPKlSvRt29frFixAkuWLEHHjh3VOp6ZmRl2796NyMhIbN++HeHh4ejbty+OHDmi0xVPu3Tpgv3798PGxgajR4/Gq6++ipycHOzcuRNDhw6t0jG6du2KyMhI/P777+jYsSPatm2LuLg4ODs7Y9euXbC2tsbrr7+OsWPHwtbWtsKpMp9Wr149xMTEQCKRoFOnTioNxKxo3+7du2PVqlU4f/48+vfvj5kzZ+Kll17CjBkzKj1O6fW/9dZbKnXj+uKLL+Dr64sxY8Zg7Nix8PT0xIEDB1C/fv0qH+NJ2niNnqdPnz7YvXs39u7di4EDB+LRo0fo1KkTLly4gMmTJ6NXr16YOnUqGjVqhJiYmDIf/iozaNAgWFpaonfv3mjYsGG55yMjI7FixQqcPXsWgwYNwqRJk9CsWTMcO3aswu3Voe336fMMHz4ce/bsKdNNslWrVpDJZJg9ezbCw8MxYsQI3Lt3Dzt37lSOa6kOZs+ejZdffhkvv/wyHj9+jIMHDyp/frrFaMeOHXBxcalW10fVm0QQNJgol4jIQF27dg2DBw/GmTNn1J71hDQzbdo0REdHIzk5uUr9/w8ePIhu3bphy5YteOmll/QQoWH7/fffMWDAAOzatavMbF41WWpqKvz8/LB27VqtJWvVjVwuR4MGDTBs2DB8/vnnYodDRoJdhoioRsnLy8ORI0cgl8tx5coVXLx4Ea1atRI7LKNy/PhxXLlyBYsXL8abb76p1mBgY5aYmIjbt28rVy1Xdcao6szLywtTpkzB559/jpdffllvEwQYknXr1iE/P1+5gjmRPjAhIKIaJT8/H2PHjsX9+/fRtWtXlVZKJe0ICQmBtbU1+vXrh88++0zscKqdiRMn4ujRo2jTpg1++uknnczyZchmzZoFa2trpKSkwMfHR+xw9E6hUGD9+vVwdHQUOxQyIuwyRERERERkxIyvLY6IiIiIiJSYEBARERERGTEmBERERERERowJARERERGREWNCQERERERkxJgQEBEREREZMSYERERERERGjAkBEREREZERY0JARERERGTEmBAQERERERkxJgREREREREaMCQERERERkRFjQkBEREREZMTMxA5AbAqFAqmpqbCzs4NEIhE7HCIyUoIgIC8vD15e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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "plot_loss_functions(suptitle = 'Sınıflandırma için ortak kayıp fonksiyonları (sınıf=1)',\n", " functions = [zero_one_v(x), logistic_loss(x)],\n", @@ -296,9 +358,24 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "array([[ 1.77202116, -0.25384488],\n", + " [ 0.28370828, -0.39610552],\n", + " [-0.30097433, 0.30513182],\n", + " [-0.8120485 , 0.56079421],\n", + " [-1.23519653, 0.3394973 ]])" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "class Linear:\n", " def __init__(self,nin,nout):\n", @@ -335,9 +412,29 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "array([[0.88348621, 0.11651379],\n", + " [0.66369714, 0.33630286],\n", + " [0.35294795, 0.64705205],\n", + " [0.20216095, 0.79783905],\n", + " [0.17154828, 0.82845172],\n", + " [0.24279153, 0.75720847],\n", + " [0.18915732, 0.81084268],\n", + " [0.17282951, 0.82717049],\n", + " [0.13897531, 0.86102469],\n", + " [0.72746882, 0.27253118]])" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "class Softmax:\n", " def forward(self,z):\n", @@ -384,7 +481,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "metadata": { "slideshow": { "slide_type": "skip" @@ -406,14 +503,25 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": { "scrolled": true, "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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SrfUVGDrVrmuo64EAEOsNtQ/ku3b5QQvIiIiIi3873/AgwdAjRq6meRAxRCrhebNgVq1gLQ0YNs2rashIiKi0ko9KjxwoJyvoyMMsVowGIxdCtR+KERERESOlJMDbNgg13XWHxbQ8Yldujd0qEzvNnSo1pUQERFRaXT4sAyv5e8PPPqo1tVYjSFWK506yUJERESkBfVocN++gJeXtrWUALsTEBEREZVGpv1hdYghVkuKAhw7BnzxhdaVEBERUWly4QJw9izg4QH06aN1NSXC7gRaSkoC2rcHMjOlKb9hQ60rIiIiotJA7UrQtStQvrympZQUW2K15O8PdO8u1zlKARERETmK2pVAh6MSqBhitab2Q2GIJSIiIkdISAD275frOu0PCzDEak/94zlwALh1S9taiIiIyPVt3ChjxIaHAzVral1NiTHEai00FHjkEflj2rhR62qIiIjI1alHf3XcCgswxDoHtT/K2rWalkFEREQuLi0N+O03ua7j/rAAQ6xzGDJELv/4A0hP17YWIiIicl0rVgApKUCNGkDLllpX81AYYp1B8+byq+jcOcDbW+tqiIiIyBUpCvDll3J93DjAYNC2nofEcWKdRc+eWldARERErmz/fiAyEvDxAf72N62reWhsiXU2WVnAlStaV0FERESuRm2Fff55oGJFbWuxAYZYZ3LoEFCnjvSRVRStqyEiIiJXceUKsGaNXJ84UdtabIQh1pnUqydjxR49KuPGEhEREdnCggVAdrbMFNq8udbV2ARDrDOpVAkYPlyuz52rbS1ERETkGlJTgW++kesu0goLMMQ6H/WPa9Uq4No1bWshIiIi/Vu+HLhzB6hVCxgwQOtqbIYh1tmEhQHdukmT/4IFWldDREREemY6rNYrrwDu7trWY0MMsc5o0iS5XLwYePBA21qIiIhIv3btAk6dAnx9gdGjta7GphhindGAAUDNmsDt28CWLVpXQ0RERHqltsKOHAmUL69pKbbGyQ6ckbu7dCWoXBlo00braoiIiEiPoqOB9evl+oQJ2tZiBwyxzqpvX60rICIiIj2bP1/6xPbsCTRurHU1NsfuBHpw7RonPyAiIqLiu3YNWLhQrqvn2rgYhlhn969/AXXrGmfZICIiIirKO+/IyeGdOwN9+mhdjV0wxDo7gwHIyABef10uiYiIiApz/Djw/fdy/dNPJUu4IIZY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7969YTAYsGPHDps+LxFRcbEllohIQ9euXUODBg3g5+eH6OholC1b1qbPX6tWLcTExGDnzp3o1q2bzZ730KFD6NChAx555BFERETAzY1tIkTkWPzUISLS0LRp0/DgwQNMnTrV5gHWntq3b49evXohMjISP/74o9blEFEpxBBLRKSR69evY9myZfDy8sKoUaO0LsdqY8eOBQC7dIMgIioKQywRkUa++eYbZGdno2/fvggMDNS6HKupdZ8+fRr79+/XuhwiKmUYYomIHsL7778Pg8GA7t27IykpCR9++CHatm2LChUqwNvbG40aNcLMmTORnZ1t9jhFUXJPABs2bJjF546Li4PBYIDBYMBvv/1WaB2vvPIKDAYDOnbsiOKe6rB///7c51+5cqXFbQ4fPgw/Pz8YDAZMnTrV7D4vLy/85S9/AQAsXry4WK9JRGQrDLFERA9BndSgYsWKCA8Px9tvv42IiAhkZWUhIyMD586dw1tvvYWRI0eaPe7UqVO4du0aAKBLly4Wn7tq1aqoU6cOAAmTBTlx4gS+/vpruLm5Yd68eTAYDMWqvVOnThg4cCAA4F//+le+oH3u3Dn0798fKSkpGDlyJD7++ON8z/Hoo48CALZs2VKs1yQishWGWCKih6CG2FWrViEhIQFz585FYmIikpKScOnSJXTv3h0AsGzZMuzduzf3cXv27AEAhIaGolq1agU+f6dOnQAUHmInTJiA7OxsjBkzBq1atbKq/lmzZsHd3R1//vmn2QlaN27cQK9evZCQkID+/fvj22+/tRiO27VrBwCIj4/Hn3/+adVrExE9DIZYIqISunPnDq5cuQIA8PPzw86dOzFhwgT4+fkBAOrUqYOVK1eiXLlyAID169fnPlYNpeHh4YW+RseOHc22z+vHH3/E3r17UaFCBXz44YdWv4fGjRvjhRdeAADMmDEDmZmZuHfvHnr37o2YmBh07twZP//8Mzw8LM9SXr9+/dz3e/DgQatfn4iopBhiiYhKSG2FBaRvrKVW0IoVK+YG0aioqNz1N27cAABUrly50NdQW2Jv376Nixcvmt2XlJSU20/1/fffR6VKlUrwLiS8lilTBtHR0fjqq68waNAgnDx5Es2bN8eGDRtQpkyZQh9fsWJFs/dEROQIDLFERCWkhtgKFSrkDjdlSVBQUL51t27dAoAiRyVo2rQpAgICAORvjZ0xYwZiY2MRFhZW6OsXJTg4GBMnTgQAvPrqq9izZw9q1aqFLVu2oHz58kU+Xn0P6nsiInIEhlgiohKKjIwEAPTv3x8+Pj4Fbnf79m0AcqKWKi0tDQDg7e1d6Gu4ubnl9js9dOhQ7vo///wTc+fOBQDMmzcP7u7uJXgHRpMmTcqddSswMBBbt25F9erVi/VYtaVWfU9ERI7AEEtEVEJqS2zr1q0L3U5tQX3kkUdy16mH4O/evVvk61g6uWvChAnIzMzEsGHDckcIKKmsrCz8/e9/R05ODgAgNTW1yC4Epu7cuQPA+J6IiByBIZaIqASSk5Nz+6gW1hd1165diI+Ph8FgQN++fXPXq31h1QBYGLVP7YkTJ5Ceno5Vq1Zh+/bt8PPze+jZshRFwZgxY/Drr7+icuXKqF27NtLS0jB9+vRiP4f6Horq30tEZEsMsUREJXD8+PHclsvC+oKqY6s+9dRTCA4Ozl3fpEkTAOYnexWkffv2cHd3R0ZGBvbv349//OMfAIC3337b7DlLYurUqfj+++/h5+eHjRs35o5w8P333+PMmTNFPj4pKQkJCQkAZKQDIiJHYYglIioB05EJNm/ebHGbxYsXY8uWLfDx8cF7771ndp/aBUBtXS2Mn58fmjdvDgAYPXo0YmJiUL9+fbz66qsP8xbw6aef4tNPP4WnpydWrVqFNm3a4Nlnn0VYWBiys7Px5ptvFvkcERERyMnJgYeHR263ByIiR2CIJSIqATXEli9fHr/99hveeecdJCUlAQBiY2Px2muvYdy4cQCARYsWoVGjRmaP79SpEzw8PJCRkYHjx48X+XpqQLx8+TIA4Msvv4SXl1eJ6//hhx8wdepUGAwGfPfdd+jZsycAwGAw4P333wcg49ru37+/0OdR++m2bNkyd7xYIiJHYIglIioBdWSCd999F82aNcMHH3yAgIAABAQEoHr16vj0009hMBgwZ84c/PWvf833eH9/f/Tr1w+A+SQIBVH7xQLAgAED0KdPnxLXvmnTJowePRqKouDzzz/HsGHDzO4fOHBg7ogIr7/+eqHPpdae9zmIiOyNIZaIyErp6em5/UXbt2+PPXv24JVXXkFISAjS0tIQHByMESNG4NixY5g0aVKBz/PSSy8BAJYvXw5FUQp9TXW0AG9vb3zxxRclrv3gwYMYOnQosrKy8Prrr2Py5MkWt1P7xu7fvx/r1q2zuE10dDQOHjyIMmXKWAzqRET2ZHkeQSIiKtAff/yBrKwsuLu7IywsDGXKlMG8efMwb948q56nV69eqFu3Li5duoS9e/cWOFRWdnY23n33XQDAa6+9hrp165a49g4dOiAlJaXI7R5//PEig/V//vMfAMCzzz6LChUqlLgmIqKSYEssEZGV1K4EDRs2tGo81bzc3Nxy+5/OmjWrwO3mzp2LP/74A7Vq1SrWyVaOkJKSgnnz5sHb29uq4biIiGyFIZaIyErqSV0tWrR46Od69tln0bZtW2zevDnftLIA8N///hevv/46DAYDFi9eDF9f34d+TVuYP38+EhISMHHiRNSsWVPrcoioFGJ3AiIiK6kh1nQGrpIyGAxYtGgR1q5dmzve6saNG/Hyyy/j7t27SExMBAC888476NGjx0O/nq2ULVsW7777boF9aomI7I0hlojICllZWTh58iQA27TEqs9j+lz79+9HTEwMfH198cgjj+Dll1/G6NGjbfJatvLKK69oXQIRlXIGpaie+0REpFu1atVCTEwMdu7ciW7dumldDhGRzTDEEhEREZHu8MQuIiIiItIdhlgiIiIi0h2GWCIiIiLSHYZYIiIiItIdhlgiIiIi0h2GWCIiIiLSHYZYIiIiItIdhlgiIiIi0h2GWCIiIiLSHYZYIiIiItIdhlgiIiIi0p3/A8r6gwrBRMIEAAAAAElFTkSuQmCC\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "def cross_ent(prediction, ground_truth):\n", " t = 1 if ground_truth > 0.5 else 0\n", @@ -430,9 +538,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "1.429664938969559" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "class CrossEntropyLoss:\n", " def forward(self,p,y):\n", @@ -466,9 +585,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1.429664938969559\n" + ] + } + ], "source": [ "z = net.forward(train_x[0:10])\n", "p = softmax.forward(z)\n", @@ -579,7 +706,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "metadata": {}, "outputs": [], "source": [ @@ -616,7 +743,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "metadata": {}, "outputs": [], "source": [ @@ -649,16 +776,25 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Training the Model\n", + "## Model Eğitimi\n", "\n", - "Now we are ready to write the **training loop**, which will go through our dataset, and perform the optimization minibatch by minibatch.One complete pass through the dataset is often called **an epoch**:" + "Artık veri kümemiz üzerinden geçecek olan **eğitim döngüsü**nü yazmaya ve minigrup temelli eniyileme işlemini gerçekleştirmeye hazırız. Veri kümesinden tam bir geçişe genellikle **dönem** denir:" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "İlk doğruluk: 0.725\n", + "Nihai doğruluk: 0.825\n" + ] + } + ], "source": [ "lin = Linear(2,2)\n", "softmax = Softmax()\n", @@ -668,7 +804,7 @@ "\n", "pred = np.argmax(lin.forward(train_x),axis=1)\n", "acc = (pred==train_labels).mean()\n", - "print(\"Initial accuracy: \",acc)\n", + "print(\"İlk doğruluk: \",acc)\n", "\n", "batch_size=4\n", "for i in range(0,len(train_x),batch_size):\n", @@ -688,7 +824,7 @@ " \n", "pred = np.argmax(lin.forward(train_x),axis=1)\n", "acc = (pred==train_labels).mean()\n", - "print(\"Final accuracy: \",acc)\n", + "print(\"Nihai doğruluk: \",acc)\n", " " ] }, @@ -696,16 +832,16 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Nice to see how we can increase accuracy of the model from about 50% to around 80% in one epoch.\n", + "Bir dönemde modelin doğruluğunu %50 civarından yaklaşık %80'e nasıl çıkarabileceğimizi görmek güzel.\n", "\n", - "## Network Class\n", + "## Ağ Sınıfı\n", "\n", - "Since in many cases neural network is just a composition of layers, we can build a class that will allow us to stack layers together and make forward and backward passes through them without explicitly programming that logic. We will store the list of layers inside the `Net` class, and use `add()` function to add new layers:" + "Çoğu durumda sinir ağı yalnızca katmanların bir bileşimi olduğundan, bu mantığı açıkça programlamadan katmanları bir araya getirmemize ve bunlar arasında ileri ve geri geçişler yapmamıza izin verecek bir sınıf oluşturabiliriz. Katmanların listesini `Net` (Ağ) sınıfının içinde saklayacağız ve yeni katmanlar eklemek için `add()` (ekle()) işlevini kullanacağız:" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 19, "metadata": { "scrolled": true, "slideshow": { @@ -741,14 +877,24 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "With this `Net` class our model definition and training becomes more neat:" + "Bu `Net` sınıfı ile model tanımımız ve eğitimimiz daha düzenli zarif geliyor:" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 20, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "İlk kayıp=0.6212072429381601, doğruluk=0.6875: \n", + "Nihai kayıp=0.44369925927417986, doğruluk=0.8: \n", + "Test kaybı=0.4767711377257787, doğruluk=0.85: \n" + ] + } + ], "source": [ "net = Net()\n", "net.add(Linear(2,2))\n", @@ -762,7 +908,7 @@ " acc = (pred==y).mean()\n", " return l,acc\n", "\n", - "print(\"Initial loss={}, accuracy={}: \".format(*get_loss_acc(train_x,train_labels)))\n", + "print(\"İlk kayıp={}, doğruluk={}: \".format(*get_loss_acc(train_x,train_labels)))\n", "\n", "def train_epoch(net, train_x, train_labels, loss=CrossEntropyLoss(), batch_size=4, lr=0.1):\n", " for i in range(0,len(train_x),batch_size):\n", @@ -777,24 +923,24 @@ " \n", "train_epoch(net,train_x,train_labels)\n", " \n", - "print(\"Final loss={}, accuracy={}: \".format(*get_loss_acc(train_x,train_labels)))\n", - "print(\"Test loss={}, accuracy={}: \".format(*get_loss_acc(test_x,test_labels)))" + "print(\"Nihai kayıp={}, doğruluk={}: \".format(*get_loss_acc(train_x,train_labels)))\n", + "print(\"Test kaybı={}, doğruluk={}: \".format(*get_loss_acc(test_x,test_labels)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Plotting the Training Process\n", + "## Eğitim Sürecinin Görselleştirilmesi\n", "\n", - "It would be nice to see visually how the network is being trained! We will define a `train_and_plot` function for that. To visualize the state of the network we will use level map, i.e. we will represent different values of the network output using different colors.\n", + "Ağın nasıl eğitildiğini görsel olarak görmek güzel olurdu! Bunun için bir `train_and_plot` (eğit ve çizdir) fonksiyonu tanımlayacağız. Ağın durumunu görselleştirmek için seviye haritası kullanacağız, yani farklı renkler kullanarak ağ çıktısının farklı değerlerini temsil edeceğiz.\n", "\n", - "> Do not worry if you do not understand some of the plotting code below - it is more important to understand the underlying neural network concepts." + "> Aşağıdaki çizim kodlarından bazılarını anlamadıysanız endişelenmeyin - altında yatan sinir ağı kavramlarını anlamak daha önemlidir." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "metadata": { "slideshow": { "slide_type": "skip" @@ -833,7 +979,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 22, "metadata": { "slideshow": { "slide_type": "skip" @@ -845,12 +991,12 @@ "\n", "def plot_decision_boundary(net, fig, ax):\n", " draw_colorbar = True\n", - " # remove previous plot\n", + " # önceki çizimi sildir\n", " while ax.collections:\n", " ax.collections.pop()\n", " draw_colorbar = False\n", "\n", - " # generate countour grid\n", + " # kontur ızgarası oluştur\n", " x_min, x_max = train_x[:, 0].min() - 1, train_x[:, 0].max() + 1\n", " y_min, y_max = train_x[:, 1].min() - 1, train_x[:, 1].max() + 1\n", " xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),\n", @@ -858,12 +1004,12 @@ " grid_points = np.c_[xx.ravel().astype('float32'), yy.ravel().astype('float32')]\n", " n_classes = max(train_labels)+1\n", " while train_x.shape[1] > grid_points.shape[1]:\n", - " # pad dimensions (plot only the first two)\n", + " # boyutları dolgula (yalnızca ilk ikisini çizin)\n", " grid_points = np.c_[grid_points,\n", " np.empty(len(xx.ravel())).astype('float32')]\n", " grid_points[:, -1].fill(train_x[:, grid_points.shape[1]-1].mean())\n", "\n", - " # evaluate predictions\n", + " # tahminleri değerlendir\n", " prediction = np.array(net.forward(grid_points))\n", " # for two classes: prediction difference\n", " if (n_classes == 2):\n", @@ -871,7 +1017,7 @@ " else:\n", " Z = np.array([p.argsort()[-1]/float(n_classes-1) for p in prediction]).reshape(xx.shape)\n", " \n", - " # draw contour\n", + " # konturu çizdir\n", " levels = np.linspace(0, 1, 40)\n", " cs = ax.contourf(xx, yy, Z, alpha=0.4, levels = levels)\n", " if draw_colorbar:\n", @@ -883,7 +1029,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 23, "metadata": { "slideshow": { "slide_type": "skip" @@ -893,27 +1039,39 @@ "source": [ "def plot_training_progress(x, y_data, fig, ax):\n", " styles = ['k--', 'g-']\n", - " # remove previous plot\n", + " # önceki çizimi sildir\n", " while ax.lines:\n", " ax.lines.pop()\n", - " # draw updated lines\n", + " # güncellenmiş doğruları çiz\n", " for i in range(len(y_data)):\n", " ax.plot(x, y_data[i], styles[i])\n", - " ax.legend(ax.lines, ['training accuracy', 'validation accuracy'],\n", + " ax.legend(ax.lines, ['eğitim doğruluğu', 'geçerleme doğruluğu'],\n", " loc='upper center', ncol = 2)" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 24, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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n61bt/LJJ5/w6aefAhAdHd1h+XvuuYcnn3ySAQMG8LOf/Ywf/ehHREVF8ec//xmbzcZll13G3XffzTPPPNPu/kVFRVxyySUsWLCA//u//2P9+vXceuutQWVyc3O57LLLuPfee5k/fz6rV6/mhhtuID4+PhAAXHXVVVRXV/PFF19gNBpZuHAhlZWV7dZ38eLF/OlPf0Kv17NixYquLnGPhFqfcNM0jWZvc9Df1c3VlDeV41Vbm83NBjNpkWnEWGJ6ddSBzWgL+XjXX389Ozfs5KP/fERycjJ33303e7buYfbU2UxOmwzAj3/8Y/bv38+7b79LWloa77//Pr/+ya/ZsmULQ4cOZePGjfxy/i/52c9+xsvPvozBYGDFihWMSxpHQkICd911F8vfW85Lz78U+C4tWLCA6cOnc9ppp9GU0ATA3/74N/782J8ZNGgQMTExlG8rx2a0Berxwgsv8LdH/8bTTz/NxIkTycvL4/rrr2dU+iiuvvpq9nv2A/Dan18L+u48fPPDREVF8cKSFwLfnfeWvBf47nR13PbccMMNbP52M//+4N+kpKRw5513snvL7qDrdtH/XUTBngI+/s/HREVFcfvtt3P7T29n+/btGI1GVq1axR/u+AN//OMfufDCC/n000/5/e9/j17RB47xkf0jSg+UsnbZWj764CP0ej1j08Zi0psYED0gUO7gf/c0e1rQtiFxQ5icNjlwjSemTgwEF4bK1kdkSkQKekXPmm/WsPCmhdx6961cfunlrFm5ht///vch3UeicxKM9GOdzch33nnn8fHHHwf+TkpK6nAG19NOOy3oF+/AgQOprq5uU07TtJDr5nQ6eeKJJ/j888+ZMWMGAIMGDeLrr7/mueee47TTTuPZZ59l2LBhPProowAMHz6crVu38tBDD7V7TKvVSmRkJAaDIaRumdtuu41zzz0XaM2R+NGPfsRnn33GrFmzALj22msDLSvteeaZZxg0aBB/+tOfUBSF4cOHs2XLFv74xz8GyjzxxBOcddZZgX9whg0bxvbt23n00Ue55ppr2LlzJ59++mmgRQZa/+EeNmxYm/NdccUV/OxnP+vycx2N7tQn3Jq9zUQuDs+sk02LmogwdR18NzY28uqrr/LGG29w1llnAfDyyy+TlpYWKLNv3z7efPNNiouLA9tvu+02PvnkE15++WUefvhhHnnkESZP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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "%matplotlib nbagg \n", + "%matplotlib inline\n", "net = Net()\n", "net.add(Linear(2,2))\n", "net.add(Softmax())\n", @@ -929,18 +1087,18 @@ } }, "source": [ - "After running the cell above you should be able to see interactively how the boundary between classes change during training. Note that we have chosen very small learning rate so that we can see how the process happens.\n", + "Yukarıdaki hücreyi çalıştırdıktan sonra, eğitim sırasında sınıflar arasındaki sınırın nasıl değiştiğini etkileşimli olarak görebilmelisiniz. Sürecin nasıl olduğunu görebilmemiz için çok küçük bir öğrenme oranı seçtiğimizi unutmayın.\n", "\n", - "## Multi-Layered Models\n", + "## Çok Katmanlı Modeller\n", "\n", - "The network above has been constructed from several layers, but we still had only one `Linear` layer, which does the actual classification. What happens if we decide to add several such layers?\n", + "Yukarıdaki ağ birkaç katmandan oluşturulmuştur, ancak hala gerçek sınıflandırmayı yapan tek bir `Linear` (doğrusal) katmanımız vardı. Bu tür birkaç katman eklemeye karar verirsek ne olur?\n", "\n", - "Surprisingly, our code will work! Very important thing to note, however, is that in between linear layers we need to have a non-linear **activation function**, such as `tanh`. Without such non-linearity, several linear layers would have the same expressive power as just one layers - because composition of linear functions is also linear!" + "Şaşırtıcı bir şekilde, kodumuz çalışacak! Bununla birlikte, dikkat edilmesi gereken çok önemli bir nokta, doğrusal katmanlar arasında `tanh` gibi doğrusal olmayan bir **etkinleştirme fonksiyonuna** sahip olmamız gerektiğidir. Böyle bir doğrusal olmayanlık olmadan, birkaç doğrusal katman tek bir katmanla aynı ifade gücüne sahip olacaktır - çünkü doğrusal fonksiyonların bileşimi de doğrusaldır!" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 25, "metadata": {}, "outputs": [], "source": [ @@ -957,19 +1115,18 @@ "cell_type": "markdown", "metadata": {}, "source": [ - " Adding several layers make sense, because unlike one-layer network, multi-layered model will be able to accuratley classify sets that are not linearly separable. I.e., a model with several layers will be **reacher**.\n", + "Birkaç katman eklemek anlamlıdır, çünkü tek katmanlı ağdan farklı olarak çok katmanlı model, doğrusal olarak ayrılamayan kümeleri doğru bir şekilde sınıflandırabilecektir. Yani, birkaç katmana sahip bir model **rehber** olacaktır.\n", "\n", - "> It can be demonstrated that with sufficient number of neurons a two-layered model is capable to classifying any convex set of data points, and three-layered network can classify virtually any set.\n", + "> Yeterli sayıda nöronla, iki katmanlı bir modelin herhangi bir dışbükey veri noktası kümesini sınıflandırabileceği ve üç katmanlı ağın hemen hemen her kümeyi sınıflandırabileceği gösterilebilir.\n", "\n", - "Mathematically, multi-layered perceptron would be represented by a more complex function $f_\\theta$ that can be computed in several steps:\n", + "Matematiksel olarak, çok katmanlı algılayıcı, birkaç adımda hesaplanabilen daha karmaşık bir $f_\\theta$ işleviyle temsil edilir:\n", "* $z_1 = W_1\\times x+b_1$\n", "* $z_2 = W_2\\times\\alpha(z_1)+b_2$\n", "* $f = \\sigma(z_2)$\n", "\n", - "Here, $\\alpha$ is a **non-linear activation function**, $\\sigma$ is a softmax function, and $\\theta=\\langle W_1,b_1,W_2,b_2\\rangle$ are parameters.\n", - "\n", - "The gradient descent algorithm would remain the same, but it would be more difficult to calculate gradients. Given the\n", - " chain differentiation rule, we can calculate derivatives as:\n", + "Burada $\\alpha$ bir **doğrusal olmayan etkinleştirme işlevidir**, $\\sigma$ bir softmaks işlevidir ve $\\theta=\\langle W_1,b_1,W_2,b_2\\rangle$ parametrelerdir.\n", + " \n", + "Gradyan inişi algoritması aynı kalacaktır, ancak gradyanları hesaplamak daha zor olacaktır. Zincir türev alma kuralı göz önüne alındığında, türevleri şu şekilde hesaplayabiliriz:\n", "\n", "$$\\begin{align}\n", "\\frac{\\partial\\mathcal{L}}{\\partial W_2} &= \\color{red}{\\frac{\\partial\\mathcal{L}}{\\partial\\sigma}\\frac{\\partial\\sigma}{\\partial z_2}}\\color{black}{\\frac{\\partial z_2}{\\partial W_2}} \\\\\n", @@ -977,14 +1134,14 @@ "\\end{align}\n", "$$\n", "\n", - "Note that the beginning of all those expressions is still the same, and thus we can continue back propagation beyond one linear layers to adjust further weights up the computational graph.\n", + "Tüm bu ifadelerin başlangıcının hala aynı olduğuna ve dolayısıyla hesaplamalı çizgede daha fazla ağırlık ayarlamak için bir doğrusal katmanın ötesine geri yaymaya devam edebileceğimize dikkat edin.\n", "\n", - "Let's now experiment with two-layered network:" + "Şimdi iki katmanlı ağ ile deney yapalım:" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 26, "metadata": {}, "outputs": [], "source": [ @@ -998,13 +1155,24 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 27, "metadata": { "slideshow": { "slide_type": "slide" } }, - "outputs": [], + "outputs": [ + { + "data": { + "image/png": "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lbFO8YSMtz2ppqoq7kBqFvqz6C3j7jbdsmULb775Js899xz5+fl84xvfYM+ePTFjNf75n/+Z+vp6/vCHP1BUVMQzzzzDu9/9bvbv309FRQU1NTW8613v4pOf/CQ//vGP0el0vPLKK9HqxljvpUFf+cpX+P73v8+cOXPIyMhg+/btMW39+c9/zn333cfDDz/MqlWrqK6u5tOf/jRWq5Xbbrstul+y753xHneou+++m1deeYVnnnmGgoICvv71r1NVVRVz3m6//XaOHz/Oc889R3p6Ol/96le54YYbOHToEHq9njfffJPNmzfzne98h/e97328+OKL/Pu///uI5zpx4gR//OMf+ctf/jKtlYrxtkdMgDoDOBwOFVAdDkeqmzIup/pOqWU/LFO5H3XlT1eqvZ5eVVVVtdvdrX7lha+opgdNKvejcj/qbX+6Ta3ZX6N6PJ4RxwES/txwww0x+1osloT7XnHFFTH75uTkxN0vGQMDA6rJZFJ37NgRs/1Tn/qU+pGPfERVVVX96le/qi5ZsiTm/nvvvVcF1N7eyDn59a9/rdrt9uj99913n7pixYq45+KZZ55RVVVV6+rqVED9xS9+Eb3/97//vQqoL730UnTb1q1b1QULFiT8He655x510aJFajgcjm776le/GtO+j370o+q1114b87i7775bXbx4saqqqnr48GEVUHft2hW9/9ixYyqg/vCHP4xp/5133hlznOG/u6qq6jPPPBPz/2L4+bjiiivUL37xizGPuemmm9Tbbrtt3O0ZPH/V1dXRfXp7e1VAfeWVV4afpmkz4BuIvg/O9s+Ab2BcbXQ6naper1f/9Kc/Rbf19fWpFosl+v/hxIkTqqIoanNzc8xj3/Wud6n33HOPqqqq+pGPfES95JJL4p+HcbyXXnnlFRVQn3322Zh9hr8+SktL1d/97ncx+3zrW99S169fr6rqxN87Yx13uP7+ftVgMKh/+MMfotu6u7tVs9kcPW+Dr8s333wzuk9XV5dqNpvVP/7xj6qqquqmTZvU97znPTHH/tjHPjbib4Zer1c7Ojpi9ps1a1bMe1BVVXXFihXqfffdF7099O/K4DkefO+rqqpWV1ergFpXVzfu9tx2223qTTfdFLPPF7/4xRF/hwd5PB710KFDcT8Dzgfj/fyWbpop1j7QzrW/vZYGRwMLshfwj4//gwxTBgBZ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QrIcXEvFrdmwqsREjEAkzUVMvbNQJjV5ychjjz12tZtm+suRI0f49re/jdPp5NFHH83p/I8++igOhyN+GRrKvxeDTPbkUydSKHKJihS7cPV66S2yklI0ieS71RdyL2iF/HqQQFRIliM6EuN6iZIkkk5MVqycyORNXgWsn//857n//vszHtPa2so3vvENDh48iFab3OSqu7ubj370o/z4xz9O+VitVrvgMTLFpZQishxk01tkPquxt8i1RD7FrJB7QStcFZILuRW0wlUhOV/cgtZEYkISmwR8rRS3ZoNcAHttk5eMWK1WrFbrosd961vf4hvf+Eb8+sjICHfddRfPPvssN9xwQz5PLVNESiEi476enKMimRjwnM2pcHV+ima19xZZzSmaRLraGzl6Kf91xoQkV3LdYQPLLyQQlZLrUUhiyGJy7VHUmpGWlha2bNkSv6xbF/1g7+jooKlJfsOsFEpVsJovhShczZVrrbfISk3RzCffdA0sX0FrjOVM2cD1mbZJRapeJicvyE3PVhtyB9brnFIUrMbINSqyGKu1t0gqVnrhaq5t2POhEMWskF9B60reYZPI9VbcuhgxKdmyXAXG4XDmi0zWLKuMtLa2IkkSO3bsWM6nlUnDaqsTWUrh6kruLZJNimYlFq4WY1tvKpYaHYFrW0jg2u5JInN9IEdGrlNKLSKF3s6bjnwKV+dTyN4iSdfTFK6m43opXE0kFh2RhWRxZCGRWc3IMnIdU+qIyEoqXE2kmL1F5jc6k3uLLE4h0jX5FJcutQdJqYRkx8am676ORGb1IcvIdUipC1bzjYoUs3BV7i2y8llKdARyL2iFpfUggdIICchRkuVCikQyXnLlO9/5Dm1tbeh0Orq6unjjjTcyHv/aa6/R1dWFTqejvb2d733ve/m+lJIjy8h1RikLVhMpdFQkFdkUrs6nkL1F5lOs3iLZREUKSbHawGeiUMWskHvxrSwkMsvBs88+y5e+9CX++q//muPHj3PLLbdw9913Mzi4MOIKcPnyZd7znvdwyy23cPz4cb72ta/x53/+5zz33HPLvPLCIMvIdUSp60SgeFGRfAtXC9lbZD6Z2r/D8hauHhmwreqoSIxCREcgv91AspDIFJO///u/51Of+hQPPfQQGzdu5Jvf/CbNzc1897vfTXn89773PVpaWvjmN7/Jxo0beeihh/jkJz+5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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "res = train_and_plot(30,net,lr=0.01)" ] @@ -1017,23 +1185,23 @@ } }, "source": [ - "## Why Not Always Use Multi-Layered Model?\n", + "## Neden Her Zaman Çok Katmanlı Model Kullanmayız?\n", "\n", - "We have seen that multi-layered model is more *powerful* and *expressive*, than one-layered one. You may be wondering why don't we always use many-layered model. The answer to this question is **overfitting**.\n", + "Çok katmanlı modelin tek katmanlı modelden daha *güçlü* ve *ifade edici* olduğunu gördük. Neden her zaman çok katmanlı model kullanmadığımızı merak ediyor olabilirsiniz. Bu sorunun cevabı **aşırı öğrenme**dir.\n", "\n", - "We will deal with this term more in a later sections, but the idea is the following: **the more powerful the model is, the better it can approximate training data, and the more data it needs to properly generalize** for the new data it has not seen before.\n", + "Bu terimi sonraki bölümlerde daha fazla ele alacağız, ancak fikir şudur: **model ne kadar güçlüyse, eğitim verilerine o kadar iyi yaklaşıklayabilir ve** daha önce görmediği yeni veriler için **uygun şekilde genelleştirmek için o kadar fazla veriye ihtiyaç duyar**.\n", "\n", - "**A linear model:**\n", - "* We are likely to get high training loss - so-called **underfitting**, when the model does not have enough power to correctly separate all data. \n", - "* Valiadation loss and training loss are more or less the same. The model is likely to generalize well to test data.\n", + "**Doğrusal bir model:**\n", + "* Modelin tüm verileri doğru bir şekilde ayırmak için yeterli gücü olmadığında, **yetersiz öğrenme** olarak adlandırılan yüksek eğitim kaybı yaşamamız olasıdır.\n", + "* Geçerleme kaybı ve eğitim kaybı aşağı yukarı aynıdır. Modelin verileri test etmede iyi bir şekilde genellemesi muhtemeldir.\n", "\n", - "**Complex multi-layered model**\n", - "* Low training loss - the model can approximate training data well, because it has enough expressive power.\n", - "* Validation loss can be much higher than training loss and can start to increase during training - this is because the model \"memorizes\" training points, and loses the \"overall picture\"\n", + "**Karmaşık çok katmanlı model**\n", + "* Düşük eğitim kaybı olur - model, yeterli ifade gücüne sahip olduğu için eğitim verilerine iyi bir şekilde yaklaşıklayabilir.\n", + "* Geçerleme kaybı, eğitim kaybından çok daha yüksek olabilir ve eğitim sırasında artmaya başlayabilir - bunun nedeni, modelin eğitim noktalarını \"ezberlemesi\" ve \"genel resmi\" kaybetmesidir.\n", "\n", - "![Overfitting](images/overfit.png)\n", + "![Aşırı Öğrenme](../images/overfit.png)\n", "\n", - "> On this picture, `x` stands for training data, `o` - validation data. Left - linear model (one-layer), it approximates the nature of the data pretty well. Right - overfitted model, the model perfectly well approximates training data, but stops making sense with any other data (validation error is very high)" + "> Bu resimde, `x` eğitim verisi, `o` - geçerleme verisi anlamına gelir. Sol - doğrusal model (tek katmanlı), verilerin doğasına oldukça iyi yaklaşıklar. Sağ - aşırı öğrenen model, model eğitim verilerine mükemmel bir şekilde yaklaşır, ancak diğer verilerle bir anlam ifade etmez (geçerleme hatası çok yüksektir)." ] }, { @@ -1044,27 +1212,27 @@ } }, "source": [ - "## Takeaways\n", - "\n", - "* Simple models (fewer layers, fewer neurons) with low number of parameters (\"low capacity\") are less likely to overfit\n", - "* More complex models (more layers, more neurons on each layer, high capacity) are likely to overfit. We need to monitor validation error to make sure it does not start to rise with further training\n", - "* More complex models need more data to train on.\n", - "* You can solve overfitting problem by either:\n", - " - simplifying your model\n", - " - increasing the amount of training data\n", - "* **Bias-variance trade-off** is a term that shows that you need to get the compromise\n", - " - between power of the model and amount of data,\n", - " - between overfittig and underfitting\n", - "* There is not single recipe on how many layers of parameters you need - the best way is to experiment" + "## Ana Fikirler\n", + "\n", + "* Düşük sayıda parametreye (\"düşük kapasite\") sahip basit modellerin (daha az katman, daha az nöron) fazla öğrenme olasılığı daha düşüktür.\n", + "* Daha karmaşık modellerin (daha fazla katman, her katmanda daha fazla nöron, yüksek kapasite) olması muhtemeldir. Daha fazla eğitimle yükselmeye başlamadığından emin olmak için geçerleme hatasını izlememiz gerekiyor.\n", + "* Daha karmaşık modeller eğitime devam etmek için daha fazla veriye ihtiyaç duyar.\n", + "* Aşırı öğrenme sorununu aşağıdakilerden biri ile çözebilirsiniz:\n", + " - modelinizi basitleştirme\n", + " - eğitim verilerinin miktarını artırmak\n", + "* **Yanlılık-değişinti ödünleşmesi**, uzlaşmayı elde etmeniz gerektiğini gösteren bir terimdir:\n", + " - modelin gücü ile veri miktarı arasında\n", + " - aşırı ile yetersiz öğrenme arasında\n", + "* Kaç tane parametre katmanına ihtiyacınız olduğuna dair tek bir tarif yoktur - en iyi yol denemektir." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Credits\n", + "## Katkıda Bulunanlar\n", "\n", - "This notebook is a part of [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners), and has been prepared by [Dmitry Soshnikov](http://soshnikov.com). It is inspired by Neural Network Workshop at Microsoft Research Cambridge. Some code and illustrative materials are taken from presentations by [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft.com/en-us/research/people/matjoh/) and [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/), and from [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop) repository." + "Bu defter, [Yeni Başlayanlar için YZ Müfredatı](http://github.com/microsoft/ai-for-beginners)'nın bir parçasıdır ve [Dmitry Soshnikov](http://soshnikov.com) tarafından hazırlanmıştır. Microsoft Research Cambridge'deki Sinir Ağı Çalıştay'ından ilham almıştır. Bazı kodlar ve açıklayıcı materyaller [Katja Hoffmann](https://www.microsoft.com/en-us/research/people/kahofman/), [Matthew Johnson](https://www.microsoft. com/en-us/research/people/matjoh/) ve [Ryoto Tomioka](https://www.microsoft.com/en-us/research/people/ryoto/) ve [NeuroWorkshop](http:/ /github.com/shwars/NeuroWorkshop) deposundan alınmıştır." ] } ], From 8f4b03c4f1e96ab2b17f7319ea30693ac3492696 Mon Sep 17 00:00:00 2001 From: semercim Date: Mon, 3 Oct 2022 14:03:39 +0200 Subject: [PATCH 26/38] The Turkish translation of lesson 5 --- .../05-Frameworks/translations/README.tr.md | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 lessons/3-NeuralNetworks/05-Frameworks/translations/README.tr.md diff --git a/lessons/3-NeuralNetworks/05-Frameworks/translations/README.tr.md b/lessons/3-NeuralNetworks/05-Frameworks/translations/README.tr.md new file mode 100644 index 00000000..c60ec198 --- /dev/null +++ b/lessons/3-NeuralNetworks/05-Frameworks/translations/README.tr.md @@ -0,0 +1,44 @@ +# Sinir Ağları Çerçeveleri + +Daha önce öğrendiğimiz gibi, sinir ağlarını verimli bir şekilde eğitebilmek için iki şey yapmamız gerekiyor: + +* Tensörler üzerinde çalışmak için, örn. sigmoid veya softmaks gibi bazı işlevleri çarpmak, toplamak ve hesaplamak +* Gradyan inişi eniyileme gerçekleştirmek için tüm ifadelerin gradyanlarını hesaplamak + +## [Ders öncesi sınavı](https://red-field-0a6ddfd03.1.azurestaticapps.net/quiz/105) + +`numpy` kitaplığı ilk kısmı yapabilirken, gradyanları hesaplamak için bazı mekanizmalara ihtiyacımız var. Önceki bölümde geliştirdiğimiz [çerçevemiz](../../04-OwnFramework/translations/OwnFramework.tr.ipynb)de tüm türev fonksiyonlarını geri yayan `backward` (geri) yöntemi içinde elle programlamamız gerekiyordu. İdeal olarak, bir çerçeve bize tanımlayabileceğimiz *herhangi bir ifadenin* gradyanlarını hesaplama fırsatı vermelidir. + +Bir diğer önemli şey de hesaplamaları GPU'da veya [TPU](https://en.wikipedia.org/wiki/Tensor_Processing_Unit) gibi diğer özelleştirilmiş işlem birimlerinde gerçekleştirebilmektir. Derin sinir ağı eğitimi *çok* hesaplama gerektirir ve bu hesaplamaları GPU'larda paralel hale getirebilmek çok önemlidir. + +> ✅ 'Paralelleştirme' terimi, hesaplamaları birden fazla cihaza dağıtmak anlamına gelir. + +Şu anda en popüler iki sinirsel çerçeve şunlardır: [TensorFlow](http://TensorFlow.org) ve [PyTorch](https://pytorch.org/). Her ikisi de hem CPU hem de GPU üzerinde tensörlerle çalışmak için düşük düzey bir API sağlar. Düşük düzey API'nin yanı sıra, buna uygun olarak [Keras](https://keras.io/) ve [PyTorch Lightning](https://pytorchlightning.ai/) olarak adlandırılan daha üst düzey API de vardır. + +Düşük düzey API | [TensorFlow](http://TensorFlow.org) | [PyTorch](https://pytorch.org/) +--------------|-------------------------------------|-------------------------------- +Üst düzey API| [Keras](https://keras.io/) | [PyTorch Lightning](https://pytorchlightning.ai/) + +**Düşük düzey API'ler** her iki çerçevede de **hesaplamalı çizgeler** oluşturmanıza olanak tanır. Bu çizge, verilen girdi parametreleriyle çıktının (genellikle kayıp işlevi) nasıl hesaplanacağını tanımlar ve varsa GPU'da hesaplama için gönderilebilir. Bu hesaplama çizgesinde türev almak ve daha sonra model parametrelerini optimize etmede kullanılabilecek gradyanları hesaplamak için işlevler vardır. + +**Üst düzey API'ler** sinir ağlarını bir **katmanlar dizisi** olarak kabul eder ve sinir ağlarının çoğunu oluşturmayı çok daha kolay hale getirir. Modeli eğitmek genellikle verilerin hazırlanmasını ve ardından işi yapmak için bir `fit` (oturt) işlevinin çağrılmasını gerektirir. + +Üst düzey API, çok fazla ayrıntı hakkında endişelenmeden tipik sinir ağlarını çok hızlı bir şekilde oluşturmanıza olanak tanır. Aynı zamanda, düşük seviyeli API, eğitim süreci üzerinde çok daha fazla kontrol sunar ve bu nedenle, yeni sinir ağı mimarileriyle uğraşırken araştırmalarda çok kullanılırlar. + +Her iki API'yi birlikte kullanabileceğinizi anlamak da önemlidir, örn. düşük seviyeli API kullanarak kendi ağ katmanı mimarinizi geliştirebilir ve ardından bunu yüksek seviyeli API ile oluşturulmuş ve eğitilmiş daha büyük ağ içinde kullanabilirsiniz. Ayrıca bir dizi katman olarak üst düzey API'yi kullanarak bir ağ tanımlayabilir ve ardından eniyilemeyi gerçekleştirmek için kendi düşük düzeyli eğitim döngünüzü kullanabilirsiniz. Her iki API de aynı basit temel kavramları kullanır ve birlikte iyi çalışacak şekilde tasarlanmışlardır. + +## Öğrenme + +Bu kursta, içeriğin çoğunu hem PyTorch hem de TensorFlow için sunuyoruz. Tercih ettiğiniz çerçeveyi seçebilir ve yalnızca ilgili not defterlerini inceleyebilirsiniz. Hangi çerçeveyi seçeceğinizden emin değilseniz, internette **PyTorch ve TensorFlow** ile ilgili bazı tartışmaları okuyun. Daha iyi anlamak için her iki çerçeveye de bakabilirsiniz. + +Mümkün olduğunda, basitlik için üst düzey API'leri kullanacağız. Ancak, sinir ağlarının sıfırdan nasıl çalıştığını anlamanın önemli olduğuna inanıyoruz, bu nedenle başlangıçta düşük seviye API ve tensörlerle çalışmaya başlıyoruz. Ancak, hızlı ilerlemek istiyorsanız ve bu ayrıntıları öğrenmek için çok fazla zaman harcamak istemiyorsanız, bunları atlayabilir ve doğrudan üst düzey API not defterlerine geçebilirsiniz. + +## ✍️ Alıştırmalar: Çerçeveler + +Öğrenmenize aşağıdaki not defterlerinde devam edin: + +Düşük düzey API | [TensorFlow+Keras Not Defteri](IntroKerasTF.tr.ipynb) | [PyTorch](IntroPyTorch.tr.ipynb) +--------------|-------------------------------------|-------------------------------- +Üst düzey API| [Keras](IntroKeras.tr.pynb) | *PyTorch Lightning* + +Çerçevelere hakim olduktan sonra, [aşırı öğrenme](Overfitting.tr.md) kavramını tekrarlayalım. \ No newline at end of file From fa21ee02321fee387ef20ce2014cc770fc980748 Mon Sep 17 00:00:00 2001 From: semercim Date: Tue, 4 Oct 2022 22:37:45 +0200 Subject: [PATCH 27/38] WIP: the Turkish translation of lesson 5 --- .../04-OwnFramework/OwnFramework.ipynb | 5862 +---------------- .../05-Frameworks/IntroKeras.ipynb | 1396 ++-- 2 files changed, 709 insertions(+), 6549 deletions(-) diff --git a/lessons/3-NeuralNetworks/04-OwnFramework/OwnFramework.ipynb b/lessons/3-NeuralNetworks/04-OwnFramework/OwnFramework.ipynb index babe2ebd..15b791d4 100644 --- a/lessons/3-NeuralNetworks/04-OwnFramework/OwnFramework.ipynb +++ b/lessons/3-NeuralNetworks/04-OwnFramework/OwnFramework.ipynb @@ -106,980 +106,7 @@ "outputs": [ { "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "/* global mpl */\n", - "window.mpl = {};\n", - "\n", - "mpl.get_websocket_type = function () {\n", - " if (typeof WebSocket !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof MozWebSocket !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert(\n", - " 'Your browser does not have WebSocket support. ' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.'\n", - " );\n", - " }\n", - "};\n", - "\n", - "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = this.ws.binaryType !== undefined;\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById('mpl-warnings');\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent =\n", - " 'This browser does not support binary websocket messages. ' +\n", - " 'Performance may be slow.';\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = document.createElement('div');\n", - " this.root.setAttribute('style', 'display: inline-block');\n", - " this._root_extra_style(this.root);\n", - "\n", - " parent_element.appendChild(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message('supports_binary', { value: fig.supports_binary });\n", - " fig.send_message('send_image_mode', {});\n", - " if (fig.ratio !== 1) {\n", - " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", - " }\n", - " fig.send_message('refresh', {});\n", - " };\n", - "\n", - " this.imageObj.onload = function () {\n", - " if (fig.image_mode === 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function () {\n", - " fig.ws.close();\n", - " };\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "};\n", - "\n", - "mpl.figure.prototype._init_header = function () {\n", - " var titlebar = document.createElement('div');\n", - " titlebar.classList =\n", - " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", - " var titletext = document.createElement('div');\n", - " titletext.classList = 'ui-dialog-title';\n", - " titletext.setAttribute(\n", - " 'style',\n", - " 'width: 100%; text-align: center; padding: 3px;'\n", - " );\n", - " titlebar.appendChild(titletext);\n", - " this.root.appendChild(titlebar);\n", - " this.header = titletext;\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._init_canvas = function () {\n", - " var fig = this;\n", - "\n", - " var canvas_div = (this.canvas_div = document.createElement('div'));\n", - " canvas_div.setAttribute(\n", - " 'style',\n", - " 'border: 1px solid #ddd;' +\n", - " 'box-sizing: content-box;' +\n", - " 'clear: both;' +\n", - " 'min-height: 1px;' +\n", - " 'min-width: 1px;' +\n", - " 'outline: 0;' +\n", - " 'overflow: hidden;' +\n", - " 'position: relative;' +\n", - " 'resize: both;'\n", - " );\n", - "\n", - " function on_keyboard_event_closure(name) {\n", - " return function (event) {\n", - " return fig.key_event(event, name);\n", - " };\n", - " }\n", - "\n", - " canvas_div.addEventListener(\n", - " 'keydown',\n", - " on_keyboard_event_closure('key_press')\n", - " );\n", - " canvas_div.addEventListener(\n", - " 'keyup',\n", - " on_keyboard_event_closure('key_release')\n", - " );\n", - "\n", - " this._canvas_extra_style(canvas_div);\n", - " this.root.appendChild(canvas_div);\n", - "\n", - " var canvas = (this.canvas = document.createElement('canvas'));\n", - " canvas.classList.add('mpl-canvas');\n", - " canvas.setAttribute('style', 'box-sizing: content-box;');\n", - "\n", - " this.context = canvas.getContext('2d');\n", - "\n", - " var backingStore =\n", - " this.context.backingStorePixelRatio ||\n", - " this.context.webkitBackingStorePixelRatio ||\n", - " this.context.mozBackingStorePixelRatio ||\n", - " this.context.msBackingStorePixelRatio ||\n", - " this.context.oBackingStorePixelRatio ||\n", - " this.context.backingStorePixelRatio ||\n", - " 1;\n", - "\n", - " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", - " 'canvas'\n", - " ));\n", - " rubberband_canvas.setAttribute(\n", - " 'style',\n", - " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", - " );\n", - "\n", - " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", - " if (this.ResizeObserver === undefined) {\n", - " if (window.ResizeObserver !== undefined) {\n", - " this.ResizeObserver = window.ResizeObserver;\n", - " } else {\n", - " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", - " this.ResizeObserver = obs.ResizeObserver;\n", - " }\n", - " }\n", - "\n", - " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", - " var nentries = entries.length;\n", - " for (var i = 0; i < nentries; i++) {\n", - " var entry = entries[i];\n", - " var width, height;\n", - " if (entry.contentBoxSize) {\n", - " if (entry.contentBoxSize instanceof Array) {\n", - " // Chrome 84 implements new version of spec.\n", - " width = entry.contentBoxSize[0].inlineSize;\n", - " height = entry.contentBoxSize[0].blockSize;\n", - " } else {\n", - " // Firefox implements old version of spec.\n", - " width = entry.contentBoxSize.inlineSize;\n", - " height = entry.contentBoxSize.blockSize;\n", - " }\n", - " } else {\n", - " // Chrome <84 implements even older version of spec.\n", - " width = entry.contentRect.width;\n", - " height = entry.contentRect.height;\n", - " }\n", - "\n", - " // Keep the size of the canvas and rubber band canvas in sync with\n", - " // the canvas container.\n", - " if (entry.devicePixelContentBoxSize) {\n", - " // Chrome 84 implements new version of spec.\n", - " canvas.setAttribute(\n", - " 'width',\n", - " entry.devicePixelContentBoxSize[0].inlineSize\n", - " );\n", - " canvas.setAttribute(\n", - " 'height',\n", - " entry.devicePixelContentBoxSize[0].blockSize\n", - " );\n", - " } else {\n", - " canvas.setAttribute('width', width * fig.ratio);\n", - " canvas.setAttribute('height', height * fig.ratio);\n", - " }\n", - " canvas.setAttribute(\n", - " 'style',\n", - " 'width: ' + width + 'px; height: ' + height + 'px;'\n", - " );\n", - "\n", - " rubberband_canvas.setAttribute('width', width);\n", - " rubberband_canvas.setAttribute('height', height);\n", - "\n", - " // And update the size in Python. We ignore the initial 0/0 size\n", - " // that occurs as the element is placed into the DOM, which should\n", - " // otherwise not happen due to the minimum size styling.\n", - " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", - " fig.request_resize(width, height);\n", - " }\n", - " }\n", - " });\n", - " this.resizeObserverInstance.observe(canvas_div);\n", - "\n", - " function on_mouse_event_closure(name) {\n", - " return function (event) {\n", - " return fig.mouse_event(event, name);\n", - " };\n", - " }\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mousedown',\n", - " on_mouse_event_closure('button_press')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseup',\n", - " on_mouse_event_closure('button_release')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'dblclick',\n", - " on_mouse_event_closure('dblclick')\n", - " );\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband_canvas.addEventListener(\n", - " 'mousemove',\n", - " on_mouse_event_closure('motion_notify')\n", - " );\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseenter',\n", - " on_mouse_event_closure('figure_enter')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseleave',\n", - " on_mouse_event_closure('figure_leave')\n", - " );\n", - "\n", - " canvas_div.addEventListener('wheel', function (event) {\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " on_mouse_event_closure('scroll')(event);\n", - " });\n", - "\n", - " canvas_div.appendChild(canvas);\n", - " canvas_div.appendChild(rubberband_canvas);\n", - "\n", - " this.rubberband_context = rubberband_canvas.getContext('2d');\n", - " this.rubberband_context.strokeStyle = '#000000';\n", - "\n", - " this._resize_canvas = function (width, height, forward) {\n", - " if (forward) {\n", - " canvas_div.style.width = width + 'px';\n", - " canvas_div.style.height = height + 'px';\n", - " }\n", - " };\n", - "\n", - " // Disable right mouse context menu.\n", - " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", - " event.preventDefault();\n", - " return false;\n", - " });\n", - "\n", - " function set_focus() {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'mpl-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " continue;\n", - " }\n", - "\n", - " var button = (fig.buttons[name] = document.createElement('button'));\n", - " button.classList = 'mpl-widget';\n", - " button.setAttribute('role', 'button');\n", - " button.setAttribute('aria-disabled', 'false');\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - "\n", - " var icon_img = document.createElement('img');\n", - " icon_img.src = '_images/' + image + '.png';\n", - " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", - " icon_img.alt = tooltip;\n", - " button.appendChild(icon_img);\n", - "\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " var fmt_picker = document.createElement('select');\n", - " fmt_picker.classList = 'mpl-widget';\n", - " toolbar.appendChild(fmt_picker);\n", - " this.format_dropdown = fmt_picker;\n", - "\n", - " for (var ind in mpl.extensions) {\n", - " var fmt = mpl.extensions[ind];\n", - " var option = document.createElement('option');\n", - " option.selected = fmt === mpl.default_extension;\n", - " option.innerHTML = fmt;\n", - " fmt_picker.appendChild(option);\n", - " }\n", - "\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "};\n", - "\n", - "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", - " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", - " // which will in turn request a refresh of the image.\n", - " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", - "};\n", - "\n", - "mpl.figure.prototype.send_message = function (type, properties) {\n", - " properties['type'] = type;\n", - " properties['figure_id'] = this.id;\n", - " this.ws.send(JSON.stringify(properties));\n", - "};\n", - "\n", - "mpl.figure.prototype.send_draw_message = function () {\n", - " if (!this.waiting) {\n", - " this.waiting = true;\n", - " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " var format_dropdown = fig.format_dropdown;\n", - " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", - " fig.ondownload(fig, format);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", - " var size = msg['size'];\n", - " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", - " fig._resize_canvas(size[0], size[1], msg['forward']);\n", - " fig.send_message('refresh', {});\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", - " var x0 = msg['x0'] / fig.ratio;\n", - " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", - " var x1 = msg['x1'] / fig.ratio;\n", - " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", - " x0 = Math.floor(x0) + 0.5;\n", - " y0 = Math.floor(y0) + 0.5;\n", - " x1 = Math.floor(x1) + 0.5;\n", - " y1 = Math.floor(y1) + 0.5;\n", - " var min_x = Math.min(x0, x1);\n", - " var min_y = Math.min(y0, y1);\n", - " var width = Math.abs(x1 - x0);\n", - " var height = Math.abs(y1 - y0);\n", - "\n", - " fig.rubberband_context.clearRect(\n", - " 0,\n", - " 0,\n", - " fig.canvas.width / fig.ratio,\n", - " fig.canvas.height / fig.ratio\n", - " );\n", - "\n", - " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", - " // Updates the figure title.\n", - " fig.header.textContent = msg['label'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", - " var cursor = msg['cursor'];\n", - " switch (cursor) {\n", - " case 0:\n", - " cursor = 'pointer';\n", - " break;\n", - " case 1:\n", - " cursor = 'default';\n", - " break;\n", - " case 2:\n", - " cursor = 'crosshair';\n", - " break;\n", - " case 3:\n", - " cursor = 'move';\n", - " break;\n", - " }\n", - " fig.rubberband_canvas.style.cursor = cursor;\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_message = function (fig, msg) {\n", - " fig.message.textContent = msg['message'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", - " // Request the server to send over a new figure.\n", - " fig.send_draw_message();\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", - " fig.image_mode = msg['mode'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", - " for (var key in msg) {\n", - " if (!(key in fig.buttons)) {\n", - " continue;\n", - " }\n", - " fig.buttons[key].disabled = !msg[key];\n", - " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", - " if (msg['mode'] === 'PAN') {\n", - " fig.buttons['Pan'].classList.add('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " } else if (msg['mode'] === 'ZOOM') {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.add('active');\n", - " } else {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Called whenever the canvas gets updated.\n", - " this.send_message('ack', {});\n", - "};\n", - "\n", - "// A function to construct a web socket function for onmessage handling.\n", - "// Called in the figure constructor.\n", - "mpl.figure.prototype._make_on_message_function = function (fig) {\n", - " return function socket_on_message(evt) {\n", - " if (evt.data instanceof Blob) {\n", - " var img = evt.data;\n", - " if (img.type !== 'image/png') {\n", - " /* FIXME: We get \"Resource interpreted as Image but\n", - " * transferred with MIME type text/plain:\" errors on\n", - " * Chrome. But how to set the MIME type? It doesn't seem\n", - " * to be part of the websocket stream */\n", - " img.type = 'image/png';\n", - " }\n", - "\n", - " /* Free the memory for the previous frames */\n", - " if (fig.imageObj.src) {\n", - " (window.URL || window.webkitURL).revokeObjectURL(\n", - " fig.imageObj.src\n", - " );\n", - " }\n", - "\n", - " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", - " img\n", - " );\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " } else if (\n", - " typeof evt.data === 'string' &&\n", - " evt.data.slice(0, 21) === 'data:image/png;base64'\n", - " ) {\n", - " fig.imageObj.src = evt.data;\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " }\n", - "\n", - " var msg = JSON.parse(evt.data);\n", - " var msg_type = msg['type'];\n", - "\n", - " // Call the \"handle_{type}\" callback, which takes\n", - " // the figure and JSON message as its only arguments.\n", - " try {\n", - " var callback = fig['handle_' + msg_type];\n", - " } catch (e) {\n", - " console.log(\n", - " \"No handler for the '\" + msg_type + \"' message type: \",\n", - " msg\n", - " );\n", - " return;\n", - " }\n", - "\n", - " if (callback) {\n", - " try {\n", - " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", - " callback(fig, msg);\n", - " } catch (e) {\n", - " console.log(\n", - " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", - " e,\n", - " e.stack,\n", - " msg\n", - " );\n", - " }\n", - " }\n", - " };\n", - "};\n", - "\n", - "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", - "mpl.findpos = function (e) {\n", - " //this section is from http://www.quirksmode.org/js/events_properties.html\n", - " var targ;\n", - " if (!e) {\n", - " e = window.event;\n", - " }\n", - " if (e.target) {\n", - " targ = e.target;\n", - " } else if (e.srcElement) {\n", - " targ = e.srcElement;\n", - " }\n", - " if (targ.nodeType === 3) {\n", - " // defeat Safari bug\n", - " targ = targ.parentNode;\n", - " }\n", - "\n", - " // pageX,Y are the mouse positions relative to the document\n", - " var boundingRect = targ.getBoundingClientRect();\n", - " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", - " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", - "\n", - " return { x: x, y: y };\n", - "};\n", - "\n", - "/*\n", - " * return a copy of an object with only non-object keys\n", - " * we need this to avoid circular references\n", - " * http://stackoverflow.com/a/24161582/3208463\n", - " */\n", - "function simpleKeys(original) {\n", - " return Object.keys(original).reduce(function (obj, key) {\n", - " if (typeof original[key] !== 'object') {\n", - " obj[key] = original[key];\n", - " }\n", - " return obj;\n", - " }, {});\n", - "}\n", - "\n", - "mpl.figure.prototype.mouse_event = function (event, name) {\n", - " var canvas_pos = mpl.findpos(event);\n", - "\n", - " if (name === 'button_press') {\n", - " this.canvas.focus();\n", - " this.canvas_div.focus();\n", - " }\n", - "\n", - " var x = canvas_pos.x * this.ratio;\n", - " var y = canvas_pos.y * this.ratio;\n", - "\n", - " this.send_message(name, {\n", - " x: x,\n", - " y: y,\n", - " button: event.button,\n", - " step: event.step,\n", - " guiEvent: simpleKeys(event),\n", - " });\n", - "\n", - " /* This prevents the web browser from automatically changing to\n", - " * the text insertion cursor when the button is pressed. We want\n", - " * to control all of the cursor setting manually through the\n", - " * 'cursor' event from matplotlib */\n", - " event.preventDefault();\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", - " // Handle any extra behaviour associated with a key event\n", - "};\n", - "\n", - "mpl.figure.prototype.key_event = function (event, name) {\n", - " // Prevent repeat events\n", - " if (name === 'key_press') {\n", - " if (event.key === this._key) {\n", - " return;\n", - " } else {\n", - " this._key = event.key;\n", - " }\n", - " }\n", - " if (name === 'key_release') {\n", - " this._key = null;\n", - " }\n", - "\n", - " var value = '';\n", - " if (event.ctrlKey && event.key !== 'Control') {\n", - " value += 'ctrl+';\n", - " }\n", - " else if (event.altKey && event.key !== 'Alt') {\n", - " value += 'alt+';\n", - " }\n", - " else if (event.shiftKey && event.key !== 'Shift') {\n", - " value += 'shift+';\n", - " }\n", - "\n", - " value += 'k' + event.key;\n", - "\n", - " this._key_event_extra(event, name);\n", - "\n", - " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", - " if (name === 'download') {\n", - " this.handle_save(this, null);\n", - " } else {\n", - " this.send_message('toolbar_button', { name: name });\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", - " this.message.textContent = tooltip;\n", - "};\n", - "\n", - "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", - "// prettier-ignore\n", - "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", - "\n", - "mpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", - "\n", - "mpl.default_extension = \"png\";/* global mpl */\n", - "\n", - "var comm_websocket_adapter = function (comm) {\n", - " // Create a \"websocket\"-like object which calls the given IPython comm\n", - " // object with the appropriate methods. Currently this is a non binary\n", - " // socket, so there is still some room for performance tuning.\n", - " var ws = {};\n", - "\n", - " ws.binaryType = comm.kernel.ws.binaryType;\n", - " ws.readyState = comm.kernel.ws.readyState;\n", - " function updateReadyState(_event) {\n", - " if (comm.kernel.ws) {\n", - " ws.readyState = comm.kernel.ws.readyState;\n", - " } else {\n", - " ws.readyState = 3; // Closed state.\n", - " }\n", - " }\n", - " comm.kernel.ws.addEventListener('open', updateReadyState);\n", - " comm.kernel.ws.addEventListener('close', updateReadyState);\n", - " comm.kernel.ws.addEventListener('error', updateReadyState);\n", - "\n", - " ws.close = function () {\n", - " comm.close();\n", - " };\n", - " ws.send = function (m) {\n", - " //console.log('sending', m);\n", - " comm.send(m);\n", - " };\n", - " // Register the callback with on_msg.\n", - " comm.on_msg(function (msg) {\n", - " //console.log('receiving', msg['content']['data'], msg);\n", - " var data = msg['content']['data'];\n", - " if (data['blob'] !== undefined) {\n", - " data = {\n", - " data: new Blob(msg['buffers'], { type: data['blob'] }),\n", - " };\n", - " }\n", - " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", - " ws.onmessage(data);\n", - " });\n", - " return ws;\n", - "};\n", - "\n", - "mpl.mpl_figure_comm = function (comm, msg) {\n", - " // This is the function which gets called when the mpl process\n", - " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", - "\n", - " var id = msg.content.data.id;\n", - " // Get hold of the div created by the display call when the Comm\n", - " // socket was opened in Python.\n", - " var element = document.getElementById(id);\n", - " var ws_proxy = comm_websocket_adapter(comm);\n", - "\n", - " function ondownload(figure, _format) {\n", - " window.open(figure.canvas.toDataURL());\n", - " }\n", - "\n", - " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", - "\n", - " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", - " // web socket which is closed, not our websocket->open comm proxy.\n", - " ws_proxy.onopen();\n", - "\n", - " fig.parent_element = element;\n", - " fig.cell_info = mpl.find_output_cell(\"
\");\n", - " if (!fig.cell_info) {\n", - " console.error('Failed to find cell for figure', id, fig);\n", - " return;\n", - " }\n", - " fig.cell_info[0].output_area.element.on(\n", - " 'cleared',\n", - " { fig: fig },\n", - " fig._remove_fig_handler\n", - " );\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_close = function (fig, msg) {\n", - " var width = fig.canvas.width / fig.ratio;\n", - " fig.cell_info[0].output_area.element.off(\n", - " 'cleared',\n", - " fig._remove_fig_handler\n", - " );\n", - " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", - "\n", - " // Update the output cell to use the data from the current canvas.\n", - " fig.push_to_output();\n", - " var dataURL = fig.canvas.toDataURL();\n", - " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", - " // the notebook keyboard shortcuts fail.\n", - " IPython.keyboard_manager.enable();\n", - " fig.parent_element.innerHTML =\n", - " '';\n", - " fig.close_ws(fig, msg);\n", - "};\n", - "\n", - "mpl.figure.prototype.close_ws = function (fig, msg) {\n", - " fig.send_message('closing', msg);\n", - " // fig.ws.close()\n", - "};\n", - "\n", - "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", - " // Turn the data on the canvas into data in the output cell.\n", - " var width = this.canvas.width / this.ratio;\n", - " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] =\n", - " '';\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Tell IPython that the notebook contents must change.\n", - " IPython.notebook.set_dirty(true);\n", - " this.send_message('ack', {});\n", - " var fig = this;\n", - " // Wait a second, then push the new image to the DOM so\n", - " // that it is saved nicely (might be nice to debounce this).\n", - " setTimeout(function () {\n", - " fig.push_to_output();\n", - " }, 1000);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'btn-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " var button;\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " continue;\n", - " }\n", - "\n", - " button = fig.buttons[name] = document.createElement('button');\n", - " button.classList = 'btn btn-default';\n", - " button.href = '#';\n", - " button.title = name;\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message pull-right';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = document.createElement('div');\n", - " buttongrp.classList = 'btn-group inline pull-right';\n", - " button = document.createElement('button');\n", - " button.classList = 'btn btn-mini btn-primary';\n", - " button.href = '#';\n", - " button.title = 'Stop Interaction';\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', function (_evt) {\n", - " fig.handle_close(fig, {});\n", - " });\n", - " button.addEventListener(\n", - " 'mouseover',\n", - " on_mouseover_closure('Stop Interaction')\n", - " );\n", - " buttongrp.appendChild(button);\n", - " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", - " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", - "};\n", - "\n", - "mpl.figure.prototype._remove_fig_handler = function (event) {\n", - " var fig = event.data.fig;\n", - " if (event.target !== this) {\n", - " // Ignore bubbled events from children.\n", - " return;\n", - " }\n", - " fig.close_ws(fig, {});\n", - "};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (el) {\n", - " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (el) {\n", - " // this is important to make the div 'focusable\n", - " el.setAttribute('tabindex', 0);\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " } else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager) {\n", - " manager = IPython.keyboard_manager;\n", - " }\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which === 13) {\n", - " this.canvas_div.blur();\n", - " // select the cell after this one\n", - " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", - " IPython.notebook.select(index + 1);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " fig.ondownload(fig, null);\n", - "};\n", - "\n", - "mpl.find_output_cell = function (html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i = 0; i < ncells; i++) {\n", - " var cell = cells[i];\n", - " if (cell.cell_type === 'code') {\n", - " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", - " var data = cell.output_area.outputs[j];\n", - " if (data.data) {\n", - " // IPython >= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] === html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "};\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel !== null) {\n", - " IPython.notebook.kernel.comm_manager.register_target(\n", - " 'matplotlib',\n", - " mpl.mpl_figure_comm\n", - " );\n", - "}\n" - ], + "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n rubberband_canvas.addEventListener(\n 'dblclick',\n on_mouse_event_closure('dblclick')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n var img = evt.data;\n if (img.type !== 'image/png') {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n img.type = 'image/png';\n }\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n img\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.key === this._key) {\n return;\n } else {\n this._key = event.key;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.key !== 'Control') {\n value += 'ctrl+';\n }\n else if (event.altKey && event.key !== 'Alt') {\n value += 'alt+';\n }\n else if (event.shiftKey && event.key !== 'Shift') {\n value += 'shift+';\n }\n\n value += 'k' + event.key;\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.binaryType = comm.kernel.ws.binaryType;\n ws.readyState = comm.kernel.ws.readyState;\n function updateReadyState(_event) {\n if (comm.kernel.ws) {\n ws.readyState = comm.kernel.ws.readyState;\n } else {\n ws.readyState = 3; // Closed state.\n }\n }\n comm.kernel.ws.addEventListener('open', updateReadyState);\n comm.kernel.ws.addEventListener('close', updateReadyState);\n comm.kernel.ws.addEventListener('error', updateReadyState);\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n var data = msg['content']['data'];\n if (data['blob'] !== undefined) {\n data = {\n data: new Blob(msg['buffers'], { type: data['blob'] }),\n };\n }\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(data);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", "text/plain": [ "" ] @@ -1196,980 +223,7 @@ "outputs": [ { "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "/* global mpl */\n", - "window.mpl = {};\n", - "\n", - "mpl.get_websocket_type = function () {\n", - " if (typeof WebSocket !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof MozWebSocket !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert(\n", - " 'Your browser does not have WebSocket support. ' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.'\n", - " );\n", - " }\n", - "};\n", - "\n", - "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = this.ws.binaryType !== undefined;\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById('mpl-warnings');\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent =\n", - " 'This browser does not support binary websocket messages. ' +\n", - " 'Performance may be slow.';\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = document.createElement('div');\n", - " this.root.setAttribute('style', 'display: inline-block');\n", - " this._root_extra_style(this.root);\n", - "\n", - " parent_element.appendChild(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message('supports_binary', { value: fig.supports_binary });\n", - " fig.send_message('send_image_mode', {});\n", - " if (fig.ratio !== 1) {\n", - " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", - " }\n", - " fig.send_message('refresh', {});\n", - " };\n", - "\n", - " this.imageObj.onload = function () {\n", - " if (fig.image_mode === 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function () {\n", - " fig.ws.close();\n", - " };\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "};\n", - "\n", - "mpl.figure.prototype._init_header = function () {\n", - " var titlebar = document.createElement('div');\n", - " titlebar.classList =\n", - " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", - " var titletext = document.createElement('div');\n", - " titletext.classList = 'ui-dialog-title';\n", - " titletext.setAttribute(\n", - " 'style',\n", - " 'width: 100%; text-align: center; padding: 3px;'\n", - " );\n", - " titlebar.appendChild(titletext);\n", - " this.root.appendChild(titlebar);\n", - " this.header = titletext;\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._init_canvas = function () {\n", - " var fig = this;\n", - "\n", - " var canvas_div = (this.canvas_div = document.createElement('div'));\n", - " canvas_div.setAttribute(\n", - " 'style',\n", - " 'border: 1px solid #ddd;' +\n", - " 'box-sizing: content-box;' +\n", - " 'clear: both;' +\n", - " 'min-height: 1px;' +\n", - " 'min-width: 1px;' +\n", - " 'outline: 0;' +\n", - " 'overflow: hidden;' +\n", - " 'position: relative;' +\n", - " 'resize: both;'\n", - " );\n", - "\n", - " function on_keyboard_event_closure(name) {\n", - " return function (event) {\n", - " return fig.key_event(event, name);\n", - " };\n", - " }\n", - "\n", - " canvas_div.addEventListener(\n", - " 'keydown',\n", - " on_keyboard_event_closure('key_press')\n", - " );\n", - " canvas_div.addEventListener(\n", - " 'keyup',\n", - " on_keyboard_event_closure('key_release')\n", - " );\n", - "\n", - " this._canvas_extra_style(canvas_div);\n", - " this.root.appendChild(canvas_div);\n", - "\n", - " var canvas = (this.canvas = document.createElement('canvas'));\n", - " canvas.classList.add('mpl-canvas');\n", - " canvas.setAttribute('style', 'box-sizing: content-box;');\n", - "\n", - " this.context = canvas.getContext('2d');\n", - "\n", - " var backingStore =\n", - " this.context.backingStorePixelRatio ||\n", - " this.context.webkitBackingStorePixelRatio ||\n", - " this.context.mozBackingStorePixelRatio ||\n", - " this.context.msBackingStorePixelRatio ||\n", - " this.context.oBackingStorePixelRatio ||\n", - " this.context.backingStorePixelRatio ||\n", - " 1;\n", - "\n", - " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", - " 'canvas'\n", - " ));\n", - " rubberband_canvas.setAttribute(\n", - " 'style',\n", - " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", - " );\n", - "\n", - " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", - " if (this.ResizeObserver === undefined) {\n", - " if (window.ResizeObserver !== undefined) {\n", - " this.ResizeObserver = window.ResizeObserver;\n", - " } else {\n", - " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", - " this.ResizeObserver = obs.ResizeObserver;\n", - " }\n", - " }\n", - "\n", - " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", - " var nentries = entries.length;\n", - " for (var i = 0; i < nentries; i++) {\n", - " var entry = entries[i];\n", - " var width, height;\n", - " if (entry.contentBoxSize) {\n", - " if (entry.contentBoxSize instanceof Array) {\n", - " // Chrome 84 implements new version of spec.\n", - " width = entry.contentBoxSize[0].inlineSize;\n", - " height = entry.contentBoxSize[0].blockSize;\n", - " } else {\n", - " // Firefox implements old version of spec.\n", - " width = entry.contentBoxSize.inlineSize;\n", - " height = entry.contentBoxSize.blockSize;\n", - " }\n", - " } else {\n", - " // Chrome <84 implements even older version of spec.\n", - " width = entry.contentRect.width;\n", - " height = entry.contentRect.height;\n", - " }\n", - "\n", - " // Keep the size of the canvas and rubber band canvas in sync with\n", - " // the canvas container.\n", - " if (entry.devicePixelContentBoxSize) {\n", - " // Chrome 84 implements new version of spec.\n", - " canvas.setAttribute(\n", - " 'width',\n", - " entry.devicePixelContentBoxSize[0].inlineSize\n", - " );\n", - " canvas.setAttribute(\n", - " 'height',\n", - " entry.devicePixelContentBoxSize[0].blockSize\n", - " );\n", - " } else {\n", - " canvas.setAttribute('width', width * fig.ratio);\n", - " canvas.setAttribute('height', height * fig.ratio);\n", - " }\n", - " canvas.setAttribute(\n", - " 'style',\n", - " 'width: ' + width + 'px; height: ' + height + 'px;'\n", - " );\n", - "\n", - " rubberband_canvas.setAttribute('width', width);\n", - " rubberband_canvas.setAttribute('height', height);\n", - "\n", - " // And update the size in Python. We ignore the initial 0/0 size\n", - " // that occurs as the element is placed into the DOM, which should\n", - " // otherwise not happen due to the minimum size styling.\n", - " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", - " fig.request_resize(width, height);\n", - " }\n", - " }\n", - " });\n", - " this.resizeObserverInstance.observe(canvas_div);\n", - "\n", - " function on_mouse_event_closure(name) {\n", - " return function (event) {\n", - " return fig.mouse_event(event, name);\n", - " };\n", - " }\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mousedown',\n", - " on_mouse_event_closure('button_press')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseup',\n", - " on_mouse_event_closure('button_release')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'dblclick',\n", - " on_mouse_event_closure('dblclick')\n", - " );\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband_canvas.addEventListener(\n", - " 'mousemove',\n", - " on_mouse_event_closure('motion_notify')\n", - " );\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseenter',\n", - " on_mouse_event_closure('figure_enter')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseleave',\n", - " on_mouse_event_closure('figure_leave')\n", - " );\n", - "\n", - " canvas_div.addEventListener('wheel', function (event) {\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " on_mouse_event_closure('scroll')(event);\n", - " });\n", - "\n", - " canvas_div.appendChild(canvas);\n", - " canvas_div.appendChild(rubberband_canvas);\n", - "\n", - " this.rubberband_context = rubberband_canvas.getContext('2d');\n", - " this.rubberband_context.strokeStyle = '#000000';\n", - "\n", - " this._resize_canvas = function (width, height, forward) {\n", - " if (forward) {\n", - " canvas_div.style.width = width + 'px';\n", - " canvas_div.style.height = height + 'px';\n", - " }\n", - " };\n", - "\n", - " // Disable right mouse context menu.\n", - " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", - " event.preventDefault();\n", - " return false;\n", - " });\n", - "\n", - " function set_focus() {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'mpl-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " continue;\n", - " }\n", - "\n", - " var button = (fig.buttons[name] = document.createElement('button'));\n", - " button.classList = 'mpl-widget';\n", - " button.setAttribute('role', 'button');\n", - " button.setAttribute('aria-disabled', 'false');\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - "\n", - " var icon_img = document.createElement('img');\n", - " icon_img.src = '_images/' + image + '.png';\n", - " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", - " icon_img.alt = tooltip;\n", - " button.appendChild(icon_img);\n", - "\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " var fmt_picker = document.createElement('select');\n", - " fmt_picker.classList = 'mpl-widget';\n", - " toolbar.appendChild(fmt_picker);\n", - " this.format_dropdown = fmt_picker;\n", - "\n", - " for (var ind in mpl.extensions) {\n", - " var fmt = mpl.extensions[ind];\n", - " var option = document.createElement('option');\n", - " option.selected = fmt === mpl.default_extension;\n", - " option.innerHTML = fmt;\n", - " fmt_picker.appendChild(option);\n", - " }\n", - "\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "};\n", - "\n", - "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", - " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", - " // which will in turn request a refresh of the image.\n", - " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", - "};\n", - "\n", - "mpl.figure.prototype.send_message = function (type, properties) {\n", - " properties['type'] = type;\n", - " properties['figure_id'] = this.id;\n", - " this.ws.send(JSON.stringify(properties));\n", - "};\n", - "\n", - "mpl.figure.prototype.send_draw_message = function () {\n", - " if (!this.waiting) {\n", - " this.waiting = true;\n", - " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " var format_dropdown = fig.format_dropdown;\n", - " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", - " fig.ondownload(fig, format);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", - " var size = msg['size'];\n", - " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", - " fig._resize_canvas(size[0], size[1], msg['forward']);\n", - " fig.send_message('refresh', {});\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", - " var x0 = msg['x0'] / fig.ratio;\n", - " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", - " var x1 = msg['x1'] / fig.ratio;\n", - " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", - " x0 = Math.floor(x0) + 0.5;\n", - " y0 = Math.floor(y0) + 0.5;\n", - " x1 = Math.floor(x1) + 0.5;\n", - " y1 = Math.floor(y1) + 0.5;\n", - " var min_x = Math.min(x0, x1);\n", - " var min_y = Math.min(y0, y1);\n", - " var width = Math.abs(x1 - x0);\n", - " var height = Math.abs(y1 - y0);\n", - "\n", - " fig.rubberband_context.clearRect(\n", - " 0,\n", - " 0,\n", - " fig.canvas.width / fig.ratio,\n", - " fig.canvas.height / fig.ratio\n", - " );\n", - "\n", - " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", - " // Updates the figure title.\n", - " fig.header.textContent = msg['label'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", - " var cursor = msg['cursor'];\n", - " switch (cursor) {\n", - " case 0:\n", - " cursor = 'pointer';\n", - " break;\n", - " case 1:\n", - " cursor = 'default';\n", - " break;\n", - " case 2:\n", - " cursor = 'crosshair';\n", - " break;\n", - " case 3:\n", - " cursor = 'move';\n", - " break;\n", - " }\n", - " fig.rubberband_canvas.style.cursor = cursor;\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_message = function (fig, msg) {\n", - " fig.message.textContent = msg['message'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", - " // Request the server to send over a new figure.\n", - " fig.send_draw_message();\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", - " fig.image_mode = msg['mode'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", - " for (var key in msg) {\n", - " if (!(key in fig.buttons)) {\n", - " continue;\n", - " }\n", - " fig.buttons[key].disabled = !msg[key];\n", - " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", - " if (msg['mode'] === 'PAN') {\n", - " fig.buttons['Pan'].classList.add('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " } else if (msg['mode'] === 'ZOOM') {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.add('active');\n", - " } else {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Called whenever the canvas gets updated.\n", - " this.send_message('ack', {});\n", - "};\n", - "\n", - "// A function to construct a web socket function for onmessage handling.\n", - "// Called in the figure constructor.\n", - "mpl.figure.prototype._make_on_message_function = function (fig) {\n", - " return function socket_on_message(evt) {\n", - " if (evt.data instanceof Blob) {\n", - " var img = evt.data;\n", - " if (img.type !== 'image/png') {\n", - " /* FIXME: We get \"Resource interpreted as Image but\n", - " * transferred with MIME type text/plain:\" errors on\n", - " * Chrome. But how to set the MIME type? It doesn't seem\n", - " * to be part of the websocket stream */\n", - " img.type = 'image/png';\n", - " }\n", - "\n", - " /* Free the memory for the previous frames */\n", - " if (fig.imageObj.src) {\n", - " (window.URL || window.webkitURL).revokeObjectURL(\n", - " fig.imageObj.src\n", - " );\n", - " }\n", - "\n", - " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", - " img\n", - " );\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " } else if (\n", - " typeof evt.data === 'string' &&\n", - " evt.data.slice(0, 21) === 'data:image/png;base64'\n", - " ) {\n", - " fig.imageObj.src = evt.data;\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " }\n", - "\n", - " var msg = JSON.parse(evt.data);\n", - " var msg_type = msg['type'];\n", - "\n", - " // Call the \"handle_{type}\" callback, which takes\n", - " // the figure and JSON message as its only arguments.\n", - " try {\n", - " var callback = fig['handle_' + msg_type];\n", - " } catch (e) {\n", - " console.log(\n", - " \"No handler for the '\" + msg_type + \"' message type: \",\n", - " msg\n", - " );\n", - " return;\n", - " }\n", - "\n", - " if (callback) {\n", - " try {\n", - " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", - " callback(fig, msg);\n", - " } catch (e) {\n", - " console.log(\n", - " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", - " e,\n", - " e.stack,\n", - " msg\n", - " );\n", - " }\n", - " }\n", - " };\n", - "};\n", - "\n", - "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", - "mpl.findpos = function (e) {\n", - " //this section is from http://www.quirksmode.org/js/events_properties.html\n", - " var targ;\n", - " if (!e) {\n", - " e = window.event;\n", - " }\n", - " if (e.target) {\n", - " targ = e.target;\n", - " } else if (e.srcElement) {\n", - " targ = e.srcElement;\n", - " }\n", - " if (targ.nodeType === 3) {\n", - " // defeat Safari bug\n", - " targ = targ.parentNode;\n", - " }\n", - "\n", - " // pageX,Y are the mouse positions relative to the document\n", - " var boundingRect = targ.getBoundingClientRect();\n", - " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", - " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", - "\n", - " return { x: x, y: y };\n", - "};\n", - "\n", - "/*\n", - " * return a copy of an object with only non-object keys\n", - " * we need this to avoid circular references\n", - " * http://stackoverflow.com/a/24161582/3208463\n", - " */\n", - "function simpleKeys(original) {\n", - " return Object.keys(original).reduce(function (obj, key) {\n", - " if (typeof original[key] !== 'object') {\n", - " obj[key] = original[key];\n", - " }\n", - " return obj;\n", - " }, {});\n", - "}\n", - "\n", - "mpl.figure.prototype.mouse_event = function (event, name) {\n", - " var canvas_pos = mpl.findpos(event);\n", - "\n", - " if (name === 'button_press') {\n", - " this.canvas.focus();\n", - " this.canvas_div.focus();\n", - " }\n", - "\n", - " var x = canvas_pos.x * this.ratio;\n", - " var y = canvas_pos.y * this.ratio;\n", - "\n", - " this.send_message(name, {\n", - " x: x,\n", - " y: y,\n", - " button: event.button,\n", - " step: event.step,\n", - " guiEvent: simpleKeys(event),\n", - " });\n", - "\n", - " /* This prevents the web browser from automatically changing to\n", - " * the text insertion cursor when the button is pressed. We want\n", - " * to control all of the cursor setting manually through the\n", - " * 'cursor' event from matplotlib */\n", - " event.preventDefault();\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", - " // Handle any extra behaviour associated with a key event\n", - "};\n", - "\n", - "mpl.figure.prototype.key_event = function (event, name) {\n", - " // Prevent repeat events\n", - " if (name === 'key_press') {\n", - " if (event.key === this._key) {\n", - " return;\n", - " } else {\n", - " this._key = event.key;\n", - " }\n", - " }\n", - " if (name === 'key_release') {\n", - " this._key = null;\n", - " }\n", - "\n", - " var value = '';\n", - " if (event.ctrlKey && event.key !== 'Control') {\n", - " value += 'ctrl+';\n", - " }\n", - " else if (event.altKey && event.key !== 'Alt') {\n", - " value += 'alt+';\n", - " }\n", - " else if (event.shiftKey && event.key !== 'Shift') {\n", - " value += 'shift+';\n", - " }\n", - "\n", - " value += 'k' + event.key;\n", - "\n", - " this._key_event_extra(event, name);\n", - "\n", - " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", - " if (name === 'download') {\n", - " this.handle_save(this, null);\n", - " } else {\n", - " this.send_message('toolbar_button', { name: name });\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", - " this.message.textContent = tooltip;\n", - "};\n", - "\n", - "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", - "// prettier-ignore\n", - "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", - "\n", - "mpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", - "\n", - "mpl.default_extension = \"png\";/* global mpl */\n", - "\n", - "var comm_websocket_adapter = function (comm) {\n", - " // Create a \"websocket\"-like object which calls the given IPython comm\n", - " // object with the appropriate methods. Currently this is a non binary\n", - " // socket, so there is still some room for performance tuning.\n", - " var ws = {};\n", - "\n", - " ws.binaryType = comm.kernel.ws.binaryType;\n", - " ws.readyState = comm.kernel.ws.readyState;\n", - " function updateReadyState(_event) {\n", - " if (comm.kernel.ws) {\n", - " ws.readyState = comm.kernel.ws.readyState;\n", - " } else {\n", - " ws.readyState = 3; // Closed state.\n", - " }\n", - " }\n", - " comm.kernel.ws.addEventListener('open', updateReadyState);\n", - " comm.kernel.ws.addEventListener('close', updateReadyState);\n", - " comm.kernel.ws.addEventListener('error', updateReadyState);\n", - "\n", - " ws.close = function () {\n", - " comm.close();\n", - " };\n", - " ws.send = function (m) {\n", - " //console.log('sending', m);\n", - " comm.send(m);\n", - " };\n", - " // Register the callback with on_msg.\n", - " comm.on_msg(function (msg) {\n", - " //console.log('receiving', msg['content']['data'], msg);\n", - " var data = msg['content']['data'];\n", - " if (data['blob'] !== undefined) {\n", - " data = {\n", - " data: new Blob(msg['buffers'], { type: data['blob'] }),\n", - " };\n", - " }\n", - " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", - " ws.onmessage(data);\n", - " });\n", - " return ws;\n", - "};\n", - "\n", - "mpl.mpl_figure_comm = function (comm, msg) {\n", - " // This is the function which gets called when the mpl process\n", - " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", - "\n", - " var id = msg.content.data.id;\n", - " // Get hold of the div created by the display call when the Comm\n", - " // socket was opened in Python.\n", - " var element = document.getElementById(id);\n", - " var ws_proxy = comm_websocket_adapter(comm);\n", - "\n", - " function ondownload(figure, _format) {\n", - " window.open(figure.canvas.toDataURL());\n", - " }\n", - "\n", - " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", - "\n", - " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", - " // web socket which is closed, not our websocket->open comm proxy.\n", - " ws_proxy.onopen();\n", - "\n", - " fig.parent_element = element;\n", - " fig.cell_info = mpl.find_output_cell(\"
\");\n", - " if (!fig.cell_info) {\n", - " console.error('Failed to find cell for figure', id, fig);\n", - " return;\n", - " }\n", - " fig.cell_info[0].output_area.element.on(\n", - " 'cleared',\n", - " { fig: fig },\n", - " fig._remove_fig_handler\n", - " );\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_close = function (fig, msg) {\n", - " var width = fig.canvas.width / fig.ratio;\n", - " fig.cell_info[0].output_area.element.off(\n", - " 'cleared',\n", - " fig._remove_fig_handler\n", - " );\n", - " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", - "\n", - " // Update the output cell to use the data from the current canvas.\n", - " fig.push_to_output();\n", - " var dataURL = fig.canvas.toDataURL();\n", - " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", - " // the notebook keyboard shortcuts fail.\n", - " IPython.keyboard_manager.enable();\n", - " fig.parent_element.innerHTML =\n", - " '';\n", - " fig.close_ws(fig, msg);\n", - "};\n", - "\n", - "mpl.figure.prototype.close_ws = function (fig, msg) {\n", - " fig.send_message('closing', msg);\n", - " // fig.ws.close()\n", - "};\n", - "\n", - "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", - " // Turn the data on the canvas into data in the output cell.\n", - " var width = this.canvas.width / this.ratio;\n", - " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] =\n", - " '';\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Tell IPython that the notebook contents must change.\n", - " IPython.notebook.set_dirty(true);\n", - " this.send_message('ack', {});\n", - " var fig = this;\n", - " // Wait a second, then push the new image to the DOM so\n", - " // that it is saved nicely (might be nice to debounce this).\n", - " setTimeout(function () {\n", - " fig.push_to_output();\n", - " }, 1000);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'btn-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " var button;\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " continue;\n", - " }\n", - "\n", - " button = fig.buttons[name] = document.createElement('button');\n", - " button.classList = 'btn btn-default';\n", - " button.href = '#';\n", - " button.title = name;\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message pull-right';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = document.createElement('div');\n", - " buttongrp.classList = 'btn-group inline pull-right';\n", - " button = document.createElement('button');\n", - " button.classList = 'btn btn-mini btn-primary';\n", - " button.href = '#';\n", - " button.title = 'Stop Interaction';\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', function (_evt) {\n", - " fig.handle_close(fig, {});\n", - " });\n", - " button.addEventListener(\n", - " 'mouseover',\n", - " on_mouseover_closure('Stop Interaction')\n", - " );\n", - " buttongrp.appendChild(button);\n", - " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", - " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", - "};\n", - "\n", - "mpl.figure.prototype._remove_fig_handler = function (event) {\n", - " var fig = event.data.fig;\n", - " if (event.target !== this) {\n", - " // Ignore bubbled events from children.\n", - " return;\n", - " }\n", - " fig.close_ws(fig, {});\n", - "};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (el) {\n", - " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (el) {\n", - " // this is important to make the div 'focusable\n", - " el.setAttribute('tabindex', 0);\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " } else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager) {\n", - " manager = IPython.keyboard_manager;\n", - " }\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which === 13) {\n", - " this.canvas_div.blur();\n", - " // select the cell after this one\n", - " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", - " IPython.notebook.select(index + 1);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " fig.ondownload(fig, null);\n", - "};\n", - "\n", - "mpl.find_output_cell = function (html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i = 0; i < ncells; i++) {\n", - " var cell = cells[i];\n", - " if (cell.cell_type === 'code') {\n", - " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", - " var data = cell.output_area.outputs[j];\n", - " if (data.data) {\n", - " // IPython >= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] === html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "};\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel !== null) {\n", - " IPython.notebook.kernel.comm_manager.register_target(\n", - " 'matplotlib',\n", - " mpl.mpl_figure_comm\n", - " );\n", - "}\n" - ], + "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n rubberband_canvas.addEventListener(\n 'dblclick',\n on_mouse_event_closure('dblclick')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n var img = evt.data;\n if (img.type !== 'image/png') {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n img.type = 'image/png';\n }\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n img\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.key === this._key) {\n return;\n } else {\n this._key = event.key;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.key !== 'Control') {\n value += 'ctrl+';\n }\n else if (event.altKey && event.key !== 'Alt') {\n value += 'alt+';\n }\n else if (event.shiftKey && event.key !== 'Shift') {\n value += 'shift+';\n }\n\n value += 'k' + event.key;\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.binaryType = comm.kernel.ws.binaryType;\n ws.readyState = comm.kernel.ws.readyState;\n function updateReadyState(_event) {\n if (comm.kernel.ws) {\n ws.readyState = comm.kernel.ws.readyState;\n } else {\n ws.readyState = 3; // Closed state.\n }\n }\n comm.kernel.ws.addEventListener('open', updateReadyState);\n comm.kernel.ws.addEventListener('close', updateReadyState);\n comm.kernel.ws.addEventListener('error', updateReadyState);\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n var data = msg['content']['data'];\n if (data['blob'] !== undefined) {\n data = {\n data: new Blob(msg['buffers'], { type: data['blob'] }),\n };\n }\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(data);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", "text/plain": [ "" ] @@ -2266,980 +320,7 @@ }, { "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "/* global mpl */\n", - "window.mpl = {};\n", - "\n", - "mpl.get_websocket_type = function () {\n", - " if (typeof WebSocket !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof MozWebSocket !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert(\n", - " 'Your browser does not have WebSocket support. ' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.'\n", - " );\n", - " }\n", - "};\n", - "\n", - "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = this.ws.binaryType !== undefined;\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById('mpl-warnings');\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent =\n", - " 'This browser does not support binary websocket messages. ' +\n", - " 'Performance may be slow.';\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = document.createElement('div');\n", - " this.root.setAttribute('style', 'display: inline-block');\n", - " this._root_extra_style(this.root);\n", - "\n", - " parent_element.appendChild(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message('supports_binary', { value: fig.supports_binary });\n", - " fig.send_message('send_image_mode', {});\n", - " if (fig.ratio !== 1) {\n", - " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", - " }\n", - " fig.send_message('refresh', {});\n", - " };\n", - "\n", - " this.imageObj.onload = function () {\n", - " if (fig.image_mode === 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function () {\n", - " fig.ws.close();\n", - " };\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "};\n", - "\n", - "mpl.figure.prototype._init_header = function () {\n", - " var titlebar = document.createElement('div');\n", - " titlebar.classList =\n", - " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", - " var titletext = document.createElement('div');\n", - " titletext.classList = 'ui-dialog-title';\n", - " titletext.setAttribute(\n", - " 'style',\n", - " 'width: 100%; text-align: center; padding: 3px;'\n", - " );\n", - " titlebar.appendChild(titletext);\n", - " this.root.appendChild(titlebar);\n", - " this.header = titletext;\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._init_canvas = function () {\n", - " var fig = this;\n", - "\n", - " var canvas_div = (this.canvas_div = document.createElement('div'));\n", - " canvas_div.setAttribute(\n", - " 'style',\n", - " 'border: 1px solid #ddd;' +\n", - " 'box-sizing: content-box;' +\n", - " 'clear: both;' +\n", - " 'min-height: 1px;' +\n", - " 'min-width: 1px;' +\n", - " 'outline: 0;' +\n", - " 'overflow: hidden;' +\n", - " 'position: relative;' +\n", - " 'resize: both;'\n", - " );\n", - "\n", - " function on_keyboard_event_closure(name) {\n", - " return function (event) {\n", - " return fig.key_event(event, name);\n", - " };\n", - " }\n", - "\n", - " canvas_div.addEventListener(\n", - " 'keydown',\n", - " on_keyboard_event_closure('key_press')\n", - " );\n", - " canvas_div.addEventListener(\n", - " 'keyup',\n", - " on_keyboard_event_closure('key_release')\n", - " );\n", - "\n", - " this._canvas_extra_style(canvas_div);\n", - " this.root.appendChild(canvas_div);\n", - "\n", - " var canvas = (this.canvas = document.createElement('canvas'));\n", - " canvas.classList.add('mpl-canvas');\n", - " canvas.setAttribute('style', 'box-sizing: content-box;');\n", - "\n", - " this.context = canvas.getContext('2d');\n", - "\n", - " var backingStore =\n", - " this.context.backingStorePixelRatio ||\n", - " this.context.webkitBackingStorePixelRatio ||\n", - " this.context.mozBackingStorePixelRatio ||\n", - " this.context.msBackingStorePixelRatio ||\n", - " this.context.oBackingStorePixelRatio ||\n", - " this.context.backingStorePixelRatio ||\n", - " 1;\n", - "\n", - " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", - " 'canvas'\n", - " ));\n", - " rubberband_canvas.setAttribute(\n", - " 'style',\n", - " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", - " );\n", - "\n", - " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", - " if (this.ResizeObserver === undefined) {\n", - " if (window.ResizeObserver !== undefined) {\n", - " this.ResizeObserver = window.ResizeObserver;\n", - " } else {\n", - " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", - " this.ResizeObserver = obs.ResizeObserver;\n", - " }\n", - " }\n", - "\n", - " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", - " var nentries = entries.length;\n", - " for (var i = 0; i < nentries; i++) {\n", - " var entry = entries[i];\n", - " var width, height;\n", - " if (entry.contentBoxSize) {\n", - " if (entry.contentBoxSize instanceof Array) {\n", - " // Chrome 84 implements new version of spec.\n", - " width = entry.contentBoxSize[0].inlineSize;\n", - " height = entry.contentBoxSize[0].blockSize;\n", - " } else {\n", - " // Firefox implements old version of spec.\n", - " width = entry.contentBoxSize.inlineSize;\n", - " height = entry.contentBoxSize.blockSize;\n", - " }\n", - " } else {\n", - " // Chrome <84 implements even older version of spec.\n", - " width = entry.contentRect.width;\n", - " height = entry.contentRect.height;\n", - " }\n", - "\n", - " // Keep the size of the canvas and rubber band canvas in sync with\n", - " // the canvas container.\n", - " if (entry.devicePixelContentBoxSize) {\n", - " // Chrome 84 implements new version of spec.\n", - " canvas.setAttribute(\n", - " 'width',\n", - " entry.devicePixelContentBoxSize[0].inlineSize\n", - " );\n", - " canvas.setAttribute(\n", - " 'height',\n", - " entry.devicePixelContentBoxSize[0].blockSize\n", - " );\n", - " } else {\n", - " canvas.setAttribute('width', width * fig.ratio);\n", - " canvas.setAttribute('height', height * fig.ratio);\n", - " }\n", - " canvas.setAttribute(\n", - " 'style',\n", - " 'width: ' + width + 'px; height: ' + height + 'px;'\n", - " );\n", - "\n", - " rubberband_canvas.setAttribute('width', width);\n", - " rubberband_canvas.setAttribute('height', height);\n", - "\n", - " // And update the size in Python. We ignore the initial 0/0 size\n", - " // that occurs as the element is placed into the DOM, which should\n", - " // otherwise not happen due to the minimum size styling.\n", - " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", - " fig.request_resize(width, height);\n", - " }\n", - " }\n", - " });\n", - " this.resizeObserverInstance.observe(canvas_div);\n", - "\n", - " function on_mouse_event_closure(name) {\n", - " return function (event) {\n", - " return fig.mouse_event(event, name);\n", - " };\n", - " }\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mousedown',\n", - " on_mouse_event_closure('button_press')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseup',\n", - " on_mouse_event_closure('button_release')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'dblclick',\n", - " on_mouse_event_closure('dblclick')\n", - " );\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband_canvas.addEventListener(\n", - " 'mousemove',\n", - " on_mouse_event_closure('motion_notify')\n", - " );\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseenter',\n", - " on_mouse_event_closure('figure_enter')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseleave',\n", - " on_mouse_event_closure('figure_leave')\n", - " );\n", - "\n", - " canvas_div.addEventListener('wheel', function (event) {\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " on_mouse_event_closure('scroll')(event);\n", - " });\n", - "\n", - " canvas_div.appendChild(canvas);\n", - " canvas_div.appendChild(rubberband_canvas);\n", - "\n", - " this.rubberband_context = rubberband_canvas.getContext('2d');\n", - " this.rubberband_context.strokeStyle = '#000000';\n", - "\n", - " this._resize_canvas = function (width, height, forward) {\n", - " if (forward) {\n", - " canvas_div.style.width = width + 'px';\n", - " canvas_div.style.height = height + 'px';\n", - " }\n", - " };\n", - "\n", - " // Disable right mouse context menu.\n", - " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", - " event.preventDefault();\n", - " return false;\n", - " });\n", - "\n", - " function set_focus() {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'mpl-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " continue;\n", - " }\n", - "\n", - " var button = (fig.buttons[name] = document.createElement('button'));\n", - " button.classList = 'mpl-widget';\n", - " button.setAttribute('role', 'button');\n", - " button.setAttribute('aria-disabled', 'false');\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - "\n", - " var icon_img = document.createElement('img');\n", - " icon_img.src = '_images/' + image + '.png';\n", - " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", - " icon_img.alt = tooltip;\n", - " button.appendChild(icon_img);\n", - "\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " var fmt_picker = document.createElement('select');\n", - " fmt_picker.classList = 'mpl-widget';\n", - " toolbar.appendChild(fmt_picker);\n", - " this.format_dropdown = fmt_picker;\n", - "\n", - " for (var ind in mpl.extensions) {\n", - " var fmt = mpl.extensions[ind];\n", - " var option = document.createElement('option');\n", - " option.selected = fmt === mpl.default_extension;\n", - " option.innerHTML = fmt;\n", - " fmt_picker.appendChild(option);\n", - " }\n", - "\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "};\n", - "\n", - "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", - " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", - " // which will in turn request a refresh of the image.\n", - " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", - "};\n", - "\n", - "mpl.figure.prototype.send_message = function (type, properties) {\n", - " properties['type'] = type;\n", - " properties['figure_id'] = this.id;\n", - " this.ws.send(JSON.stringify(properties));\n", - "};\n", - "\n", - "mpl.figure.prototype.send_draw_message = function () {\n", - " if (!this.waiting) {\n", - " this.waiting = true;\n", - " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " var format_dropdown = fig.format_dropdown;\n", - " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", - " fig.ondownload(fig, format);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", - " var size = msg['size'];\n", - " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", - " fig._resize_canvas(size[0], size[1], msg['forward']);\n", - " fig.send_message('refresh', {});\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", - " var x0 = msg['x0'] / fig.ratio;\n", - " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", - " var x1 = msg['x1'] / fig.ratio;\n", - " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", - " x0 = Math.floor(x0) + 0.5;\n", - " y0 = Math.floor(y0) + 0.5;\n", - " x1 = Math.floor(x1) + 0.5;\n", - " y1 = Math.floor(y1) + 0.5;\n", - " var min_x = Math.min(x0, x1);\n", - " var min_y = Math.min(y0, y1);\n", - " var width = Math.abs(x1 - x0);\n", - " var height = Math.abs(y1 - y0);\n", - "\n", - " fig.rubberband_context.clearRect(\n", - " 0,\n", - " 0,\n", - " fig.canvas.width / fig.ratio,\n", - " fig.canvas.height / fig.ratio\n", - " );\n", - "\n", - " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", - " // Updates the figure title.\n", - " fig.header.textContent = msg['label'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", - " var cursor = msg['cursor'];\n", - " switch (cursor) {\n", - " case 0:\n", - " cursor = 'pointer';\n", - " break;\n", - " case 1:\n", - " cursor = 'default';\n", - " break;\n", - " case 2:\n", - " cursor = 'crosshair';\n", - " break;\n", - " case 3:\n", - " cursor = 'move';\n", - " break;\n", - " }\n", - " fig.rubberband_canvas.style.cursor = cursor;\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_message = function (fig, msg) {\n", - " fig.message.textContent = msg['message'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", - " // Request the server to send over a new figure.\n", - " fig.send_draw_message();\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", - " fig.image_mode = msg['mode'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", - " for (var key in msg) {\n", - " if (!(key in fig.buttons)) {\n", - " continue;\n", - " }\n", - " fig.buttons[key].disabled = !msg[key];\n", - " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", - " if (msg['mode'] === 'PAN') {\n", - " fig.buttons['Pan'].classList.add('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " } else if (msg['mode'] === 'ZOOM') {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.add('active');\n", - " } else {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Called whenever the canvas gets updated.\n", - " this.send_message('ack', {});\n", - "};\n", - "\n", - "// A function to construct a web socket function for onmessage handling.\n", - "// Called in the figure constructor.\n", - "mpl.figure.prototype._make_on_message_function = function (fig) {\n", - " return function socket_on_message(evt) {\n", - " if (evt.data instanceof Blob) {\n", - " var img = evt.data;\n", - " if (img.type !== 'image/png') {\n", - " /* FIXME: We get \"Resource interpreted as Image but\n", - " * transferred with MIME type text/plain:\" errors on\n", - " * Chrome. But how to set the MIME type? It doesn't seem\n", - " * to be part of the websocket stream */\n", - " img.type = 'image/png';\n", - " }\n", - "\n", - " /* Free the memory for the previous frames */\n", - " if (fig.imageObj.src) {\n", - " (window.URL || window.webkitURL).revokeObjectURL(\n", - " fig.imageObj.src\n", - " );\n", - " }\n", - "\n", - " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", - " img\n", - " );\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " } else if (\n", - " typeof evt.data === 'string' &&\n", - " evt.data.slice(0, 21) === 'data:image/png;base64'\n", - " ) {\n", - " fig.imageObj.src = evt.data;\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " }\n", - "\n", - " var msg = JSON.parse(evt.data);\n", - " var msg_type = msg['type'];\n", - "\n", - " // Call the \"handle_{type}\" callback, which takes\n", - " // the figure and JSON message as its only arguments.\n", - " try {\n", - " var callback = fig['handle_' + msg_type];\n", - " } catch (e) {\n", - " console.log(\n", - " \"No handler for the '\" + msg_type + \"' message type: \",\n", - " msg\n", - " );\n", - " return;\n", - " }\n", - "\n", - " if (callback) {\n", - " try {\n", - " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", - " callback(fig, msg);\n", - " } catch (e) {\n", - " console.log(\n", - " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", - " e,\n", - " e.stack,\n", - " msg\n", - " );\n", - " }\n", - " }\n", - " };\n", - "};\n", - "\n", - "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", - "mpl.findpos = function (e) {\n", - " //this section is from http://www.quirksmode.org/js/events_properties.html\n", - " var targ;\n", - " if (!e) {\n", - " e = window.event;\n", - " }\n", - " if (e.target) {\n", - " targ = e.target;\n", - " } else if (e.srcElement) {\n", - " targ = e.srcElement;\n", - " }\n", - " if (targ.nodeType === 3) {\n", - " // defeat Safari bug\n", - " targ = targ.parentNode;\n", - " }\n", - "\n", - " // pageX,Y are the mouse positions relative to the document\n", - " var boundingRect = targ.getBoundingClientRect();\n", - " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", - " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", - "\n", - " return { x: x, y: y };\n", - "};\n", - "\n", - "/*\n", - " * return a copy of an object with only non-object keys\n", - " * we need this to avoid circular references\n", - " * http://stackoverflow.com/a/24161582/3208463\n", - " */\n", - "function simpleKeys(original) {\n", - " return Object.keys(original).reduce(function (obj, key) {\n", - " if (typeof original[key] !== 'object') {\n", - " obj[key] = original[key];\n", - " }\n", - " return obj;\n", - " }, {});\n", - "}\n", - "\n", - "mpl.figure.prototype.mouse_event = function (event, name) {\n", - " var canvas_pos = mpl.findpos(event);\n", - "\n", - " if (name === 'button_press') {\n", - " this.canvas.focus();\n", - " this.canvas_div.focus();\n", - " }\n", - "\n", - " var x = canvas_pos.x * this.ratio;\n", - " var y = canvas_pos.y * this.ratio;\n", - "\n", - " this.send_message(name, {\n", - " x: x,\n", - " y: y,\n", - " button: event.button,\n", - " step: event.step,\n", - " guiEvent: simpleKeys(event),\n", - " });\n", - "\n", - " /* This prevents the web browser from automatically changing to\n", - " * the text insertion cursor when the button is pressed. We want\n", - " * to control all of the cursor setting manually through the\n", - " * 'cursor' event from matplotlib */\n", - " event.preventDefault();\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", - " // Handle any extra behaviour associated with a key event\n", - "};\n", - "\n", - "mpl.figure.prototype.key_event = function (event, name) {\n", - " // Prevent repeat events\n", - " if (name === 'key_press') {\n", - " if (event.key === this._key) {\n", - " return;\n", - " } else {\n", - " this._key = event.key;\n", - " }\n", - " }\n", - " if (name === 'key_release') {\n", - " this._key = null;\n", - " }\n", - "\n", - " var value = '';\n", - " if (event.ctrlKey && event.key !== 'Control') {\n", - " value += 'ctrl+';\n", - " }\n", - " else if (event.altKey && event.key !== 'Alt') {\n", - " value += 'alt+';\n", - " }\n", - " else if (event.shiftKey && event.key !== 'Shift') {\n", - " value += 'shift+';\n", - " }\n", - "\n", - " value += 'k' + event.key;\n", - "\n", - " this._key_event_extra(event, name);\n", - "\n", - " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", - " if (name === 'download') {\n", - " this.handle_save(this, null);\n", - " } else {\n", - " this.send_message('toolbar_button', { name: name });\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", - " this.message.textContent = tooltip;\n", - "};\n", - "\n", - "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", - "// prettier-ignore\n", - "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", - "\n", - "mpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", - "\n", - "mpl.default_extension = \"png\";/* global mpl */\n", - "\n", - "var comm_websocket_adapter = function (comm) {\n", - " // Create a \"websocket\"-like object which calls the given IPython comm\n", - " // object with the appropriate methods. Currently this is a non binary\n", - " // socket, so there is still some room for performance tuning.\n", - " var ws = {};\n", - "\n", - " ws.binaryType = comm.kernel.ws.binaryType;\n", - " ws.readyState = comm.kernel.ws.readyState;\n", - " function updateReadyState(_event) {\n", - " if (comm.kernel.ws) {\n", - " ws.readyState = comm.kernel.ws.readyState;\n", - " } else {\n", - " ws.readyState = 3; // Closed state.\n", - " }\n", - " }\n", - " comm.kernel.ws.addEventListener('open', updateReadyState);\n", - " comm.kernel.ws.addEventListener('close', updateReadyState);\n", - " comm.kernel.ws.addEventListener('error', updateReadyState);\n", - "\n", - " ws.close = function () {\n", - " comm.close();\n", - " };\n", - " ws.send = function (m) {\n", - " //console.log('sending', m);\n", - " comm.send(m);\n", - " };\n", - " // Register the callback with on_msg.\n", - " comm.on_msg(function (msg) {\n", - " //console.log('receiving', msg['content']['data'], msg);\n", - " var data = msg['content']['data'];\n", - " if (data['blob'] !== undefined) {\n", - " data = {\n", - " data: new Blob(msg['buffers'], { type: data['blob'] }),\n", - " };\n", - " }\n", - " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", - " ws.onmessage(data);\n", - " });\n", - " return ws;\n", - "};\n", - "\n", - "mpl.mpl_figure_comm = function (comm, msg) {\n", - " // This is the function which gets called when the mpl process\n", - " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", - "\n", - " var id = msg.content.data.id;\n", - " // Get hold of the div created by the display call when the Comm\n", - " // socket was opened in Python.\n", - " var element = document.getElementById(id);\n", - " var ws_proxy = comm_websocket_adapter(comm);\n", - "\n", - " function ondownload(figure, _format) {\n", - " window.open(figure.canvas.toDataURL());\n", - " }\n", - "\n", - " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", - "\n", - " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", - " // web socket which is closed, not our websocket->open comm proxy.\n", - " ws_proxy.onopen();\n", - "\n", - " fig.parent_element = element;\n", - " fig.cell_info = mpl.find_output_cell(\"
\");\n", - " if (!fig.cell_info) {\n", - " console.error('Failed to find cell for figure', id, fig);\n", - " return;\n", - " }\n", - " fig.cell_info[0].output_area.element.on(\n", - " 'cleared',\n", - " { fig: fig },\n", - " fig._remove_fig_handler\n", - " );\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_close = function (fig, msg) {\n", - " var width = fig.canvas.width / fig.ratio;\n", - " fig.cell_info[0].output_area.element.off(\n", - " 'cleared',\n", - " fig._remove_fig_handler\n", - " );\n", - " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", - "\n", - " // Update the output cell to use the data from the current canvas.\n", - " fig.push_to_output();\n", - " var dataURL = fig.canvas.toDataURL();\n", - " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", - " // the notebook keyboard shortcuts fail.\n", - " IPython.keyboard_manager.enable();\n", - " fig.parent_element.innerHTML =\n", - " '';\n", - " fig.close_ws(fig, msg);\n", - "};\n", - "\n", - "mpl.figure.prototype.close_ws = function (fig, msg) {\n", - " fig.send_message('closing', msg);\n", - " // fig.ws.close()\n", - "};\n", - "\n", - "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", - " // Turn the data on the canvas into data in the output cell.\n", - " var width = this.canvas.width / this.ratio;\n", - " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] =\n", - " '';\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Tell IPython that the notebook contents must change.\n", - " IPython.notebook.set_dirty(true);\n", - " this.send_message('ack', {});\n", - " var fig = this;\n", - " // Wait a second, then push the new image to the DOM so\n", - " // that it is saved nicely (might be nice to debounce this).\n", - " setTimeout(function () {\n", - " fig.push_to_output();\n", - " }, 1000);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'btn-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " var button;\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " continue;\n", - " }\n", - "\n", - " button = fig.buttons[name] = document.createElement('button');\n", - " button.classList = 'btn btn-default';\n", - " button.href = '#';\n", - " button.title = name;\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message pull-right';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = document.createElement('div');\n", - " buttongrp.classList = 'btn-group inline pull-right';\n", - " button = document.createElement('button');\n", - " button.classList = 'btn btn-mini btn-primary';\n", - " button.href = '#';\n", - " button.title = 'Stop Interaction';\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', function (_evt) {\n", - " fig.handle_close(fig, {});\n", - " });\n", - " button.addEventListener(\n", - " 'mouseover',\n", - " on_mouseover_closure('Stop Interaction')\n", - " );\n", - " buttongrp.appendChild(button);\n", - " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", - " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", - "};\n", - "\n", - "mpl.figure.prototype._remove_fig_handler = function (event) {\n", - " var fig = event.data.fig;\n", - " if (event.target !== this) {\n", - " // Ignore bubbled events from children.\n", - " return;\n", - " }\n", - " fig.close_ws(fig, {});\n", - "};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (el) {\n", - " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (el) {\n", - " // this is important to make the div 'focusable\n", - " el.setAttribute('tabindex', 0);\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " } else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager) {\n", - " manager = IPython.keyboard_manager;\n", - " }\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which === 13) {\n", - " this.canvas_div.blur();\n", - " // select the cell after this one\n", - " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", - " IPython.notebook.select(index + 1);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " fig.ondownload(fig, null);\n", - "};\n", - "\n", - "mpl.find_output_cell = function (html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i = 0; i < ncells; i++) {\n", - " var cell = cells[i];\n", - " if (cell.cell_type === 'code') {\n", - " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", - " var data = cell.output_area.outputs[j];\n", - " if (data.data) {\n", - " // IPython >= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] === html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "};\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel !== null) {\n", - " IPython.notebook.kernel.comm_manager.register_target(\n", - " 'matplotlib',\n", - " mpl.mpl_figure_comm\n", - " );\n", - "}\n" - ], + "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n rubberband_canvas.addEventListener(\n 'dblclick',\n on_mouse_event_closure('dblclick')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n var img = evt.data;\n if (img.type !== 'image/png') {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n img.type = 'image/png';\n }\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n img\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.key === this._key) {\n return;\n } else {\n this._key = event.key;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.key !== 'Control') {\n value += 'ctrl+';\n }\n else if (event.altKey && event.key !== 'Alt') {\n value += 'alt+';\n }\n else if (event.shiftKey && event.key !== 'Shift') {\n value += 'shift+';\n }\n\n value += 'k' + event.key;\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.binaryType = comm.kernel.ws.binaryType;\n ws.readyState = comm.kernel.ws.readyState;\n function updateReadyState(_event) {\n if (comm.kernel.ws) {\n ws.readyState = comm.kernel.ws.readyState;\n } else {\n ws.readyState = 3; // Closed state.\n }\n }\n comm.kernel.ws.addEventListener('open', updateReadyState);\n comm.kernel.ws.addEventListener('close', updateReadyState);\n comm.kernel.ws.addEventListener('error', updateReadyState);\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n var data = msg['content']['data'];\n if (data['blob'] !== undefined) {\n data = {\n data: new Blob(msg['buffers'], { type: data['blob'] }),\n };\n }\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(data);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", "text/plain": [ "" ] @@ -3459,980 +540,7 @@ "outputs": [ { "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "/* global mpl */\n", - "window.mpl = {};\n", - "\n", - "mpl.get_websocket_type = function () {\n", - " if (typeof WebSocket !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof MozWebSocket !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert(\n", - " 'Your browser does not have WebSocket support. ' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.'\n", - " );\n", - " }\n", - "};\n", - "\n", - "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = this.ws.binaryType !== undefined;\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById('mpl-warnings');\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent =\n", - " 'This browser does not support binary websocket messages. ' +\n", - " 'Performance may be slow.';\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = document.createElement('div');\n", - " this.root.setAttribute('style', 'display: inline-block');\n", - " this._root_extra_style(this.root);\n", - "\n", - " parent_element.appendChild(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message('supports_binary', { value: fig.supports_binary });\n", - " fig.send_message('send_image_mode', {});\n", - " if (fig.ratio !== 1) {\n", - " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", - " }\n", - " fig.send_message('refresh', {});\n", - " };\n", - "\n", - " this.imageObj.onload = function () {\n", - " if (fig.image_mode === 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function () {\n", - " fig.ws.close();\n", - " };\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "};\n", - "\n", - "mpl.figure.prototype._init_header = function () {\n", - " var titlebar = document.createElement('div');\n", - " titlebar.classList =\n", - " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", - " var titletext = document.createElement('div');\n", - " titletext.classList = 'ui-dialog-title';\n", - " titletext.setAttribute(\n", - " 'style',\n", - " 'width: 100%; text-align: center; padding: 3px;'\n", - " );\n", - " titlebar.appendChild(titletext);\n", - " this.root.appendChild(titlebar);\n", - " this.header = titletext;\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._init_canvas = function () {\n", - " var fig = this;\n", - "\n", - " var canvas_div = (this.canvas_div = document.createElement('div'));\n", - " canvas_div.setAttribute(\n", - " 'style',\n", - " 'border: 1px solid #ddd;' +\n", - " 'box-sizing: content-box;' +\n", - " 'clear: both;' +\n", - " 'min-height: 1px;' +\n", - " 'min-width: 1px;' +\n", - " 'outline: 0;' +\n", - " 'overflow: hidden;' +\n", - " 'position: relative;' +\n", - " 'resize: both;'\n", - " );\n", - "\n", - " function on_keyboard_event_closure(name) {\n", - " return function (event) {\n", - " return fig.key_event(event, name);\n", - " };\n", - " }\n", - "\n", - " canvas_div.addEventListener(\n", - " 'keydown',\n", - " on_keyboard_event_closure('key_press')\n", - " );\n", - " canvas_div.addEventListener(\n", - " 'keyup',\n", - " on_keyboard_event_closure('key_release')\n", - " );\n", - "\n", - " this._canvas_extra_style(canvas_div);\n", - " this.root.appendChild(canvas_div);\n", - "\n", - " var canvas = (this.canvas = document.createElement('canvas'));\n", - " canvas.classList.add('mpl-canvas');\n", - " canvas.setAttribute('style', 'box-sizing: content-box;');\n", - "\n", - " this.context = canvas.getContext('2d');\n", - "\n", - " var backingStore =\n", - " this.context.backingStorePixelRatio ||\n", - " this.context.webkitBackingStorePixelRatio ||\n", - " this.context.mozBackingStorePixelRatio ||\n", - " this.context.msBackingStorePixelRatio ||\n", - " this.context.oBackingStorePixelRatio ||\n", - " this.context.backingStorePixelRatio ||\n", - " 1;\n", - "\n", - " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", - " 'canvas'\n", - " ));\n", - " rubberband_canvas.setAttribute(\n", - " 'style',\n", - " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", - " );\n", - "\n", - " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", - " if (this.ResizeObserver === undefined) {\n", - " if (window.ResizeObserver !== undefined) {\n", - " this.ResizeObserver = window.ResizeObserver;\n", - " } else {\n", - " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", - " this.ResizeObserver = obs.ResizeObserver;\n", - " }\n", - " }\n", - "\n", - " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", - " var nentries = entries.length;\n", - " for (var i = 0; i < nentries; i++) {\n", - " var entry = entries[i];\n", - " var width, height;\n", - " if (entry.contentBoxSize) {\n", - " if (entry.contentBoxSize instanceof Array) {\n", - " // Chrome 84 implements new version of spec.\n", - " width = entry.contentBoxSize[0].inlineSize;\n", - " height = entry.contentBoxSize[0].blockSize;\n", - " } else {\n", - " // Firefox implements old version of spec.\n", - " width = entry.contentBoxSize.inlineSize;\n", - " height = entry.contentBoxSize.blockSize;\n", - " }\n", - " } else {\n", - " // Chrome <84 implements even older version of spec.\n", - " width = entry.contentRect.width;\n", - " height = entry.contentRect.height;\n", - " }\n", - "\n", - " // Keep the size of the canvas and rubber band canvas in sync with\n", - " // the canvas container.\n", - " if (entry.devicePixelContentBoxSize) {\n", - " // Chrome 84 implements new version of spec.\n", - " canvas.setAttribute(\n", - " 'width',\n", - " entry.devicePixelContentBoxSize[0].inlineSize\n", - " );\n", - " canvas.setAttribute(\n", - " 'height',\n", - " entry.devicePixelContentBoxSize[0].blockSize\n", - " );\n", - " } else {\n", - " canvas.setAttribute('width', width * fig.ratio);\n", - " canvas.setAttribute('height', height * fig.ratio);\n", - " }\n", - " canvas.setAttribute(\n", - " 'style',\n", - " 'width: ' + width + 'px; height: ' + height + 'px;'\n", - " );\n", - "\n", - " rubberband_canvas.setAttribute('width', width);\n", - " rubberband_canvas.setAttribute('height', height);\n", - "\n", - " // And update the size in Python. We ignore the initial 0/0 size\n", - " // that occurs as the element is placed into the DOM, which should\n", - " // otherwise not happen due to the minimum size styling.\n", - " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", - " fig.request_resize(width, height);\n", - " }\n", - " }\n", - " });\n", - " this.resizeObserverInstance.observe(canvas_div);\n", - "\n", - " function on_mouse_event_closure(name) {\n", - " return function (event) {\n", - " return fig.mouse_event(event, name);\n", - " };\n", - " }\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mousedown',\n", - " on_mouse_event_closure('button_press')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseup',\n", - " on_mouse_event_closure('button_release')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'dblclick',\n", - " on_mouse_event_closure('dblclick')\n", - " );\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband_canvas.addEventListener(\n", - " 'mousemove',\n", - " on_mouse_event_closure('motion_notify')\n", - " );\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseenter',\n", - " on_mouse_event_closure('figure_enter')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseleave',\n", - " on_mouse_event_closure('figure_leave')\n", - " );\n", - "\n", - " canvas_div.addEventListener('wheel', function (event) {\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " on_mouse_event_closure('scroll')(event);\n", - " });\n", - "\n", - " canvas_div.appendChild(canvas);\n", - " canvas_div.appendChild(rubberband_canvas);\n", - "\n", - " this.rubberband_context = rubberband_canvas.getContext('2d');\n", - " this.rubberband_context.strokeStyle = '#000000';\n", - "\n", - " this._resize_canvas = function (width, height, forward) {\n", - " if (forward) {\n", - " canvas_div.style.width = width + 'px';\n", - " canvas_div.style.height = height + 'px';\n", - " }\n", - " };\n", - "\n", - " // Disable right mouse context menu.\n", - " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", - " event.preventDefault();\n", - " return false;\n", - " });\n", - "\n", - " function set_focus() {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'mpl-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " continue;\n", - " }\n", - "\n", - " var button = (fig.buttons[name] = document.createElement('button'));\n", - " button.classList = 'mpl-widget';\n", - " button.setAttribute('role', 'button');\n", - " button.setAttribute('aria-disabled', 'false');\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - "\n", - " var icon_img = document.createElement('img');\n", - " icon_img.src = '_images/' + image + '.png';\n", - " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", - " icon_img.alt = tooltip;\n", - " button.appendChild(icon_img);\n", - "\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " var fmt_picker = document.createElement('select');\n", - " fmt_picker.classList = 'mpl-widget';\n", - " toolbar.appendChild(fmt_picker);\n", - " this.format_dropdown = fmt_picker;\n", - "\n", - " for (var ind in mpl.extensions) {\n", - " var fmt = mpl.extensions[ind];\n", - " var option = document.createElement('option');\n", - " option.selected = fmt === mpl.default_extension;\n", - " option.innerHTML = fmt;\n", - " fmt_picker.appendChild(option);\n", - " }\n", - "\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "};\n", - "\n", - "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", - " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", - " // which will in turn request a refresh of the image.\n", - " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", - "};\n", - "\n", - "mpl.figure.prototype.send_message = function (type, properties) {\n", - " properties['type'] = type;\n", - " properties['figure_id'] = this.id;\n", - " this.ws.send(JSON.stringify(properties));\n", - "};\n", - "\n", - "mpl.figure.prototype.send_draw_message = function () {\n", - " if (!this.waiting) {\n", - " this.waiting = true;\n", - " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " var format_dropdown = fig.format_dropdown;\n", - " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", - " fig.ondownload(fig, format);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", - " var size = msg['size'];\n", - " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", - " fig._resize_canvas(size[0], size[1], msg['forward']);\n", - " fig.send_message('refresh', {});\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", - " var x0 = msg['x0'] / fig.ratio;\n", - " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", - " var x1 = msg['x1'] / fig.ratio;\n", - " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", - " x0 = Math.floor(x0) + 0.5;\n", - " y0 = Math.floor(y0) + 0.5;\n", - " x1 = Math.floor(x1) + 0.5;\n", - " y1 = Math.floor(y1) + 0.5;\n", - " var min_x = Math.min(x0, x1);\n", - " var min_y = Math.min(y0, y1);\n", - " var width = Math.abs(x1 - x0);\n", - " var height = Math.abs(y1 - y0);\n", - "\n", - " fig.rubberband_context.clearRect(\n", - " 0,\n", - " 0,\n", - " fig.canvas.width / fig.ratio,\n", - " fig.canvas.height / fig.ratio\n", - " );\n", - "\n", - " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", - " // Updates the figure title.\n", - " fig.header.textContent = msg['label'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", - " var cursor = msg['cursor'];\n", - " switch (cursor) {\n", - " case 0:\n", - " cursor = 'pointer';\n", - " break;\n", - " case 1:\n", - " cursor = 'default';\n", - " break;\n", - " case 2:\n", - " cursor = 'crosshair';\n", - " break;\n", - " case 3:\n", - " cursor = 'move';\n", - " break;\n", - " }\n", - " fig.rubberband_canvas.style.cursor = cursor;\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_message = function (fig, msg) {\n", - " fig.message.textContent = msg['message'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", - " // Request the server to send over a new figure.\n", - " fig.send_draw_message();\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", - " fig.image_mode = msg['mode'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", - " for (var key in msg) {\n", - " if (!(key in fig.buttons)) {\n", - " continue;\n", - " }\n", - " fig.buttons[key].disabled = !msg[key];\n", - " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", - " if (msg['mode'] === 'PAN') {\n", - " fig.buttons['Pan'].classList.add('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " } else if (msg['mode'] === 'ZOOM') {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.add('active');\n", - " } else {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Called whenever the canvas gets updated.\n", - " this.send_message('ack', {});\n", - "};\n", - "\n", - "// A function to construct a web socket function for onmessage handling.\n", - "// Called in the figure constructor.\n", - "mpl.figure.prototype._make_on_message_function = function (fig) {\n", - " return function socket_on_message(evt) {\n", - " if (evt.data instanceof Blob) {\n", - " var img = evt.data;\n", - " if (img.type !== 'image/png') {\n", - " /* FIXME: We get \"Resource interpreted as Image but\n", - " * transferred with MIME type text/plain:\" errors on\n", - " * Chrome. But how to set the MIME type? It doesn't seem\n", - " * to be part of the websocket stream */\n", - " img.type = 'image/png';\n", - " }\n", - "\n", - " /* Free the memory for the previous frames */\n", - " if (fig.imageObj.src) {\n", - " (window.URL || window.webkitURL).revokeObjectURL(\n", - " fig.imageObj.src\n", - " );\n", - " }\n", - "\n", - " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", - " img\n", - " );\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " } else if (\n", - " typeof evt.data === 'string' &&\n", - " evt.data.slice(0, 21) === 'data:image/png;base64'\n", - " ) {\n", - " fig.imageObj.src = evt.data;\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " }\n", - "\n", - " var msg = JSON.parse(evt.data);\n", - " var msg_type = msg['type'];\n", - "\n", - " // Call the \"handle_{type}\" callback, which takes\n", - " // the figure and JSON message as its only arguments.\n", - " try {\n", - " var callback = fig['handle_' + msg_type];\n", - " } catch (e) {\n", - " console.log(\n", - " \"No handler for the '\" + msg_type + \"' message type: \",\n", - " msg\n", - " );\n", - " return;\n", - " }\n", - "\n", - " if (callback) {\n", - " try {\n", - " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", - " callback(fig, msg);\n", - " } catch (e) {\n", - " console.log(\n", - " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", - " e,\n", - " e.stack,\n", - " msg\n", - " );\n", - " }\n", - " }\n", - " };\n", - "};\n", - "\n", - "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", - "mpl.findpos = function (e) {\n", - " //this section is from http://www.quirksmode.org/js/events_properties.html\n", - " var targ;\n", - " if (!e) {\n", - " e = window.event;\n", - " }\n", - " if (e.target) {\n", - " targ = e.target;\n", - " } else if (e.srcElement) {\n", - " targ = e.srcElement;\n", - " }\n", - " if (targ.nodeType === 3) {\n", - " // defeat Safari bug\n", - " targ = targ.parentNode;\n", - " }\n", - "\n", - " // pageX,Y are the mouse positions relative to the document\n", - " var boundingRect = targ.getBoundingClientRect();\n", - " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", - " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", - "\n", - " return { x: x, y: y };\n", - "};\n", - "\n", - "/*\n", - " * return a copy of an object with only non-object keys\n", - " * we need this to avoid circular references\n", - " * http://stackoverflow.com/a/24161582/3208463\n", - " */\n", - "function simpleKeys(original) {\n", - " return Object.keys(original).reduce(function (obj, key) {\n", - " if (typeof original[key] !== 'object') {\n", - " obj[key] = original[key];\n", - " }\n", - " return obj;\n", - " }, {});\n", - "}\n", - "\n", - "mpl.figure.prototype.mouse_event = function (event, name) {\n", - " var canvas_pos = mpl.findpos(event);\n", - "\n", - " if (name === 'button_press') {\n", - " this.canvas.focus();\n", - " this.canvas_div.focus();\n", - " }\n", - "\n", - " var x = canvas_pos.x * this.ratio;\n", - " var y = canvas_pos.y * this.ratio;\n", - "\n", - " this.send_message(name, {\n", - " x: x,\n", - " y: y,\n", - " button: event.button,\n", - " step: event.step,\n", - " guiEvent: simpleKeys(event),\n", - " });\n", - "\n", - " /* This prevents the web browser from automatically changing to\n", - " * the text insertion cursor when the button is pressed. We want\n", - " * to control all of the cursor setting manually through the\n", - " * 'cursor' event from matplotlib */\n", - " event.preventDefault();\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", - " // Handle any extra behaviour associated with a key event\n", - "};\n", - "\n", - "mpl.figure.prototype.key_event = function (event, name) {\n", - " // Prevent repeat events\n", - " if (name === 'key_press') {\n", - " if (event.key === this._key) {\n", - " return;\n", - " } else {\n", - " this._key = event.key;\n", - " }\n", - " }\n", - " if (name === 'key_release') {\n", - " this._key = null;\n", - " }\n", - "\n", - " var value = '';\n", - " if (event.ctrlKey && event.key !== 'Control') {\n", - " value += 'ctrl+';\n", - " }\n", - " else if (event.altKey && event.key !== 'Alt') {\n", - " value += 'alt+';\n", - " }\n", - " else if (event.shiftKey && event.key !== 'Shift') {\n", - " value += 'shift+';\n", - " }\n", - "\n", - " value += 'k' + event.key;\n", - "\n", - " this._key_event_extra(event, name);\n", - "\n", - " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", - " if (name === 'download') {\n", - " this.handle_save(this, null);\n", - " } else {\n", - " this.send_message('toolbar_button', { name: name });\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", - " this.message.textContent = tooltip;\n", - "};\n", - "\n", - "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", - "// prettier-ignore\n", - "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", - "\n", - "mpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", - "\n", - "mpl.default_extension = \"png\";/* global mpl */\n", - "\n", - "var comm_websocket_adapter = function (comm) {\n", - " // Create a \"websocket\"-like object which calls the given IPython comm\n", - " // object with the appropriate methods. Currently this is a non binary\n", - " // socket, so there is still some room for performance tuning.\n", - " var ws = {};\n", - "\n", - " ws.binaryType = comm.kernel.ws.binaryType;\n", - " ws.readyState = comm.kernel.ws.readyState;\n", - " function updateReadyState(_event) {\n", - " if (comm.kernel.ws) {\n", - " ws.readyState = comm.kernel.ws.readyState;\n", - " } else {\n", - " ws.readyState = 3; // Closed state.\n", - " }\n", - " }\n", - " comm.kernel.ws.addEventListener('open', updateReadyState);\n", - " comm.kernel.ws.addEventListener('close', updateReadyState);\n", - " comm.kernel.ws.addEventListener('error', updateReadyState);\n", - "\n", - " ws.close = function () {\n", - " comm.close();\n", - " };\n", - " ws.send = function (m) {\n", - " //console.log('sending', m);\n", - " comm.send(m);\n", - " };\n", - " // Register the callback with on_msg.\n", - " comm.on_msg(function (msg) {\n", - " //console.log('receiving', msg['content']['data'], msg);\n", - " var data = msg['content']['data'];\n", - " if (data['blob'] !== undefined) {\n", - " data = {\n", - " data: new Blob(msg['buffers'], { type: data['blob'] }),\n", - " };\n", - " }\n", - " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", - " ws.onmessage(data);\n", - " });\n", - " return ws;\n", - "};\n", - "\n", - "mpl.mpl_figure_comm = function (comm, msg) {\n", - " // This is the function which gets called when the mpl process\n", - " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", - "\n", - " var id = msg.content.data.id;\n", - " // Get hold of the div created by the display call when the Comm\n", - " // socket was opened in Python.\n", - " var element = document.getElementById(id);\n", - " var ws_proxy = comm_websocket_adapter(comm);\n", - "\n", - " function ondownload(figure, _format) {\n", - " window.open(figure.canvas.toDataURL());\n", - " }\n", - "\n", - " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", - "\n", - " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", - " // web socket which is closed, not our websocket->open comm proxy.\n", - " ws_proxy.onopen();\n", - "\n", - " fig.parent_element = element;\n", - " fig.cell_info = mpl.find_output_cell(\"
\");\n", - " if (!fig.cell_info) {\n", - " console.error('Failed to find cell for figure', id, fig);\n", - " return;\n", - " }\n", - " fig.cell_info[0].output_area.element.on(\n", - " 'cleared',\n", - " { fig: fig },\n", - " fig._remove_fig_handler\n", - " );\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_close = function (fig, msg) {\n", - " var width = fig.canvas.width / fig.ratio;\n", - " fig.cell_info[0].output_area.element.off(\n", - " 'cleared',\n", - " fig._remove_fig_handler\n", - " );\n", - " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", - "\n", - " // Update the output cell to use the data from the current canvas.\n", - " fig.push_to_output();\n", - " var dataURL = fig.canvas.toDataURL();\n", - " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", - " // the notebook keyboard shortcuts fail.\n", - " IPython.keyboard_manager.enable();\n", - " fig.parent_element.innerHTML =\n", - " '';\n", - " fig.close_ws(fig, msg);\n", - "};\n", - "\n", - "mpl.figure.prototype.close_ws = function (fig, msg) {\n", - " fig.send_message('closing', msg);\n", - " // fig.ws.close()\n", - "};\n", - "\n", - "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", - " // Turn the data on the canvas into data in the output cell.\n", - " var width = this.canvas.width / this.ratio;\n", - " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] =\n", - " '';\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Tell IPython that the notebook contents must change.\n", - " IPython.notebook.set_dirty(true);\n", - " this.send_message('ack', {});\n", - " var fig = this;\n", - " // Wait a second, then push the new image to the DOM so\n", - " // that it is saved nicely (might be nice to debounce this).\n", - " setTimeout(function () {\n", - " fig.push_to_output();\n", - " }, 1000);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'btn-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " var button;\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " continue;\n", - " }\n", - "\n", - " button = fig.buttons[name] = document.createElement('button');\n", - " button.classList = 'btn btn-default';\n", - " button.href = '#';\n", - " button.title = name;\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message pull-right';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = document.createElement('div');\n", - " buttongrp.classList = 'btn-group inline pull-right';\n", - " button = document.createElement('button');\n", - " button.classList = 'btn btn-mini btn-primary';\n", - " button.href = '#';\n", - " button.title = 'Stop Interaction';\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', function (_evt) {\n", - " fig.handle_close(fig, {});\n", - " });\n", - " button.addEventListener(\n", - " 'mouseover',\n", - " on_mouseover_closure('Stop Interaction')\n", - " );\n", - " buttongrp.appendChild(button);\n", - " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", - " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", - "};\n", - "\n", - "mpl.figure.prototype._remove_fig_handler = function (event) {\n", - " var fig = event.data.fig;\n", - " if (event.target !== this) {\n", - " // Ignore bubbled events from children.\n", - " return;\n", - " }\n", - " fig.close_ws(fig, {});\n", - "};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (el) {\n", - " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (el) {\n", - " // this is important to make the div 'focusable\n", - " el.setAttribute('tabindex', 0);\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " } else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager) {\n", - " manager = IPython.keyboard_manager;\n", - " }\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which === 13) {\n", - " this.canvas_div.blur();\n", - " // select the cell after this one\n", - " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", - " IPython.notebook.select(index + 1);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " fig.ondownload(fig, null);\n", - "};\n", - "\n", - "mpl.find_output_cell = function (html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i = 0; i < ncells; i++) {\n", - " var cell = cells[i];\n", - " if (cell.cell_type === 'code') {\n", - " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", - " var data = cell.output_area.outputs[j];\n", - " if (data.data) {\n", - " // IPython >= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] === html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "};\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel !== null) {\n", - " IPython.notebook.kernel.comm_manager.register_target(\n", - " 'matplotlib',\n", - " mpl.mpl_figure_comm\n", - " );\n", - "}\n" - ], + "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n rubberband_canvas.addEventListener(\n 'dblclick',\n on_mouse_event_closure('dblclick')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n var img = evt.data;\n if (img.type !== 'image/png') {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n img.type = 'image/png';\n }\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n img\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.key === this._key) {\n return;\n } else {\n this._key = event.key;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.key !== 'Control') {\n value += 'ctrl+';\n }\n else if (event.altKey && event.key !== 'Alt') {\n value += 'alt+';\n }\n else if (event.shiftKey && event.key !== 'Shift') {\n value += 'shift+';\n }\n\n value += 'k' + event.key;\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.binaryType = comm.kernel.ws.binaryType;\n ws.readyState = comm.kernel.ws.readyState;\n function updateReadyState(_event) {\n if (comm.kernel.ws) {\n ws.readyState = comm.kernel.ws.readyState;\n } else {\n ws.readyState = 3; // Closed state.\n }\n }\n comm.kernel.ws.addEventListener('open', updateReadyState);\n comm.kernel.ws.addEventListener('close', updateReadyState);\n comm.kernel.ws.addEventListener('error', updateReadyState);\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n var data = msg['content']['data'];\n if (data['blob'] !== undefined) {\n data = {\n data: new Blob(msg['buffers'], { type: data['blob'] }),\n };\n }\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(data);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", "text/plain": [ "" ] @@ -4992,980 +1100,7 @@ "outputs": [ { "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "/* global mpl */\n", - "window.mpl = {};\n", - "\n", - "mpl.get_websocket_type = function () {\n", - " if (typeof WebSocket !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof MozWebSocket !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert(\n", - " 'Your browser does not have WebSocket support. ' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.'\n", - " );\n", - " }\n", - "};\n", - "\n", - "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = this.ws.binaryType !== undefined;\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById('mpl-warnings');\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent =\n", - " 'This browser does not support binary websocket messages. ' +\n", - " 'Performance may be slow.';\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = document.createElement('div');\n", - " this.root.setAttribute('style', 'display: inline-block');\n", - " this._root_extra_style(this.root);\n", - "\n", - " parent_element.appendChild(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message('supports_binary', { value: fig.supports_binary });\n", - " fig.send_message('send_image_mode', {});\n", - " if (fig.ratio !== 1) {\n", - " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", - " }\n", - " fig.send_message('refresh', {});\n", - " };\n", - "\n", - " this.imageObj.onload = function () {\n", - " if (fig.image_mode === 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function () {\n", - " fig.ws.close();\n", - " };\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "};\n", - "\n", - "mpl.figure.prototype._init_header = function () {\n", - " var titlebar = document.createElement('div');\n", - " titlebar.classList =\n", - " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", - " var titletext = document.createElement('div');\n", - " titletext.classList = 'ui-dialog-title';\n", - " titletext.setAttribute(\n", - " 'style',\n", - " 'width: 100%; text-align: center; padding: 3px;'\n", - " );\n", - " titlebar.appendChild(titletext);\n", - " this.root.appendChild(titlebar);\n", - " this.header = titletext;\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._init_canvas = function () {\n", - " var fig = this;\n", - "\n", - " var canvas_div = (this.canvas_div = document.createElement('div'));\n", - " canvas_div.setAttribute(\n", - " 'style',\n", - " 'border: 1px solid #ddd;' +\n", - " 'box-sizing: content-box;' +\n", - " 'clear: both;' +\n", - " 'min-height: 1px;' +\n", - " 'min-width: 1px;' +\n", - " 'outline: 0;' +\n", - " 'overflow: hidden;' +\n", - " 'position: relative;' +\n", - " 'resize: both;'\n", - " );\n", - "\n", - " function on_keyboard_event_closure(name) {\n", - " return function (event) {\n", - " return fig.key_event(event, name);\n", - " };\n", - " }\n", - "\n", - " canvas_div.addEventListener(\n", - " 'keydown',\n", - " on_keyboard_event_closure('key_press')\n", - " );\n", - " canvas_div.addEventListener(\n", - " 'keyup',\n", - " on_keyboard_event_closure('key_release')\n", - " );\n", - "\n", - " this._canvas_extra_style(canvas_div);\n", - " this.root.appendChild(canvas_div);\n", - "\n", - " var canvas = (this.canvas = document.createElement('canvas'));\n", - " canvas.classList.add('mpl-canvas');\n", - " canvas.setAttribute('style', 'box-sizing: content-box;');\n", - "\n", - " this.context = canvas.getContext('2d');\n", - "\n", - " var backingStore =\n", - " this.context.backingStorePixelRatio ||\n", - " this.context.webkitBackingStorePixelRatio ||\n", - " this.context.mozBackingStorePixelRatio ||\n", - " this.context.msBackingStorePixelRatio ||\n", - " this.context.oBackingStorePixelRatio ||\n", - " this.context.backingStorePixelRatio ||\n", - " 1;\n", - "\n", - " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", - " 'canvas'\n", - " ));\n", - " rubberband_canvas.setAttribute(\n", - " 'style',\n", - " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", - " );\n", - "\n", - " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", - " if (this.ResizeObserver === undefined) {\n", - " if (window.ResizeObserver !== undefined) {\n", - " this.ResizeObserver = window.ResizeObserver;\n", - " } else {\n", - " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", - " this.ResizeObserver = obs.ResizeObserver;\n", - " }\n", - " }\n", - "\n", - " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", - " var nentries = entries.length;\n", - " for (var i = 0; i < nentries; i++) {\n", - " var entry = entries[i];\n", - " var width, height;\n", - " if (entry.contentBoxSize) {\n", - " if (entry.contentBoxSize instanceof Array) {\n", - " // Chrome 84 implements new version of spec.\n", - " width = entry.contentBoxSize[0].inlineSize;\n", - " height = entry.contentBoxSize[0].blockSize;\n", - " } else {\n", - " // Firefox implements old version of spec.\n", - " width = entry.contentBoxSize.inlineSize;\n", - " height = entry.contentBoxSize.blockSize;\n", - " }\n", - " } else {\n", - " // Chrome <84 implements even older version of spec.\n", - " width = entry.contentRect.width;\n", - " height = entry.contentRect.height;\n", - " }\n", - "\n", - " // Keep the size of the canvas and rubber band canvas in sync with\n", - " // the canvas container.\n", - " if (entry.devicePixelContentBoxSize) {\n", - " // Chrome 84 implements new version of spec.\n", - " canvas.setAttribute(\n", - " 'width',\n", - " entry.devicePixelContentBoxSize[0].inlineSize\n", - " );\n", - " canvas.setAttribute(\n", - " 'height',\n", - " entry.devicePixelContentBoxSize[0].blockSize\n", - " );\n", - " } else {\n", - " canvas.setAttribute('width', width * fig.ratio);\n", - " canvas.setAttribute('height', height * fig.ratio);\n", - " }\n", - " canvas.setAttribute(\n", - " 'style',\n", - " 'width: ' + width + 'px; height: ' + height + 'px;'\n", - " );\n", - "\n", - " rubberband_canvas.setAttribute('width', width);\n", - " rubberband_canvas.setAttribute('height', height);\n", - "\n", - " // And update the size in Python. We ignore the initial 0/0 size\n", - " // that occurs as the element is placed into the DOM, which should\n", - " // otherwise not happen due to the minimum size styling.\n", - " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", - " fig.request_resize(width, height);\n", - " }\n", - " }\n", - " });\n", - " this.resizeObserverInstance.observe(canvas_div);\n", - "\n", - " function on_mouse_event_closure(name) {\n", - " return function (event) {\n", - " return fig.mouse_event(event, name);\n", - " };\n", - " }\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mousedown',\n", - " on_mouse_event_closure('button_press')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseup',\n", - " on_mouse_event_closure('button_release')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'dblclick',\n", - " on_mouse_event_closure('dblclick')\n", - " );\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband_canvas.addEventListener(\n", - " 'mousemove',\n", - " on_mouse_event_closure('motion_notify')\n", - " );\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseenter',\n", - " on_mouse_event_closure('figure_enter')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseleave',\n", - " on_mouse_event_closure('figure_leave')\n", - " );\n", - "\n", - " canvas_div.addEventListener('wheel', function (event) {\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " on_mouse_event_closure('scroll')(event);\n", - " });\n", - "\n", - " canvas_div.appendChild(canvas);\n", - " canvas_div.appendChild(rubberband_canvas);\n", - "\n", - " this.rubberband_context = rubberband_canvas.getContext('2d');\n", - " this.rubberband_context.strokeStyle = '#000000';\n", - "\n", - " this._resize_canvas = function (width, height, forward) {\n", - " if (forward) {\n", - " canvas_div.style.width = width + 'px';\n", - " canvas_div.style.height = height + 'px';\n", - " }\n", - " };\n", - "\n", - " // Disable right mouse context menu.\n", - " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", - " event.preventDefault();\n", - " return false;\n", - " });\n", - "\n", - " function set_focus() {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'mpl-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " continue;\n", - " }\n", - "\n", - " var button = (fig.buttons[name] = document.createElement('button'));\n", - " button.classList = 'mpl-widget';\n", - " button.setAttribute('role', 'button');\n", - " button.setAttribute('aria-disabled', 'false');\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - "\n", - " var icon_img = document.createElement('img');\n", - " icon_img.src = '_images/' + image + '.png';\n", - " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", - " icon_img.alt = tooltip;\n", - " button.appendChild(icon_img);\n", - "\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " var fmt_picker = document.createElement('select');\n", - " fmt_picker.classList = 'mpl-widget';\n", - " toolbar.appendChild(fmt_picker);\n", - " this.format_dropdown = fmt_picker;\n", - "\n", - " for (var ind in mpl.extensions) {\n", - " var fmt = mpl.extensions[ind];\n", - " var option = document.createElement('option');\n", - " option.selected = fmt === mpl.default_extension;\n", - " option.innerHTML = fmt;\n", - " fmt_picker.appendChild(option);\n", - " }\n", - "\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "};\n", - "\n", - "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", - " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", - " // which will in turn request a refresh of the image.\n", - " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", - "};\n", - "\n", - "mpl.figure.prototype.send_message = function (type, properties) {\n", - " properties['type'] = type;\n", - " properties['figure_id'] = this.id;\n", - " this.ws.send(JSON.stringify(properties));\n", - "};\n", - "\n", - "mpl.figure.prototype.send_draw_message = function () {\n", - " if (!this.waiting) {\n", - " this.waiting = true;\n", - " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " var format_dropdown = fig.format_dropdown;\n", - " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", - " fig.ondownload(fig, format);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", - " var size = msg['size'];\n", - " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", - " fig._resize_canvas(size[0], size[1], msg['forward']);\n", - " fig.send_message('refresh', {});\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", - " var x0 = msg['x0'] / fig.ratio;\n", - " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", - " var x1 = msg['x1'] / fig.ratio;\n", - " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", - " x0 = Math.floor(x0) + 0.5;\n", - " y0 = Math.floor(y0) + 0.5;\n", - " x1 = Math.floor(x1) + 0.5;\n", - " y1 = Math.floor(y1) + 0.5;\n", - " var min_x = Math.min(x0, x1);\n", - " var min_y = Math.min(y0, y1);\n", - " var width = Math.abs(x1 - x0);\n", - " var height = Math.abs(y1 - y0);\n", - "\n", - " fig.rubberband_context.clearRect(\n", - " 0,\n", - " 0,\n", - " fig.canvas.width / fig.ratio,\n", - " fig.canvas.height / fig.ratio\n", - " );\n", - "\n", - " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", - " // Updates the figure title.\n", - " fig.header.textContent = msg['label'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", - " var cursor = msg['cursor'];\n", - " switch (cursor) {\n", - " case 0:\n", - " cursor = 'pointer';\n", - " break;\n", - " case 1:\n", - " cursor = 'default';\n", - " break;\n", - " case 2:\n", - " cursor = 'crosshair';\n", - " break;\n", - " case 3:\n", - " cursor = 'move';\n", - " break;\n", - " }\n", - " fig.rubberband_canvas.style.cursor = cursor;\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_message = function (fig, msg) {\n", - " fig.message.textContent = msg['message'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", - " // Request the server to send over a new figure.\n", - " fig.send_draw_message();\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", - " fig.image_mode = msg['mode'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", - " for (var key in msg) {\n", - " if (!(key in fig.buttons)) {\n", - " continue;\n", - " }\n", - " fig.buttons[key].disabled = !msg[key];\n", - " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", - " if (msg['mode'] === 'PAN') {\n", - " fig.buttons['Pan'].classList.add('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " } else if (msg['mode'] === 'ZOOM') {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.add('active');\n", - " } else {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Called whenever the canvas gets updated.\n", - " this.send_message('ack', {});\n", - "};\n", - "\n", - "// A function to construct a web socket function for onmessage handling.\n", - "// Called in the figure constructor.\n", - "mpl.figure.prototype._make_on_message_function = function (fig) {\n", - " return function socket_on_message(evt) {\n", - " if (evt.data instanceof Blob) {\n", - " var img = evt.data;\n", - " if (img.type !== 'image/png') {\n", - " /* FIXME: We get \"Resource interpreted as Image but\n", - " * transferred with MIME type text/plain:\" errors on\n", - " * Chrome. But how to set the MIME type? It doesn't seem\n", - " * to be part of the websocket stream */\n", - " img.type = 'image/png';\n", - " }\n", - "\n", - " /* Free the memory for the previous frames */\n", - " if (fig.imageObj.src) {\n", - " (window.URL || window.webkitURL).revokeObjectURL(\n", - " fig.imageObj.src\n", - " );\n", - " }\n", - "\n", - " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", - " img\n", - " );\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " } else if (\n", - " typeof evt.data === 'string' &&\n", - " evt.data.slice(0, 21) === 'data:image/png;base64'\n", - " ) {\n", - " fig.imageObj.src = evt.data;\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " }\n", - "\n", - " var msg = JSON.parse(evt.data);\n", - " var msg_type = msg['type'];\n", - "\n", - " // Call the \"handle_{type}\" callback, which takes\n", - " // the figure and JSON message as its only arguments.\n", - " try {\n", - " var callback = fig['handle_' + msg_type];\n", - " } catch (e) {\n", - " console.log(\n", - " \"No handler for the '\" + msg_type + \"' message type: \",\n", - " msg\n", - " );\n", - " return;\n", - " }\n", - "\n", - " if (callback) {\n", - " try {\n", - " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", - " callback(fig, msg);\n", - " } catch (e) {\n", - " console.log(\n", - " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", - " e,\n", - " e.stack,\n", - " msg\n", - " );\n", - " }\n", - " }\n", - " };\n", - "};\n", - "\n", - "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", - "mpl.findpos = function (e) {\n", - " //this section is from http://www.quirksmode.org/js/events_properties.html\n", - " var targ;\n", - " if (!e) {\n", - " e = window.event;\n", - " }\n", - " if (e.target) {\n", - " targ = e.target;\n", - " } else if (e.srcElement) {\n", - " targ = e.srcElement;\n", - " }\n", - " if (targ.nodeType === 3) {\n", - " // defeat Safari bug\n", - " targ = targ.parentNode;\n", - " }\n", - "\n", - " // pageX,Y are the mouse positions relative to the document\n", - " var boundingRect = targ.getBoundingClientRect();\n", - " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", - " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", - "\n", - " return { x: x, y: y };\n", - "};\n", - "\n", - "/*\n", - " * return a copy of an object with only non-object keys\n", - " * we need this to avoid circular references\n", - " * http://stackoverflow.com/a/24161582/3208463\n", - " */\n", - "function simpleKeys(original) {\n", - " return Object.keys(original).reduce(function (obj, key) {\n", - " if (typeof original[key] !== 'object') {\n", - " obj[key] = original[key];\n", - " }\n", - " return obj;\n", - " }, {});\n", - "}\n", - "\n", - "mpl.figure.prototype.mouse_event = function (event, name) {\n", - " var canvas_pos = mpl.findpos(event);\n", - "\n", - " if (name === 'button_press') {\n", - " this.canvas.focus();\n", - " this.canvas_div.focus();\n", - " }\n", - "\n", - " var x = canvas_pos.x * this.ratio;\n", - " var y = canvas_pos.y * this.ratio;\n", - "\n", - " this.send_message(name, {\n", - " x: x,\n", - " y: y,\n", - " button: event.button,\n", - " step: event.step,\n", - " guiEvent: simpleKeys(event),\n", - " });\n", - "\n", - " /* This prevents the web browser from automatically changing to\n", - " * the text insertion cursor when the button is pressed. We want\n", - " * to control all of the cursor setting manually through the\n", - " * 'cursor' event from matplotlib */\n", - " event.preventDefault();\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", - " // Handle any extra behaviour associated with a key event\n", - "};\n", - "\n", - "mpl.figure.prototype.key_event = function (event, name) {\n", - " // Prevent repeat events\n", - " if (name === 'key_press') {\n", - " if (event.key === this._key) {\n", - " return;\n", - " } else {\n", - " this._key = event.key;\n", - " }\n", - " }\n", - " if (name === 'key_release') {\n", - " this._key = null;\n", - " }\n", - "\n", - " var value = '';\n", - " if (event.ctrlKey && event.key !== 'Control') {\n", - " value += 'ctrl+';\n", - " }\n", - " else if (event.altKey && event.key !== 'Alt') {\n", - " value += 'alt+';\n", - " }\n", - " else if (event.shiftKey && event.key !== 'Shift') {\n", - " value += 'shift+';\n", - " }\n", - "\n", - " value += 'k' + event.key;\n", - "\n", - " this._key_event_extra(event, name);\n", - "\n", - " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", - " if (name === 'download') {\n", - " this.handle_save(this, null);\n", - " } else {\n", - " this.send_message('toolbar_button', { name: name });\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", - " this.message.textContent = tooltip;\n", - "};\n", - "\n", - "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", - "// prettier-ignore\n", - "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", - "\n", - "mpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", - "\n", - "mpl.default_extension = \"png\";/* global mpl */\n", - "\n", - "var comm_websocket_adapter = function (comm) {\n", - " // Create a \"websocket\"-like object which calls the given IPython comm\n", - " // object with the appropriate methods. Currently this is a non binary\n", - " // socket, so there is still some room for performance tuning.\n", - " var ws = {};\n", - "\n", - " ws.binaryType = comm.kernel.ws.binaryType;\n", - " ws.readyState = comm.kernel.ws.readyState;\n", - " function updateReadyState(_event) {\n", - " if (comm.kernel.ws) {\n", - " ws.readyState = comm.kernel.ws.readyState;\n", - " } else {\n", - " ws.readyState = 3; // Closed state.\n", - " }\n", - " }\n", - " comm.kernel.ws.addEventListener('open', updateReadyState);\n", - " comm.kernel.ws.addEventListener('close', updateReadyState);\n", - " comm.kernel.ws.addEventListener('error', updateReadyState);\n", - "\n", - " ws.close = function () {\n", - " comm.close();\n", - " };\n", - " ws.send = function (m) {\n", - " //console.log('sending', m);\n", - " comm.send(m);\n", - " };\n", - " // Register the callback with on_msg.\n", - " comm.on_msg(function (msg) {\n", - " //console.log('receiving', msg['content']['data'], msg);\n", - " var data = msg['content']['data'];\n", - " if (data['blob'] !== undefined) {\n", - " data = {\n", - " data: new Blob(msg['buffers'], { type: data['blob'] }),\n", - " };\n", - " }\n", - " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", - " ws.onmessage(data);\n", - " });\n", - " return ws;\n", - "};\n", - "\n", - "mpl.mpl_figure_comm = function (comm, msg) {\n", - " // This is the function which gets called when the mpl process\n", - " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", - "\n", - " var id = msg.content.data.id;\n", - " // Get hold of the div created by the display call when the Comm\n", - " // socket was opened in Python.\n", - " var element = document.getElementById(id);\n", - " var ws_proxy = comm_websocket_adapter(comm);\n", - "\n", - " function ondownload(figure, _format) {\n", - " window.open(figure.canvas.toDataURL());\n", - " }\n", - "\n", - " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", - "\n", - " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", - " // web socket which is closed, not our websocket->open comm proxy.\n", - " ws_proxy.onopen();\n", - "\n", - " fig.parent_element = element;\n", - " fig.cell_info = mpl.find_output_cell(\"
\");\n", - " if (!fig.cell_info) {\n", - " console.error('Failed to find cell for figure', id, fig);\n", - " return;\n", - " }\n", - " fig.cell_info[0].output_area.element.on(\n", - " 'cleared',\n", - " { fig: fig },\n", - " fig._remove_fig_handler\n", - " );\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_close = function (fig, msg) {\n", - " var width = fig.canvas.width / fig.ratio;\n", - " fig.cell_info[0].output_area.element.off(\n", - " 'cleared',\n", - " fig._remove_fig_handler\n", - " );\n", - " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", - "\n", - " // Update the output cell to use the data from the current canvas.\n", - " fig.push_to_output();\n", - " var dataURL = fig.canvas.toDataURL();\n", - " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", - " // the notebook keyboard shortcuts fail.\n", - " IPython.keyboard_manager.enable();\n", - " fig.parent_element.innerHTML =\n", - " '';\n", - " fig.close_ws(fig, msg);\n", - "};\n", - "\n", - "mpl.figure.prototype.close_ws = function (fig, msg) {\n", - " fig.send_message('closing', msg);\n", - " // fig.ws.close()\n", - "};\n", - "\n", - "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", - " // Turn the data on the canvas into data in the output cell.\n", - " var width = this.canvas.width / this.ratio;\n", - " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] =\n", - " '';\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Tell IPython that the notebook contents must change.\n", - " IPython.notebook.set_dirty(true);\n", - " this.send_message('ack', {});\n", - " var fig = this;\n", - " // Wait a second, then push the new image to the DOM so\n", - " // that it is saved nicely (might be nice to debounce this).\n", - " setTimeout(function () {\n", - " fig.push_to_output();\n", - " }, 1000);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'btn-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " var button;\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " continue;\n", - " }\n", - "\n", - " button = fig.buttons[name] = document.createElement('button');\n", - " button.classList = 'btn btn-default';\n", - " button.href = '#';\n", - " button.title = name;\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message pull-right';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = document.createElement('div');\n", - " buttongrp.classList = 'btn-group inline pull-right';\n", - " button = document.createElement('button');\n", - " button.classList = 'btn btn-mini btn-primary';\n", - " button.href = '#';\n", - " button.title = 'Stop Interaction';\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', function (_evt) {\n", - " fig.handle_close(fig, {});\n", - " });\n", - " button.addEventListener(\n", - " 'mouseover',\n", - " on_mouseover_closure('Stop Interaction')\n", - " );\n", - " buttongrp.appendChild(button);\n", - " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", - " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", - "};\n", - "\n", - "mpl.figure.prototype._remove_fig_handler = function (event) {\n", - " var fig = event.data.fig;\n", - " if (event.target !== this) {\n", - " // Ignore bubbled events from children.\n", - " return;\n", - " }\n", - " fig.close_ws(fig, {});\n", - "};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (el) {\n", - " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (el) {\n", - " // this is important to make the div 'focusable\n", - " el.setAttribute('tabindex', 0);\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " } else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager) {\n", - " manager = IPython.keyboard_manager;\n", - " }\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which === 13) {\n", - " this.canvas_div.blur();\n", - " // select the cell after this one\n", - " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", - " IPython.notebook.select(index + 1);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " fig.ondownload(fig, null);\n", - "};\n", - "\n", - "mpl.find_output_cell = function (html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i = 0; i < ncells; i++) {\n", - " var cell = cells[i];\n", - " if (cell.cell_type === 'code') {\n", - " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", - " var data = cell.output_area.outputs[j];\n", - " if (data.data) {\n", - " // IPython >= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] === html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "};\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel !== null) {\n", - " IPython.notebook.kernel.comm_manager.register_target(\n", - " 'matplotlib',\n", - " mpl.mpl_figure_comm\n", - " );\n", - "}\n" - ], + "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n rubberband_canvas.addEventListener(\n 'dblclick',\n on_mouse_event_closure('dblclick')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n var img = evt.data;\n if (img.type !== 'image/png') {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n img.type = 'image/png';\n }\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n img\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.key === this._key) {\n return;\n } else {\n this._key = event.key;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.key !== 'Control') {\n value += 'ctrl+';\n }\n else if (event.altKey && event.key !== 'Alt') {\n value += 'alt+';\n }\n else if (event.shiftKey && event.key !== 'Shift') {\n value += 'shift+';\n }\n\n value += 'k' + event.key;\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.binaryType = comm.kernel.ws.binaryType;\n ws.readyState = comm.kernel.ws.readyState;\n function updateReadyState(_event) {\n if (comm.kernel.ws) {\n ws.readyState = comm.kernel.ws.readyState;\n } else {\n ws.readyState = 3; // Closed state.\n }\n }\n comm.kernel.ws.addEventListener('open', updateReadyState);\n comm.kernel.ws.addEventListener('close', updateReadyState);\n comm.kernel.ws.addEventListener('error', updateReadyState);\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n var data = msg['content']['data'];\n if (data['blob'] !== undefined) {\n data = {\n data: new Blob(msg['buffers'], { type: data['blob'] }),\n };\n }\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(data);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", "text/plain": [ "" ] @@ -6081,980 +1216,7 @@ "outputs": [ { "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "/* global mpl */\n", - "window.mpl = {};\n", - "\n", - "mpl.get_websocket_type = function () {\n", - " if (typeof WebSocket !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof MozWebSocket !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert(\n", - " 'Your browser does not have WebSocket support. ' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.'\n", - " );\n", - " }\n", - "};\n", - "\n", - "mpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = this.ws.binaryType !== undefined;\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById('mpl-warnings');\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent =\n", - " 'This browser does not support binary websocket messages. ' +\n", - " 'Performance may be slow.';\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = document.createElement('div');\n", - " this.root.setAttribute('style', 'display: inline-block');\n", - " this._root_extra_style(this.root);\n", - "\n", - " parent_element.appendChild(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message('supports_binary', { value: fig.supports_binary });\n", - " fig.send_message('send_image_mode', {});\n", - " if (fig.ratio !== 1) {\n", - " fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n", - " }\n", - " fig.send_message('refresh', {});\n", - " };\n", - "\n", - " this.imageObj.onload = function () {\n", - " if (fig.image_mode === 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function () {\n", - " fig.ws.close();\n", - " };\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "};\n", - "\n", - "mpl.figure.prototype._init_header = function () {\n", - " var titlebar = document.createElement('div');\n", - " titlebar.classList =\n", - " 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n", - " var titletext = document.createElement('div');\n", - " titletext.classList = 'ui-dialog-title';\n", - " titletext.setAttribute(\n", - " 'style',\n", - " 'width: 100%; text-align: center; padding: 3px;'\n", - " );\n", - " titlebar.appendChild(titletext);\n", - " this.root.appendChild(titlebar);\n", - " this.header = titletext;\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n", - "\n", - "mpl.figure.prototype._init_canvas = function () {\n", - " var fig = this;\n", - "\n", - " var canvas_div = (this.canvas_div = document.createElement('div'));\n", - " canvas_div.setAttribute(\n", - " 'style',\n", - " 'border: 1px solid #ddd;' +\n", - " 'box-sizing: content-box;' +\n", - " 'clear: both;' +\n", - " 'min-height: 1px;' +\n", - " 'min-width: 1px;' +\n", - " 'outline: 0;' +\n", - " 'overflow: hidden;' +\n", - " 'position: relative;' +\n", - " 'resize: both;'\n", - " );\n", - "\n", - " function on_keyboard_event_closure(name) {\n", - " return function (event) {\n", - " return fig.key_event(event, name);\n", - " };\n", - " }\n", - "\n", - " canvas_div.addEventListener(\n", - " 'keydown',\n", - " on_keyboard_event_closure('key_press')\n", - " );\n", - " canvas_div.addEventListener(\n", - " 'keyup',\n", - " on_keyboard_event_closure('key_release')\n", - " );\n", - "\n", - " this._canvas_extra_style(canvas_div);\n", - " this.root.appendChild(canvas_div);\n", - "\n", - " var canvas = (this.canvas = document.createElement('canvas'));\n", - " canvas.classList.add('mpl-canvas');\n", - " canvas.setAttribute('style', 'box-sizing: content-box;');\n", - "\n", - " this.context = canvas.getContext('2d');\n", - "\n", - " var backingStore =\n", - " this.context.backingStorePixelRatio ||\n", - " this.context.webkitBackingStorePixelRatio ||\n", - " this.context.mozBackingStorePixelRatio ||\n", - " this.context.msBackingStorePixelRatio ||\n", - " this.context.oBackingStorePixelRatio ||\n", - " this.context.backingStorePixelRatio ||\n", - " 1;\n", - "\n", - " this.ratio = (window.devicePixelRatio || 1) / backingStore;\n", - "\n", - " var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n", - " 'canvas'\n", - " ));\n", - " rubberband_canvas.setAttribute(\n", - " 'style',\n", - " 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n", - " );\n", - "\n", - " // Apply a ponyfill if ResizeObserver is not implemented by browser.\n", - " if (this.ResizeObserver === undefined) {\n", - " if (window.ResizeObserver !== undefined) {\n", - " this.ResizeObserver = window.ResizeObserver;\n", - " } else {\n", - " var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n", - " this.ResizeObserver = obs.ResizeObserver;\n", - " }\n", - " }\n", - "\n", - " this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n", - " var nentries = entries.length;\n", - " for (var i = 0; i < nentries; i++) {\n", - " var entry = entries[i];\n", - " var width, height;\n", - " if (entry.contentBoxSize) {\n", - " if (entry.contentBoxSize instanceof Array) {\n", - " // Chrome 84 implements new version of spec.\n", - " width = entry.contentBoxSize[0].inlineSize;\n", - " height = entry.contentBoxSize[0].blockSize;\n", - " } else {\n", - " // Firefox implements old version of spec.\n", - " width = entry.contentBoxSize.inlineSize;\n", - " height = entry.contentBoxSize.blockSize;\n", - " }\n", - " } else {\n", - " // Chrome <84 implements even older version of spec.\n", - " width = entry.contentRect.width;\n", - " height = entry.contentRect.height;\n", - " }\n", - "\n", - " // Keep the size of the canvas and rubber band canvas in sync with\n", - " // the canvas container.\n", - " if (entry.devicePixelContentBoxSize) {\n", - " // Chrome 84 implements new version of spec.\n", - " canvas.setAttribute(\n", - " 'width',\n", - " entry.devicePixelContentBoxSize[0].inlineSize\n", - " );\n", - " canvas.setAttribute(\n", - " 'height',\n", - " entry.devicePixelContentBoxSize[0].blockSize\n", - " );\n", - " } else {\n", - " canvas.setAttribute('width', width * fig.ratio);\n", - " canvas.setAttribute('height', height * fig.ratio);\n", - " }\n", - " canvas.setAttribute(\n", - " 'style',\n", - " 'width: ' + width + 'px; height: ' + height + 'px;'\n", - " );\n", - "\n", - " rubberband_canvas.setAttribute('width', width);\n", - " rubberband_canvas.setAttribute('height', height);\n", - "\n", - " // And update the size in Python. We ignore the initial 0/0 size\n", - " // that occurs as the element is placed into the DOM, which should\n", - " // otherwise not happen due to the minimum size styling.\n", - " if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n", - " fig.request_resize(width, height);\n", - " }\n", - " }\n", - " });\n", - " this.resizeObserverInstance.observe(canvas_div);\n", - "\n", - " function on_mouse_event_closure(name) {\n", - " return function (event) {\n", - " return fig.mouse_event(event, name);\n", - " };\n", - " }\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mousedown',\n", - " on_mouse_event_closure('button_press')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseup',\n", - " on_mouse_event_closure('button_release')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'dblclick',\n", - " on_mouse_event_closure('dblclick')\n", - " );\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband_canvas.addEventListener(\n", - " 'mousemove',\n", - " on_mouse_event_closure('motion_notify')\n", - " );\n", - "\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseenter',\n", - " on_mouse_event_closure('figure_enter')\n", - " );\n", - " rubberband_canvas.addEventListener(\n", - " 'mouseleave',\n", - " on_mouse_event_closure('figure_leave')\n", - " );\n", - "\n", - " canvas_div.addEventListener('wheel', function (event) {\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " on_mouse_event_closure('scroll')(event);\n", - " });\n", - "\n", - " canvas_div.appendChild(canvas);\n", - " canvas_div.appendChild(rubberband_canvas);\n", - "\n", - " this.rubberband_context = rubberband_canvas.getContext('2d');\n", - " this.rubberband_context.strokeStyle = '#000000';\n", - "\n", - " this._resize_canvas = function (width, height, forward) {\n", - " if (forward) {\n", - " canvas_div.style.width = width + 'px';\n", - " canvas_div.style.height = height + 'px';\n", - " }\n", - " };\n", - "\n", - " // Disable right mouse context menu.\n", - " this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n", - " event.preventDefault();\n", - " return false;\n", - " });\n", - "\n", - " function set_focus() {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'mpl-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'mpl-button-group';\n", - " continue;\n", - " }\n", - "\n", - " var button = (fig.buttons[name] = document.createElement('button'));\n", - " button.classList = 'mpl-widget';\n", - " button.setAttribute('role', 'button');\n", - " button.setAttribute('aria-disabled', 'false');\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - "\n", - " var icon_img = document.createElement('img');\n", - " icon_img.src = '_images/' + image + '.png';\n", - " icon_img.srcset = '_images/' + image + '_large.png 2x';\n", - " icon_img.alt = tooltip;\n", - " button.appendChild(icon_img);\n", - "\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " var fmt_picker = document.createElement('select');\n", - " fmt_picker.classList = 'mpl-widget';\n", - " toolbar.appendChild(fmt_picker);\n", - " this.format_dropdown = fmt_picker;\n", - "\n", - " for (var ind in mpl.extensions) {\n", - " var fmt = mpl.extensions[ind];\n", - " var option = document.createElement('option');\n", - " option.selected = fmt === mpl.default_extension;\n", - " option.innerHTML = fmt;\n", - " fmt_picker.appendChild(option);\n", - " }\n", - "\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "};\n", - "\n", - "mpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n", - " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", - " // which will in turn request a refresh of the image.\n", - " this.send_message('resize', { width: x_pixels, height: y_pixels });\n", - "};\n", - "\n", - "mpl.figure.prototype.send_message = function (type, properties) {\n", - " properties['type'] = type;\n", - " properties['figure_id'] = this.id;\n", - " this.ws.send(JSON.stringify(properties));\n", - "};\n", - "\n", - "mpl.figure.prototype.send_draw_message = function () {\n", - " if (!this.waiting) {\n", - " this.waiting = true;\n", - " this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " var format_dropdown = fig.format_dropdown;\n", - " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", - " fig.ondownload(fig, format);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_resize = function (fig, msg) {\n", - " var size = msg['size'];\n", - " if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n", - " fig._resize_canvas(size[0], size[1], msg['forward']);\n", - " fig.send_message('refresh', {});\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_rubberband = function (fig, msg) {\n", - " var x0 = msg['x0'] / fig.ratio;\n", - " var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n", - " var x1 = msg['x1'] / fig.ratio;\n", - " var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n", - " x0 = Math.floor(x0) + 0.5;\n", - " y0 = Math.floor(y0) + 0.5;\n", - " x1 = Math.floor(x1) + 0.5;\n", - " y1 = Math.floor(y1) + 0.5;\n", - " var min_x = Math.min(x0, x1);\n", - " var min_y = Math.min(y0, y1);\n", - " var width = Math.abs(x1 - x0);\n", - " var height = Math.abs(y1 - y0);\n", - "\n", - " fig.rubberband_context.clearRect(\n", - " 0,\n", - " 0,\n", - " fig.canvas.width / fig.ratio,\n", - " fig.canvas.height / fig.ratio\n", - " );\n", - "\n", - " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_figure_label = function (fig, msg) {\n", - " // Updates the figure title.\n", - " fig.header.textContent = msg['label'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_cursor = function (fig, msg) {\n", - " var cursor = msg['cursor'];\n", - " switch (cursor) {\n", - " case 0:\n", - " cursor = 'pointer';\n", - " break;\n", - " case 1:\n", - " cursor = 'default';\n", - " break;\n", - " case 2:\n", - " cursor = 'crosshair';\n", - " break;\n", - " case 3:\n", - " cursor = 'move';\n", - " break;\n", - " }\n", - " fig.rubberband_canvas.style.cursor = cursor;\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_message = function (fig, msg) {\n", - " fig.message.textContent = msg['message'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_draw = function (fig, _msg) {\n", - " // Request the server to send over a new figure.\n", - " fig.send_draw_message();\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_image_mode = function (fig, msg) {\n", - " fig.image_mode = msg['mode'];\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n", - " for (var key in msg) {\n", - " if (!(key in fig.buttons)) {\n", - " continue;\n", - " }\n", - " fig.buttons[key].disabled = !msg[key];\n", - " fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n", - " if (msg['mode'] === 'PAN') {\n", - " fig.buttons['Pan'].classList.add('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " } else if (msg['mode'] === 'ZOOM') {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.add('active');\n", - " } else {\n", - " fig.buttons['Pan'].classList.remove('active');\n", - " fig.buttons['Zoom'].classList.remove('active');\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Called whenever the canvas gets updated.\n", - " this.send_message('ack', {});\n", - "};\n", - "\n", - "// A function to construct a web socket function for onmessage handling.\n", - "// Called in the figure constructor.\n", - "mpl.figure.prototype._make_on_message_function = function (fig) {\n", - " return function socket_on_message(evt) {\n", - " if (evt.data instanceof Blob) {\n", - " var img = evt.data;\n", - " if (img.type !== 'image/png') {\n", - " /* FIXME: We get \"Resource interpreted as Image but\n", - " * transferred with MIME type text/plain:\" errors on\n", - " * Chrome. But how to set the MIME type? It doesn't seem\n", - " * to be part of the websocket stream */\n", - " img.type = 'image/png';\n", - " }\n", - "\n", - " /* Free the memory for the previous frames */\n", - " if (fig.imageObj.src) {\n", - " (window.URL || window.webkitURL).revokeObjectURL(\n", - " fig.imageObj.src\n", - " );\n", - " }\n", - "\n", - " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", - " img\n", - " );\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " } else if (\n", - " typeof evt.data === 'string' &&\n", - " evt.data.slice(0, 21) === 'data:image/png;base64'\n", - " ) {\n", - " fig.imageObj.src = evt.data;\n", - " fig.updated_canvas_event();\n", - " fig.waiting = false;\n", - " return;\n", - " }\n", - "\n", - " var msg = JSON.parse(evt.data);\n", - " var msg_type = msg['type'];\n", - "\n", - " // Call the \"handle_{type}\" callback, which takes\n", - " // the figure and JSON message as its only arguments.\n", - " try {\n", - " var callback = fig['handle_' + msg_type];\n", - " } catch (e) {\n", - " console.log(\n", - " \"No handler for the '\" + msg_type + \"' message type: \",\n", - " msg\n", - " );\n", - " return;\n", - " }\n", - "\n", - " if (callback) {\n", - " try {\n", - " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", - " callback(fig, msg);\n", - " } catch (e) {\n", - " console.log(\n", - " \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n", - " e,\n", - " e.stack,\n", - " msg\n", - " );\n", - " }\n", - " }\n", - " };\n", - "};\n", - "\n", - "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", - "mpl.findpos = function (e) {\n", - " //this section is from http://www.quirksmode.org/js/events_properties.html\n", - " var targ;\n", - " if (!e) {\n", - " e = window.event;\n", - " }\n", - " if (e.target) {\n", - " targ = e.target;\n", - " } else if (e.srcElement) {\n", - " targ = e.srcElement;\n", - " }\n", - " if (targ.nodeType === 3) {\n", - " // defeat Safari bug\n", - " targ = targ.parentNode;\n", - " }\n", - "\n", - " // pageX,Y are the mouse positions relative to the document\n", - " var boundingRect = targ.getBoundingClientRect();\n", - " var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n", - " var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n", - "\n", - " return { x: x, y: y };\n", - "};\n", - "\n", - "/*\n", - " * return a copy of an object with only non-object keys\n", - " * we need this to avoid circular references\n", - " * http://stackoverflow.com/a/24161582/3208463\n", - " */\n", - "function simpleKeys(original) {\n", - " return Object.keys(original).reduce(function (obj, key) {\n", - " if (typeof original[key] !== 'object') {\n", - " obj[key] = original[key];\n", - " }\n", - " return obj;\n", - " }, {});\n", - "}\n", - "\n", - "mpl.figure.prototype.mouse_event = function (event, name) {\n", - " var canvas_pos = mpl.findpos(event);\n", - "\n", - " if (name === 'button_press') {\n", - " this.canvas.focus();\n", - " this.canvas_div.focus();\n", - " }\n", - "\n", - " var x = canvas_pos.x * this.ratio;\n", - " var y = canvas_pos.y * this.ratio;\n", - "\n", - " this.send_message(name, {\n", - " x: x,\n", - " y: y,\n", - " button: event.button,\n", - " step: event.step,\n", - " guiEvent: simpleKeys(event),\n", - " });\n", - "\n", - " /* This prevents the web browser from automatically changing to\n", - " * the text insertion cursor when the button is pressed. We want\n", - " * to control all of the cursor setting manually through the\n", - " * 'cursor' event from matplotlib */\n", - " event.preventDefault();\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (_event, _name) {\n", - " // Handle any extra behaviour associated with a key event\n", - "};\n", - "\n", - "mpl.figure.prototype.key_event = function (event, name) {\n", - " // Prevent repeat events\n", - " if (name === 'key_press') {\n", - " if (event.key === this._key) {\n", - " return;\n", - " } else {\n", - " this._key = event.key;\n", - " }\n", - " }\n", - " if (name === 'key_release') {\n", - " this._key = null;\n", - " }\n", - "\n", - " var value = '';\n", - " if (event.ctrlKey && event.key !== 'Control') {\n", - " value += 'ctrl+';\n", - " }\n", - " else if (event.altKey && event.key !== 'Alt') {\n", - " value += 'alt+';\n", - " }\n", - " else if (event.shiftKey && event.key !== 'Shift') {\n", - " value += 'shift+';\n", - " }\n", - "\n", - " value += 'k' + event.key;\n", - "\n", - " this._key_event_extra(event, name);\n", - "\n", - " this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n", - " return false;\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onclick = function (name) {\n", - " if (name === 'download') {\n", - " this.handle_save(this, null);\n", - " } else {\n", - " this.send_message('toolbar_button', { name: name });\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n", - " this.message.textContent = tooltip;\n", - "};\n", - "\n", - "///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n", - "// prettier-ignore\n", - "var _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\n", - "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", - "\n", - "mpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", - "\n", - "mpl.default_extension = \"png\";/* global mpl */\n", - "\n", - "var comm_websocket_adapter = function (comm) {\n", - " // Create a \"websocket\"-like object which calls the given IPython comm\n", - " // object with the appropriate methods. Currently this is a non binary\n", - " // socket, so there is still some room for performance tuning.\n", - " var ws = {};\n", - "\n", - " ws.binaryType = comm.kernel.ws.binaryType;\n", - " ws.readyState = comm.kernel.ws.readyState;\n", - " function updateReadyState(_event) {\n", - " if (comm.kernel.ws) {\n", - " ws.readyState = comm.kernel.ws.readyState;\n", - " } else {\n", - " ws.readyState = 3; // Closed state.\n", - " }\n", - " }\n", - " comm.kernel.ws.addEventListener('open', updateReadyState);\n", - " comm.kernel.ws.addEventListener('close', updateReadyState);\n", - " comm.kernel.ws.addEventListener('error', updateReadyState);\n", - "\n", - " ws.close = function () {\n", - " comm.close();\n", - " };\n", - " ws.send = function (m) {\n", - " //console.log('sending', m);\n", - " comm.send(m);\n", - " };\n", - " // Register the callback with on_msg.\n", - " comm.on_msg(function (msg) {\n", - " //console.log('receiving', msg['content']['data'], msg);\n", - " var data = msg['content']['data'];\n", - " if (data['blob'] !== undefined) {\n", - " data = {\n", - " data: new Blob(msg['buffers'], { type: data['blob'] }),\n", - " };\n", - " }\n", - " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", - " ws.onmessage(data);\n", - " });\n", - " return ws;\n", - "};\n", - "\n", - "mpl.mpl_figure_comm = function (comm, msg) {\n", - " // This is the function which gets called when the mpl process\n", - " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", - "\n", - " var id = msg.content.data.id;\n", - " // Get hold of the div created by the display call when the Comm\n", - " // socket was opened in Python.\n", - " var element = document.getElementById(id);\n", - " var ws_proxy = comm_websocket_adapter(comm);\n", - "\n", - " function ondownload(figure, _format) {\n", - " window.open(figure.canvas.toDataURL());\n", - " }\n", - "\n", - " var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n", - "\n", - " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", - " // web socket which is closed, not our websocket->open comm proxy.\n", - " ws_proxy.onopen();\n", - "\n", - " fig.parent_element = element;\n", - " fig.cell_info = mpl.find_output_cell(\"
\");\n", - " if (!fig.cell_info) {\n", - " console.error('Failed to find cell for figure', id, fig);\n", - " return;\n", - " }\n", - " fig.cell_info[0].output_area.element.on(\n", - " 'cleared',\n", - " { fig: fig },\n", - " fig._remove_fig_handler\n", - " );\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_close = function (fig, msg) {\n", - " var width = fig.canvas.width / fig.ratio;\n", - " fig.cell_info[0].output_area.element.off(\n", - " 'cleared',\n", - " fig._remove_fig_handler\n", - " );\n", - " fig.resizeObserverInstance.unobserve(fig.canvas_div);\n", - "\n", - " // Update the output cell to use the data from the current canvas.\n", - " fig.push_to_output();\n", - " var dataURL = fig.canvas.toDataURL();\n", - " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", - " // the notebook keyboard shortcuts fail.\n", - " IPython.keyboard_manager.enable();\n", - " fig.parent_element.innerHTML =\n", - " '';\n", - " fig.close_ws(fig, msg);\n", - "};\n", - "\n", - "mpl.figure.prototype.close_ws = function (fig, msg) {\n", - " fig.send_message('closing', msg);\n", - " // fig.ws.close()\n", - "};\n", - "\n", - "mpl.figure.prototype.push_to_output = function (_remove_interactive) {\n", - " // Turn the data on the canvas into data in the output cell.\n", - " var width = this.canvas.width / this.ratio;\n", - " var dataURL = this.canvas.toDataURL();\n", - " this.cell_info[1]['text/html'] =\n", - " '';\n", - "};\n", - "\n", - "mpl.figure.prototype.updated_canvas_event = function () {\n", - " // Tell IPython that the notebook contents must change.\n", - " IPython.notebook.set_dirty(true);\n", - " this.send_message('ack', {});\n", - " var fig = this;\n", - " // Wait a second, then push the new image to the DOM so\n", - " // that it is saved nicely (might be nice to debounce this).\n", - " setTimeout(function () {\n", - " fig.push_to_output();\n", - " }, 1000);\n", - "};\n", - "\n", - "mpl.figure.prototype._init_toolbar = function () {\n", - " var fig = this;\n", - "\n", - " var toolbar = document.createElement('div');\n", - " toolbar.classList = 'btn-toolbar';\n", - " this.root.appendChild(toolbar);\n", - "\n", - " function on_click_closure(name) {\n", - " return function (_event) {\n", - " return fig.toolbar_button_onclick(name);\n", - " };\n", - " }\n", - "\n", - " function on_mouseover_closure(tooltip) {\n", - " return function (event) {\n", - " if (!event.currentTarget.disabled) {\n", - " return fig.toolbar_button_onmouseover(tooltip);\n", - " }\n", - " };\n", - " }\n", - "\n", - " fig.buttons = {};\n", - " var buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " var button;\n", - " for (var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " /* Instead of a spacer, we start a new button group. */\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - " buttonGroup = document.createElement('div');\n", - " buttonGroup.classList = 'btn-group';\n", - " continue;\n", - " }\n", - "\n", - " button = fig.buttons[name] = document.createElement('button');\n", - " button.classList = 'btn btn-default';\n", - " button.href = '#';\n", - " button.title = name;\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', on_click_closure(method_name));\n", - " button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n", - " buttonGroup.appendChild(button);\n", - " }\n", - "\n", - " if (buttonGroup.hasChildNodes()) {\n", - " toolbar.appendChild(buttonGroup);\n", - " }\n", - "\n", - " // Add the status bar.\n", - " var status_bar = document.createElement('span');\n", - " status_bar.classList = 'mpl-message pull-right';\n", - " toolbar.appendChild(status_bar);\n", - " this.message = status_bar;\n", - "\n", - " // Add the close button to the window.\n", - " var buttongrp = document.createElement('div');\n", - " buttongrp.classList = 'btn-group inline pull-right';\n", - " button = document.createElement('button');\n", - " button.classList = 'btn btn-mini btn-primary';\n", - " button.href = '#';\n", - " button.title = 'Stop Interaction';\n", - " button.innerHTML = '';\n", - " button.addEventListener('click', function (_evt) {\n", - " fig.handle_close(fig, {});\n", - " });\n", - " button.addEventListener(\n", - " 'mouseover',\n", - " on_mouseover_closure('Stop Interaction')\n", - " );\n", - " buttongrp.appendChild(button);\n", - " var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n", - " titlebar.insertBefore(buttongrp, titlebar.firstChild);\n", - "};\n", - "\n", - "mpl.figure.prototype._remove_fig_handler = function (event) {\n", - " var fig = event.data.fig;\n", - " if (event.target !== this) {\n", - " // Ignore bubbled events from children.\n", - " return;\n", - " }\n", - " fig.close_ws(fig, {});\n", - "};\n", - "\n", - "mpl.figure.prototype._root_extra_style = function (el) {\n", - " el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n", - "};\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function (el) {\n", - " // this is important to make the div 'focusable\n", - " el.setAttribute('tabindex', 0);\n", - " // reach out to IPython and tell the keyboard manager to turn it's self\n", - " // off when our div gets focus\n", - "\n", - " // location in version 3\n", - " if (IPython.notebook.keyboard_manager) {\n", - " IPython.notebook.keyboard_manager.register_events(el);\n", - " } else {\n", - " // location in version 2\n", - " IPython.keyboard_manager.register_events(el);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype._key_event_extra = function (event, _name) {\n", - " var manager = IPython.notebook.keyboard_manager;\n", - " if (!manager) {\n", - " manager = IPython.keyboard_manager;\n", - " }\n", - "\n", - " // Check for shift+enter\n", - " if (event.shiftKey && event.which === 13) {\n", - " this.canvas_div.blur();\n", - " // select the cell after this one\n", - " var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n", - " IPython.notebook.select(index + 1);\n", - " }\n", - "};\n", - "\n", - "mpl.figure.prototype.handle_save = function (fig, _msg) {\n", - " fig.ondownload(fig, null);\n", - "};\n", - "\n", - "mpl.find_output_cell = function (html_output) {\n", - " // Return the cell and output element which can be found *uniquely* in the notebook.\n", - " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", - " // IPython event is triggered only after the cells have been serialised, which for\n", - " // our purposes (turning an active figure into a static one), is too late.\n", - " var cells = IPython.notebook.get_cells();\n", - " var ncells = cells.length;\n", - " for (var i = 0; i < ncells; i++) {\n", - " var cell = cells[i];\n", - " if (cell.cell_type === 'code') {\n", - " for (var j = 0; j < cell.output_area.outputs.length; j++) {\n", - " var data = cell.output_area.outputs[j];\n", - " if (data.data) {\n", - " // IPython >= 3 moved mimebundle to data attribute of output\n", - " data = data.data;\n", - " }\n", - " if (data['text/html'] === html_output) {\n", - " return [cell, data, j];\n", - " }\n", - " }\n", - " }\n", - " }\n", - "};\n", - "\n", - "// Register the function which deals with the matplotlib target/channel.\n", - "// The kernel may be null if the page has been refreshed.\n", - "if (IPython.notebook.kernel !== null) {\n", - " IPython.notebook.kernel.comm_manager.register_target(\n", - " 'matplotlib',\n", - " mpl.mpl_figure_comm\n", - " );\n", - "}\n" - ], + "application/javascript": "/* Put everything inside the global mpl namespace */\n/* global mpl */\nwindow.mpl = {};\n\nmpl.get_websocket_type = function () {\n if (typeof WebSocket !== 'undefined') {\n return WebSocket;\n } else if (typeof MozWebSocket !== 'undefined') {\n return MozWebSocket;\n } else {\n alert(\n 'Your browser does not have WebSocket support. ' +\n 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n 'Firefox 4 and 5 are also supported but you ' +\n 'have to enable WebSockets in about:config.'\n );\n }\n};\n\nmpl.figure = function (figure_id, websocket, ondownload, parent_element) {\n this.id = figure_id;\n\n this.ws = websocket;\n\n this.supports_binary = this.ws.binaryType !== undefined;\n\n if (!this.supports_binary) {\n var warnings = document.getElementById('mpl-warnings');\n if (warnings) {\n warnings.style.display = 'block';\n warnings.textContent =\n 'This browser does not support binary websocket messages. ' +\n 'Performance may be slow.';\n }\n }\n\n this.imageObj = new Image();\n\n this.context = undefined;\n this.message = undefined;\n this.canvas = undefined;\n this.rubberband_canvas = undefined;\n this.rubberband_context = undefined;\n this.format_dropdown = undefined;\n\n this.image_mode = 'full';\n\n this.root = document.createElement('div');\n this.root.setAttribute('style', 'display: inline-block');\n this._root_extra_style(this.root);\n\n parent_element.appendChild(this.root);\n\n this._init_header(this);\n this._init_canvas(this);\n this._init_toolbar(this);\n\n var fig = this;\n\n this.waiting = false;\n\n this.ws.onopen = function () {\n fig.send_message('supports_binary', { value: fig.supports_binary });\n fig.send_message('send_image_mode', {});\n if (fig.ratio !== 1) {\n fig.send_message('set_dpi_ratio', { dpi_ratio: fig.ratio });\n }\n fig.send_message('refresh', {});\n };\n\n this.imageObj.onload = function () {\n if (fig.image_mode === 'full') {\n // Full images could contain transparency (where diff images\n // almost always do), so we need to clear the canvas so that\n // there is no ghosting.\n fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n }\n fig.context.drawImage(fig.imageObj, 0, 0);\n };\n\n this.imageObj.onunload = function () {\n fig.ws.close();\n };\n\n this.ws.onmessage = this._make_on_message_function(this);\n\n this.ondownload = ondownload;\n};\n\nmpl.figure.prototype._init_header = function () {\n var titlebar = document.createElement('div');\n titlebar.classList =\n 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix';\n var titletext = document.createElement('div');\n titletext.classList = 'ui-dialog-title';\n titletext.setAttribute(\n 'style',\n 'width: 100%; text-align: center; padding: 3px;'\n );\n titlebar.appendChild(titletext);\n this.root.appendChild(titlebar);\n this.header = titletext;\n};\n\nmpl.figure.prototype._canvas_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._root_extra_style = function (_canvas_div) {};\n\nmpl.figure.prototype._init_canvas = function () {\n var fig = this;\n\n var canvas_div = (this.canvas_div = document.createElement('div'));\n canvas_div.setAttribute(\n 'style',\n 'border: 1px solid #ddd;' +\n 'box-sizing: content-box;' +\n 'clear: both;' +\n 'min-height: 1px;' +\n 'min-width: 1px;' +\n 'outline: 0;' +\n 'overflow: hidden;' +\n 'position: relative;' +\n 'resize: both;'\n );\n\n function on_keyboard_event_closure(name) {\n return function (event) {\n return fig.key_event(event, name);\n };\n }\n\n canvas_div.addEventListener(\n 'keydown',\n on_keyboard_event_closure('key_press')\n );\n canvas_div.addEventListener(\n 'keyup',\n on_keyboard_event_closure('key_release')\n );\n\n this._canvas_extra_style(canvas_div);\n this.root.appendChild(canvas_div);\n\n var canvas = (this.canvas = document.createElement('canvas'));\n canvas.classList.add('mpl-canvas');\n canvas.setAttribute('style', 'box-sizing: content-box;');\n\n this.context = canvas.getContext('2d');\n\n var backingStore =\n this.context.backingStorePixelRatio ||\n this.context.webkitBackingStorePixelRatio ||\n this.context.mozBackingStorePixelRatio ||\n this.context.msBackingStorePixelRatio ||\n this.context.oBackingStorePixelRatio ||\n this.context.backingStorePixelRatio ||\n 1;\n\n this.ratio = (window.devicePixelRatio || 1) / backingStore;\n\n var rubberband_canvas = (this.rubberband_canvas = document.createElement(\n 'canvas'\n ));\n rubberband_canvas.setAttribute(\n 'style',\n 'box-sizing: content-box; position: absolute; left: 0; top: 0; z-index: 1;'\n );\n\n // Apply a ponyfill if ResizeObserver is not implemented by browser.\n if (this.ResizeObserver === undefined) {\n if (window.ResizeObserver !== undefined) {\n this.ResizeObserver = window.ResizeObserver;\n } else {\n var obs = _JSXTOOLS_RESIZE_OBSERVER({});\n this.ResizeObserver = obs.ResizeObserver;\n }\n }\n\n this.resizeObserverInstance = new this.ResizeObserver(function (entries) {\n var nentries = entries.length;\n for (var i = 0; i < nentries; i++) {\n var entry = entries[i];\n var width, height;\n if (entry.contentBoxSize) {\n if (entry.contentBoxSize instanceof Array) {\n // Chrome 84 implements new version of spec.\n width = entry.contentBoxSize[0].inlineSize;\n height = entry.contentBoxSize[0].blockSize;\n } else {\n // Firefox implements old version of spec.\n width = entry.contentBoxSize.inlineSize;\n height = entry.contentBoxSize.blockSize;\n }\n } else {\n // Chrome <84 implements even older version of spec.\n width = entry.contentRect.width;\n height = entry.contentRect.height;\n }\n\n // Keep the size of the canvas and rubber band canvas in sync with\n // the canvas container.\n if (entry.devicePixelContentBoxSize) {\n // Chrome 84 implements new version of spec.\n canvas.setAttribute(\n 'width',\n entry.devicePixelContentBoxSize[0].inlineSize\n );\n canvas.setAttribute(\n 'height',\n entry.devicePixelContentBoxSize[0].blockSize\n );\n } else {\n canvas.setAttribute('width', width * fig.ratio);\n canvas.setAttribute('height', height * fig.ratio);\n }\n canvas.setAttribute(\n 'style',\n 'width: ' + width + 'px; height: ' + height + 'px;'\n );\n\n rubberband_canvas.setAttribute('width', width);\n rubberband_canvas.setAttribute('height', height);\n\n // And update the size in Python. We ignore the initial 0/0 size\n // that occurs as the element is placed into the DOM, which should\n // otherwise not happen due to the minimum size styling.\n if (fig.ws.readyState == 1 && width != 0 && height != 0) {\n fig.request_resize(width, height);\n }\n }\n });\n this.resizeObserverInstance.observe(canvas_div);\n\n function on_mouse_event_closure(name) {\n return function (event) {\n return fig.mouse_event(event, name);\n };\n }\n\n rubberband_canvas.addEventListener(\n 'mousedown',\n on_mouse_event_closure('button_press')\n );\n rubberband_canvas.addEventListener(\n 'mouseup',\n on_mouse_event_closure('button_release')\n );\n rubberband_canvas.addEventListener(\n 'dblclick',\n on_mouse_event_closure('dblclick')\n );\n // Throttle sequential mouse events to 1 every 20ms.\n rubberband_canvas.addEventListener(\n 'mousemove',\n on_mouse_event_closure('motion_notify')\n );\n\n rubberband_canvas.addEventListener(\n 'mouseenter',\n on_mouse_event_closure('figure_enter')\n );\n rubberband_canvas.addEventListener(\n 'mouseleave',\n on_mouse_event_closure('figure_leave')\n );\n\n canvas_div.addEventListener('wheel', function (event) {\n if (event.deltaY < 0) {\n event.step = 1;\n } else {\n event.step = -1;\n }\n on_mouse_event_closure('scroll')(event);\n });\n\n canvas_div.appendChild(canvas);\n canvas_div.appendChild(rubberband_canvas);\n\n this.rubberband_context = rubberband_canvas.getContext('2d');\n this.rubberband_context.strokeStyle = '#000000';\n\n this._resize_canvas = function (width, height, forward) {\n if (forward) {\n canvas_div.style.width = width + 'px';\n canvas_div.style.height = height + 'px';\n }\n };\n\n // Disable right mouse context menu.\n this.rubberband_canvas.addEventListener('contextmenu', function (_e) {\n event.preventDefault();\n return false;\n });\n\n function set_focus() {\n canvas.focus();\n canvas_div.focus();\n }\n\n window.setTimeout(set_focus, 100);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'mpl-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'mpl-button-group';\n continue;\n }\n\n var button = (fig.buttons[name] = document.createElement('button'));\n button.classList = 'mpl-widget';\n button.setAttribute('role', 'button');\n button.setAttribute('aria-disabled', 'false');\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n\n var icon_img = document.createElement('img');\n icon_img.src = '_images/' + image + '.png';\n icon_img.srcset = '_images/' + image + '_large.png 2x';\n icon_img.alt = tooltip;\n button.appendChild(icon_img);\n\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n var fmt_picker = document.createElement('select');\n fmt_picker.classList = 'mpl-widget';\n toolbar.appendChild(fmt_picker);\n this.format_dropdown = fmt_picker;\n\n for (var ind in mpl.extensions) {\n var fmt = mpl.extensions[ind];\n var option = document.createElement('option');\n option.selected = fmt === mpl.default_extension;\n option.innerHTML = fmt;\n fmt_picker.appendChild(option);\n }\n\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n};\n\nmpl.figure.prototype.request_resize = function (x_pixels, y_pixels) {\n // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n // which will in turn request a refresh of the image.\n this.send_message('resize', { width: x_pixels, height: y_pixels });\n};\n\nmpl.figure.prototype.send_message = function (type, properties) {\n properties['type'] = type;\n properties['figure_id'] = this.id;\n this.ws.send(JSON.stringify(properties));\n};\n\nmpl.figure.prototype.send_draw_message = function () {\n if (!this.waiting) {\n this.waiting = true;\n this.ws.send(JSON.stringify({ type: 'draw', figure_id: this.id }));\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n var format_dropdown = fig.format_dropdown;\n var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n fig.ondownload(fig, format);\n};\n\nmpl.figure.prototype.handle_resize = function (fig, msg) {\n var size = msg['size'];\n if (size[0] !== fig.canvas.width || size[1] !== fig.canvas.height) {\n fig._resize_canvas(size[0], size[1], msg['forward']);\n fig.send_message('refresh', {});\n }\n};\n\nmpl.figure.prototype.handle_rubberband = function (fig, msg) {\n var x0 = msg['x0'] / fig.ratio;\n var y0 = (fig.canvas.height - msg['y0']) / fig.ratio;\n var x1 = msg['x1'] / fig.ratio;\n var y1 = (fig.canvas.height - msg['y1']) / fig.ratio;\n x0 = Math.floor(x0) + 0.5;\n y0 = Math.floor(y0) + 0.5;\n x1 = Math.floor(x1) + 0.5;\n y1 = Math.floor(y1) + 0.5;\n var min_x = Math.min(x0, x1);\n var min_y = Math.min(y0, y1);\n var width = Math.abs(x1 - x0);\n var height = Math.abs(y1 - y0);\n\n fig.rubberband_context.clearRect(\n 0,\n 0,\n fig.canvas.width / fig.ratio,\n fig.canvas.height / fig.ratio\n );\n\n fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n};\n\nmpl.figure.prototype.handle_figure_label = function (fig, msg) {\n // Updates the figure title.\n fig.header.textContent = msg['label'];\n};\n\nmpl.figure.prototype.handle_cursor = function (fig, msg) {\n var cursor = msg['cursor'];\n switch (cursor) {\n case 0:\n cursor = 'pointer';\n break;\n case 1:\n cursor = 'default';\n break;\n case 2:\n cursor = 'crosshair';\n break;\n case 3:\n cursor = 'move';\n break;\n }\n fig.rubberband_canvas.style.cursor = cursor;\n};\n\nmpl.figure.prototype.handle_message = function (fig, msg) {\n fig.message.textContent = msg['message'];\n};\n\nmpl.figure.prototype.handle_draw = function (fig, _msg) {\n // Request the server to send over a new figure.\n fig.send_draw_message();\n};\n\nmpl.figure.prototype.handle_image_mode = function (fig, msg) {\n fig.image_mode = msg['mode'];\n};\n\nmpl.figure.prototype.handle_history_buttons = function (fig, msg) {\n for (var key in msg) {\n if (!(key in fig.buttons)) {\n continue;\n }\n fig.buttons[key].disabled = !msg[key];\n fig.buttons[key].setAttribute('aria-disabled', !msg[key]);\n }\n};\n\nmpl.figure.prototype.handle_navigate_mode = function (fig, msg) {\n if (msg['mode'] === 'PAN') {\n fig.buttons['Pan'].classList.add('active');\n fig.buttons['Zoom'].classList.remove('active');\n } else if (msg['mode'] === 'ZOOM') {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.add('active');\n } else {\n fig.buttons['Pan'].classList.remove('active');\n fig.buttons['Zoom'].classList.remove('active');\n }\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Called whenever the canvas gets updated.\n this.send_message('ack', {});\n};\n\n// A function to construct a web socket function for onmessage handling.\n// Called in the figure constructor.\nmpl.figure.prototype._make_on_message_function = function (fig) {\n return function socket_on_message(evt) {\n if (evt.data instanceof Blob) {\n var img = evt.data;\n if (img.type !== 'image/png') {\n /* FIXME: We get \"Resource interpreted as Image but\n * transferred with MIME type text/plain:\" errors on\n * Chrome. But how to set the MIME type? It doesn't seem\n * to be part of the websocket stream */\n img.type = 'image/png';\n }\n\n /* Free the memory for the previous frames */\n if (fig.imageObj.src) {\n (window.URL || window.webkitURL).revokeObjectURL(\n fig.imageObj.src\n );\n }\n\n fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n img\n );\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n } else if (\n typeof evt.data === 'string' &&\n evt.data.slice(0, 21) === 'data:image/png;base64'\n ) {\n fig.imageObj.src = evt.data;\n fig.updated_canvas_event();\n fig.waiting = false;\n return;\n }\n\n var msg = JSON.parse(evt.data);\n var msg_type = msg['type'];\n\n // Call the \"handle_{type}\" callback, which takes\n // the figure and JSON message as its only arguments.\n try {\n var callback = fig['handle_' + msg_type];\n } catch (e) {\n console.log(\n \"No handler for the '\" + msg_type + \"' message type: \",\n msg\n );\n return;\n }\n\n if (callback) {\n try {\n // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n callback(fig, msg);\n } catch (e) {\n console.log(\n \"Exception inside the 'handler_\" + msg_type + \"' callback:\",\n e,\n e.stack,\n msg\n );\n }\n }\n };\n};\n\n// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\nmpl.findpos = function (e) {\n //this section is from http://www.quirksmode.org/js/events_properties.html\n var targ;\n if (!e) {\n e = window.event;\n }\n if (e.target) {\n targ = e.target;\n } else if (e.srcElement) {\n targ = e.srcElement;\n }\n if (targ.nodeType === 3) {\n // defeat Safari bug\n targ = targ.parentNode;\n }\n\n // pageX,Y are the mouse positions relative to the document\n var boundingRect = targ.getBoundingClientRect();\n var x = e.pageX - (boundingRect.left + document.body.scrollLeft);\n var y = e.pageY - (boundingRect.top + document.body.scrollTop);\n\n return { x: x, y: y };\n};\n\n/*\n * return a copy of an object with only non-object keys\n * we need this to avoid circular references\n * http://stackoverflow.com/a/24161582/3208463\n */\nfunction simpleKeys(original) {\n return Object.keys(original).reduce(function (obj, key) {\n if (typeof original[key] !== 'object') {\n obj[key] = original[key];\n }\n return obj;\n }, {});\n}\n\nmpl.figure.prototype.mouse_event = function (event, name) {\n var canvas_pos = mpl.findpos(event);\n\n if (name === 'button_press') {\n this.canvas.focus();\n this.canvas_div.focus();\n }\n\n var x = canvas_pos.x * this.ratio;\n var y = canvas_pos.y * this.ratio;\n\n this.send_message(name, {\n x: x,\n y: y,\n button: event.button,\n step: event.step,\n guiEvent: simpleKeys(event),\n });\n\n /* This prevents the web browser from automatically changing to\n * the text insertion cursor when the button is pressed. We want\n * to control all of the cursor setting manually through the\n * 'cursor' event from matplotlib */\n event.preventDefault();\n return false;\n};\n\nmpl.figure.prototype._key_event_extra = function (_event, _name) {\n // Handle any extra behaviour associated with a key event\n};\n\nmpl.figure.prototype.key_event = function (event, name) {\n // Prevent repeat events\n if (name === 'key_press') {\n if (event.key === this._key) {\n return;\n } else {\n this._key = event.key;\n }\n }\n if (name === 'key_release') {\n this._key = null;\n }\n\n var value = '';\n if (event.ctrlKey && event.key !== 'Control') {\n value += 'ctrl+';\n }\n else if (event.altKey && event.key !== 'Alt') {\n value += 'alt+';\n }\n else if (event.shiftKey && event.key !== 'Shift') {\n value += 'shift+';\n }\n\n value += 'k' + event.key;\n\n this._key_event_extra(event, name);\n\n this.send_message(name, { key: value, guiEvent: simpleKeys(event) });\n return false;\n};\n\nmpl.figure.prototype.toolbar_button_onclick = function (name) {\n if (name === 'download') {\n this.handle_save(this, null);\n } else {\n this.send_message('toolbar_button', { name: name });\n }\n};\n\nmpl.figure.prototype.toolbar_button_onmouseover = function (tooltip) {\n this.message.textContent = tooltip;\n};\n\n///////////////// REMAINING CONTENT GENERATED BY embed_js.py /////////////////\n// prettier-ignore\nvar _JSXTOOLS_RESIZE_OBSERVER=function(A){var t,i=new WeakMap,n=new WeakMap,a=new WeakMap,r=new WeakMap,o=new Set;function s(e){if(!(this instanceof s))throw new TypeError(\"Constructor requires 'new' operator\");i.set(this,e)}function h(){throw new TypeError(\"Function is not a constructor\")}function c(e,t,i,n){e=0 in arguments?Number(arguments[0]):0,t=1 in arguments?Number(arguments[1]):0,i=2 in arguments?Number(arguments[2]):0,n=3 in arguments?Number(arguments[3]):0,this.right=(this.x=this.left=e)+(this.width=i),this.bottom=(this.y=this.top=t)+(this.height=n),Object.freeze(this)}function d(){t=requestAnimationFrame(d);var s=new WeakMap,p=new Set;o.forEach((function(t){r.get(t).forEach((function(i){var r=t instanceof window.SVGElement,o=a.get(t),d=r?0:parseFloat(o.paddingTop),f=r?0:parseFloat(o.paddingRight),l=r?0:parseFloat(o.paddingBottom),u=r?0:parseFloat(o.paddingLeft),g=r?0:parseFloat(o.borderTopWidth),m=r?0:parseFloat(o.borderRightWidth),w=r?0:parseFloat(o.borderBottomWidth),b=u+f,F=d+l,v=(r?0:parseFloat(o.borderLeftWidth))+m,W=g+w,y=r?0:t.offsetHeight-W-t.clientHeight,E=r?0:t.offsetWidth-v-t.clientWidth,R=b+v,z=F+W,M=r?t.width:parseFloat(o.width)-R-E,O=r?t.height:parseFloat(o.height)-z-y;if(n.has(t)){var k=n.get(t);if(k[0]===M&&k[1]===O)return}n.set(t,[M,O]);var S=Object.create(h.prototype);S.target=t,S.contentRect=new c(u,d,M,O),s.has(i)||(s.set(i,[]),p.add(i)),s.get(i).push(S)}))})),p.forEach((function(e){i.get(e).call(e,s.get(e),e)}))}return s.prototype.observe=function(i){if(i instanceof window.Element){r.has(i)||(r.set(i,new Set),o.add(i),a.set(i,window.getComputedStyle(i)));var n=r.get(i);n.has(this)||n.add(this),cancelAnimationFrame(t),t=requestAnimationFrame(d)}},s.prototype.unobserve=function(i){if(i instanceof window.Element&&r.has(i)){var n=r.get(i);n.has(this)&&(n.delete(this),n.size||(r.delete(i),o.delete(i))),n.size||r.delete(i),o.size||cancelAnimationFrame(t)}},A.DOMRectReadOnly=c,A.ResizeObserver=s,A.ResizeObserverEntry=h,A}; // eslint-disable-line\nmpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Left button pans, Right button zooms\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\\nx/y fixes axis, CTRL fixes aspect\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n\nmpl.extensions = [\"eps\", \"jpeg\", \"pgf\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n\nmpl.default_extension = \"png\";/* global mpl */\n\nvar comm_websocket_adapter = function (comm) {\n // Create a \"websocket\"-like object which calls the given IPython comm\n // object with the appropriate methods. Currently this is a non binary\n // socket, so there is still some room for performance tuning.\n var ws = {};\n\n ws.binaryType = comm.kernel.ws.binaryType;\n ws.readyState = comm.kernel.ws.readyState;\n function updateReadyState(_event) {\n if (comm.kernel.ws) {\n ws.readyState = comm.kernel.ws.readyState;\n } else {\n ws.readyState = 3; // Closed state.\n }\n }\n comm.kernel.ws.addEventListener('open', updateReadyState);\n comm.kernel.ws.addEventListener('close', updateReadyState);\n comm.kernel.ws.addEventListener('error', updateReadyState);\n\n ws.close = function () {\n comm.close();\n };\n ws.send = function (m) {\n //console.log('sending', m);\n comm.send(m);\n };\n // Register the callback with on_msg.\n comm.on_msg(function (msg) {\n //console.log('receiving', msg['content']['data'], msg);\n var data = msg['content']['data'];\n if (data['blob'] !== undefined) {\n data = {\n data: new Blob(msg['buffers'], { type: data['blob'] }),\n };\n }\n // Pass the mpl event to the overridden (by mpl) onmessage function.\n ws.onmessage(data);\n });\n return ws;\n};\n\nmpl.mpl_figure_comm = function (comm, msg) {\n // This is the function which gets called when the mpl process\n // starts-up an IPython Comm through the \"matplotlib\" channel.\n\n var id = msg.content.data.id;\n // Get hold of the div created by the display call when the Comm\n // socket was opened in Python.\n var element = document.getElementById(id);\n var ws_proxy = comm_websocket_adapter(comm);\n\n function ondownload(figure, _format) {\n window.open(figure.canvas.toDataURL());\n }\n\n var fig = new mpl.figure(id, ws_proxy, ondownload, element);\n\n // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n // web socket which is closed, not our websocket->open comm proxy.\n ws_proxy.onopen();\n\n fig.parent_element = element;\n fig.cell_info = mpl.find_output_cell(\"
\");\n if (!fig.cell_info) {\n console.error('Failed to find cell for figure', id, fig);\n return;\n }\n fig.cell_info[0].output_area.element.on(\n 'cleared',\n { fig: fig },\n fig._remove_fig_handler\n );\n};\n\nmpl.figure.prototype.handle_close = function (fig, msg) {\n var width = fig.canvas.width / fig.ratio;\n fig.cell_info[0].output_area.element.off(\n 'cleared',\n fig._remove_fig_handler\n );\n fig.resizeObserverInstance.unobserve(fig.canvas_div);\n\n // Update the output cell to use the data from the current canvas.\n fig.push_to_output();\n var dataURL = fig.canvas.toDataURL();\n // Re-enable the keyboard manager in IPython - without this line, in FF,\n // the notebook keyboard shortcuts fail.\n IPython.keyboard_manager.enable();\n fig.parent_element.innerHTML =\n '';\n fig.close_ws(fig, msg);\n};\n\nmpl.figure.prototype.close_ws = function (fig, msg) {\n fig.send_message('closing', msg);\n // fig.ws.close()\n};\n\nmpl.figure.prototype.push_to_output = function (_remove_interactive) {\n // Turn the data on the canvas into data in the output cell.\n var width = this.canvas.width / this.ratio;\n var dataURL = this.canvas.toDataURL();\n this.cell_info[1]['text/html'] =\n '';\n};\n\nmpl.figure.prototype.updated_canvas_event = function () {\n // Tell IPython that the notebook contents must change.\n IPython.notebook.set_dirty(true);\n this.send_message('ack', {});\n var fig = this;\n // Wait a second, then push the new image to the DOM so\n // that it is saved nicely (might be nice to debounce this).\n setTimeout(function () {\n fig.push_to_output();\n }, 1000);\n};\n\nmpl.figure.prototype._init_toolbar = function () {\n var fig = this;\n\n var toolbar = document.createElement('div');\n toolbar.classList = 'btn-toolbar';\n this.root.appendChild(toolbar);\n\n function on_click_closure(name) {\n return function (_event) {\n return fig.toolbar_button_onclick(name);\n };\n }\n\n function on_mouseover_closure(tooltip) {\n return function (event) {\n if (!event.currentTarget.disabled) {\n return fig.toolbar_button_onmouseover(tooltip);\n }\n };\n }\n\n fig.buttons = {};\n var buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n var button;\n for (var toolbar_ind in mpl.toolbar_items) {\n var name = mpl.toolbar_items[toolbar_ind][0];\n var tooltip = mpl.toolbar_items[toolbar_ind][1];\n var image = mpl.toolbar_items[toolbar_ind][2];\n var method_name = mpl.toolbar_items[toolbar_ind][3];\n\n if (!name) {\n /* Instead of a spacer, we start a new button group. */\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n buttonGroup = document.createElement('div');\n buttonGroup.classList = 'btn-group';\n continue;\n }\n\n button = fig.buttons[name] = document.createElement('button');\n button.classList = 'btn btn-default';\n button.href = '#';\n button.title = name;\n button.innerHTML = '';\n button.addEventListener('click', on_click_closure(method_name));\n button.addEventListener('mouseover', on_mouseover_closure(tooltip));\n buttonGroup.appendChild(button);\n }\n\n if (buttonGroup.hasChildNodes()) {\n toolbar.appendChild(buttonGroup);\n }\n\n // Add the status bar.\n var status_bar = document.createElement('span');\n status_bar.classList = 'mpl-message pull-right';\n toolbar.appendChild(status_bar);\n this.message = status_bar;\n\n // Add the close button to the window.\n var buttongrp = document.createElement('div');\n buttongrp.classList = 'btn-group inline pull-right';\n button = document.createElement('button');\n button.classList = 'btn btn-mini btn-primary';\n button.href = '#';\n button.title = 'Stop Interaction';\n button.innerHTML = '';\n button.addEventListener('click', function (_evt) {\n fig.handle_close(fig, {});\n });\n button.addEventListener(\n 'mouseover',\n on_mouseover_closure('Stop Interaction')\n );\n buttongrp.appendChild(button);\n var titlebar = this.root.querySelector('.ui-dialog-titlebar');\n titlebar.insertBefore(buttongrp, titlebar.firstChild);\n};\n\nmpl.figure.prototype._remove_fig_handler = function (event) {\n var fig = event.data.fig;\n if (event.target !== this) {\n // Ignore bubbled events from children.\n return;\n }\n fig.close_ws(fig, {});\n};\n\nmpl.figure.prototype._root_extra_style = function (el) {\n el.style.boxSizing = 'content-box'; // override notebook setting of border-box.\n};\n\nmpl.figure.prototype._canvas_extra_style = function (el) {\n // this is important to make the div 'focusable\n el.setAttribute('tabindex', 0);\n // reach out to IPython and tell the keyboard manager to turn it's self\n // off when our div gets focus\n\n // location in version 3\n if (IPython.notebook.keyboard_manager) {\n IPython.notebook.keyboard_manager.register_events(el);\n } else {\n // location in version 2\n IPython.keyboard_manager.register_events(el);\n }\n};\n\nmpl.figure.prototype._key_event_extra = function (event, _name) {\n var manager = IPython.notebook.keyboard_manager;\n if (!manager) {\n manager = IPython.keyboard_manager;\n }\n\n // Check for shift+enter\n if (event.shiftKey && event.which === 13) {\n this.canvas_div.blur();\n // select the cell after this one\n var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n IPython.notebook.select(index + 1);\n }\n};\n\nmpl.figure.prototype.handle_save = function (fig, _msg) {\n fig.ondownload(fig, null);\n};\n\nmpl.find_output_cell = function (html_output) {\n // Return the cell and output element which can be found *uniquely* in the notebook.\n // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n // IPython event is triggered only after the cells have been serialised, which for\n // our purposes (turning an active figure into a static one), is too late.\n var cells = IPython.notebook.get_cells();\n var ncells = cells.length;\n for (var i = 0; i < ncells; i++) {\n var cell = cells[i];\n if (cell.cell_type === 'code') {\n for (var j = 0; j < cell.output_area.outputs.length; j++) {\n var data = cell.output_area.outputs[j];\n if (data.data) {\n // IPython >= 3 moved mimebundle to data attribute of output\n data = data.data;\n }\n if (data['text/html'] === html_output) {\n return [cell, data, j];\n }\n }\n }\n }\n};\n\n// Register the function which deals with the matplotlib target/channel.\n// The kernel may be null if the page has been refreshed.\nif (IPython.notebook.kernel !== null) {\n IPython.notebook.kernel.comm_manager.register_target(\n 'matplotlib',\n mpl.mpl_figure_comm\n );\n}\n", "text/plain": [ "" ] @@ -7140,11 +1302,8 @@ ], "metadata": { "celltoolbar": "Slideshow", - "interpreter": { - "hash": "86193a1ab0ba47eac1c69c1756090baa3b420b3eea7d4aafab8b85f8b312f0c5" - }, "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "Python 3.10.7 64-bit", "language": "python", "name": "python3" }, @@ -7158,10 +1317,15 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.13" + "version": "3.10.7" }, "livereveal": { "start_slideshow_at": "selected" + }, + "vscode": { + "interpreter": { + "hash": "b0fa6594d8f4cbf19f97940f81e996739fb7646882a419484c72d19e05852a7e" + } } }, "nbformat": 4, diff --git a/lessons/3-NeuralNetworks/05-Frameworks/IntroKeras.ipynb b/lessons/3-NeuralNetworks/05-Frameworks/IntroKeras.ipynb index 9b634fc0..1346760a 100644 --- a/lessons/3-NeuralNetworks/05-Frameworks/IntroKeras.ipynb +++ b/lessons/3-NeuralNetworks/05-Frameworks/IntroKeras.ipynb @@ -1,733 +1,729 @@ { - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "En2vX4FuwHlu" - }, - "source": [ - "## Simplest Introduction to Neural Networks with Keras\n", - "\n", - "> This notebook is a part of [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners). Visit the repository for complete set of learning materials.\n", - "\n", - "### Neural Frameworks\n", - "\n", - "There are several frameworks for training neural networks. However, if you want to get started fast and not go into much detail on how things work internally - you should consider using [Keras](https://keras.io/). This short tutorial will get you started, and if you want to get deeper into understanding how things work - look into [Introduction to Tensorflow and Keras](IntroKerasTF.ipynb) notebook." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "8cACQoFMwHl3" - }, - "source": [ - "### Getting things ready\n", - "\n", - "Keras is a part of Tensorflow 2.x framework. Let's make sure we have version 2.x.x of Tensorflow installed:\n", - "```\n", - "pip install tensorflow\n", - "```\n", - "or\n", - "```\n", - "conda install tensorflow\n", - "```" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "xwqVx9-bwHl3", - "outputId": "2aa591b4-b647-441f-9c8e-4e0da2d517a0", - "tags": [] - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Tensorflow version = 2.7.0\n", - "Keras version = 2.7.0\n" - ] - } - ], - "source": [ - "import tensorflow as tf\n", - "from tensorflow import keras\n", - "import numpy as np\n", - "from sklearn.datasets import make_classification\n", - "import matplotlib.pyplot as plt\n", - "print(f'Tensorflow version = {tf.__version__}')\n", - "print(f'Keras version = {keras.__version__}')" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "6tp2xGV7wHl4" - }, - "source": [ - "## Basic Concepts: Tensor\n", - "\n", - "**Tensor** is a multi-dimensional array. It is very convenient to use tensors to represent different types of data:\n", - "* 400x400 - black-and-white picture\n", - "* 400x400x3 - color picture \n", - "* 16x400x400x3 - minibatch of 16 color pictures\n", - "* 25x400x400x3 - one second of 25-fps video\n", - "* 8x25x400x400x3 - minibatch of 8 1-second videos\n", - "\n", - "Tensors give us a convenient way to represent input/output data, as well we weights inside the neural network." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "A10prCPowHl7" - }, - "source": [ - "## Sample Problem\n", - "\n", - "Let's consider binary classification problem. A good example of such a problem would be a tumour classification between malignant and benign based on it's size and age. Let's start by generating some sample data:\n" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "id": "j0OTPkGpwHl7", - "scrolled": false, - "trusted": true - }, - "outputs": [], - "source": [ - "np.random.seed(0) # pick the seed for reproducibility - change it to explore the effects of random variations\n", - "\n", - "n = 100\n", - "X, Y = make_classification(n_samples = n, n_features=2,\n", - " n_redundant=0, n_informative=2, flip_y=0.05,class_sep=1.5)\n", - "X = X.astype(np.float32)\n", - "Y = Y.astype(np.int32)\n", - "\n", - "split = [ 70*n//100 ]\n", - "train_x, test_x = np.split(X, split)\n", - "train_labels, test_labels = np.split(Y, split)" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "id": "c-_BjSHPwHl8", - "scrolled": false, - "trusted": true - }, - "outputs": [], - "source": [ - "def plot_dataset(features, labels, W=None, b=None):\n", - " # prepare the plot\n", - " fig, ax = plt.subplots(1, 1)\n", - " ax.set_xlabel('$x_i[0]$ -- (feature 1)')\n", - " ax.set_ylabel('$x_i[1]$ -- (feature 2)')\n", - " colors = ['r' if l else 'b' for l in labels]\n", - " ax.scatter(features[:, 0], features[:, 1], marker='o', c=colors, s=100, alpha = 0.5)\n", - " if W is not None:\n", - " min_x = min(features[:,0])\n", - " max_x = max(features[:,1])\n", - " min_y = min(features[:,1])*(1-.1)\n", - " max_y = max(features[:,1])*(1+.1)\n", - " cx = np.array([min_x,max_x],dtype=np.float32)\n", - " cy = (0.5-W[0]*cx-b)/W[1]\n", - " ax.plot(cx,cy,'g')\n", - " ax.set_ylim(min_y,max_y)\n", - " fig.show()" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 283 - }, - "id": "tq0vFchQwHl8", - "outputId": "9a5aa6a0-c92f-4d72-9e78-c0f615804bff", - "scrolled": false, - "trusted": true - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "C:\\Users\\dmitryso\\AppData\\Local\\Temp/ipykernel_103052/2721537645.py:17: UserWarning: Matplotlib is currently using module://matplotlib_inline.backend_inline, which is a non-GUI backend, so cannot show the figure.\n", - " fig.show()\n" - ] - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "plot_dataset(train_x, train_labels)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Normalizing Data\n", - "\n", - "Before training, it is common to bring our input features to the standard range of [0,1] (or [-1,1]). The exact reasons for that we will discuss later in the course, but in short the reason is the following. We want to avoid values that flow through our network getting too big or too small, and we normally agree to keep all values in the small range close to 0. Thus we initialize the weights with small random numbers, and we keep signals in the same range.\n", - "\n", - "When normalizing data, we need to subtract min value and divide by range. We compute min value and range using training data, and then normalize test/validation dataset using the same min/range values from the training set. This is because in real life we will only know the training set, and not all incoming new values that the network would be asked to predict. Occasionally, the new value may fall out of the [0,1] range, but that's not crucial. " - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], - "source": [ - "train_x_norm = (train_x-np.min(train_x,axis=0)) / (np.max(train_x,axis=0)-np.min(train_x,axis=0))\n", - "test_x_norm = (test_x-np.min(train_x,axis=0)) / (np.max(train_x,axis=0)-np.min(train_x,axis=0))" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "SjPlpf2-wHl8" - }, - "source": [ - "## Training One-Layer Network (Perceptron)\n", - "\n", - "In many cases, a neural network would be a sequence of layers. It can be defined in Keras using `Sequential` model in the following manner:" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Model: \"sequential_2\"\n", - "_________________________________________________________________\n", - " Layer (type) Output Shape Param # \n", - "=================================================================\n", - " dense_2 (Dense) (None, 1) 3 \n", - " \n", - " activation_1 (Activation) (None, 1) 0 \n", - " \n", - "=================================================================\n", - "Total params: 3\n", - "Trainable params: 3\n", - "Non-trainable params: 0\n", - "_________________________________________________________________\n" - ] - } - ], - "source": [ - "model = keras.models.Sequential()\n", - "model.add(keras.Input(shape=(2,)))\n", - "model.add(keras.layers.Dense(1))\n", - "model.add(keras.layers.Activation(keras.activations.sigmoid))\n", - "\n", - "model.summary()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Here, we first create the model, and then add layers to it:\n", - "* First `Input` layer (which is not strictly speaking a layer) contains the specification of network's input size\n", - "* `Dense` layer is the actual perceptron that contains trainable weights\n", - "* Finally, there is a layer with *sigmoid* `Activation` function to bring the result of the network into 0-1 range (to make it a probability).\n", - "\n", - "Input size, as well as activation function, can also be specified directly in the `Dense` layer for brevity: " - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Model: \"sequential_9\"\n", - "_________________________________________________________________\n", - " Layer (type) Output Shape Param # \n", - "=================================================================\n", - " dense_9 (Dense) (None, 1) 3 \n", - " \n", - "=================================================================\n", - "Total params: 3\n", - "Trainable params: 3\n", - "Non-trainable params: 0\n", - "_________________________________________________________________\n" - ] - } - ], - "source": [ - "model = keras.models.Sequential()\n", - "model.add(keras.layers.Dense(1,input_shape=(2,),activation='sigmoid'))\n", - "model.summary()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Before training the model, we need to **compile it**, which essentially mean specifying:\n", - "* **Loss function**, which defines how loss is calculated. Because we have two-class classification problem, we will use *binary cross-entropy loss*.\n", - "* **Optimizer** to use. The simplest option would be to use `sgd` for *stochastic gradient descent*, or you can use more sophisticated optimizers such as `adam`.\n", - "* **Metrics** that we want to use to measure success of our training. Since it is classification task, a good metrics would be `Accuracy` (or `acc` for short)\n", - "\n", - "We can specify loss, metrics and optimizer either as strings, or by providing some objects from Keras framework. In our example, we need to specify `learning_rate` parameter to fine-tune learning speed of our model, and thus we provide full name of Keras SGD optimizer." - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "metadata": {}, - "outputs": [], - "source": [ - "model.compile(optimizer=keras.optimizers.SGD(learning_rate=0.2),loss='binary_crossentropy',metrics=['acc'])" - ] + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "En2vX4FuwHlu" + }, + "source": [ + "## Simplest Introduction to Neural Networks with Keras\n", + "\n", + "> This notebook is a part of [AI for Beginners Curricula](http://github.com/microsoft/ai-for-beginners). Visit the repository for complete set of learning materials.\n", + "\n", + "### Neural Frameworks\n", + "\n", + "There are several frameworks for training neural networks. However, if you want to get started fast and not go into much detail on how things work internally - you should consider using [Keras](https://keras.io/). This short tutorial will get you started, and if you want to get deeper into understanding how things work - look into [Introduction to Tensorflow and Keras](IntroKerasTF.ipynb) notebook." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "8cACQoFMwHl3" + }, + "source": [ + "### Getting things ready\n", + "\n", + "Keras is a part of Tensorflow 2.x framework. Let's make sure we have version 2.x.x of Tensorflow installed:\n", + "```\n", + "pip install tensorflow\n", + "```\n", + "or\n", + "```\n", + "conda install tensorflow\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" }, + "id": "xwqVx9-bwHl3", + "outputId": "2aa591b4-b647-441f-9c8e-4e0da2d517a0", + "tags": [] + }, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "After compiling the model, we can do the actual training by calling `fit` method. The most important parameters are:\n", - "* `x` and `y` specify training data, features and labels respectively\n", - "* If we want validation to be performed on each epoch, we can specify `validation_data` parameter, which would be a tuple of features and labels\n", - "* `epochs` specified the number of epochs\n", - "* If we want training to happen in minibatches, we can speficu `batch_size` parameter. You can also pre-batch the data manually before passing it to `x`/`y`/`validation_data`, in which case you do not need `batch_size`" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "Tensorflow version = 2.7.0\n", + "Keras version = 2.7.0\n" + ] + } + ], + "source": [ + "import tensorflow as tf\n", + "from tensorflow import keras\n", + "import numpy as np\n", + "from sklearn.datasets import make_classification\n", + "import matplotlib.pyplot as plt\n", + "print(f'Tensorflow version = {tf.__version__}')\n", + "print(f'Keras version = {keras.__version__}')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6tp2xGV7wHl4" + }, + "source": [ + "## Basic Concepts: Tensor\n", + "\n", + "**Tensor** is a multi-dimensional array. It is very convenient to use tensors to represent different types of data:\n", + "* 400x400 - black-and-white picture\n", + "* 400x400x3 - color picture \n", + "* 16x400x400x3 - minibatch of 16 color pictures\n", + "* 25x400x400x3 - one second of 25-fps video\n", + "* 8x25x400x400x3 - minibatch of 8 1-second videos\n", + "\n", + "Tensors give us a convenient way to represent input/output data, as well we weights inside the neural network." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "A10prCPowHl7" + }, + "source": [ + "## Sample Problem\n", + "\n", + "Let's consider binary classification problem. A good example of such a problem would be a tumour classification between malignant and benign based on it's size and age. Let's start by generating some sample data:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "id": "j0OTPkGpwHl7" + }, + "outputs": [], + "source": [ + "np.random.seed(0) # pick the seed for reproducibility - change it to explore the effects of random variations\n", + "\n", + "n = 100\n", + "X, Y = make_classification(n_samples = n, n_features=2,\n", + " n_redundant=0, n_informative=2, flip_y=0.05,class_sep=1.5)\n", + "X = X.astype(np.float32)\n", + "Y = Y.astype(np.int32)\n", + "\n", + "split = [ 70*n//100 ]\n", + "train_x, test_x = np.split(X, split)\n", + "train_labels, test_labels = np.split(Y, split)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "id": "c-_BjSHPwHl8" + }, + "outputs": [], + "source": [ + "def plot_dataset(features, labels, W=None, b=None):\n", + " # prepare the plot\n", + " fig, ax = plt.subplots(1, 1)\n", + " ax.set_xlabel('$x_i[0]$ -- (feature 1)')\n", + " ax.set_ylabel('$x_i[1]$ -- (feature 2)')\n", + " colors = ['r' if l else 'b' for l in labels]\n", + " ax.scatter(features[:, 0], features[:, 1], marker='o', c=colors, s=100, alpha = 0.5)\n", + " if W is not None:\n", + " min_x = min(features[:,0])\n", + " max_x = max(features[:,1])\n", + " min_y = min(features[:,1])*(1-.1)\n", + " max_y = max(features[:,1])*(1+.1)\n", + " cx = np.array([min_x,max_x],dtype=np.float32)\n", + " cy = (0.5-W[0]*cx-b)/W[1]\n", + " ax.plot(cx,cy,'g')\n", + " ax.set_ylim(min_y,max_y)\n", + " fig.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 283 }, + "id": "tq0vFchQwHl8", + "outputId": "9a5aa6a0-c92f-4d72-9e78-c0f615804bff" + }, + "outputs": [ { - "cell_type": "code", - "execution_count": 44, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Epoch 1/10\n", - "70/70 [==============================] - 0s 4ms/step - loss: 0.3379 - acc: 0.9000 - val_loss: 0.3282 - val_acc: 0.9000\n", - "Epoch 2/10\n", - "70/70 [==============================] - 0s 2ms/step - loss: 0.3270 - acc: 0.9429 - val_loss: 0.3336 - val_acc: 0.9000\n", - "Epoch 3/10\n", - "70/70 [==============================] - 0s 2ms/step - loss: 0.3195 - acc: 0.9143 - val_loss: 0.3137 - val_acc: 0.9000\n", - "Epoch 4/10\n", - "70/70 [==============================] - 0s 2ms/step - loss: 0.3087 - acc: 0.9286 - val_loss: 0.2970 - val_acc: 0.9333\n", - "Epoch 5/10\n", - "70/70 [==============================] - 0s 3ms/step - loss: 0.3006 - acc: 0.9429 - val_loss: 0.3210 - val_acc: 0.9000\n", - "Epoch 6/10\n", - "70/70 [==============================] - 0s 3ms/step - loss: 0.3003 - acc: 0.9000 - val_loss: 0.2985 - val_acc: 0.9000\n", - "Epoch 7/10\n", - "70/70 [==============================] - 0s 3ms/step - loss: 0.2956 - acc: 0.9286 - val_loss: 0.3037 - val_acc: 0.9000\n", - "Epoch 8/10\n", - "70/70 [==============================] - 0s 3ms/step - loss: 0.2891 - acc: 0.9429 - val_loss: 0.3035 - val_acc: 0.9000\n", - "Epoch 9/10\n", - "70/70 [==============================] - 0s 3ms/step - loss: 0.2809 - acc: 0.9000 - val_loss: 0.2815 - val_acc: 0.9000\n", - "Epoch 10/10\n", - "70/70 [==============================] - 0s 3ms/step - loss: 0.2809 - acc: 0.9286 - val_loss: 0.2907 - val_acc: 0.9000\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 44, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "model.fit(x=train_x_norm,y=train_labels,validation_data=(test_x_norm,test_labels),epochs=10,batch_size=1)" - ] + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\dmitryso\\AppData\\Local\\Temp/ipykernel_103052/2721537645.py:17: UserWarning: Matplotlib is currently using module://matplotlib_inline.backend_inline, which is a non-GUI backend, so cannot show the figure.\n", + " fig.show()\n" + ] }, { - "cell_type": "markdown", - "metadata": { - "id": "s4_Atvn5K4K9" - }, - "source": [ - "You can try to experiment with different training parameters to see how they affect the training:\n", - "* Setting `batch_size` to be too large (or not specifying it at all) may result in less stable training, because with low-dimensional data small batch sizes provide more precise direction of the gradient for each specific case\n", - "* Too high `learning_rate` may result in overfitting, or in less stable results, while too low learning rate means it will take more epochs to achieve the result\n", - "\n", - "> Note that you can call `fit` function several times in a row to further train the network. If you want to start training from scratch - you need to re-run the cell with the model definition. \n", - "\n", - "To make sure our training worked, let's plot the line that separates two classes. Separation line is defined by the equation $W\\times x + b = 0.5$" + "data": { + "image/png": "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", + "text/plain": [ + "
" ] - }, + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plot_dataset(train_x, train_labels)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Normalizing Data\n", + "\n", + "Before training, it is common to bring our input features to the standard range of [0,1] (or [-1,1]). The exact reasons for that we will discuss later in the course, but in short the reason is the following. We want to avoid values that flow through our network getting too big or too small, and we normally agree to keep all values in the small range close to 0. Thus we initialize the weights with small random numbers, and we keep signals in the same range.\n", + "\n", + "When normalizing data, we need to subtract min value and divide by range. We compute min value and range using training data, and then normalize test/validation dataset using the same min/range values from the training set. This is because in real life we will only know the training set, and not all incoming new values that the network would be asked to predict. Occasionally, the new value may fall out of the [0,1] range, but that's not crucial. " + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "train_x_norm = (train_x-np.min(train_x,axis=0)) / (np.max(train_x,axis=0)-np.min(train_x,axis=0))\n", + "test_x_norm = (test_x-np.min(train_x,axis=0)) / (np.max(train_x,axis=0)-np.min(train_x,axis=0))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "SjPlpf2-wHl8" + }, + "source": [ + "## Training One-Layer Network (Perceptron)\n", + "\n", + "In many cases, a neural network would be a sequence of layers. It can be defined in Keras using `Sequential` model in the following manner:" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 43, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 283 - }, - "id": "PgRTHttLwHl9", - "outputId": "e4407e1b-edf5-48e5-fdc2-da28120a3c6b", - "trusted": true - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "C:\\Users\\dmitryso\\AppData\\Local\\Temp/ipykernel_103052/2721537645.py:17: UserWarning: Matplotlib is currently using module://matplotlib_inline.backend_inline, which is a non-GUI backend, so cannot show the figure.\n", - " fig.show()\n" - ] - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "plot_dataset(train_x,train_labels,model.layers[0].weights[0],model.layers[0].weights[1])" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "Model: \"sequential_2\"\n", + "_________________________________________________________________\n", + " Layer (type) Output Shape Param # \n", + "=================================================================\n", + " dense_2 (Dense) (None, 1) 3 \n", + " \n", + " activation_1 (Activation) (None, 1) 0 \n", + " \n", + "=================================================================\n", + "Total params: 3\n", + "Trainable params: 3\n", + "Non-trainable params: 0\n", + "_________________________________________________________________\n" + ] + } + ], + "source": [ + "model = keras.models.Sequential()\n", + "model.add(keras.Input(shape=(2,)))\n", + "model.add(keras.layers.Dense(1))\n", + "model.add(keras.layers.Activation(keras.activations.sigmoid))\n", + "\n", + "model.summary()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here, we first create the model, and then add layers to it:\n", + "* First `Input` layer (which is not strictly speaking a layer) contains the specification of network's input size\n", + "* `Dense` layer is the actual perceptron that contains trainable weights\n", + "* Finally, there is a layer with *sigmoid* `Activation` function to bring the result of the network into 0-1 range (to make it a probability).\n", + "\n", + "Input size, as well as activation function, can also be specified directly in the `Dense` layer for brevity: " + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": { - "id": "dvAiaj_JndyP" - }, - "source": [ - "## Plotting the training graphs\n", - "\n", - "`fit` function returns `history` object as a result, which can be used to observe loss and metrics on each epoch. In the example below, we will re-start the training with small learning rate, and will observe how the loss and accuracy behave.\n", - "\n", - "> **Note** that we are using slightly different syntax for defining `Sequential` model. Instead of `add`-ing layers one by one, we can also specify the list of layers right when creating the model in the first place - this is a bit shorter syntax, and you may prefer to use it." - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "Model: \"sequential_9\"\n", + "_________________________________________________________________\n", + " Layer (type) Output Shape Param # \n", + "=================================================================\n", + " dense_9 (Dense) (None, 1) 3 \n", + " \n", + "=================================================================\n", + "Total params: 3\n", + "Trainable params: 3\n", + "Non-trainable params: 0\n", + "_________________________________________________________________\n" + ] + } + ], + "source": [ + "model = keras.models.Sequential()\n", + "model.add(keras.layers.Dense(1,input_shape=(2,),activation='sigmoid'))\n", + "model.summary()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Before training the model, we need to **compile it**, which essentially mean specifying:\n", + "* **Loss function**, which defines how loss is calculated. Because we have two-class classification problem, we will use *binary cross-entropy loss*.\n", + "* **Optimizer** to use. The simplest option would be to use `sgd` for *stochastic gradient descent*, or you can use more sophisticated optimizers such as `adam`.\n", + "* **Metrics** that we want to use to measure success of our training. Since it is classification task, a good metrics would be `Accuracy` (or `acc` for short)\n", + "\n", + "We can specify loss, metrics and optimizer either as strings, or by providing some objects from Keras framework. In our example, we need to specify `learning_rate` parameter to fine-tune learning speed of our model, and thus we provide full name of Keras SGD optimizer." + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [], + "source": [ + "model.compile(optimizer=keras.optimizers.SGD(learning_rate=0.2),loss='binary_crossentropy',metrics=['acc'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "After compiling the model, we can do the actual training by calling `fit` method. The most important parameters are:\n", + "* `x` and `y` specify training data, features and labels respectively\n", + "* If we want validation to be performed on each epoch, we can specify `validation_data` parameter, which would be a tuple of features and labels\n", + "* `epochs` specified the number of epochs\n", + "* If we want training to happen in minibatches, we can speficy `batch_size` parameter. You can also pre-batch the data manually before passing it to `x`/`y`/`validation_data`, in which case you do not need `batch_size`" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 47, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Epoch 1/10\n", - "70/70 [==============================] - 1s 5ms/step - loss: 0.6600 - acc: 0.6143 - val_loss: 0.6351 - val_acc: 0.8000\n", - "Epoch 2/10\n", - "70/70 [==============================] - 0s 2ms/step - loss: 0.6384 - acc: 0.7143 - val_loss: 0.6187 - val_acc: 0.8333\n", - "Epoch 3/10\n", - "70/70 [==============================] - 0s 2ms/step - loss: 0.6188 - acc: 0.7571 - val_loss: 0.6001 - val_acc: 0.8667\n", - "Epoch 4/10\n", - "70/70 [==============================] - 0s 3ms/step - loss: 0.6022 - acc: 0.7714 - val_loss: 0.5837 - val_acc: 0.9000\n", - "Epoch 5/10\n", - "70/70 [==============================] - 0s 2ms/step - loss: 0.5860 - acc: 0.8571 - val_loss: 0.5673 - val_acc: 0.9000\n", - "Epoch 6/10\n", - "70/70 [==============================] - 0s 2ms/step - loss: 0.5702 - acc: 0.8571 - val_loss: 0.5597 - val_acc: 0.8667\n", - "Epoch 7/10\n", - "70/70 [==============================] - 0s 2ms/step - loss: 0.5568 - acc: 0.8286 - val_loss: 0.5458 - val_acc: 0.9000\n", - "Epoch 8/10\n", - "70/70 [==============================] - 0s 2ms/step - loss: 0.5430 - acc: 0.8714 - val_loss: 0.5325 - val_acc: 0.9000\n", - "Epoch 9/10\n", - "70/70 [==============================] - 0s 2ms/step - loss: 0.5308 - acc: 0.8714 - val_loss: 0.5234 - val_acc: 0.9000\n", - "Epoch 10/10\n", - "70/70 [==============================] - 0s 3ms/step - loss: 0.5175 - acc: 0.9143 - val_loss: 0.5170 - val_acc: 0.8667\n" - ] - } - ], - "source": [ - "model = keras.models.Sequential([\n", - " keras.layers.Dense(1,input_shape=(2,),activation='sigmoid')])\n", - "model.compile(optimizer=keras.optimizers.SGD(learning_rate=0.05),loss='binary_crossentropy',metrics=['acc'])\n", - "hist = model.fit(x=train_x_norm,y=train_labels,validation_data=(test_x_norm,test_labels),epochs=10,batch_size=1)" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 1/10\n", + "70/70 [==============================] - 0s 4ms/step - loss: 0.3379 - acc: 0.9000 - val_loss: 0.3282 - val_acc: 0.9000\n", + "Epoch 2/10\n", + "70/70 [==============================] - 0s 2ms/step - loss: 0.3270 - acc: 0.9429 - val_loss: 0.3336 - val_acc: 0.9000\n", + "Epoch 3/10\n", + "70/70 [==============================] - 0s 2ms/step - loss: 0.3195 - acc: 0.9143 - val_loss: 0.3137 - val_acc: 0.9000\n", + "Epoch 4/10\n", + "70/70 [==============================] - 0s 2ms/step - loss: 0.3087 - acc: 0.9286 - val_loss: 0.2970 - val_acc: 0.9333\n", + "Epoch 5/10\n", + "70/70 [==============================] - 0s 3ms/step - loss: 0.3006 - acc: 0.9429 - val_loss: 0.3210 - val_acc: 0.9000\n", + "Epoch 6/10\n", + "70/70 [==============================] - 0s 3ms/step - loss: 0.3003 - acc: 0.9000 - val_loss: 0.2985 - val_acc: 0.9000\n", + "Epoch 7/10\n", + "70/70 [==============================] - 0s 3ms/step - loss: 0.2956 - acc: 0.9286 - val_loss: 0.3037 - val_acc: 0.9000\n", + "Epoch 8/10\n", + "70/70 [==============================] - 0s 3ms/step - loss: 0.2891 - acc: 0.9429 - val_loss: 0.3035 - val_acc: 0.9000\n", + "Epoch 9/10\n", + "70/70 [==============================] - 0s 3ms/step - loss: 0.2809 - acc: 0.9000 - val_loss: 0.2815 - val_acc: 0.9000\n", + "Epoch 10/10\n", + "70/70 [==============================] - 0s 3ms/step - loss: 0.2809 - acc: 0.9286 - val_loss: 0.2907 - val_acc: 0.9000\n" + ] }, { - "cell_type": "code", - "execution_count": 50, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[]" - ] - }, - "execution_count": 50, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXoAAAD4CAYAAADiry33AAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8rg+JYAAAACXBIWXMAAAsTAAALEwEAmpwYAAAsWklEQVR4nO3dd3xUVfrH8c9DCpDQISAl9AREkBZAmjRBrLhWbLgWEBUVe9t1LbuuXVFwEUFF+SlrQ0CRIiJFQAm9JyEECKEkdALpz++PG9cYAkxgkjuZed6vV14wM/fOPBnIN2fOueccUVWMMcb4r3JuF2CMMaZkWdAbY4yfs6A3xhg/Z0FvjDF+zoLeGGP8XLDbBRSlVq1a2rhxY7fLMMaYMmP58uVpqhpR1GM+GfSNGzcmNjbW7TKMMabMEJFtJ3vMum6MMcbPWdAbY4yfs6A3xhg/Z0FvjDF+zoLeGGP8nAW9Mcb4OQt6Y4zxcxb0xhjjA5ZvO8D787eUyHNb0BtjjMumrEzmxnFL+ey37aRn5nj9+X1yZqwxxgSCvDzljTmbGTNvC12a1GDsLR0JL+/9WLagN8YYFxzLyuGh/65i1vo9DO4UyQuDWhMaXDKdLBb0xhhTylIOHueuibFs2n2Yv1/eiju6N0ZESuz1LOiNMaYUrdx+gKGfLCcjO5cJt3WiT8vaJf6aFvTGGFNKpq7ayWNfraFOlfJ8NrQL0XUql8rretQhJCIDRWSziCSIyJNFPF5dRKaIyBoR+U1EWnt6rjHG+Lu8POXN2Zt5cPIq2jWoxtT7epRayIMHQS8iQcAY4BKgFXCjiLQqdNjTwCpVPR8YAowqxrnGGOO3jmXlcN9nK3jnpwSu69iASXd1oUZ4aKnW4EnXTWcgQVUTAURkMjAI2FDgmFbAvwFUdZOINBaROkBTD841/kwV0tNA89yuBCpWh+DS/QHzWVnpkHnU7Sp8R2g4lK/k9afddeg4Qz+JZX3KYZ659Fzu6tmkRAddT8aToK8P7ChwOxnoUuiY1cDVwCIR6Qw0Ahp4eK7xV/u2wLQHYNsitytxVDoHLn8TWl7mdiXuyc2BJaPh539DTobb1fiOoFC48HHoMRKCQrzylKt3HGToJ7GkZ+YwfkgM/c6t45XnPROeBH1Rv3600O2XgVEisgpYC6wEcjw813kRkWHAMICGDRt6UJbxWbk5sHQMzHsJgspD379BxRru1qR5sHwiTL4JzrsaLnkVKhW5vab/2r0Wpt4Hu1ZDy8uhWV+3K/IdSQth3j9hw7cwaDTUa39WTzd9dQqPfrmaiMrl+eTObrQ8p4p36jxDngR9MhBZ4HYDIKXgAap6GLgdQJzPJVvzv8JOd26B5xgHjAOIiYkp8peBKQN2r4NpIyBlpRMml74OVeq6XZWj41/hl7dh/quQOA8GvgLnXw8ufJQuVTmZsOA1WPSW03113URoNcj/v+/i6HQntLkevn8YPugL3e6H3k9BSMViPY2q8vaP8YyaG09Mo+qMvbUjtSqVL6GiPSeqp85UEQkG4oB+wE5gGXCTqq4vcEw14JiqZonIUKCnqg7x5NyixMTEqG0OXsbkZMKC12HRm06YXPoatLrKN8MkdTNMHQHJv0HUALj8LajawO2qSsaO35zvNW0ztL0RLn4Jwlz+dOXLjh+EOc/CiolQoxlc+Q407uHZqVm5PPrVar5fs4trOjTgpatbUz44qGTrLUBElqtqTJGPnS7o85/gUuBtIAj4UFX/JSLDAVR1rIh0BT4BcnEGWu9U1QMnO/d0r2dBX8aUxTDJy4XfPoC5z4MEQf/noOMdUM5P1vnLPAo//RN+Hev8Erv8bYi6yO2qyo7E+TD9ATiQBDF3wEXPQ4WTd7/sOZzB0E9iWbvzEE8ObMmwC5uW+qDrWQd9abOgLyOy0mHui06YVKkPV7wNUf3drqp4DiTB9Ach8Wdo2A2ufBdqNXe7qrOz5Sfnezq4HToNhYv+AeVL75ptv5GV7owzLX0PKtd1fllGDzjhsLXJh7jrk2Ucychh1OD29G/lzqCrBb3xvi3znBaPP4SJKqz6P5j1tNMF1fsp6DoCgsrYxPHjB2DW32DVJKjZ3Pml1aib21WVfcmxzifW1I1OP/7AlyG8JgAz1u7i4S9WUTO8PONvi+Hcuu4NulrQG+85fhBmPwMrJzl9mING+0+YHNkN3z8Cm76Dum1h0Bg4p43bVXlm43Sn9vQ06P4g9HoCQiq4XZX/yMmChW84XxWqope8yrt72vDmj/F0aFiN92+NIaKyu4OuFvTGOzZ+lx8mqdD9gfwwKd5VCWXChqnw/aNwfD/0eAgufAyC3b9yokhH9sAPjzk1n9MGrhwN9dq5XZX/2rOevG9HUG7XCubkdmRxi6d44oa+VAgpvUHXkzlV0PvJyJMpUUf3whe3wX9vhvAIGDoXLnrOP0MenEsP7/vV+Zi+4DUY29MZcPYlqrDqcxjTGTbPhH7PwtB5FvIlbG/FZlyT/Tz/yrmZ3iHreHbHHVRY86nz7+HDLOjNyanC6sn5YTID+v4dhs0768kkZUJYDfjLf+CWryH7GEwYAD886RvLBhzcDpOugW+HQ0QLGL4Iej7itRmdpmjrdh5i0Jhf2LTnGDE3PkvIfUuQum2dge+JV8D+RLdLPCnrujFFO7gDvhsJCT9CZBenSyAi2u2q3JF5BOa+AL+Ng2oN4YpR7swqzcuDZePhx+ec2xc9B53u8p9LQn3YzHW7eOi/q6keFsIHt8VwXr2qzgN5ebDyE5j9d8jNdmaBX3APlCv9rhzrozeey8uD2AlOmKg6V9N0GmphArBtCUy7H/bFQ7tb4OJ/OpPDSkNavHPlx46lzi+Zy9+G6o1K57UDmKoyZl4Cr8+Oo11kNcYN6UjtykUMch9Oge8ehrgfoH5Hp2FUp3QX6rWgN55Ji3eCbPsSaNrHablamPxZdgbMfwV+GQXhteCyN+DcK0ru9XKzYfE78PMrzpjIwH87k9J8ccaxn8nIzuXJr9fw7aoUBrWrxyvXnH/qQVdVWPc1/PA4ZByGCx+FHg+X2oqpFvTm1HJz8sPkZeeSvIv/De1usjA5lV2rnQXCdq91Bm8veQ0qe3mizK7VTit+95qSew1TpL1HMrj70+Ws3H6Qxy5uwb29m3k+0zV9H8x8AtZ+CbVbOa37Bh1LtmAs6M2p7FrjLEK2a7XTMr30DQsTT53Q2n4Z2g4++1+QBT81hNV0PjW0utI7NZvT2pBymLsmLuPAsWzeuqEtA1uf4aJ8m2fCdw/B0d1wwb3Q5xkIDfNusQVY0JsTZWfAgldh0dv5YfK602o0xZca53R57VgKzfo5S0FUO8OltrcvdVrxbowDGGat381D/11FlQohjL8thtb1q57dE2Yccsa7Yj+E6o2d2cpNLvRGqSewoDd/VjBM2t4EF//L9xch83UFr4gRca6IibnT80Hs/13Z8wFUjXR+WTTvV4IFm4JUlbHzE3l11ibOb1CND27tSO0qXpxZnLTIaQzsT3SWy+7/AlQ4y18ihVjQG0fm0T8uE6waCVe8Bc1tRUOvOrgdpo+ELXMh8gJniYhaUac+J+FH55xDydDlbme+Qglsa+drVJWVOw5yLDPX7VL4ZmUy36zYyRVt6/HatacZdD1TWcecnb2WjIZKdZzlsVtc4rWnt6A3kDA3P0x2QOdhzkzKAAgTV6jC6s9h5lOQfRx6PwHdHjhxQtOx/c5Caqs/h1rRzsf6hhe4U3Mpy8jO5Ymv1zB1VZH7ELni4f7R3N+3eckvL7xzhfOJeu96aH2Ns9tZeK2zfloL+kB2bD/M/puzOmPNKKeFGSBh4ro/rUNzvvPe123rPLb+W5jxqLPiZPeRzno6AbII2d4jGQz7ZDmrdhzkwX5R9Ig6+5A7WzXCQ2kWUYoNn5ysP3Y7K1/ZCfs2157VQL4FfaD6fXGuY/ucTY8vfDxgwsSnbJjmhHp6GnQb4fTTbpzuhP6Vo6Hu+W5XWGrWpxxi6MTYs7+ixV/s3ej03Scvg6iLnc3rz3C3Mwv6QHNktxMsG6fntyTHBFSY+KSCa8UHlYc+T0HX+8vemvdnYdb63YycvIpqYSF8MMQLV7T4i7xcZ9xs7gsQEgYj10BoeLGf5lRBHzj/ywKBKqz6DGY95Vw+2e/ZovuGTemrWB2uGuNccRFeE2o0dbuiUqOqvPfzFl6btZm2kSVwRUtZVy7IWR8neiDsXH5GIX86FvT+4sC2/C3x5kHDrvlb4p3mag9T+iI7uV1BqcrIzuWpb9YyZWUJX9HiD2o0cb5KgAV9WZeXB8s+gB+fdwZyLn29eNdvG1NCUo9kcvensazYfpBH+kczojSuaDFFsqAvy1I358/I/NW5Hv7yt858RqYxXrQh5TBDP4llX3om793cgUvbBPigq8ss6Mui3Ow/Ls0KDYe/vA/n32CLkBmfMGfDHh6cvJLKFYL58u5utGlgg65us6Ava1JWOZMt9qyFVlfBpa9BpdpuV+Xzxi3Ywme/bne7DAA6N6nBw/1bcE5V/xqQVFXeX5DIKzM30aZ+VT4YEkMdG3T1CRb0ZUX2cWcZ4cXvOrPobphUsuug+5H1KYd4+YdNtGlQjcY1S271QE9k5eTx7coUpq1OYVjPptzdqxnh5cv+j2FmTi5Pf7OOr1ckc9n5dXn92rZUDLVBV1/h0f8wERkIjAKCgPGq+nKhx6sCk4CG+c/5uqp+lP9YEnAEyAVyTnadpzmFbYvzdzZKgPa3wABb0dBTeXnKs1PXUz0slE9u70zVMPcvNd2x/xivztrMOz8l8NlvO3hkQDTXx0QSVK5sdr2lHc1k+KfLid12gJEXRfFgvygbdPUxp700Q0SCgDHAJUAr4EYRKbxH1n3ABlVtC/QG3hCRgtuq9FHVdhbyxZRxGL5/BD66BHKz4NZvnclPFvIe+2blTpZvO8ATl7T0iZAHiKwRxrs3tmfKvd1oXDOMp75Zy6WjFvLz5r1ul1Zsm3YfZtDoX1i78xCjb2rPyIuiLeR9kCfX4HUGElQ1UVWzgMlA4YXLFagszr9wJWA/kOPVSgNN/Bx4ryssm+BsWnDvUmjWx+2qypRDx7N5+YeNtG9YjWs7nNm08pLUvmF1vhzelf/c3IGMnFz++tEybp3wKxt3HXa7NI/M3biHa95bTHZuHl/c3ZXLz6/ndknmJDzpuqkP7ChwOxnoUuiY0cA0IAWoDNygqnn5jykwW0QUeF9Vx51dyX7u2H5n1cM1k6FWC7hzNkR2druqMumtOXHsS8/i49s7U85Hu0VEhEva1KXfuXX4dOk23pkbz6XvLOT6jpE8PCDaJwczVZUPFiby7x82cV69Kowf0snvBpb9jSdBX9RPSOEFci4GVgF9gWbAHBFZqKqHge6qmiIitfPv36SqC054EZFhwDCAhg0D8FpwVVg/BWY8BhkHnQXILnwUgsu7XVmZtCHlMJ8sSeLmLg3LxJoqocHluLNHE67t0IB3f4pn4pIkpq1O4e5eTRl2YVPCQn1jwDYrJ49npqzly+XJXNrmHN64rp0NupYBnnTdJAORBW43wGm5F3Q78I06EoCtQEsAVU3J/3MvMAWnK+gEqjpOVWNUNSYiIqJ430VZd3gX/PcW+Op2Z+W6YT9D32cs5M+QqvKPaeuoFhbKowNauF1OsVQNC+Fvl7fix4d70bdlbd7+MZ7er/3MF8t2kJvn7gKE+45mcsv4X/lyeTIP9Iti9I0dLOTLCE+CfhkQJSJN8gdYB+N00xS0HegHICJ1gBZAooiEi0jl/PvDgQHAOm8VX+apwopPYEwXZ5eh/i/AXXPhnDZuV1amTVm5k2VJB3hiYAuqhYWe/gQf1KhmOGNu7sDX93SlfvWKPP71Gi57ZyEL41NdqSduzxGueu8XViUfZNTgdjzcP9pnu8PMiU77eVBVc0RkBDAL5/LKD1V1vYgMz398LPAi8LGIrMXp6nlCVdNEpCkwJX8UPhj4TFVnltD3Urbs3wrTH4CtC6BRd2cRsprN3K6qzDuckc1LMzbRLrIa13WMPP0JPq5joxp8c083ZqzdzcszN3LrhN/oFR3B05eeS4tzKpdKDfM27eX+z1dSMTSI/w67gPYN7aqvssbWoy9tebnw6/vw04sgQdD/eeh4uy1C5iXPT1/Px4uTmHZfD7+bep+Zk8unS5wB26OZOdzQKZKH+kdTu3LJDISqKhMWbeWlGRtpeU4Vxt8WQ71qFUvktczZs/XofcXejc7yBTtjIWqAswjZGe4mY060cddhPlmyjZs6N/S7kAcoHxzEXT2bck2HBrz7UwKfLk1i6qoUhvdqxtCeTb3aX56Vk8ezU9cxedkOBp53Dm/e0NZnBoRN8VmLvjScsD/kK9DmOluEzItUlevfX0LC3qPMe7R3me2bL46ktHRembmJH9btpk6V8jw6oAVXd2hw1jNsD6RnMXzScn7dup8RfZpbf3wZYS16N+1cDlPv/2PH94GvQKUAu6qoFHy7yhmAffnqNgER8gCNa4Xzn1s6sixpP//8fiOPfbWGj35J4pnLzqV78zPbcDth7xHunBjLrkMZvH1DO65qX9/LVRs3WIu+pGQdg59fgiVjoFIduOxNaHmp21X5pSMZ2fR9Yz71qlVkyj3dArL1qapMX7OLV37YxM6Dx+nbsjZPXdKSqDqeD9j+vHkv93+2kvIhQYwb0pEONuhapliLvrQlLXIWIdufCB1ucy6brFjN7ar81ts/xpN2NJMJt8UEZMiDM8P2yrb1GNCqDhMXJzF6XgIDRy1kcKdIRl4UTUTlk8/JUFU+XpzEi99toEX+oGt9G3T1Kxb03pRxCOb8A5Z/BNUbw5Bp0LSX21X5tU27D/Px4iQGd2rI+Q2quV2O6yqEBHF3r2ZcFxPJO3PjmbR0G1NXpXBP72bc2aPJCfu1Zufm8ezU9Xz+23YGtKrDWze084tlk82fWdeNt8TNgukj4ehuZxGyPk+XyG7u5g+qyg3jlhK35wjzHulN9fDA6JsvjsTUo7z8wyZmb9hD3aoVeOziFlzVrj7lygkHj2Vxz6QVLEncx729m/HogBYB+4nIH1jXTUlKT4OZT8LaLyHiXLjhU2hgqzGXhmmrU/ht635e+ksbC/mTaBpRiXFDYliauI+XZmzk4S9W8+EvWxnasylvzYkj5WAGb17flqt9cHVP4z3Woj9TqrDua/jhcWfd+J6POF/BFjil4fcB2LpVKzDl3u5ldtOO0pSXp0xfk8KrMzez8+BxaoaHMm5IRzo2quF2acYLrEXvbYd2wvcPQ9xMqNcBBo2GOue5XVVAGZU/ADt+SIyFvIfKlRMGtavPxeedw/TVKXRrXssGXQOEBX1x5OXBiokw51nIzYYB/4IL7oFytoJfadq8+wgfLU5icKdI2kZWc7ucMqdCSBDXxZT9dYCM5yzoPbVvC0x/EJIWQuOecOU7UKOp21UFHFXl2anrqFwhmMcubul2OcaUCRb0p5OXC0vfg5/+BUEhcMUo59p4W77AFdNWp/Dr1v386y+tqWEDsMZ4xIL+VPZsgKn3QcoKiL4ELn8Tqti+mG45mpnDSzM20qZ+VQZ3CsBdyIw5Qxb0RcnJgoVvOF8VqsA1E5x1aqwV76p35saz53AmY2/paAOwxhSDBX1hybHOUsKpG6HN9TDwZQiv6XZVAS9+zxE+XLSVG2IibeMLY4rJgv53WelOP/zS95zumZu+gOiL3a7K8PsA7HrCywfz+MCytQesMb7Agh4gcb6zrd+BJIi5Ay563umyMT7huzW7WJK4jxevak3NSrZhujHFFdhBf/wgzPm7s0F3jabw1++hcQ+3qzIFHM3M4Z/fb6B1/Src1NkGYI05E4Eb9JtmOLNbj+6Bbg9A76cgNMztqkwh7+YPwP7HBmCNOWOBF/RHU531adZ/A7XPg8GfQf0ObldlipCw9wgTFm3l+pgGtgmGMWchcIJe1Vlh8ocnIPMI9HkGuo+0Rch8lKryj2nrCQsN4omBNgPWmLMRGEF/KBm+ewjiZ0ODTnDlaKht4eHLvl+7i18S9vHCoPNsANaYs+TfQZ+XB8s/hDnPgeY618R3HmaLkPm49Mwc/vndRs6rV4WbuzRyuxxjyrxynhwkIgNFZLOIJIjIk0U8XlVEpovIahFZLyK3e3puidm3BSZeDt8/4vTB37PYVposI979KYHdhzN4YVBrG4A1xgtO26IXkSBgDNAfSAaWicg0Vd1Q4LD7gA2qeoWIRACbReT/gFwPzvWu3BxYMhp+/jcElXe6adrfYssXlBEJe48yfmEi13ZsQMdGNgBrjDd40nXTGUhQ1UQAEZkMDAIKhrUClUVEgErAfiAH6OLBud6ze62zfMGuVdDiMrjsDahSt0ReynifqvLctPVUDA3iyUtsDMUYb/Ek6OsDOwrcTsYJ8IJGA9OAFKAycIOq5omIJ+d6x/EDMOFi51r46z6GVldZK76M+WHdbhYlpPH8ledRywZgjfEaT4K+qLQsvNHsxcAqoC/QDJgjIgs9PNd5EZFhwDCAhg3PYAZkxepwzXhoeAGE2R6YZU16Zg4vfreBc+tW4eYuNgPWGG/yZDA2GSi471gDnJZ7QbcD36gjAdgKtPTwXABUdZyqxqhqTEREhKf1/1nLSy3ky6jR8xLYdSiDFwedR3CQR9cIGGM85MlP1DIgSkSaiEgoMBinm6ag7UA/ABGpA7QAEj081wS4LanOAOw1HRoQ09h+URvjbaftulHVHBEZAcwCgoAPVXW9iAzPf3ws8CLwsYisxemueUJV0wCKOrdkvhVTFv0+AFshxAZgjSkpHk2YUtUZwIxC940t8PcUYICn5xrzu5nrdrMwPo1/XNGKiMo2AGtMSbDOUOOaY1nOAGzLcypz6wU2A9aYkmJBb1wzZl4CKYcyePGq1jYAa0wJsp8u44rE1KOMW5DI1e3r08kGYI0pURb0ptSpKs9N30CF4CCevNQGYI0paRb0ptTNWr+HBXGpPNQ/mtqVK7hdjjF+z4LelKrjWbn/G4Ad0tUGYI0pDf69Hr3xOWPmJbDz4HG+uLurDcAaU0rsJ82Umq1p6YxbkMhf2tencxMbgDWmtFjQm1Khqjw/fT2hweV4ymbAGlOqLOhNqZi9YQ8/b05l5EVR1K5iA7DGlCYLelPijmfl8sL0DbSoU5nbujV2uxxjAo4NxpoS95+fnQHY/w67gBAbgDWm1FnQmxKTl6csS9rP2PmJDGpXjy5Na7pdkjEByYLeeNXeIxksjEtjQXwqi+LT2JeeRbWwEJ6+9Fy3SzMmYFnQm7OSlZNH7Lb9LIhLY0FcKht2HQagZngoPaNq0atFBL2ia1MjPNTlSo0JXBb0ptiS0tJZEJ/KgrhUFm/Zx7GsXILLCR0bVeexi1vQKzqCVnWrUK6cbc5ujC+woDendTQzhyVb9rEgLpX5cals338MgMgaFbm6Q30ujIqga7OaVK4Q4nKlxpiiWNCbE+TlKRt2HWZ+nNNqX7H9ANm5SlhoEF2b1uTOHk24MDqCxjXDELFWuzG+zoLeAJB2NJNF8WnMj0tlYXwqaUezADi3bhXu6NGEXlERdGxcnfLBQS5XaowpLgv6AJWdm8eKbQecVnt8Kut2OoOoNcJD6dG8Fr2iI+gZVctmsRrjByzoA8j2fceYnz+IumTLPo5m5hBUTujQsBqPDojmwugIWteraoOoxvgZC3o/lp6Zw9JEZxB1QXwaW9PSAahfrSJXtqvHhVERdGtekyo2iGqMX7Og91OfLknixe83kpWTR4WQcnRtWpMhXRtxYXQETWuF2yCqMQHEgt7PZOfm8cL0DXy6dBt9WkRwZ4+mxDSuToUQG0Q1JlB5FPQiMhAYBQQB41X15UKPPwbcXOA5zwUiVHW/iCQBR4BcIEdVY7xUuynk0LFs7v1sOb8k7OPuXk15/OKWBFl/uzEB77RBLyJBwBigP5AMLBORaaq64fdjVPU14LX8468AHlLV/QWepo+qpnm1cvMnialHuWtiLDsOHOO1a8/nuphIt0syxvgIT1r0nYEEVU0EEJHJwCBgw0mOvxH43DvlGU/8kpDGPZOWExxUjs+GXkCnxrZNnzHmD54sDl4f2FHgdnL+fScQkTBgIPB1gbsVmC0iy0Vk2MleRESGiUisiMSmpqZ6UJYBmLR0G0M+/I26VSsy9b7uFvLGmBN40qIvqpNXT3LsFcAvhbptuqtqiojUBuaIyCZVXXDCE6qOA8YBxMTEnOz5Tb6c3Dxe/G4DE5dso2/L2owa3M7WmjHGFMmToE8GCnb4NgBSTnLsYAp126hqSv6fe0VkCk5X0AlBbzx36Hg2Iz5bwcL4NIb2bMKTl5xrg67GmJPyJOiXAVEi0gTYiRPmNxU+SESqAr2AWwrcFw6UU9Uj+X8fALzgjcIDVVJaOndMXMaO/cd49Zrzub6TDboaY07ttEGvqjkiMgKYhXN55Yequl5Ehuc/Pjb/0L8As1U1vcDpdYAp+ZNzgoHPVHWmN7+BQLJ4Sxr3TFpBOYFJd3axrfmMMR4RVd/rDo+JidHY2Fi3y/Apn/26nWenrqNJrXAm3NaJhjXD3C7JGONDRGT5yeYp2cxYH5eTm8e/Zmzko1+S6N0igndubG9r0xhjisWC3ocdzshmxGcrWRCXyh3dm/DMZTboaowpPgt6H7VtXzp3TowlKS2df1/dhhs7N3S7JGNMGWVB74OWJu5j+KTlAHx6Zxe6NrNBV2PMmbOg9zGTf9vO375dR6OaYUy4rRONa4W7XZIxpoyzoPcRuXnKSzM2MmHRVi6MjuDdG9tTtaINuhpjzp4FvQ84kpHNA5+vZN7mVP7arTF/u+xcgoM8WYbIGGNOz4LeZdv3HePOictITEvnn1e15pYLGrldkjHGz1jQu+i3rfsZPmk5uXnKp3d0plvzWm6XZIzxQxb0Lvli2Q6e+XYtkdXDmPDXTjSxQVdjTAmxoC9luXnKKzM3MW5BIj2a12LMTR2oGmaDrsaYkmNBX4qOZGQzcvIq5m7ay5Cujfj75a0IsUFXY0wJs6AvJTv2H+OuibEkpB7lhUHnMaRrY7dLMsYECAv6UrAsaT/DP11Odm4eH9/eiZ5REW6XZIwJIBb0Jeyr5ck8/c1a6levyPjbYmgWUcntkowxAcaCvoTk5imvztrE+/MT6dasJu/d3IFqYaFul2WMCUAW9CXgaGYOIyev4seNe7ipS0Oev/I8G3Q1xrjGgt7L0jNzuG7sEjbvPsxzV7Titm6Nyd9K0RhjXGFB72UfL05i467DjB8Sw0Wt6rhdjjHGYP0JXnToeDbvz99Cv5a1LeSNMT7Dgt6LJizayuGMHB7qH+12KcYY8z8W9F5yID2LDxdt5ZLW59C6flW3yzHGmP+xoPeS9xckkp5lrXljjO+xoPeC1COZTFycxJVt6xFdp7Lb5RhjzJ94FPQiMlBENotIgog8WcTjj4nIqvyvdSKSKyI1PDnXH4ydv4XMnFwe7BfldinGGHOC0wa9iAQBY4BLgFbAjSLSquAxqvqaqrZT1XbAU8B8Vd3vybll3e5DGXy6dBvXdGhAU1vewBjjgzxp0XcGElQ1UVWzgMnAoFMcfyPw+RmeW+aMmZdAXp7ygLXmjTE+ypOgrw/sKHA7Of++E4hIGDAQ+PoMzh0mIrEiEpuamupBWe5LPnCMycu2c32nSCJrhLldjjHGFMmToC9q/r6e5NgrgF9UdX9xz1XVcaoao6oxERFlYxnfd+cmICLc37e526UYY8xJeRL0yUBkgdsNgJSTHDuYP7ptintumZKUls5XK5K5qXND6lat6HY5xhhzUp4E/TIgSkSaiEgoTphPK3yQiFQFegFTi3tuWTRqbjwhQcK9fZq5XYoxxpzSaRc1U9UcERkBzAKCgA9Vdb2IDM9/fGz+oX8BZqtq+unO9fY3Udri9xzh21U7GdazKbUrV3C7HGOMOSWPVq9U1RnAjEL3jS10+2PgY0/OLeve/jGesJAg7u5lrXljjO+zmbHFtCHlMN+v3cUdPZpQI9x2jDLG+D4L+mJ668c4KlcI5q4eTd0uxRhjPGJBXwyrdxxkzoY9DOvZlKphIW6XY4wxHrGgL4Y358RRPSyE23s0cbsUY4zxmAW9h2KT9jM/LpW7ezWjUnnbgdEYU3ZY0Hvojdlx1KpUniFdG7ldijHGFIsFvQcWJ6SxJHEf9/ZuRlioteaNMWWLBf1pqCpvzInjnCoVuKlLQ7fLMcaYYrOgP435caks33aAEX2bUyEkyO1yjDGm2CzoT0FVeXNOHA2qV+T6mMjTn2CMMT7Igv4U5mzYw5rkQzzQL4rQYHurjDFlk6XXSeTlOa35JrXCubp9kXulGGNMmWBBfxIz1u1i0+4jjLwoiuAge5uMMWWXJVgRcvOUt3+MJ6p2JS4/v57b5RhjzFmxoC/CtNU7Sdh7lIf6RxNUrqjdEI0xpuywoC8kOzePt3+Mp1XdKgw87xy3yzHGmLNmQV/INyuS2bbvGA/3j6acteaNMX7Agr6AzJxc3pmbQNvIavQ7t7bb5RhjjFdY0BfwxbId7Dx4nEf6RyNirXljjH+woM+XkZ3L6HkJdGpcnZ5RtdwuxxhjvMaCPt+kpdvYcziTRwa0sNa8McavWNADx7JyGDt/C92b1+SCpjXdLscYY7zKFlcHJi7eRtrRLN7v38LtUowxxusCvkV/JCOb9xdsoU+LCDo2qu52OcYY43UeBb2IDBSRzSKSICJPnuSY3iKySkTWi8j8Avcnicja/MdivVW4t3y4KImDx7J52Frzxhg/ddquGxEJAsYA/YFkYJmITFPVDQWOqQa8BwxU1e0iUvgi9D6qmua9sr3j4LEsxi9M5OLz6tCmQVW3yzHGmBLhSYu+M5CgqomqmgVMBgYVOuYm4BtV3Q6gqnu9W2bJ+GBhIkezcniof7TbpRhjTInxJOjrAzsK3E7Ov6+gaKC6iPwsIstFZEiBxxSYnX//sJO9iIgME5FYEYlNTU31tP4ztu9oJh/9ksTl59ej5TlVSvz1jDHGLZ5cdVPUReVaxPN0BPoBFYElIrJUVeOA7qqakt+dM0dENqnqghOeUHUcMA4gJiam8PN73dj5W8jIzmXkRVEl/VLGGOMqT1r0yUDBDVMbAClFHDNTVdPz++IXAG0BVDUl/8+9wBScriBX7T2cwSdLtnFV+/o0i6jkdjnGGFOiPAn6ZUCUiDQRkVBgMDCt0DFTgZ4iEiwiYUAXYKOIhItIZQARCQcGAOu8V/6ZGTMvgdw85cF+1po3xvi/03bdqGqOiIwAZgFBwIequl5Ehuc/PlZVN4rITGANkAeMV9V1ItIUmJK/pEAw8Jmqziypb8YTOw8e5/PfdnBdTAMa1Qx3sxRjjCkVHs2MVdUZwIxC940tdPs14LVC9yWS34XjK0b/lADAiL7WmjfGBIaAmhm7fd8xvozdwY2dI6lfraLb5RhjTKkIqKAfNTeeoHLCfX2au12KMcaUmoAJ+i2pR5myMpkhXRtRu0oFt8sxxphSEzBB//aP8VQICWJ4r2Zul2KMMaUqIIJ+0+7DfLcmhdu7N6ZmpfJul2OMMaUqIIL+rTlxVAoNZmjPpm6XYowxpc7vg37dzkPMWr+HO3s2oVpYqNvlGGNMqfP7oH9zThzVwkK4o0cTt0sxxhhX+HXQL992gJ827WXYhU2pUiHE7XKMMcYVfh30b82Jo1alUP7arbHbpRhjjGv8NuiXJu5jUUIaw3s1IyzU9kA3xgQuvwx6VeXN2XHUqVKeWy5o5HY5xhjjKr8M+kUJafyWtJ8RfZpTISTI7XKMMcZVfhf0qsrrs+OoX60i13eKPP0Jxhjj5/wu6H/atJfVOw7yQL/mlA+21rwxxvhV0OflKW/MjqNRzTCu7tDA7XKMMcYn+FXQz1q/mw27DvNgvyhCgvzqWzPGmDPmN2mYm6e89WMczSLCGdSuvtvlGGOMz/CbC8yPZ+fSPrI6vVtEEFRO3C7HGGN8ht8EfaXywbxy7flul2GMMT7Hb7pujDHGFM2C3hhj/JwFvTHG+DkLemOM8XMeBb2IDBSRzSKSICJPnuSY3iKySkTWi8j84pxrjDGm5Jz2qhsRCQLGAP2BZGCZiExT1Q0FjqkGvAcMVNXtIlLb03ONMcaULE9a9J2BBFVNVNUsYDIwqNAxNwHfqOp2AFXdW4xzjTHGlCBPgr4+sKPA7eT8+wqKBqqLyM8islxEhhTjXABEZJiIxIpIbGpqqmfVG2OMOS1PJkwVNc1Ui3iejkA/oCKwRESWeniuc6fqOGAcgIikisg2D2orSi0g7QzP9Tf2XvyZvR9/Zu/HH/zhvTjpLkueBH0yUHBh9wZAShHHpKlqOpAuIguAth6eewJVjfCgriKJSKyqxpzp+f7E3os/s/fjz+z9+IO/vxeedN0sA6JEpImIhAKDgWmFjpkK9BSRYBEJA7oAGz081xhjTAk6bYteVXNEZAQwCwgCPlTV9SIyPP/xsaq6UURmAmuAPGC8qq4DKOrcEvpejDHGFEFUi+wyL7NEZFh+f3/As/fiz+z9+DN7P/7g7++F3wW9McaYP7MlEIwxxs9Z0BtjjJ/zm6C3NXX+ICKRIjJPRDbmrz30oNs1uU1EgkRkpYh853YtbhORaiLylYhsyv8/0tXtmtwkIg/l/5ysE5HPRaSC2zV5m18EfYE1dS4BWgE3ikgrd6tyVQ7wiKqeC1wA3Bfg7wfAgziX/BoYBcxU1ZY4810C9n0RkfrAA0CMqrbGuTpwsLtVeZ9fBD22ps6fqOouVV2R//cjOD/IAbtjuog0AC4Dxrtdi9tEpApwITABQFWzVPWgq0W5LxioKCLBQBgeTOosa/wl6D1eUyfQiEhjoD3wq8uluOlt4HGcOR6BrimQCnyU35U1XkTC3S7KLaq6E3gd2A7sAg6p6mx3q/I+fwl6j9fUCSQiUgn4GhipqofdrscNInI5sFdVl7tdi48IBjoA/1HV9kA6ELBjWiJSHefTfxOgHhAuIre4W5X3+UvQn9GaOv5MREJwQv7/VPUbt+txUXfgShFJwunS6ysik9wtyVXJQLKq/v4J7yuc4A9UFwFbVTVVVbOBb4BuLtfkdf4S9LamTgEiIjh9sBtV9U2363GTqj6lqg1UtTHO/4ufVNXvWmyeUtXdwA4RaZF/Vz8gkDcC2g5cICJh+T83/fDDwWlPVq/0eSdbj8flstzUHbgVWCsiq/Lve1pVZ7hXkvEh9wP/l98oSgRud7ke16jqryLyFbAC52q1leQvl+5PbAkEY4zxc/7SdWOMMeYkLOiNMcbPWdAbY4yfs6A3xhg/Z0FvjDF+zoLeGGP8nAW9Mcb4uf8HL4zLvVpYuQ8AAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "plt.plot(hist.history['acc'])\n", - "plt.plot(hist.history['val_acc'])" + "data": { + "text/plain": [ + "" ] + }, + "execution_count": 44, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "model.fit(x=train_x_norm,y=train_labels,validation_data=(test_x_norm,test_labels),epochs=10,batch_size=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "s4_Atvn5K4K9" + }, + "source": [ + "You can try to experiment with different training parameters to see how they affect the training:\n", + "* Setting `batch_size` to be too large (or not specifying it at all) may result in less stable training, because with low-dimensional data small batch sizes provide more precise direction of the gradient for each specific case\n", + "* Too high `learning_rate` may result in overfitting, or in less stable results, while too low learning rate means it will take more epochs to achieve the result\n", + "\n", + "> Note that you can call `fit` function several times in a row to further train the network. If you want to start training from scratch - you need to re-run the cell with the model definition. \n", + "\n", + "To make sure our training worked, let's plot the line that separates two classes. Separation line is defined by the equation $W\\times x + b = 0.5$" + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 283 }, + "id": "PgRTHttLwHl9", + "outputId": "e4407e1b-edf5-48e5-fdc2-da28120a3c6b" + }, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Multi-Class Classification\n", - "\n", - "If you need to solve a problem of multi-class classification, your network would have more that one output - corresponding to the number of classes $C$. Each output will contain the probability of a given class.\n", - "\n", - "> Note that you can also use a network with two outputs to perform binary classification in the same manner. That is exactly what we will demonstrate now.\n", - "\n", - "When you expect a network to output a set of probabilities $p_1,\\dots, p_C$, we need all of them to add up to 1. To ensure this, we use `softmax` as a final activation function on the last layer. **Softmax** takes a vector input, and makes sure that all components of that vector are transformed into probabilities.\n", - "\n", - "Also, since the output of the network is a $C$-dimensional vector, we need labels to have the same form. This can be achieved by using **one-hot encoding**, when the number of a class $i$ is converted to a vector of zeroes, with 1 at the $i$-th position.\n", - "\n", - "To compare the probability output of the neural network with expected one-hot-encoded label, we use **cross-entropy loss** function. It takes two probability distributions, and outputs a value of how different they are.\n", - "\n", - "So, to summarize what we need to do for multi-class classification with $C$ classes:\n", - "* The network should have $C$ neurons in the last layer\n", - "* Last activation function should be **softmax**\n", - "* Loss should be **cross-entropy loss**\n", - "* Labels should be converted to **one-hot encoding** (this can be done using `numpy`, or using Keras utils `to_categorical`)" - ] + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\dmitryso\\AppData\\Local\\Temp/ipykernel_103052/2721537645.py:17: UserWarning: Matplotlib is currently using module://matplotlib_inline.backend_inline, which is a non-GUI backend, so cannot show the figure.\n", + " fig.show()\n" + ] }, { - "cell_type": "code", - "execution_count": 54, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Epoch 1/10\n", - "70/70 [==============================] - 1s 6ms/step - loss: 0.6524 - acc: 0.7000 - val_loss: 0.5936 - val_acc: 0.9000\n", - "Epoch 2/10\n", - "70/70 [==============================] - 0s 2ms/step - loss: 0.5715 - acc: 0.8286 - val_loss: 0.5255 - val_acc: 0.8333\n", - "Epoch 3/10\n", - "70/70 [==============================] - 0s 3ms/step - loss: 0.4820 - acc: 0.8714 - val_loss: 0.4213 - val_acc: 0.9000\n", - "Epoch 4/10\n", - "70/70 [==============================] - 0s 3ms/step - loss: 0.4426 - acc: 0.9000 - val_loss: 0.3694 - val_acc: 0.9333\n", - "Epoch 5/10\n", - "70/70 [==============================] - 0s 3ms/step - loss: 0.3602 - acc: 0.9000 - val_loss: 0.3454 - val_acc: 0.9000\n", - "Epoch 6/10\n", - "70/70 [==============================] - 0s 3ms/step - loss: 0.3209 - acc: 0.8857 - val_loss: 0.2862 - val_acc: 0.9333\n", - "Epoch 7/10\n", - "70/70 [==============================] - 0s 3ms/step - loss: 0.2905 - acc: 0.9286 - val_loss: 0.2787 - val_acc: 0.9000\n", - "Epoch 8/10\n", - "70/70 [==============================] - 0s 3ms/step - loss: 0.2698 - acc: 0.9000 - val_loss: 0.2381 - val_acc: 0.9333\n", - "Epoch 9/10\n", - "70/70 [==============================] - 0s 3ms/step - loss: 0.2639 - acc: 0.8857 - val_loss: 0.2217 - val_acc: 0.9667\n", - "Epoch 10/10\n", - "70/70 [==============================] - 0s 2ms/step - loss: 0.2592 - acc: 0.9286 - val_loss: 0.2391 - val_acc: 0.9000\n" - ] - } - ], - "source": [ - "model = keras.models.Sequential([\n", - " keras.layers.Dense(5,input_shape=(2,),activation='relu'),\n", - " keras.layers.Dense(2,activation='softmax')\n", - "])\n", - "model.compile(keras.optimizers.Adam(0.01),'categorical_crossentropy',['acc'])\n", - "\n", - "# Two ways to convert to one-hot encoding\n", - "train_labels_onehot = keras.utils.to_categorical(train_labels)\n", - "test_labels_onehot = np.eye(2)[test_labels]\n", - "\n", - "hist = model.fit(x=train_x_norm,y=train_labels_onehot,\n", - " validation_data=[test_x_norm,test_labels_onehot],batch_size=1,epochs=10)" + "data": { + "image/png": "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", + "text/plain": [ + "
" ] - }, + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plot_dataset(train_x,train_labels,model.layers[0].weights[0],model.layers[0].weights[1])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dvAiaj_JndyP" + }, + "source": [ + "## Plotting the training graphs\n", + "\n", + "`fit` function returns `history` object as a result, which can be used to observe loss and metrics on each epoch. In the example below, we will re-start the training with small learning rate, and will observe how the loss and accuracy behave.\n", + "\n", + "> **Note** that we are using slightly different syntax for defining `Sequential` model. Instead of `add`-ing layers one by one, we can also specify the list of layers right when creating the model in the first place - this is a bit shorter syntax, and you may prefer to use it." + ] + }, + { + "cell_type": "code", + "execution_count": 47, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Sparse Categorical Cross-Entropy\n", - "\n", - "Often labels in multi-class classification are represented by class numbers. Keras also supports another kind of loss function called **sparse categorical crossentropy**, which expects class number to be integers, and not one-hot vectors. Using this kind of loss function, we can simplify our training code:" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 1/10\n", + "70/70 [==============================] - 1s 5ms/step - loss: 0.6600 - acc: 0.6143 - val_loss: 0.6351 - val_acc: 0.8000\n", + "Epoch 2/10\n", + "70/70 [==============================] - 0s 2ms/step - loss: 0.6384 - acc: 0.7143 - val_loss: 0.6187 - val_acc: 0.8333\n", + "Epoch 3/10\n", + "70/70 [==============================] - 0s 2ms/step - loss: 0.6188 - acc: 0.7571 - val_loss: 0.6001 - val_acc: 0.8667\n", + "Epoch 4/10\n", + "70/70 [==============================] - 0s 3ms/step - loss: 0.6022 - acc: 0.7714 - val_loss: 0.5837 - val_acc: 0.9000\n", + "Epoch 5/10\n", + "70/70 [==============================] - 0s 2ms/step - loss: 0.5860 - acc: 0.8571 - val_loss: 0.5673 - val_acc: 0.9000\n", + "Epoch 6/10\n", + "70/70 [==============================] - 0s 2ms/step - loss: 0.5702 - acc: 0.8571 - val_loss: 0.5597 - val_acc: 0.8667\n", + "Epoch 7/10\n", + "70/70 [==============================] - 0s 2ms/step - loss: 0.5568 - acc: 0.8286 - val_loss: 0.5458 - val_acc: 0.9000\n", + "Epoch 8/10\n", + "70/70 [==============================] - 0s 2ms/step - loss: 0.5430 - acc: 0.8714 - val_loss: 0.5325 - val_acc: 0.9000\n", + "Epoch 9/10\n", + "70/70 [==============================] - 0s 2ms/step - loss: 0.5308 - acc: 0.8714 - val_loss: 0.5234 - val_acc: 0.9000\n", + "Epoch 10/10\n", + "70/70 [==============================] - 0s 3ms/step - loss: 0.5175 - acc: 0.9143 - val_loss: 0.5170 - val_acc: 0.8667\n" + ] + } + ], + "source": [ + "model = keras.models.Sequential([\n", + " keras.layers.Dense(1,input_shape=(2,),activation='sigmoid')])\n", + "model.compile(optimizer=keras.optimizers.SGD(learning_rate=0.05),loss='binary_crossentropy',metrics=['acc'])\n", + "hist = model.fit(x=train_x_norm,y=train_labels,validation_data=(test_x_norm,test_labels),epochs=10,batch_size=1)" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [ { - "cell_type": "code", - "execution_count": 55, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Epoch 1/10\n", - "70/70 [==============================] - 1s 6ms/step - loss: 0.2353 - acc: 0.9143 - val_loss: 0.2190 - val_acc: 0.9000\n", - "Epoch 2/10\n", - "70/70 [==============================] - 0s 3ms/step - loss: 0.2243 - acc: 0.9286 - val_loss: 0.1886 - val_acc: 0.9333\n", - "Epoch 3/10\n", - "70/70 [==============================] - 0s 2ms/step - loss: 0.2366 - acc: 0.9143 - val_loss: 0.2262 - val_acc: 0.9000\n", - "Epoch 4/10\n", - "70/70 [==============================] - 0s 2ms/step - loss: 0.2259 - acc: 0.9429 - val_loss: 0.2124 - val_acc: 0.9000\n", - "Epoch 5/10\n", - "70/70 [==============================] - 0s 2ms/step - loss: 0.2061 - acc: 0.9429 - val_loss: 0.2691 - val_acc: 0.9000\n", - "Epoch 6/10\n", - "70/70 [==============================] - 0s 2ms/step - loss: 0.2200 - acc: 0.9286 - val_loss: 0.2344 - val_acc: 0.9000\n", - "Epoch 7/10\n", - "70/70 [==============================] - 0s 3ms/step - loss: 0.2133 - acc: 0.9286 - val_loss: 0.1973 - val_acc: 0.9000\n", - "Epoch 8/10\n", - "70/70 [==============================] - 0s 3ms/step - loss: 0.2062 - acc: 0.9429 - val_loss: 0.1893 - val_acc: 0.9000\n", - "Epoch 9/10\n", - "70/70 [==============================] - 0s 3ms/step - loss: 0.2060 - acc: 0.9571 - val_loss: 0.2719 - val_acc: 0.9000\n", - "Epoch 10/10\n", - "70/70 [==============================] - 0s 3ms/step - loss: 0.2021 - acc: 0.9571 - val_loss: 0.2293 - val_acc: 0.9000\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 55, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "model.compile(keras.optimizers.Adam(0.01),'sparse_categorical_crossentropy',['acc'])\n", - "model.fit(x=train_x_norm,y=train_labels,validation_data=[test_x_norm,test_labels],batch_size=1,epochs=10)" + "data": { + "text/plain": [ + "[]" ] + }, + "execution_count": 50, + "metadata": {}, + "output_type": "execute_result" }, { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Multi-Label Classification\n", - "\n", - "Sometime we have cases when our objects can belong to two classes at once. As an example, suppose we want to develop a classifier for cats and dogs on the picture, but we also want to allow cases when both cats and dogs are present.\n", - "\n", - "With multi-label classification, instead of one-hot encoded vector, we will have a vector that has 1 in position corresponding to all classes relevant to the input sample. Thus, output of the network should not have normalized probabilities for all classes, but rather for each class individually - which corresponds to using **sigmoid** activation function. Cross-entropy loss can still be used as a loss function.\n", - "\n", - "> **Note** that this is very similar to using **different neural networks** to do binary classification for each particular class - only the initial part of the network (up to final classification layer) is shared for all classes." + "data": { + "image/png": "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", + "text/plain": [ + "
" ] - }, + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(hist.history['acc'])\n", + "plt.plot(hist.history['val_acc'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Multi-Class Classification\n", + "\n", + "If you need to solve a problem of multi-class classification, your network would have more that one output - corresponding to the number of classes $C$. Each output will contain the probability of a given class.\n", + "\n", + "> Note that you can also use a network with two outputs to perform binary classification in the same manner. That is exactly what we will demonstrate now.\n", + "\n", + "When you expect a network to output a set of probabilities $p_1,\\dots, p_C$, we need all of them to add up to 1. To ensure this, we use `softmax` as a final activation function on the last layer. **Softmax** takes a vector input, and makes sure that all components of that vector are transformed into probabilities.\n", + "\n", + "Also, since the output of the network is a $C$-dimensional vector, we need labels to have the same form. This can be achieved by using **one-hot encoding**, when the number of a class $i$ is converted to a vector of zeroes, with 1 at the $i$-th position.\n", + "\n", + "To compare the probability output of the neural network with expected one-hot-encoded label, we use **cross-entropy loss** function. It takes two probability distributions, and outputs a value of how different they are.\n", + "\n", + "So, to summarize what we need to do for multi-class classification with $C$ classes:\n", + "* The network should have $C$ neurons in the last layer\n", + "* Last activation function should be **softmax**\n", + "* Loss should be **cross-entropy loss**\n", + "* Labels should be converted to **one-hot encoding** (this can be done using `numpy`, or using Keras utils `to_categorical`)" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": { - "id": "BmHNhUU8bqEX" - }, - "source": [ - "## Summary of Classification Loss Functions\n", - "\n", - "We have seen that binary, multi-class and multi-label classification differ by the type of loss function and activation function on the last layer of the network. It may all be a little bit confusing if you are just starting to learn, but here are a few rules to keep in mind:\n", - "* If the network has one output (**binary classification**), we use **sigmoid** activation function, for **multiclass classification** - **softmax**\n", - "* If the output class is represented as one-hot-encoding, the loss function will be **cross entropy loss** (categorical cross-entropy), if the output contains class number - **sparse categorical cross-entropy**. For **binary classification** - use **binary cross-entropy** (same as **log loss**)\n", - "* **Multi-label classification** is when we can have an object belonging to several classes at the same time. In this case, we need to encode labels using one-hot encoding, and use **sigmoid** as activation function, so that each class probability is between 0 and 1.\n", - "\n", - "| Classification | Label Format | Activation Function | Loss |\n", - "|---------------|-----------------------|-----------------|----------|\n", - "| Binary | Probability of 1st class | sigmoid | binary crossentropy |\n", - "| Binary | One-hot encoding (2 outputs) | softmax | categorical crossentropy |\n", - "| Multiclass | One-hot encoding | softmax | categorical crossentropy |\n", - "| Multiclass | Class Number | softmax | sparse categorical crossentropy |\n", - "| Multilabel | One-hot encoding | sigmoid | categorical crossentropy |\n" - ] - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 1/10\n", + "70/70 [==============================] - 1s 6ms/step - loss: 0.6524 - acc: 0.7000 - val_loss: 0.5936 - val_acc: 0.9000\n", + "Epoch 2/10\n", + "70/70 [==============================] - 0s 2ms/step - loss: 0.5715 - acc: 0.8286 - val_loss: 0.5255 - val_acc: 0.8333\n", + "Epoch 3/10\n", + "70/70 [==============================] - 0s 3ms/step - loss: 0.4820 - acc: 0.8714 - val_loss: 0.4213 - val_acc: 0.9000\n", + "Epoch 4/10\n", + "70/70 [==============================] - 0s 3ms/step - loss: 0.4426 - acc: 0.9000 - val_loss: 0.3694 - val_acc: 0.9333\n", + "Epoch 5/10\n", + "70/70 [==============================] - 0s 3ms/step - loss: 0.3602 - acc: 0.9000 - val_loss: 0.3454 - val_acc: 0.9000\n", + "Epoch 6/10\n", + "70/70 [==============================] - 0s 3ms/step - loss: 0.3209 - acc: 0.8857 - val_loss: 0.2862 - val_acc: 0.9333\n", + "Epoch 7/10\n", + "70/70 [==============================] - 0s 3ms/step - loss: 0.2905 - acc: 0.9286 - val_loss: 0.2787 - val_acc: 0.9000\n", + "Epoch 8/10\n", + "70/70 [==============================] - 0s 3ms/step - loss: 0.2698 - acc: 0.9000 - val_loss: 0.2381 - val_acc: 0.9333\n", + "Epoch 9/10\n", + "70/70 [==============================] - 0s 3ms/step - loss: 0.2639 - acc: 0.8857 - val_loss: 0.2217 - val_acc: 0.9667\n", + "Epoch 10/10\n", + "70/70 [==============================] - 0s 2ms/step - loss: 0.2592 - acc: 0.9286 - val_loss: 0.2391 - val_acc: 0.9000\n" + ] + } + ], + "source": [ + "model = keras.models.Sequential([\n", + " keras.layers.Dense(5,input_shape=(2,),activation='relu'),\n", + " keras.layers.Dense(2,activation='softmax')\n", + "])\n", + "model.compile(keras.optimizers.Adam(0.01),'categorical_crossentropy',['acc'])\n", + "\n", + "# Two ways to convert to one-hot encoding\n", + "train_labels_onehot = keras.utils.to_categorical(train_labels)\n", + "test_labels_onehot = np.eye(2)[test_labels]\n", + "\n", + "hist = model.fit(x=train_x_norm,y=train_labels_onehot,\n", + " validation_data=[test_x_norm,test_labels_onehot],batch_size=1,epochs=10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Sparse Categorical Cross-Entropy\n", + "\n", + "Often labels in multi-class classification are represented by class numbers. Keras also supports another kind of loss function called **sparse categorical crossentropy**, which expects class number to be integers, and not one-hot vectors. Using this kind of loss function, we can simplify our training code:" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [ { - "cell_type": "markdown", - "metadata": { - "id": "gZ-kWx84bMDH" - }, - "source": [ - "**Task**: \n", - "Use Keras to train a classifier for MNIST handwritten digits:\n", - "* Notice that Keras contains some standard datasets, including MNIST. To use MNIST from Keras, you only need a couple of lines of code (more information [here](https://www.tensorflow.org/api_docs/python/tf/keras/datasets/mnist))\n", - "* Try several network configuration, with different number of layers/neurons, activation functions.\n", - "\n", - "What is the best accuracy you were able to achieve?" - ] + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 1/10\n", + "70/70 [==============================] - 1s 6ms/step - loss: 0.2353 - acc: 0.9143 - val_loss: 0.2190 - val_acc: 0.9000\n", + "Epoch 2/10\n", + "70/70 [==============================] - 0s 3ms/step - loss: 0.2243 - acc: 0.9286 - val_loss: 0.1886 - val_acc: 0.9333\n", + "Epoch 3/10\n", + "70/70 [==============================] - 0s 2ms/step - loss: 0.2366 - acc: 0.9143 - val_loss: 0.2262 - val_acc: 0.9000\n", + "Epoch 4/10\n", + "70/70 [==============================] - 0s 2ms/step - loss: 0.2259 - acc: 0.9429 - val_loss: 0.2124 - val_acc: 0.9000\n", + "Epoch 5/10\n", + "70/70 [==============================] - 0s 2ms/step - loss: 0.2061 - acc: 0.9429 - val_loss: 0.2691 - val_acc: 0.9000\n", + "Epoch 6/10\n", + "70/70 [==============================] - 0s 2ms/step - loss: 0.2200 - acc: 0.9286 - val_loss: 0.2344 - val_acc: 0.9000\n", + "Epoch 7/10\n", + "70/70 [==============================] - 0s 3ms/step - loss: 0.2133 - acc: 0.9286 - val_loss: 0.1973 - val_acc: 0.9000\n", + "Epoch 8/10\n", + "70/70 [==============================] - 0s 3ms/step - loss: 0.2062 - acc: 0.9429 - val_loss: 0.1893 - val_acc: 0.9000\n", + "Epoch 9/10\n", + "70/70 [==============================] - 0s 3ms/step - loss: 0.2060 - acc: 0.9571 - val_loss: 0.2719 - val_acc: 0.9000\n", + "Epoch 10/10\n", + "70/70 [==============================] - 0s 3ms/step - loss: 0.2021 - acc: 0.9571 - val_loss: 0.2293 - val_acc: 0.9000\n" + ] }, { - "cell_type": "markdown", - "metadata": { - "id": "yX6hqiafwHl9" - }, - "source": [ - "## Takeaways\n", - "\n", - "* **Keras** is really recommended for beginners, because it allows to construct networks from layers quite easily, and then train it with just a couple of lines of code\n", - "* If non-standard architecture is needed, you would need to learn a bit deeper into Tensorflow. Or you can ask someone to implement custom logic as a Keras layer, and then use it in Keras models\n", - "* It is a good idea to look at PyTorch as well and compare approaches. \n", - "\n", - "A good sample notebook from the creator of Keras on Keras and Tensorflow 2.0 can be found [here](https://t.co/k694J95PI8)." + "data": { + "text/plain": [ + "" ] + }, + "execution_count": 55, + "metadata": {}, + "output_type": "execute_result" } - ], - "metadata": { - "celltoolbar": "Slideshow", - "colab": { - "collapsed_sections": [], - "name": "IntroKerasTF.ipynb", - "provenance": [] - }, - "interpreter": { - "hash": "0cb620c6d4b9f7a635928804c26cf22403d89d98d79684e4529119355ee6d5a5" - }, - "kernelspec": { - "display_name": "Python 3.8.12 64-bit (conda)", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.12" - }, - "livereveal": { - "start_slideshow_at": "selected" - } + ], + "source": [ + "model.compile(keras.optimizers.Adam(0.01),'sparse_categorical_crossentropy',['acc'])\n", + "model.fit(x=train_x_norm,y=train_labels,validation_data=[test_x_norm,test_labels],batch_size=1,epochs=10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Multi-Label Classification\n", + "\n", + "Sometime we have cases when our objects can belong to two classes at once. As an example, suppose we want to develop a classifier for cats and dogs on the picture, but we also want to allow cases when both cats and dogs are present.\n", + "\n", + "With multi-label classification, instead of one-hot encoded vector, we will have a vector that has 1 in position corresponding to all classes relevant to the input sample. Thus, output of the network should not have normalized probabilities for all classes, but rather for each class individually - which corresponds to using **sigmoid** activation function. Cross-entropy loss can still be used as a loss function.\n", + "\n", + "> **Note** that this is very similar to using **different neural networks** to do binary classification for each particular class - only the initial part of the network (up to final classification layer) is shared for all classes." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BmHNhUU8bqEX" + }, + "source": [ + "## Summary of Classification Loss Functions\n", + "\n", + "We have seen that binary, multi-class and multi-label classification differ by the type of loss function and activation function on the last layer of the network. It may all be a little bit confusing if you are just starting to learn, but here are a few rules to keep in mind:\n", + "* If the network has one output (**binary classification**), we use **sigmoid** activation function, for **multiclass classification** - **softmax**\n", + "* If the output class is represented as one-hot-encoding, the loss function will be **cross entropy loss** (categorical cross-entropy), if the output contains class number - **sparse categorical cross-entropy**. For **binary classification** - use **binary cross-entropy** (same as **log loss**)\n", + "* **Multi-label classification** is when we can have an object belonging to several classes at the same time. In this case, we need to encode labels using one-hot encoding, and use **sigmoid** as activation function, so that each class probability is between 0 and 1.\n", + "\n", + "| Classification | Label Format | Activation Function | Loss |\n", + "|---------------|-----------------------|-----------------|----------|\n", + "| Binary | Probability of 1st class | sigmoid | binary crossentropy |\n", + "| Binary | One-hot encoding (2 outputs) | softmax | categorical crossentropy |\n", + "| Multiclass | One-hot encoding | softmax | categorical crossentropy |\n", + "| Multiclass | Class Number | softmax | sparse categorical crossentropy |\n", + "| Multilabel | One-hot encoding | sigmoid | categorical crossentropy |\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "gZ-kWx84bMDH" + }, + "source": [ + "**Task**: \n", + "Use Keras to train a classifier for MNIST handwritten digits:\n", + "* Notice that Keras contains some standard datasets, including MNIST. To use MNIST from Keras, you only need a couple of lines of code (more information [here](https://www.tensorflow.org/api_docs/python/tf/keras/datasets/mnist))\n", + "* Try several network configuration, with different number of layers/neurons, activation functions.\n", + "\n", + "What is the best accuracy you were able to achieve?" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "yX6hqiafwHl9" + }, + "source": [ + "## Takeaways\n", + "\n", + "* **Keras** is really recommended for beginners, because it allows to construct networks from layers quite easily, and then train it with just a couple of lines of code\n", + "* If non-standard architecture is needed, you would need to learn a bit deeper into Tensorflow. Or you can ask someone to implement custom logic as a Keras layer, and then use it in Keras models\n", + "* It is a good idea to look at PyTorch as well and compare approaches. \n", + "\n", + "A good sample notebook from the creator of Keras on Keras and Tensorflow 2.0 can be found [here](https://t.co/k694J95PI8)." + ] + } + ], + "metadata": { + "celltoolbar": "Slideshow", + "colab": { + "collapsed_sections": [], + "name": "IntroKerasTF.ipynb", + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + }, + "livereveal": { + "start_slideshow_at": "selected" }, - "nbformat": 4, - "nbformat_minor": 0 + "vscode": { + "interpreter": { + "hash": "b0fa6594d8f4cbf19f97940f81e996739fb7646882a419484c72d19e05852a7e" + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 } From f02651105a5fcb04f6bef0aa85c1547c8651f200 Mon Sep 17 00:00:00 2001 From: semercim Date: Wed, 5 Oct 2022 10:26:19 +0200 Subject: [PATCH 28/38] WIP: the Turkish translation of lesson 5 --- .../translations/IntroKeras.tr.ipynb | 492 ++++++++++++++++++ 1 file changed, 492 insertions(+) create mode 100644 lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKeras.tr.ipynb diff --git a/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKeras.tr.ipynb b/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKeras.tr.ipynb new file mode 100644 index 00000000..235c5fd1 --- /dev/null +++ b/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKeras.tr.ipynb @@ -0,0 +1,492 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "En2vX4FuwHlu" + }, + "source": [ + "## Keras ile Sinir Ağlarına En Basit Giriş\n", + "\n", + "> Bu not defteri, [Yeni Başlayanlar için YZ Müfredatı](http://github.com/microsoft/ai-for-beginners)'nın bir parçasıdır. Eksiksiz öğrenme materyalleri kümesi için kod deposunu ziyaret edin.\n", + "\n", + "### Sinir Çerçeveleri\n", + "\n", + "Sinir ağlarını eğitmek için çeşitli çerçeveler vardır. Ancak, hızlı bir başlangıç yapmak ve işlerin içeride nasıl çalıştığına dair fazla ayrıntıya girmek istemiyorsanız [Keras](https://keras.io/) kullanmayı düşünmelisiniz. Bu kısa eğitim başlamanıza yardımcı olacak ve işlerin nasıl yürüdüğünü daha iyi anlamak istiyorsanız - [Tensorflow ve Keras'a Giriş](IntroKerasTF.tr.ipynb) not defterine bakın." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "8cACQoFMwHl3" + }, + "source": [ + "### İşleri hazırlamak\n", + "\n", + "Keras, Tensorflow 2.x çerçevesinin bir parçasıdır. Tensorflow'un 2.x.x sürümünün kurulu olduğundan emin olalım:\n", + "```\n", + "pip install tensorflow\n", + "```\n", + "veya\n", + "```\n", + "conda install tensorflow\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "xwqVx9-bwHl3", + "outputId": "2aa591b4-b647-441f-9c8e-4e0da2d517a0", + "tags": [] + }, + "outputs": [], + "source": [ + "import tensorflow as tf\n", + "from tensorflow import keras\n", + "import numpy as np\n", + "from sklearn.datasets import make_classification\n", + "import matplotlib.pyplot as plt\n", + "print(f'Tensorflow sürümü = {tf.__version__}')\n", + "print(f'Keras sürümü\" = {keras.__version__}')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6tp2xGV7wHl4" + }, + "source": [ + "## Temel Kavramlar: Tensör\n", + "\n", + "**Tensör** çok boyutlu bir dizidir. Farklı veri türlerini temsil etmek için tensör kullanmak çok uygundur:\n", + "* 400x400 - siyah beyaz resim\n", + "* 400x400x3 - renkli resim \n", + "* 16x400x400x3 - 16 adet renkli resimden minigrup\n", + "* 25x400x400x3 - 25 fps'lik videonun bir saniyesi\n", + "* 8x25x400x400x3 - 8 adet 1 saniyelik videodan minigrup\n", + "\n", + "Tensörler, sinir ağı içindeki ağırlıkların yanı sıra, girdi/çıktı verilerini temsil etmek için de bize uygun bir yol sağlar." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "A10prCPowHl7" + }, + "source": [ + "## Örnek Problem\n", + "\n", + "İkili sınıflandırma problemini ele alalım. Böyle bir soruna iyi bir örnek, boyutuna ve yaşına göre kötü ve iyi huylular arasında tümör sınıflandırması olabilir. Bazı örnek veriler oluşturarak başlayalım:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "j0OTPkGpwHl7" + }, + "outputs": [], + "source": [ + "np.random.seed(0) # tekrarlanabilirlik için tohumu seçin - rastgele varyasyonların etkilerini keşfetmek için değiştirin\n", + "\n", + "n = 100\n", + "X, Y = make_classification(n_samples = n, n_features=2,\n", + " n_redundant=0, n_informative=2, flip_y=0.05,class_sep=1.5)\n", + "X = X.astype(np.float32)\n", + "Y = Y.astype(np.int32)\n", + "\n", + "split = [ 70*n//100 ]\n", + "train_x, test_x = np.split(X, split)\n", + "train_labels, test_labels = np.split(Y, split)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "c-_BjSHPwHl8" + }, + "outputs": [], + "source": [ + "def plot_dataset(features, labels, W=None, b=None):\n", + " # çizimi hazırlamak\n", + " fig, ax = plt.subplots(1, 1)\n", + " ax.set_xlabel('$x_i[0]$ -- (öznitelik 1)')\n", + " ax.set_ylabel('$x_i[1]$ -- (öznitelik 2)')\n", + " colors = ['r' if l else 'b' for l in labels]\n", + " ax.scatter(features[:, 0], features[:, 1], marker='o', c=colors, s=100, alpha = 0.5)\n", + " if W is not None:\n", + " min_x = min(features[:,0])\n", + " max_x = max(features[:,1])\n", + " min_y = min(features[:,1])*(1-.1)\n", + " max_y = max(features[:,1])*(1+.1)\n", + " cx = np.array([min_x,max_x],dtype=np.float32)\n", + " cy = (0.5-W[0]*cx-b)/W[1]\n", + " ax.plot(cx,cy,'g')\n", + " ax.set_ylim(min_y,max_y)\n", + " fig.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 283 + }, + "id": "tq0vFchQwHl8", + "outputId": "9a5aa6a0-c92f-4d72-9e78-c0f615804bff" + }, + "outputs": [], + "source": [ + "%matplotlib inline\n", + "plot_dataset(train_x, train_labels)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Verileri Normalleştirme\n", + "\n", + "Eğitimden önce, girdi özniteliklerimizi [0,1] (veya [-1,1]) standart aralığına getirmek yaygındır. Bunun tam nedenlerini kursun ilerleyen kısımlarında tartışacağız, ancak kısaca nedeni şudur. Ağımız üzerinden akan değerlerin çok büyük veya çok küçük olmasını önlemek istiyoruz ve normalde tüm değerleri 0'a yakın küçük bir aralıktaki tutmada hemfikiriz. Böylece ağırlıkları küçük rastgele sayılarla ilkliyoruz ve sinyalleri aynı değer aralığında tutuyoruz.\n", + "\n", + "Verileri normalleştirirken en küçük değeri çıkarmamız ve aralığa bölmemiz gerekiyor. Eğitim verilerini kullanarak en küçük değeri ve değer aralığını hesaplıyoruz ve ardından eğitim kümesindeki aynı minimum/aralık değerlerini kullanarak test/geçerleme veri kümesini normalleştiriyoruz. Bunun nedeni, gerçek hayatta sadece eğitim kümesini bileceğiz ve ağın tahmin etmesi istenecek gelen tüm yeni değerleri değil. Bazen yeni değer [0,1] aralığının dışına çıkabilir, ancak bu çok önemli değildir." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "train_x_norm = (train_x-np.min(train_x,axis=0)) / (np.max(train_x,axis=0)-np.min(train_x,axis=0))\n", + "test_x_norm = (test_x-np.min(train_x,axis=0)) / (np.max(train_x,axis=0)-np.min(train_x,axis=0))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "SjPlpf2-wHl8" + }, + "source": [ + "## Tek Katmanlı Ağ Eğitimi (Algılayıcı)\n", + "\n", + "Çoğu durumda, bir sinir ağı bir dizi katman olacaktır. Keras'ta `Sequential` (dizili) model kullanılarak aşağıdaki şekilde tanımlanabilir:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "model = keras.models.Sequential()\n", + "model.add(keras.Input(shape=(2,)))\n", + "model.add(keras.layers.Dense(1))\n", + "model.add(keras.layers.Activation(keras.activations.sigmoid))\n", + "\n", + "model.summary()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Burada önce modeli oluşturuyoruz ve ardından ona katmanlar ekliyoruz:\n", + "* İlk `Input` (Girdi) katmanı (aslında katman diyemeyiz) ağın girdi boyutunun beyanını içerir.\n", + "* `Dense` (yoğun) katman, eğitilebilir ağırlıkları içeren gerçek algılayıcıdır.\n", + "* Son olarak, ağın sonucunu 0-1 aralığına getirmek (onu olasılık yapmak) için *sigmoid* `Activation` (etkinleştirme) işlevine sahip bir katman vardır.\n", + "\n", + "Girdi boyutu ve etkinleştirme işlevi, kısa olması için doğrudan `Dense` katmanında da belirtilebilir:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "model = keras.models.Sequential()\n", + "model.add(keras.layers.Dense(1,input_shape=(2,),activation='sigmoid'))\n", + "model.summary()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Modeli eğitmeden önce, onu **derlememiz** gerekir, bu da esasen şunu belirtmek anlamına gelir:\n", + "* **Kayıp fonksiyonu**, kaybın nasıl hesaplandığını tanımlar. İki sınıflı sınıflandırma problemimiz olduğu için *ikili çapraz entropi kaybı* kullanacağız.\n", + "* **Optimizer (eniyileyici)** kullanmak için. En basit seçenek, *rasgele gradyan inişi* için `sgd`'yi kullanmaktır veya `adam` gibi daha karmaşık eniyileyicileri kullanabilirsiniz.\n", + "* Eğitimimizin başarısını ölçmek için kullanmak istediğimiz **metrikler**. Sınıflandırma görevi olduğundan, iyi bir metrik `Accuracy` (doğruluk) (veya kısaca `acc`) olacaktır.\n", + "\n", + "Kaybı, metrikleri ve eniyileyiciyi dizgiler (string) olarak veya Keras çerçevesinden bazı nesneler sağlayarak belirtebiliriz. Örneğimizde, modelimizin öğrenme oranına ince ayar yapmak için `learning_rate` parametresini belirtmemiz gerekiyor ve bu nedenle Keras SGD eniyileyicisinin tam adını sağlıyoruz." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "model.compile(optimizer=keras.optimizers.SGD(learning_rate=0.2),loss='binary_crossentropy',metrics=['acc'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Modeli derledikten sonra `fit` metodunu çağırarak asıl eğitimi yapabiliriz. En önemli parametreler şunlardır:\n", + "* `x` ve `y` sırasıyla eğitim verilerini, öznitelikleri ve etiketleri belirtir.\n", + "* Her dönemde geçerlemenin yapılmasını istiyorsak, bir dizi özellik ve etiket olacak olan `validation_data` parametresini belirtebiliriz.\n", + "* `epochs`, dönemlerin sayısını belirtti.\n", + "* Eğitimin minigruplarda gerçekleşmesini istiyorsak, `batch_size` parametresini belirtebiliriz. Ayrıca verileri `x`/`y`/`validation_data`'ya aktarmadan önce manuel olarak önceden toplu işleyebilirsiniz; bu durumda `batch_size` gerekmez." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "model.fit(x=train_x_norm,y=train_labels,validation_data=(test_x_norm,test_labels),epochs=10,batch_size=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "s4_Atvn5K4K9" + }, + "source": [ + "Eğitimi nasıl etkilediklerini görmek için farklı eğitim parametreleriyle denemeler yapabilirsiniz:\n", + "* `batch_size` ayarının çok büyük olması (veya hiç belirtilmemesi) daha az kararlı eğitime neden olabilir, çünkü düşük boyutlu verilerle küçük toplu iş boyutları her bir özel durum için gradyanın daha kesin yönünü sağlar.\n", + "* Çok yüksek `learning_rate` (öğrenme oranı), aşırı öğrenme ile veya daha az kararlı sonuçlarla sonuçlanabilirken, çok düşük öğrenme oranı, sonuca ulaşmanın daha fazla dönem alacağı anlamına gelir.\n", + "\n", + "> Ağı daha fazla eğitmek için `fit` (oturt) işlevini arka arkaya birkaç kez çağırabileceğinizi unutmayın. Eğitime sıfırdan başlamak istiyorsanız - hücreyi model tanımıyla yeniden çalıştırmanız gerekir.\n", + "\n", + "Eğitimimizin işe yaradığından emin olmak için iki sınıfı ayıran çizgiyi çizelim. Ayırma çizgisi $W\\times x + b = 0.5$ denklemiyle tanımlanır." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 283 + }, + "id": "PgRTHttLwHl9", + "outputId": "e4407e1b-edf5-48e5-fdc2-da28120a3c6b" + }, + "outputs": [], + "source": [ + "plot_dataset(train_x,train_labels,model.layers[0].weights[0],model.layers[0].weights[1])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dvAiaj_JndyP" + }, + "source": [ + "## Eğitim grafiklerini çizme\n", + "\n", + "`fit` işlevi, sonuç olarak, her dönemdeki kaybı ve metrikleri gözlemlemek için kullanılabilen `history` (tarih) nesnesini döndürür. Aşağıdaki örnekte küçük bir öğrenme oranı ile eğitime yeniden başlayacağız ve kayıp ve doğruluğun nasıl davrandığını gözlemleyeceğiz.\n", + "\n", + "> `Sequential` modeli tanımlamak için biraz farklı sözdizimi kullandığımızı **unutmayın**. Katmanları tek tek eklemek (`add`) yerine, ilk etapta modeli oluştururken katmanların listesini de belirtebiliriz - bu biraz daha kısa sözdizimidir ve onu kullanmayı tercih edebilirsiniz." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "model = keras.models.Sequential([\n", + " keras.layers.Dense(1,input_shape=(2,),activation='sigmoid')])\n", + "model.compile(optimizer=keras.optimizers.SGD(learning_rate=0.05),loss='binary_crossentropy',metrics=['acc'])\n", + "hist = model.fit(x=train_x_norm,y=train_labels,validation_data=(test_x_norm,test_labels),epochs=10,batch_size=1)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "plt.plot(hist.history['acc'])\n", + "plt.plot(hist.history['val_acc'])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Çok Sınıflı Sınıflandırma\n", + "\n", + "Bir çok sınıflı sınıflandırma problemini çözmeniz gerekiyorsa, ağınızın birden fazla çıktısı olacaktır - ki $C$ sınıflarının sayısına karşılık gelir. Her çıktı belirli bir sınıfın olasılığını içerecektir.\n", + "\n", + "> Aynı şekilde ikili sınıflandırma gerçekleştirmek için iki çıktılı bir ağ da kullanabileceğinizi unutmayın. Şimdi tam olarak bunu göstereceğiz.\n", + "\n", + "Bir ağdan bir $p_1,\\dots, p_C$ olasılıkları kümesi çıktılamasını beklediğinizde, hepsinin toplamının 1'e eşit olmasına ihtiyacımız var. Bunu sağlamak için, son katmanda son etkinleştirme fonksiyonu olarak `softmax` kullanıyoruz. **Softmaks** bir vektör girdisi alır ve bu vektörün tüm bileşenlerinin olasılıklara dönüştürülmesini sağlar.\n", + "\n", + "Ayrıca, ağın çıktısı $C$ boyutlu bir vektör olduğundan, aynı forma sahip etiketlere ihtiyacımız var. Bu, $i$ sınıfının değeri, $i$. konumda 1 ile sıfırlardan oluşan bir vektöre dönüştürüldüğünde **bire bir kodlama** kullanılarak gerçekleştirilebilir.\n", + "\n", + "Sinir ağının olasılık çıktısını beklenen bire bir kodlanmış etiketle karşılaştırmak için **çapraz entropi kaybı** işlevini kullanırız. İki olasılık dağılımı alır ve ne kadar farklı olduklarının bir değerini verir.\n", + "\n", + "O halde $C$ sınıfı olan çok sınıflı sınıflandırma için yapmamız gerekenleri özetlemek gerekirse:\n", + "* Ağın son katmanında $C$ adet nöronları olmalıdır.\n", + "* Son etkinleştirme işlevi **softmaks** olmalıdır.\n", + "* Kayıp, **çapraz entropi kaybı** olmalıdır.\n", + "* Etiketler **bire bir kodlamaya** dönüştürülmelidir (bu, `numpy` kullanılarak veya Keras utils `to_categorical` kullanılarak yapılabilir)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "model = keras.models.Sequential([\n", + " keras.layers.Dense(5,input_shape=(2,),activation='relu'),\n", + " keras.layers.Dense(2,activation='softmax')\n", + "])\n", + "model.compile(keras.optimizers.Adam(0.01),'categorical_crossentropy',['acc'])\n", + "\n", + "# Bire bir kodlamaya dönüştürmenin iki yolu\n", + "train_labels_onehot = keras.utils.to_categorical(train_labels)\n", + "test_labels_onehot = np.eye(2)[test_labels]\n", + "\n", + "hist = model.fit(x=train_x_norm,y=train_labels_onehot,\n", + " validation_data=[test_x_norm,test_labels_onehot],batch_size=1,epochs=10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Seyrek Kategorik Çapraz Entropi\n", + "\n", + "Çok sınıflı sınıflandırmadaki etiketler genellikle sınıf numaralarıyla temsil edilir. Keras ayrıca, sınıf numarasının bire bir vektörler değil, tamsayılar olmasını bekleyen **seyrek kategorik çapraz entropi** adı verilen başka bir tür kayıp işlevini de destekler. Bu tür bir kayıp fonksiyonunu kullanarak eğitim kodumuzu basitleştirebiliriz:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "model.compile(keras.optimizers.Adam(0.01),'sparse_categorical_crossentropy',['acc'])\n", + "model.fit(x=train_x_norm,y=train_labels,validation_data=[test_x_norm,test_labels],batch_size=1,epochs=10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Çok Etiketli Sınıflandırma\n", + "\n", + "> **Note** that this is very similar to using **different neural networks** to do binary classification for each particular class - only the initial part of the network (up to final classification layer) is shared for all classes.\n", + "\n", + "Bazen nesnelerimizin aynı anda iki sınıfa ait olabileceği durumlar olur. Örnek olarak, resimdeki kediler ve köpekler için bir sınıflandırıcı geliştirmek istediğimizi, ancak hem kedilerin hem de köpeklerin bulunduğu durumlara da izin vermek istediğimizi varsayalım.\n", + "\n", + "Çok etiketli sınıflandırma ile, bire bir kodlanmış vektör yerine, girdi örneğiyle ilgili tüm sınıflara karşılık gelen 1 konumunda bir vektöre sahip olacağız. Bu nedenle, ağın çıktısı tüm sınıflar için normalleştirilmiş olasılıklara sahip olmamalı, bunun yerine her sınıf için ayrı ayrı olmalıdır - bu, **sigmoid** etkinleştirme fonksiyonunun kullanılmasına karşılık gelir. Çapraz entropi kaybı hala bir kayıp fonksiyonu olarak kullanılabilir.\n", + "\n", + "> Bunun her bir sınıf için ikili sınıflandırma yapmak için **farklı sinir ağları** kullanmaya çok benzer olduğuna **dikkat edin** - tüm sınıflar için ağın yalnızca ilk kısmı (son sınıflandırma katmanına kadar) paylaşılır." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BmHNhUU8bqEX" + }, + "source": [ + "## Sınıflandırma Kaybı Fonksiyonlarının Özeti\n", + "\n", + "Ağın son katmanındaki kayıp fonksiyonu ve etkinleştirme fonksiyonuna göre ikili, çok sınıflı ve çok etiketli sınıflandırmanın farklılık gösterdiğini gördük. Yeni öğrenmeye başlıyorsanız, biraz kafa karıştırıcı olabilir, ancak burada aklınızda bulundurmanız gereken birkaç kural vardır:\n", + "* Eğer ağda bir tane çıktılı (**ikili sınıflandırma**) varsa **sigmoid** etkinleştirme işlevini kullanırız, **çok sınıflı sınıflandırma** içinse **softmaks**.\n", + "* Çıktı sınıfı bire bir kodlama olarak temsil edilirse, kayıp işlevi **çapraz entropi kaybı** (kategorik çapraz entropi) eğer çıktı sınıf numarası içeriyorsa **seyrek kategorik çapraz entropi** olacaktır. **İkili sınıflandırma** için **ikili çapraz entropi** kullanın (**logaritmik kayıp** ile aynıdır).\n", + "* **Çok etiketli sınıflandırma**, aynı anda birkaç sınıfa ait bir nesneye sahip olabileceğimiz zamandır. Bu durumda, etiketleri bire bir kodlama kullanarak kodlamamız ve etkinleştirme fonksiyonu olarak **sigmoid** kullanmamız gerekir, böylece her sınıf olasılığı 0 ile 1 arasında olur.\n", + "\n", + "| Sınıflandırma | Etiket Formatı | Etkinleştirme Fonksiyonu | Kayıp |\n", + "|---------------|-----------------------|-----------------|----------|\n", + "| İkili | 1. sınıf olasılığı | sigmoid | ikili çapraz entropi |\n", + "| İkili | Bire bir kodlama (2 çıktılı) | softmax | kategorik çapraz entropi |\n", + "| Çok sınıflı | Bire bir kodlama | softmaks | kategorik çapraz entropi |\n", + "| Çok sınıflı | Sınıf sayısı | softmaks | seyrek kategorik çapraz entropi |\n", + "| Çok sınıflı | Bire bir kodlama | sigmoid | kategorik çapraz entropi |\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "gZ-kWx84bMDH" + }, + "source": [ + "**Görev**:\n", + "MNIST el yazısı rakamları için bir sınıflandırıcı eğitmede Keras'ı kullanın:\n", + "* Keras'ın MNIST dahil bazı standart veri kümeleri içerdiğine dikkat edin. MNIST'i Keras'tan kullanmak için yalnızca birkaç satır koda ihtiyacınız vardır (daha fazla bilgi [burada](https://www.tensorflow.org/api_docs/python/tf/keras/datasets/mnist)dır).\n", + "* Farklı sayıda katman/nöron, etkinleştirme işlevleriyle birkaç ağ yapılandırması deneyin.\n", + "\n", + "Ulaşabildiğiniz en iyi doğruluk nedir?" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "yX6hqiafwHl9" + }, + "source": [ + "## Ana Fikirler\n", + "\n", + "* **Keras**, yeni başlayanlar için gerçekten tavsiye edilir, çünkü katmanlardan ağları oldukça kolay bir şekilde oluşturmaya ve ardından sadece birkaç satır kodla eğitmeye olanak tanır.\n", + "* Standart olmayan bir mimari gerekiyorsa, Tensorflow'u biraz daha derinlemesine öğrenmeniz gerekir. Veya birinden özel mantığı bir Keras katmanı olarak uygulamasını isteyebilir ve ardından bunu Keras modellerinde kullanabilirsiniz.\n", + "* PyTorch'a da bakmak ve yaklaşımları karşılaştırmak iyi bir fikirdir.\n", + "\n", + "Keras üzerine Keras ve Tensorflow 2.0'nin yaratıcısından güzel bir örnek not defterini [burada](https://t.co/k694J95PI8) bulabilirsiniz." + ] + } + ], + "metadata": { + "celltoolbar": "Slideshow", + "colab": { + "collapsed_sections": [], + "name": "IntroKerasTF.ipynb", + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3.10.7 64-bit", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.7" + }, + "livereveal": { + "start_slideshow_at": "selected" + }, + "vscode": { + "interpreter": { + "hash": "b0fa6594d8f4cbf19f97940f81e996739fb7646882a419484c72d19e05852a7e" + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} From bbb24f99a48c853399c9ee86f71f21230cad54b4 Mon Sep 17 00:00:00 2001 From: semercim Date: Mon, 31 Oct 2022 23:08:35 +0100 Subject: [PATCH 29/38] WIP: the Turkish translation of lesson 5 --- .../05-Frameworks/translations/IntroKeras.tr.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKeras.tr.ipynb b/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKeras.tr.ipynb index 235c5fd1..4bf087b7 100644 --- a/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKeras.tr.ipynb +++ b/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKeras.tr.ipynb @@ -462,7 +462,7 @@ "provenance": [] }, "kernelspec": { - "display_name": "Python 3.10.7 64-bit", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -476,7 +476,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.7" + "version": "3.10.8" }, "livereveal": { "start_slideshow_at": "selected" From c8be3e6bc8e685183b619aec04ad43802281edd3 Mon Sep 17 00:00:00 2001 From: semercim Date: Mon, 31 Oct 2022 23:09:05 +0100 Subject: [PATCH 30/38] WIP: the Turkish translation of lesson 5 --- .../translations/IntroKerasTF.tr.ipynb | 1014 +++++++++++++++++ 1 file changed, 1014 insertions(+) create mode 100644 lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKerasTF.tr.ipynb diff --git a/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKerasTF.tr.ipynb b/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKerasTF.tr.ipynb new file mode 100644 index 00000000..e338a859 --- /dev/null +++ b/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKerasTF.tr.ipynb @@ -0,0 +1,1014 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "En2vX4FuwHlu" + }, + "source": [ + "## Tensorflow ve Keras'a Giriş\n", + "\n", + "> Bu not defteri, [Yeni Başlayanlar İçin YZ Müfredatı](http://github.com/microsoft/ai-for-beginners)'nın bir parçasıdır. Eksiksiz öğrenme materyalleri kümesi için kod deposunu ziyaret edin.\n", + "\n", + "### Sinirsel Çerçeveler\n", + "\n", + "Sinir ağlarını eğitmek için şunlara ihtiyacınız olduğunu öğrendik:\n", + "* Matrisleri hızla çarpmalısınız (tensörler).\n", + "* Gradyan inişi optimizasyonunu gerçekleştirmek için gradyanları hesaplamalısınız.\n", + "\n", + "Sinir ağı çerçevelerinin yapmanıza izin verdikleri şunlardır:\n", + "* Kullanılabilir herhangi bir hesaplamada, CPU veya GPU'da ve hatta TPU'da tensörlerle çalışırsınız.\n", + "* Gradyanları otomatik olarak hesaplarsınız (tüm yerleşik tensör işlevleri için açıkça programlanmıştır).\n", + "\n", + "İsteğe bağlı olarak:\n", + "* Sinir Ağı kurucusu / daha üst seviye APIler (ağı bir dizi katman olarak tanımlayın).\n", + "* Basit eğitim işlevleri (Scikit Learn'de olduğu gibi `fit`)\n", + "* Gradyan inişine ek olarak bir dizi optimizasyon (eniyileme) algoritması.\n", + "* Veri işleme soyutlamaları (bu ideal olarak GPU'da da çalışacaktır)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "8cACQoFMwHl3" + }, + "source": [ + "### En Popüler Çerçeveler\n", + "\n", + "* Tensorflow 1.x - yaygın olarak kullanılabilen ilk çerçevedir (Google). Statik hesaplama çizgesini tanımlamaya, GPU'ya göndermeye ve açıkça değerlendirmeye izin verir.\n", + "* PyTorch - Facebook'tan popülaritesi artan bir çerçevedir.\n", + "* Keras - sinir ağlarını kullanarak birleştirmek ve basitleştirmek için Tensorflow/PyTorch'un üstünde daha üst seviye API'dir (Francois Chollet).\n", + "* Tensorflow 2.x + Keras - **dinamik hesaplama çizgesini** destekleyen ve numpy'ya (ve PyTorch'a) çok benzer tensör işlemlerini gerçekleştirmeye olanak tanıyan tümleşik Keras işlevselliğine sahip Tensorflow'un yeni sürümüdür.\n", + "\n", + "Tensorflow 2.x ve Keras'ı ele alacağız. Tensorflow'un 2.x.x sürümünün kurulu olduğundan emin olun:\n", + "```\n", + "pip install tensorflow\n", + "```\n", + "veya\n", + "```\n", + "conda install tensorflow\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "xwqVx9-bwHl3", + "outputId": "2aa591b4-b647-441f-9c8e-4e0da2d517a0", + "tags": [] + }, + "outputs": [], + "source": [ + "import tensorflow as tf\n", + "import numpy as np\n", + "print(tf.__version__)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6tp2xGV7wHl4" + }, + "source": [ + "## Temel Kavramlar: Tensör\n", + "\n", + "**Tensör** çok boyutlu bir dizilimdir. Farklı veri türlerini temsil etmek için tensörleri kullanmak çok uygundur:\n", + "* 400x400 - siyah beyaz resim\n", + "* 400x400x3 - renkli resim\n", + "* 16x400x400x3 - 16 renkli resimden oluşan minigrup\n", + "* 25x400x400x3 - 25 fps'lik videonun bir saniyesi\n", + "* 8x25x400x400x3 - 8 adet 1 saniyelik videodan oluşan minigrup" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "qG2bsaR7wHl4" + }, + "source": [ + "### Simple Tensors\n", + "\n", + "You can easily create simple tensors from lists of np-arrays, or generate random ones:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ybpnk08HwHl4", + "outputId": "fad9ed4a-df82-44a0-84ea-324bc71ea46f" + }, + "outputs": [], + "source": [ + "a = tf.constant([[1,2],[3,4]])\n", + "print(a)\n", + "a = tf.random.normal(shape=(10,3))\n", + "print(a)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "AXFMsV3r09Ux" + }, + "source": [ + "You can use arithmetic operations on tensors, which are performed element-wise, as in numpy. Tensors are automatically expanded to required dimension, if needed. To extract numpy-array from tensor, use `.numpy()`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "e5Nu5Xgj1DnQ", + "outputId": "0dfc8758-4ffd-4968-c7bf-6ba8d435df2e" + }, + "outputs": [], + "source": [ + "print(a-a[0])\n", + "print(tf.exp(a)[0].numpy())" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "uQ5zN6cVyrG7" + }, + "source": [ + "## Variables\n", + "\n", + "Variables are useful to represent tensor values that can be modified using `assign` and `assign_add`. They are often used to represent neural network weights.\n", + "\n", + "As an example, here is a silly way to get a sum of all rows of tensor `a`:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "7pu0UZ-_yqfB", + "outputId": "6708c83e-02e6-4442-8757-45918eb1fbc2" + }, + "outputs": [], + "source": [ + "s = tf.Variable(tf.zeros_like(a[0]))\n", + "for i in a:\n", + " s.assign_add(i)\n", + "\n", + "print(s)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "rIh1EHcezlNo" + }, + "source": [ + "Much better way to do it:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "aQIdWZ1kzn6P", + "outputId": "1c123d9a-ecd2-4f2e-828e-5ade85ac8f63" + }, + "outputs": [], + "source": [ + "tf.reduce_sum(a,axis=0)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "U-auwezDwHl6" + }, + "source": [ + "## Computing Gradients\n", + "\n", + "For back propagation, you need to compute gradients. This is done using `tf.GradientTape()` idiom:\n", + " * Add `with tf.GradientTape` block around our computations\n", + " * Mark those tensors with respect to which we need to compute gradients by calling `tape.watch` (all variables are watched automatically)\n", + " * Compute whatever we need (build computational graph)\n", + " * Obtain gradients using `tape.gradient` " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "m8vFOXr7wHl6", + "outputId": "860ac72e-50c7-4ff2-f258-747f27194f90" + }, + "outputs": [], + "source": [ + "a = tf.random.normal(shape=(2, 2))\n", + "b = tf.random.normal(shape=(2, 2))\n", + "\n", + "with tf.GradientTape() as tape:\n", + " tape.watch(a) # Start recording the history of operations applied to `a`\n", + " c = tf.sqrt(tf.square(a) + tf.square(b)) # Do some math using `a`\n", + " # What's the gradient of `c` with respect to `a`?\n", + " dc_da = tape.gradient(c, a)\n", + " print(dc_da)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "8sfjBMBu59B5" + }, + "source": [ + "## Example 1: Linear Regression\n", + "\n", + "Now we know enough to solve the classical problem of **Linear regression**. Let's generate small synthetic dataset:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "j723455WwHl7" + }, + "outputs": [], + "source": [ + "import matplotlib.pyplot as plt\n", + "from sklearn.datasets import make_classification, make_regression\n", + "from sklearn.model_selection import train_test_split\n", + "import random" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 282 + }, + "id": "WJNK_J6v6I-Z", + "outputId": "eb4a66a6-6b9a-4c8a-bc24-d81eeb2d3f27" + }, + "outputs": [], + "source": [ + "np.random.seed(13) # pick the seed for reproducability - change it to explore the effects of random variations\n", + "\n", + "train_x = np.linspace(0, 3, 120)\n", + "train_labels = 2 * train_x + 0.9 + np.random.randn(*train_x.shape) * 0.5\n", + "\n", + "plt.scatter(train_x,train_labels)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Ng4rZmGc6oxk" + }, + "source": [ + "Linear regression is defined by a straight line $f_{W,b}(x) = Wx+b$, where $W, b$ are model parameters that we need to find. An error on our dataset $\\{x_i,y_u\\}_{i=1}^N$ (also called **loss function**) can be defined as mean square error:\n", + "$$\n", + "\\mathcal{L}(W,b) = {1\\over N}\\sum_{i=1}^N (f_{W,b}(x_i)-y_i)^2\n", + "$$\n", + "\n", + "Let's define our model and loss function:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "QxhI4GlB6aiH" + }, + "outputs": [], + "source": [ + "input_dim = 1\n", + "output_dim = 1\n", + "learning_rate = 0.1\n", + "\n", + "# This is our weight matrix\n", + "w = tf.Variable([[100.0]])\n", + "# This is our bias vector\n", + "b = tf.Variable(tf.zeros(shape=(output_dim,)))\n", + "\n", + "def f(x):\n", + " return tf.matmul(x,w) + b\n", + "\n", + "def compute_loss(labels, predictions):\n", + " return tf.reduce_mean(tf.square(labels - predictions))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "JUxwj3367gD2" + }, + "source": [ + "We will train the model on a series of minibatches. We will use gradient descent, adjusting model parameters using the following formulae:\n", + "$$\n", + "\\begin{array}{l}\n", + "W^{(n+1)}=W^{(n)}-\\eta\\frac{\\partial\\mathcal{L}}{\\partial W} \\\\\n", + "b^{(n+1)}=b^{(n)}-\\eta\\frac{\\partial\\mathcal{L}}{\\partial b} \\\\\n", + "\\end{array}\n", + "$$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "-991PErM7fJU" + }, + "outputs": [], + "source": [ + "def train_on_batch(x, y):\n", + " with tf.GradientTape() as tape:\n", + " predictions = f(x)\n", + " loss = compute_loss(y, predictions)\n", + " # Note that `tape.gradient` works with a list as well (w, b).\n", + " dloss_dw, dloss_db = tape.gradient(loss, [w, b])\n", + " w.assign_sub(learning_rate * dloss_dw)\n", + " b.assign_sub(learning_rate * dloss_db)\n", + " return loss" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "idr2VEWb9rr0" + }, + "source": [ + "Let's do the training. We will do several passes through the dataset (so-called **epochs**), divide it into minibatches and call the function defined above:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "nOuu0qpx-wAp" + }, + "outputs": [], + "source": [ + "# Shuffle the data.\n", + "indices = np.random.permutation(len(train_x))\n", + "features = tf.constant(train_x[indices],dtype=tf.float32)\n", + "labels = tf.constant(train_labels[indices],dtype=tf.float32)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "3zdIf6c_85Ht", + "outputId": "43b04684-8b90-4c65-d5ff-20ebac61c73c" + }, + "outputs": [], + "source": [ + "batch_size = 4\n", + "for epoch in range(10):\n", + " for i in range(0,len(features),batch_size):\n", + " loss = train_on_batch(tf.reshape(features[i:i+batch_size],(-1,1)),tf.reshape(labels[i:i+batch_size],(-1,1)))\n", + " print('Epoch %d: last batch loss = %.4f' % (epoch, float(loss)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We now have obtained optimized parameters $W$ and $b$. Note that their values are similar to the original values used when generating the dataset ($W=2, b=1$)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "US6q0nCBD-LL", + "outputId": "65a79620-a3eb-445b-aafb-60a60575ab0e" + }, + "outputs": [], + "source": [ + "w,b" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 282 + }, + "id": "_e6xRMZFDnyI", + "outputId": "d202b7fe-4383-4d82-b98e-a20f3180093e" + }, + "outputs": [], + "source": [ + "plt.scatter(train_x,train_labels)\n", + "x = np.array([min(train_x),max(train_x)])\n", + "y = w.numpy()[0,0]*x+b.numpy()[0]\n", + "plt.plot(x,y,color='red')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0giuwC9GHzi8" + }, + "source": [ + "## Computational Graph and GPU Computations\n", + "\n", + "Whenever we compute tensor expression, Tensorflow builds a computational graph that can be computed on the available computing device, e.g. CPU or GPU. Since we were using arbitrary Python function in our code, they cannot be included as part of computational graph, and thus when running our code on GPU we would need to pass the data between CPU and GPU back and forth, and compute custom function on CPU.\n", + "\n", + "Tensorflow allows us to mark our Python function using `@tf.function` decorator, which will make this function a part of the same computational graph. This decorator can be applied to functions that use standard Tensorflow tensor operations. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "HK7HPLz3Hyrl" + }, + "outputs": [], + "source": [ + "@tf.function\n", + "def train_on_batch(x, y):\n", + " with tf.GradientTape() as tape:\n", + " predictions = f(x)\n", + " loss = compute_loss(y, predictions)\n", + " # Note that `tape.gradient` works with a list as well (w, b).\n", + " dloss_dw, dloss_db = tape.gradient(loss, [w, b])\n", + " w.assign_sub(learning_rate * dloss_dw)\n", + " b.assign_sub(learning_rate * dloss_db)\n", + " return loss" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "J7HusxWkGjLX" + }, + "source": [ + "The code has not changed, but if you were running this code on GPU and on larger dataset - you would have noticed the difference in speed. \n", + "\n", + "## Dataset API\n", + "\n", + "Tensorflow contains a convenient API to work with data. Let's try to use it. We will also train our model from scratch." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "oYro9Lbr8q0M", + "outputId": "78c0a6de-71bd-4eef-8819-439495b28672" + }, + "outputs": [], + "source": [ + "w.assign([[10.0]])\n", + "b.assign([0.0])\n", + "\n", + "# Create a tf.data.Dataset object for easy batched iteration\n", + "dataset = tf.data.Dataset.from_tensor_slices((train_x.astype(np.float32), train_labels.astype(np.float32)))\n", + "dataset = dataset.shuffle(buffer_size=1024).batch(256)\n", + "\n", + "for epoch in range(10):\n", + " for step, (x, y) in enumerate(dataset):\n", + " loss = train_on_batch(tf.reshape(x,(-1,1)), tf.reshape(y,(-1,1)))\n", + " print('Epoch %d: last batch loss = %.4f' % (epoch, float(loss)))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "A10prCPowHl7" + }, + "source": [ + "## Example 2: Classification\n", + "\n", + "Now we will consider binary classification problem. A good example of such a problem would be a tumour classification between malignant and benign based on it's size and age.\n", + "\n", + "The core model is similar to regression, but we need to use different loss function. Let's start by generating sample data:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "j0OTPkGpwHl7", + "scrolled": false + }, + "outputs": [], + "source": [ + "np.random.seed(0) # pick the seed for reproducibility - change it to explore the effects of random variations\n", + "\n", + "n = 100\n", + "X, Y = make_classification(n_samples = n, n_features=2,\n", + " n_redundant=0, n_informative=2, flip_y=0.05,class_sep=1.5)\n", + "X = X.astype(np.float32)\n", + "Y = Y.astype(np.int32)\n", + "\n", + "split = [ 70*n//100, (15+70)*n//100 ]\n", + "train_x, valid_x, test_x = np.split(X, split)\n", + "train_labels, valid_labels, test_labels = np.split(Y, split)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "c-_BjSHPwHl8", + "scrolled": false + }, + "outputs": [], + "source": [ + "def plot_dataset(features, labels, W=None, b=None):\n", + " # prepare the plot\n", + " fig, ax = plt.subplots(1, 1)\n", + " ax.set_xlabel('$x_i[0]$ -- (feature 1)')\n", + " ax.set_ylabel('$x_i[1]$ -- (feature 2)')\n", + " colors = ['r' if l else 'b' for l in labels]\n", + " ax.scatter(features[:, 0], features[:, 1], marker='o', c=colors, s=100, alpha = 0.5)\n", + " if W is not None:\n", + " min_x = min(features[:,0])\n", + " max_x = max(features[:,1])\n", + " min_y = min(features[:,1])*(1-.1)\n", + " max_y = max(features[:,1])*(1+.1)\n", + " cx = np.array([min_x,max_x],dtype=np.float32)\n", + " cy = (0.5-W[0]*cx-b)/W[1]\n", + " ax.plot(cx,cy,'g')\n", + " ax.set_ylim(min_y,max_y)\n", + " fig.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 283 + }, + "id": "tq0vFchQwHl8", + "outputId": "9a5aa6a0-c92f-4d72-9e78-c0f615804bff", + "scrolled": false + }, + "outputs": [], + "source": [ + "plot_dataset(train_x, train_labels)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Normalizing Data\n", + "\n", + "Before training, it is common to bring our input features to the standard range of [0,1] (or [-1,1]). The exact reasons for that we will discuss later in the course, but in short the reason is the following. We want to avoid values that flow through our network getting too big or too small, and we normally agree to keep all values in the small range close to 0. Thus we initialize the weights with small random numbers, and we keep signals in the same range.\n", + "\n", + "When normalizing data, we need to subtract min value and divide by range. We compute min value and range using training data, and then normalize test/validation dataset using the same min/range values from the training set. This is because in real life we will only know the training set, and not all incoming new values that the network would be asked to predict. Occasionally, the new value may fall out of the [0,1] range, but that's not crucial. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "train_x_norm = (train_x-np.min(train_x)) / (np.max(train_x)-np.min(train_x))\n", + "valid_x_norm = (valid_x-np.min(train_x)) / (np.max(train_x)-np.min(train_x))\n", + "test_x_norm = (test_x-np.min(train_x)) / (np.max(train_x)-np.min(train_x))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "SjPlpf2-wHl8" + }, + "source": [ + "## Training One-Layer Perceptron\n", + "\n", + "Let's use Tensorflow gradient computing machinery to train one-layer perceptron.\n", + "\n", + "Our neural network will have 2 inputs and 1 output. The weight matrix $W$ will have size $2\\times1$, and bias vector $b$ -- $1$.\n", + "\n", + "Core model will be the same as in previous example, but loss function will be a logistic loss. To apply logistic loss, we need to get the value of **probability** as the output of our network, i.e. we need to bring the output $z$ to the range [0,1] using `sigmoid` activation function: $p=\\sigma(z)$.\n", + "\n", + "If we get the probability $p_i$ for the i-th input value corresponding to the actual class $y_i\\in\\{0,1\\}$, we compute the loss as $\\mathcal{L_i}=-(y_i\\log p_i + (1-y_i)log(1-p_i))$. \n", + "\n", + "In Tensorflow, both those steps (applying sigmoid and then logistic loss) can be done using one call to `sigmoid_cross_entropy_with_logits` function. Since we are training our network in minibatches, we need to average out the loss across all elements of a minibatch using `reduce_mean`: " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "id": "kdDxWeCqwHl8" + }, + "outputs": [], + "source": [ + "W = tf.Variable(tf.random.normal(shape=(2,1)),dtype=tf.float32)\n", + "b = tf.Variable(tf.zeros(shape=(1,),dtype=tf.float32))\n", + "\n", + "learning_rate = 0.1\n", + "\n", + "@tf.function\n", + "def train_on_batch(x, y):\n", + " with tf.GradientTape() as tape:\n", + " z = tf.matmul(x, W) + b\n", + " loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(labels=y,logits=z))\n", + " dloss_dw, dloss_db = tape.gradient(loss, [W, b])\n", + " W.assign_sub(learning_rate * dloss_dw)\n", + " b.assign_sub(learning_rate * dloss_db)\n", + " return loss" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "zAAgw0h6KzUd" + }, + "source": [ + "We will use minibatches of 16 elements, and do a few epochs of training:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "PfyqjVb2wHl8", + "outputId": "308850b8-fe17-4cda-ac27-8bcda210f113" + }, + "outputs": [], + "source": [ + "# Create a tf.data.Dataset object for easy batched iteration\n", + "dataset = tf.data.Dataset.from_tensor_slices((train_x_norm.astype(np.float32), train_labels.astype(np.float32)))\n", + "dataset = dataset.shuffle(128).batch(2)\n", + "\n", + "for epoch in range(10):\n", + " for step, (x, y) in enumerate(dataset):\n", + " loss = train_on_batch(x, tf.expand_dims(y,1))\n", + " print('Epoch %d: last batch loss = %.4f' % (epoch, float(loss)))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "s4_Atvn5K4K9" + }, + "source": [ + "To make sure our training worked, let's plot the line that separates two classes. Separation line is defined by the equation $W\\times x + b = 0.5$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 283 + }, + "id": "PgRTHttLwHl9", + "outputId": "e4407e1b-edf5-48e5-fdc2-da28120a3c6b" + }, + "outputs": [], + "source": [ + "plot_dataset(train_x,train_labels,W.numpy(),b.numpy())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's see how our model behaves on the validation data." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 282 + }, + "id": "oEQswfCGrmHw", + "outputId": "3cf61882-60e1-4baa-8e51-0c31ea80875c" + }, + "outputs": [], + "source": [ + "pred = tf.matmul(test_x,W)+b\n", + "fig,ax = plt.subplots(1,2)\n", + "ax[0].scatter(test_x[:,0],test_x[:,1],c=pred[:,0]>0.5)\n", + "ax[1].scatter(test_x[:,0],test_x[:,1],c=valid_labels)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To compute the accuracy on the validation data, we can cast boolean type to float, and compute the mean:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "HUjdeIefsIsg", + "outputId": "f267f505-8ba4-43ef-9ebe-df124c3c05a1" + }, + "outputs": [], + "source": [ + "tf.reduce_mean(tf.cast(((pred[0]>0.5)==test_labels),tf.float32))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's explain what goes on here:\n", + "* `pred` is the values predicted by the network. They are not quite probabilities, because we have not used an activation function, but values greater than 0.5 correspond to class 1, and smaller - to class 0.\n", + "* `pred[0]>0.5` creates a boolean tensor of results, where `True` corresponds to class 1, and `False` - to class 0\n", + "* We compare that tensor to expected labels `valid_labels`, getting the boolean vector or correct predictions, where `True` corresponds to the correct prediction, and `False` - to incorrect one.\n", + "* We convert that tensor to floating point using `tf.cast`\n", + "* We then compute the mean value using `tf.reduce_mean` - that is exactly our desired accuracy " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "_95qF9lY2kHp" + }, + "source": [ + "## Using TensorFlow/Keras Optimizers\n", + "\n", + "Tensorflow is closely integrated with Keras, which contains a lot of useful functionality. For example, we can use different **optimization algorithms**. Let's do that, and also print obtained accuracy during training." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ups7nlV22ofp", + "outputId": "aa4dff06-82b9-4b2f-ca00-33970ea2b989" + }, + "outputs": [], + "source": [ + "optimizer = tf.keras.optimizers.Adam(0.01)\n", + "\n", + "W = tf.Variable(tf.random.normal(shape=(2,1)))\n", + "b = tf.Variable(tf.zeros(shape=(1,),dtype=tf.float32))\n", + "\n", + "@tf.function\n", + "def train_on_batch(x, y):\n", + " vars = [W, b]\n", + " with tf.GradientTape() as tape:\n", + " z = tf.sigmoid(tf.matmul(x, W) + b)\n", + " loss = tf.reduce_mean(tf.keras.losses.binary_crossentropy(z,y))\n", + " correct_prediction = tf.equal(tf.round(y), tf.round(z))\n", + " acc = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))\n", + " grads = tape.gradient(loss, vars)\n", + " optimizer.apply_gradients(zip(grads,vars))\n", + " return loss,acc\n", + "\n", + "for epoch in range(20):\n", + " for step, (x, y) in enumerate(dataset):\n", + " loss,acc = train_on_batch(tf.reshape(x,(-1,2)), tf.reshape(y,(-1,1)))\n", + " print('Epoch %d: last batch loss = %.4f, acc = %.4f' % (epoch, float(loss),acc))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dvAiaj_JndyP" + }, + "source": [ + "**Task 1**: Plot the graphs of loss function and accuracy on training and validation data during training\n", + "\n", + "**Task 2**: Try to solve MNIST classificiation problem using this code. Hint: use `softmax_crossentropy_with_logits` or `sparse_softmax_cross_entropy_with_logits` as loss function. In the first case you need to feed expected output values in *one hot encoding*, and in the second case - as integer class number." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "995iCprDrgYQ" + }, + "source": [ + "## Keras\n", + "### Deep Learning for Humans\n", + "\n", + "* Keras is a library originally developed by Francois Chollet to work on top of Tensorflow, CNTK and Theano, to unify all lower-level frameworks. You can still install Keras as a separate library, but it is not advised to do so. \n", + "* Now Keras is included as part of Tensorflow library\n", + "* You can easily construct neural networks from layers\n", + "* Contains `fit` function to do all training, plus a lot of functions to work with typical data (pictures, text, etc.)\n", + "* A lot of samples\n", + "* Functional API vs. Sequential API\n", + "\n", + "Keras provides higher level abstractions for neural networks, allowing us to operate in terms of layers, models and optimizers, and not in terms of tensors and gradients. \n", + "\n", + "Classical Deep Learning book from the creator of Keras: [Deep Learning with Python](https://www.manning.com/books/deep-learning-with-python)\n", + "\n", + "### Functional API\n", + "\n", + "When using functional API, we define the **input** to the network as `keras.Input`, and then compute the **output** by passing it through a series of computations. Finally, we define **model** as an object that transforms input into output.\n", + "\n", + "Once we obtained **model** object, we need to:\n", + "* **Compile it**, by specifying loss function and the optimizer that we want to use with our model\n", + "* **Train it** by calling `fit` function with the training (and possibly validation) data" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "QJWplVfy34Eo", + "outputId": "9be976f2-4f9a-495c-bddc-a7f9ec30989a" + }, + "outputs": [], + "source": [ + "inputs = tf.keras.Input(shape=(2,))\n", + "z = tf.keras.layers.Dense(1,kernel_initializer='glorot_uniform',activation='sigmoid')(inputs)\n", + "model = tf.keras.models.Model(inputs,z)\n", + "\n", + "model.compile(tf.keras.optimizers.Adam(0.1),'binary_crossentropy',['accuracy'])\n", + "model.summary()\n", + "h = model.fit(train_x_norm,train_labels,batch_size=8,epochs=15)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 282 + }, + "id": "K2Kf60IrZcqs", + "outputId": "b60b868d-3562-4715-f5d5-1f9764e45f09" + }, + "outputs": [], + "source": [ + "plt.plot(h.history['accuracy'])" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "iJruFXmb_dur" + }, + "source": [ + "### Sequential API\n", + "\n", + "Alternatively, we can start thinking of a model as of a **sequence of layers**, and just specify those layers by adding them to the `model` object:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "iWc_kSr8_YXt", + "outputId": "345dbe65-629d-468f-ed75-1d412c966340" + }, + "outputs": [], + "source": [ + "model = tf.keras.models.Sequential()\n", + "model.add(tf.keras.layers.Dense(5,activation='sigmoid',input_shape=(2,)))\n", + "model.add(tf.keras.layers.Dense(1,activation='sigmoid'))\n", + "\n", + "model.compile(tf.keras.optimizers.Adam(0.1),'binary_crossentropy',['accuracy'])\n", + "model.summary()\n", + "model.fit(train_x_norm,train_labels,validation_data=(test_x_norm,test_labels),batch_size=8,epochs=15)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "BmHNhUU8bqEX" + }, + "source": [ + "## Classification Loss Functions\n", + "\n", + "It is important to correctly specify loss function and activation function on the last layer of the network. The main rules are the following:\n", + "* If the network has one output (**binary classification**), we use **sigmoid** activation function, for **multiclass classification** - **softmax**\n", + "* If the output class is represented as one-hot-encoding, the loss function will be **cross entropy loss** (categorical cross-entropy), if the output contains class number - **sparse categorical cross-entropy**. For **binary classification** - use **binary cross-entropy** (same as **log loss**)\n", + "* **Multi-label classification** is when we can have an object belonging to several classes at the same time. In this case, we need to encode labels using one-hot encoding, and use **sigmoid** as activation function, so that each class probability is between 0 and 1.\n", + "\n", + "| Classification | Label Format | Activation Function | Loss |\n", + "|---------------|-----------------------|-----------------|----------|\n", + "| Binary | Probability of 1st class | sigmoid | binary crossentropy |\n", + "| Binary | One-hot encoding (2 outputs) | softmax | categorical crossentropy |\n", + "| Multiclass | One-hot encoding | softmax | categorical crossentropy |\n", + "| Multiclass | Class Number | softmax | sparse categorical crossentropy |\n", + "| Multilabel | One-hot encoding | sigmoid | categorical crossentropy |\n", + "\n", + "> Binary classification can also be handled as a special case of multi-class classification with two outputs. In this case, we need to use **softmax**.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "gZ-kWx84bMDH" + }, + "source": [ + "**Task 3**: \n", + "Use Keras to train MNIST classifier:\n", + "* Notice that Keras contains some standard datasets, including MNIST. To use MNIST from Keras, you only need a couple of lines of code (more information [here](https://www.tensorflow.org/api_docs/python/tf/keras/datasets/mnist))\n", + "* Try several network configuration, with different number of layers/neurons, activation functions.\n", + "\n", + "What is the best accuracy you were able to achieve?" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "yX6hqiafwHl9" + }, + "source": [ + "## Takeaways\n", + "\n", + "* Tensorflow allows you to operate on tensors at low level, you have most flexibility.\n", + "* There are convenient tools to work with data (`td.Data`) and layers (`tf.layers`)\n", + "* For beginners/typical tasks, it is recommended to use **Keras**, which allows to construct networks from layers\n", + "* If non-standard architecture is needed, you can implement your own Keras layer, and then use it in Keras models\n", + "* It is a good idea to look at PyTorch as well and compare approaches. \n", + "\n", + "A good sample notebook from the creator of Keras on Keras and Tensorflow 2.0 can be found [here](https://t.co/k694J95PI8)." + ] + } + ], + "metadata": { + "celltoolbar": "Slideshow", + "colab": { + "collapsed_sections": [], + "name": "IntroKerasTF.ipynb", + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3.10.8 64-bit", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.8" + }, + "livereveal": { + "start_slideshow_at": "selected" + }, + "vscode": { + "interpreter": { + "hash": "b0fa6594d8f4cbf19f97940f81e996739fb7646882a419484c72d19e05852a7e" + } + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} From ce65f5bfe77cd3a710726e065496fb622d3d3175 Mon Sep 17 00:00:00 2001 From: semercim Date: Wed, 2 Nov 2022 22:04:05 +0100 Subject: [PATCH 31/38] WIP: the Turkish translation of lesson 5 --- .../translations/IntroKeras.tr.ipynb | 2 +- .../translations/IntroKerasTF.tr.ipynb | 111 +++++++++--------- 2 files changed, 55 insertions(+), 58 deletions(-) diff --git a/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKeras.tr.ipynb b/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKeras.tr.ipynb index 4bf087b7..0295a4ed 100644 --- a/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKeras.tr.ipynb +++ b/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKeras.tr.ipynb @@ -476,7 +476,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.8" + "version": "3.8.13" }, "livereveal": { "start_slideshow_at": "selected" diff --git a/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKerasTF.tr.ipynb b/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKerasTF.tr.ipynb index e338a859..fef7df2b 100644 --- a/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKerasTF.tr.ipynb +++ b/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKerasTF.tr.ipynb @@ -90,9 +90,9 @@ "id": "qG2bsaR7wHl4" }, "source": [ - "### Simple Tensors\n", + "### Basit Tensörler\n", "\n", - "You can easily create simple tensors from lists of np-arrays, or generate random ones:" + "Np dizilimleri listelerinden kolayca basit tensörler oluşturabilir veya rastgele üretebilirsiniz:" ] }, { @@ -119,7 +119,7 @@ "id": "AXFMsV3r09Ux" }, "source": [ - "You can use arithmetic operations on tensors, which are performed element-wise, as in numpy. Tensors are automatically expanded to required dimension, if needed. To extract numpy-array from tensor, use `.numpy()`:" + "Numpy'de olduğu gibi eleman bazında gerçekleştirilen tensörlerde aritmetik işlemleri kullanabilirsiniz. Gerekirse, tensörler otomatik olarak gerekli boyuta genişletilir. Tensörden numpy-dizilimini çıkarmak için `.numpy()` kullanın:" ] }, { @@ -144,11 +144,11 @@ "id": "uQ5zN6cVyrG7" }, "source": [ - "## Variables\n", + "## Değişkenler\n", "\n", - "Variables are useful to represent tensor values that can be modified using `assign` and `assign_add`. They are often used to represent neural network weights.\n", + "Değişkenler, `assign` (\"atama\") ve `assign_add` (\"atama_topla\") kullanılarak değiştirilebilen tensör değerlerini temsil etmek için kullanışlıdır. Genellikle sinir ağı ağırlıklarını temsil etmek için kullanılırlar.\n", "\n", - "As an example, here is a silly way to get a sum of all rows of tensor `a`:" + "Örnek olarak, `a` tensörünün tüm satırlarının toplamını almanın aptalca bir yolunu görelim:" ] }, { @@ -176,7 +176,7 @@ "id": "rIh1EHcezlNo" }, "source": [ - "Much better way to do it:" + "Bunu yapmanın çok daha iyi bir yolu:" ] }, { @@ -200,13 +200,13 @@ "id": "U-auwezDwHl6" }, "source": [ - "## Computing Gradients\n", + "## Gradyanları Hesaplama\n", "\n", - "For back propagation, you need to compute gradients. This is done using `tf.GradientTape()` idiom:\n", - " * Add `with tf.GradientTape` block around our computations\n", - " * Mark those tensors with respect to which we need to compute gradients by calling `tape.watch` (all variables are watched automatically)\n", - " * Compute whatever we need (build computational graph)\n", - " * Obtain gradients using `tape.gradient` " + "Geri yayma için gradyanları hesaplamanız gerekir. Bu, `tf.GradientTape()` ifadesi kullanılarak yapılır:\n", + " * Hesaplamalarımızın çevresine `with tf.GradientTape` bloğunu ekleyin.\n", + " * Gradyanları hesaplamamız gereken tensörleri `tape.watch` çağırarak işaretleyin (tüm değişkenler otomatik olarak izlenir).\n", + " * İhtiyacımız olan her şeyi hesaplayın (hesaplama çizgesi oluşturun).\n", + " * `tape.gradient` kullanarak gradyanları elde edin." ] }, { @@ -225,9 +225,9 @@ "b = tf.random.normal(shape=(2, 2))\n", "\n", "with tf.GradientTape() as tape:\n", - " tape.watch(a) # Start recording the history of operations applied to `a`\n", - " c = tf.sqrt(tf.square(a) + tf.square(b)) # Do some math using `a`\n", - " # What's the gradient of `c` with respect to `a`?\n", + " tape.watch(a) # `a` öğesine uygulanan işlemlerin geçmişini kaydetmeye başlayın\n", + " c = tf.sqrt(tf.square(a) + tf.square(b)) # `a`'yı kullanarak biraz matematik yapın\n", + " # `c`'nin `a`'ya göre gradyanı nedir?\n", " dc_da = tape.gradient(c, a)\n", " print(dc_da)" ] @@ -238,9 +238,9 @@ "id": "8sfjBMBu59B5" }, "source": [ - "## Example 1: Linear Regression\n", + "## Örnek 1: Doğrusal Bağlanım\n", "\n", - "Now we know enough to solve the classical problem of **Linear regression**. Let's generate small synthetic dataset:" + "Artık klasik **doğrusal bağlanım** problemini çözecek kadar bilgimiz var. Küçük bir sentetik veri kümesi oluşturalım:" ] }, { @@ -270,7 +270,7 @@ }, "outputs": [], "source": [ - "np.random.seed(13) # pick the seed for reproducability - change it to explore the effects of random variations\n", + "np.random.seed(13) # yeniden üretilebilirlik için tohumu seçin - rastgele değişimlerim etkilerini keşfetmek için değiştirin\n", "\n", "train_x = np.linspace(0, 3, 120)\n", "train_labels = 2 * train_x + 0.9 + np.random.randn(*train_x.shape) * 0.5\n", @@ -284,12 +284,12 @@ "id": "Ng4rZmGc6oxk" }, "source": [ - "Linear regression is defined by a straight line $f_{W,b}(x) = Wx+b$, where $W, b$ are model parameters that we need to find. An error on our dataset $\\{x_i,y_u\\}_{i=1}^N$ (also called **loss function**) can be defined as mean square error:\n", + "Doğrusal bağlanım, $f_{W,b}(x) = Wx+b$ doğrusuyla tanımlanır, burada $W$ ve $b$ bulmamız gereken model parametreleridir. $\\{x_i,y_u\\}_{i=1}^N$ (**kayıp işlevi** olarak da adlandırılır) veri kümemizdeki hata, ortalama kare hatası olarak tanımlanabilir:\n", "$$\n", "\\mathcal{L}(W,b) = {1\\over N}\\sum_{i=1}^N (f_{W,b}(x_i)-y_i)^2\n", "$$\n", "\n", - "Let's define our model and loss function:" + "Modelimizi ve kayıp fonksiyonumuzu tanımlayalım:" ] }, { @@ -304,9 +304,9 @@ "output_dim = 1\n", "learning_rate = 0.1\n", "\n", - "# This is our weight matrix\n", + "# Bu bizim ağırlık matrisimiz\n", "w = tf.Variable([[100.0]])\n", - "# This is our bias vector\n", + "# Bu bizim ek girdi vektörümüz\n", "b = tf.Variable(tf.zeros(shape=(output_dim,)))\n", "\n", "def f(x):\n", @@ -322,7 +322,7 @@ "id": "JUxwj3367gD2" }, "source": [ - "We will train the model on a series of minibatches. We will use gradient descent, adjusting model parameters using the following formulae:\n", + "Modeli bir dizi minigrup üzerinde eğiteceğiz. Aşağıdaki formülleri kullanarak model parametrelerini ayarlayarak gradyan inişini kullanacağız:\n", "$$\n", "\\begin{array}{l}\n", "W^{(n+1)}=W^{(n)}-\\eta\\frac{\\partial\\mathcal{L}}{\\partial W} \\\\\n", @@ -343,7 +343,7 @@ " with tf.GradientTape() as tape:\n", " predictions = f(x)\n", " loss = compute_loss(y, predictions)\n", - " # Note that `tape.gradient` works with a list as well (w, b).\n", + " # `tape.gradient` öğesinin bir listeyle de çalıştığını unutmayın (w, b).\n", " dloss_dw, dloss_db = tape.gradient(loss, [w, b])\n", " w.assign_sub(learning_rate * dloss_dw)\n", " b.assign_sub(learning_rate * dloss_db)\n", @@ -356,7 +356,7 @@ "id": "idr2VEWb9rr0" }, "source": [ - "Let's do the training. We will do several passes through the dataset (so-called **epochs**), divide it into minibatches and call the function defined above:" + "Eğitimi yapalım. Veri kümesinden (**dönem** olarak adlandırılan) birkaç geçiş yapacağız, onu minigruplara ayıracağız ve yukarıda tanımlanan işlevi çağıracağız:" ] }, { @@ -367,7 +367,7 @@ }, "outputs": [], "source": [ - "# Shuffle the data.\n", + "# Verileri karıştırın.\n", "indices = np.random.permutation(len(train_x))\n", "features = tf.constant(train_x[indices],dtype=tf.float32)\n", "labels = tf.constant(train_labels[indices],dtype=tf.float32)" @@ -389,14 +389,14 @@ "for epoch in range(10):\n", " for i in range(0,len(features),batch_size):\n", " loss = train_on_batch(tf.reshape(features[i:i+batch_size],(-1,1)),tf.reshape(labels[i:i+batch_size],(-1,1)))\n", - " print('Epoch %d: last batch loss = %.4f' % (epoch, float(loss)))" + " print('Dönem %d: son toplu iş kaybı = %.4f' % (epoch, float(loss)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "We now have obtained optimized parameters $W$ and $b$. Note that their values are similar to the original values used when generating the dataset ($W=2, b=1$)" + "Artık optimize edilmiş $W$ ve $b$ parametrelerini elde ettik. Değerlerinin, veri kümesi oluşturulurken kullanılan orijinal değerlere benzer olduğuna dikkat edin ($W=2, b=1$)" ] }, { @@ -439,11 +439,11 @@ "id": "0giuwC9GHzi8" }, "source": [ - "## Computational Graph and GPU Computations\n", + "## Hesaplamalı Çizge ve GPU Hesaplamaları\n", "\n", - "Whenever we compute tensor expression, Tensorflow builds a computational graph that can be computed on the available computing device, e.g. CPU or GPU. Since we were using arbitrary Python function in our code, they cannot be included as part of computational graph, and thus when running our code on GPU we would need to pass the data between CPU and GPU back and forth, and compute custom function on CPU.\n", + "Tensör ifadesini her hesapladığımızda, Tensorflow, mevcut bilgi işlem cihazında, CPU veya GPU, hesaplanabilen bir hesaplamalı çizge oluşturur. Kodumuzda keyfi Python işlevi kullandığımız için, bunlar hesaplamalı çizgenin bir parçası olarak dahil edilemezler ve bu nedenle kodumuzu GPU'da çalıştırırken verileri CPU ve GPU arasında ileri geri iletmemiz ve CPU'da özelleştirilmiş işlevi hesaplamamız gerekir.\n", "\n", - "Tensorflow allows us to mark our Python function using `@tf.function` decorator, which will make this function a part of the same computational graph. This decorator can be applied to functions that use standard Tensorflow tensor operations. " + "Tensorflow, Python işlevimizi, bu işlevi aynı hesaplamalı çizgenin bir parçası yapacak olan `@tf.function` dekoratörünü kullanarak işaretlememizi sağlar. Bu dekoratör, standart Tensorflow tensör işlemlerini kullanan işlevlere uygulanabilir." ] }, { @@ -459,7 +459,7 @@ " with tf.GradientTape() as tape:\n", " predictions = f(x)\n", " loss = compute_loss(y, predictions)\n", - " # Note that `tape.gradient` works with a list as well (w, b).\n", + " # `tape.gradient` öğesinin bir listeyle de çalıştığını unutmayın (w, b).\n", " dloss_dw, dloss_db = tape.gradient(loss, [w, b])\n", " w.assign_sub(learning_rate * dloss_dw)\n", " b.assign_sub(learning_rate * dloss_db)\n", @@ -472,11 +472,11 @@ "id": "J7HusxWkGjLX" }, "source": [ - "The code has not changed, but if you were running this code on GPU and on larger dataset - you would have noticed the difference in speed. \n", + "Kod değişmedi, ancak bu kodu GPU'da ve daha büyük veri kümesinde çalıştırıyor olsaydınız, hızdaki farkı fark ederdiniz.\n", "\n", - "## Dataset API\n", + "## Veri Kümesi API'si\n", "\n", - "Tensorflow contains a convenient API to work with data. Let's try to use it. We will also train our model from scratch." + "Tensorflow, verilerle çalışmak için uygun bir API içerir. Kullanmaya çalışalım. Modelimizi de sıfırdan eğiteceğiz." ] }, { @@ -494,14 +494,14 @@ "w.assign([[10.0]])\n", "b.assign([0.0])\n", "\n", - "# Create a tf.data.Dataset object for easy batched iteration\n", + "# Kolay toplu yineleme için bir tf.data.Dataset nesnesi oluşturun\n", "dataset = tf.data.Dataset.from_tensor_slices((train_x.astype(np.float32), train_labels.astype(np.float32)))\n", "dataset = dataset.shuffle(buffer_size=1024).batch(256)\n", "\n", "for epoch in range(10):\n", " for step, (x, y) in enumerate(dataset):\n", " loss = train_on_batch(tf.reshape(x,(-1,1)), tf.reshape(y,(-1,1)))\n", - " print('Epoch %d: last batch loss = %.4f' % (epoch, float(loss)))" + " print('Dönem %d: son toplu iş kaybı = %.4f' % (epoch, float(loss)))" ] }, { @@ -510,23 +510,22 @@ "id": "A10prCPowHl7" }, "source": [ - "## Example 2: Classification\n", + "## Örnek 2: Sınıflandırma\n", "\n", - "Now we will consider binary classification problem. A good example of such a problem would be a tumour classification between malignant and benign based on it's size and age.\n", + "Şimdi ikili sınıflandırma problemini ele alacağız. Böyle bir soruna iyi bir örnek, boyutuna ve yaşına göre habis ve iyi huylu arasında bir tümör sınıflandırması olabilir.\n", "\n", - "The core model is similar to regression, but we need to use different loss function. Let's start by generating sample data:\n" + "Çekirdek model bağlanıma benzer, ancak farklı kayıp işlevi kullanmamız gerekiyor. Örnek veriler üreterek başlayalım:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { - "id": "j0OTPkGpwHl7", - "scrolled": false + "id": "j0OTPkGpwHl7" }, "outputs": [], "source": [ - "np.random.seed(0) # pick the seed for reproducibility - change it to explore the effects of random variations\n", + "np.random.seed(0) # yeniden üretilebilirlik için tohumu seçin - rastgele değişimlerin etkilerini keşfetmek için değiştirin\n", "\n", "n = 100\n", "X, Y = make_classification(n_samples = n, n_features=2,\n", @@ -543,16 +542,15 @@ "cell_type": "code", "execution_count": null, "metadata": { - "id": "c-_BjSHPwHl8", - "scrolled": false + "id": "c-_BjSHPwHl8" }, "outputs": [], "source": [ "def plot_dataset(features, labels, W=None, b=None):\n", - " # prepare the plot\n", + " # çizimi hazırla\n", " fig, ax = plt.subplots(1, 1)\n", - " ax.set_xlabel('$x_i[0]$ -- (feature 1)')\n", - " ax.set_ylabel('$x_i[1]$ -- (feature 2)')\n", + " ax.set_xlabel('$x_i[0]$ -- (öznitelik 1)')\n", + " ax.set_ylabel('$x_i[1]$ -- (öznitelik 2)')\n", " colors = ['r' if l else 'b' for l in labels]\n", " ax.scatter(features[:, 0], features[:, 1], marker='o', c=colors, s=100, alpha = 0.5)\n", " if W is not None:\n", @@ -576,8 +574,7 @@ "height": 283 }, "id": "tq0vFchQwHl8", - "outputId": "9a5aa6a0-c92f-4d72-9e78-c0f615804bff", - "scrolled": false + "outputId": "9a5aa6a0-c92f-4d72-9e78-c0f615804bff" }, "outputs": [], "source": [ @@ -588,11 +585,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## Normalizing Data\n", + "## Verileri Normalleştirme\n", "\n", - "Before training, it is common to bring our input features to the standard range of [0,1] (or [-1,1]). The exact reasons for that we will discuss later in the course, but in short the reason is the following. We want to avoid values that flow through our network getting too big or too small, and we normally agree to keep all values in the small range close to 0. Thus we initialize the weights with small random numbers, and we keep signals in the same range.\n", + "Eğitimden önce, girdi özniteliklerimizi [0,1] (veya [-1,1]) standart aralığına getirmek yaygındır. Bunun kesin nedenlerini dersin ilerleyen kısımlarında tartışacağız, ancak kısaca nedeni şudur. Ağımız üzerinden akan değerlerin çok büyük veya çok küçük olmasını önlemek istiyoruz ve normalde küçük aralıktaki tüm değerleri 0'a yakın tutmayı kabul ediyoruz. Böylece ağırlıkları küçük rastgele sayılarla ilkliyoruz ve sinyalleri aynı aralıkta tutuyoruz.\n", "\n", - "When normalizing data, we need to subtract min value and divide by range. We compute min value and range using training data, and then normalize test/validation dataset using the same min/range values from the training set. This is because in real life we will only know the training set, and not all incoming new values that the network would be asked to predict. Occasionally, the new value may fall out of the [0,1] range, but that's not crucial. " + "Verileri normalleştirirken en küçük değeri çıkarmamız ve aralık boyuna bölmemiz gerekiyor. Eğitim verilerini kullanarak minimum değeri ve aralığı hesaplıyoruz ve ardından eğitim kümesindeki aynı minimum/aralık değerlerini kullanarak test/geçerleme veri kümesini normalleştiriyoruz. Bunun nedeni, gerçek hayatta ağın tahmin etmesi istenecek tüm gelen yeni değerleri değil sadece eğitim kümesini bileceğiz. Bazen yeni değerler [0,1] aralığının dışına çıkabilir, ancak bu çok önemli değildir." ] }, { @@ -984,7 +981,7 @@ "provenance": [] }, "kernelspec": { - "display_name": "Python 3.10.8 64-bit", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -998,7 +995,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.8" + "version": "3.8.13" }, "livereveal": { "start_slideshow_at": "selected" @@ -1010,5 +1007,5 @@ } }, "nbformat": 4, - "nbformat_minor": 0 + "nbformat_minor": 4 } From 526d2357eef93e28f1b17a26cf2d18bc9243a771 Mon Sep 17 00:00:00 2001 From: semercim Date: Sun, 6 Nov 2022 19:38:44 +0100 Subject: [PATCH 32/38] WIP: the Turkish translation of lesson 5 --- .../translations/IntroKeras.tr.ipynb | 4 +- .../translations/IntroKerasTF.tr.ipynb | 697 +++++++++++++++--- 2 files changed, 587 insertions(+), 114 deletions(-) diff --git a/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKeras.tr.ipynb b/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKeras.tr.ipynb index 0295a4ed..149ba11f 100644 --- a/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKeras.tr.ipynb +++ b/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKeras.tr.ipynb @@ -421,7 +421,7 @@ "| İkili | Bire bir kodlama (2 çıktılı) | softmax | kategorik çapraz entropi |\n", "| Çok sınıflı | Bire bir kodlama | softmaks | kategorik çapraz entropi |\n", "| Çok sınıflı | Sınıf sayısı | softmaks | seyrek kategorik çapraz entropi |\n", - "| Çok sınıflı | Bire bir kodlama | sigmoid | kategorik çapraz entropi |\n" + "| Çok etiketli | Bire bir kodlama | sigmoid | kategorik çapraz entropi |\n" ] }, { @@ -450,7 +450,7 @@ "* Standart olmayan bir mimari gerekiyorsa, Tensorflow'u biraz daha derinlemesine öğrenmeniz gerekir. Veya birinden özel mantığı bir Keras katmanı olarak uygulamasını isteyebilir ve ardından bunu Keras modellerinde kullanabilirsiniz.\n", "* PyTorch'a da bakmak ve yaklaşımları karşılaştırmak iyi bir fikirdir.\n", "\n", - "Keras üzerine Keras ve Tensorflow 2.0'nin yaratıcısından güzel bir örnek not defterini [burada](https://t.co/k694J95PI8) bulabilirsiniz." + "Keras yaratıcısından Keras ve Tensorflow 2.0'nin üzerine güzel bir örnek not defterini [burada](https://t.co/k694J95PI8) bulabilirsiniz." ] } ], diff --git a/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKerasTF.tr.ipynb b/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKerasTF.tr.ipynb index fef7df2b..d5d1150d 100644 --- a/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKerasTF.tr.ipynb +++ b/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKerasTF.tr.ipynb @@ -52,7 +52,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 30, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -61,7 +61,15 @@ "outputId": "2aa591b4-b647-441f-9c8e-4e0da2d517a0", "tags": [] }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2.9.0\n" + ] + } + ], "source": [ "import tensorflow as tf\n", "import numpy as np\n", @@ -97,7 +105,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 31, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -105,7 +113,28 @@ "id": "ybpnk08HwHl4", "outputId": "fad9ed4a-df82-44a0-84ea-324bc71ea46f" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tf.Tensor(\n", + "[[1 2]\n", + " [3 4]], shape=(2, 2), dtype=int32)\n", + "tf.Tensor(\n", + "[[-0.15611048 -0.6395791 0.15967956]\n", + " [ 1.2029059 0.6616139 1.4267689 ]\n", + " [-0.3284896 0.43672192 -0.30175865]\n", + " [ 0.0704657 -0.01082341 -1.0820643 ]\n", + " [-0.1884 -0.22958039 1.9114271 ]\n", + " [-0.02439586 -1.553597 -1.7745456 ]\n", + " [-0.05847295 -0.6536034 -0.19704701]\n", + " [ 0.12037303 -1.0853446 -0.94284475]\n", + " [-0.513617 -0.0538025 -0.580708 ]\n", + " [ 0.9643102 -1.971696 -0.7634352 ]], shape=(10, 3), dtype=float32)\n" + ] + } + ], "source": [ "a = tf.constant([[1,2],[3,4]])\n", "print(a)\n", @@ -124,7 +153,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 32, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -132,7 +161,26 @@ "id": "e5Nu5Xgj1DnQ", "outputId": "0dfc8758-4ffd-4968-c7bf-6ba8d435df2e" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tf.Tensor(\n", + "[[ 0. 0. 0. ]\n", + " [ 1.3590164 1.301193 1.2670894 ]\n", + " [-0.17237912 1.0763011 -0.4614382 ]\n", + " [ 0.22657618 0.6287557 -1.2417438 ]\n", + " [-0.03228952 0.40999871 1.7517476 ]\n", + " [ 0.13171463 -0.91401786 -1.9342251 ]\n", + " [ 0.09763753 -0.01402426 -0.3567266 ]\n", + " [ 0.2764835 -0.44576544 -1.1025243 ]\n", + " [-0.3575065 0.5857766 -0.74038756]\n", + " [ 1.1204207 -1.3321168 -0.9231148 ]], shape=(10, 3), dtype=float32)\n", + "[0.85546464 0.52751434 1.1731348 ]\n" + ] + } + ], "source": [ "print(a-a[0])\n", "print(tf.exp(a)[0].numpy())" @@ -153,7 +201,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 33, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -161,7 +209,15 @@ "id": "7pu0UZ-_yqfB", "outputId": "6708c83e-02e6-4442-8757-45918eb1fbc2" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + } + ], "source": [ "s = tf.Variable(tf.zeros_like(a[0]))\n", "for i in a:\n", @@ -181,7 +237,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 34, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -189,7 +245,18 @@ "id": "aQIdWZ1kzn6P", "outputId": "1c123d9a-ecd2-4f2e-828e-5ade85ac8f63" }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "tf.reduce_sum(a,axis=0)" ] @@ -211,7 +278,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 35, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -219,7 +286,17 @@ "id": "m8vFOXr7wHl6", "outputId": "860ac72e-50c7-4ff2-f258-747f27194f90" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tf.Tensor(\n", + "[[-0.8448666 -0.09937061]\n", + " [-0.9634435 0.8072742 ]], shape=(2, 2), dtype=float32)\n" + ] + } + ], "source": [ "a = tf.random.normal(shape=(2, 2))\n", "b = tf.random.normal(shape=(2, 2))\n", @@ -245,7 +322,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 36, "metadata": { "id": "j723455WwHl7" }, @@ -259,7 +336,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 37, "metadata": { "colab": { "base_uri": "https://localhost:8080/", @@ -268,7 +345,28 @@ "id": "WJNK_J6v6I-Z", "outputId": "eb4a66a6-6b9a-4c8a-bc24-d81eeb2d3f27" }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 37, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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duxY3uOPHDmiL37xi7rjjju0b98+Pf7443r00Ue1du1an8/cf3avlendd99VY2Nj+8+wYcN8OuPgnD9/XqNGjdKPf/xjS8cn+Xtl91qZkvi92rJli+bOnasdO3Zow4YN+uSTTzR16lSdP3++4GuS+t1ycq1MSftuDRo0SEuXLtXu3bu1e/duTZo0Sffee6/efvvtvMcH9p0yIuK2224zHnrooU6/u+GGG4yFCxfmPf573/ueccMNN3T63be//W1j3Lhxnp1jWNi9Vq+99pohyThz5owPZxdekox169YVPSbJ36uOrFwrvld/duLECUOSsWXLloLH8N1qY+Va8d36s6uuusp4+umn8/5dUN+pSGQsLl26pD179mjq1Kmdfj916lT99re/zfua7du3dzn+C1/4gnbv3q3Lly97dq5Bc3KtTLfccovq6up0991367XXXvPyNCMrqd+rcvC9kjKZjCSpb9++BY/hu9XGyrUyJfm71dLSojVr1uj8+fMaP3583mOC+k5FIrA4efKkWlpa9KlPfarT7z/1qU+pqakp72uampryHv/JJ5/o5MmTnp1r0Jxcq7q6Oq1YsUJr167V888/rxEjRujuu+/W1q1b/TjlSEnq98oJvldtDMPQ/PnzNXHiRI0cObLgcXy3rF+rJH+33nrrLV155ZWqqqrSQw89pHXr1qmhoSHvsUF9p3yfblqO3DHrhmEUHb2e7/h8v48jO9dqxIgRGjFiRPufx48fr+PHj+tf//Vfdeedd3p6nlGU5O+VHXyv2jz88MN68803tW3btpLHJv27ZfVaJfm7NWLECO3fv19nz57V2rVrNXv2bG3ZsqVgcBHEdyoSGYv+/furW7duXZ64T5w40SUaM9XW1uY9vnv37urXr59n5xo0J9cqn3HjxunQoUNun17kJfV75Zakfa8eeeQRvfTSS3rttdc0aNCgoscm/btl51rlk5TvVo8ePXT99dfr1ltv1ZIlSzRq1Cj96Ec/yntsUN+pSAQWPXr00NixY7Vhw4ZOv9+wYYNuv/32vK8ZP358l+N//etf69Zbb1VlZaVn5xo0J9cqn3379qmurs7t04u8pH6v3JKU75VhGHr44Yf1/PPPa9OmTRoyZEjJ1yT1u+XkWuWTlO9WLsMw1NzcnPfvAvtOeVoa6qI1a9YYlZWVxjPPPGMcPHjQeOyxx4xevXoZR48eNQzDMBYuXGh89atfbT/+/fffN6644gpj3rx5xsGDB41nnnnGqKysNP7rv/4rqI/gG7vX6sknnzTWrVtnvPfee8aBAweMhQsXGpKMtWvXBvURfHPu3Dlj3759xr59+wxJxr/9278Z+/btMz744APDMPhedWT3WiX5ezVnzhwjnU4bmzdvNhobG9t/Lly40H4M3602Tq5VUr9bixYtMrZu3WocOXLEePPNN43HH3/cqKioMH79618bhhGe71RkAgvDMIynnnrKGDx4sNGjRw9jzJgxnbYjzZ492/j85z/f6fjNmzcbt9xyi9GjRw/j2muvNZYvX+7zGQfHzrVatmyZMXToUKO6utq46qqrjIkTJxqvvPJKAGftP3PbWu7P7NmzDcPge9WR3WuV5O9VvuskyVi1alX7MXy32ji5Vkn9bn39619v///1q6++2rj77rvbgwrDCM93irHpAADANZGosQAAANFAYAEAAFxDYAEAAFxDYAEAAFxDYAEAAFxDYAEAAFxDYAEAAFxDYAEAAFxDYAEAAFxDYAEAAFxDYAEAAFxDYAEAAFzz/wG0npXX5xSjowAAAABJRU5ErkJggg==\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "np.random.seed(13) # yeniden üretilebilirlik için tohumu seçin - rastgele değişimlerim etkilerini keşfetmek için değiştirin\n", "\n", @@ -294,7 +392,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 38, "metadata": { "id": "QxhI4GlB6aiH" }, @@ -333,7 +431,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 39, "metadata": { "id": "-991PErM7fJU" }, @@ -361,7 +459,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 40, "metadata": { "id": "nOuu0qpx-wAp" }, @@ -375,7 +473,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 41, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -383,7 +481,24 @@ "id": "3zdIf6c_85Ht", "outputId": "43b04684-8b90-4c65-d5ff-20ebac61c73c" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dönem 0: son toplu iş kaybı = 94.5247\n", + "Dönem 1: son toplu iş kaybı = 9.3428\n", + "Dönem 2: son toplu iş kaybı = 1.4166\n", + "Dönem 3: son toplu iş kaybı = 0.5224\n", + "Dönem 4: son toplu iş kaybı = 0.3807\n", + "Dönem 5: son toplu iş kaybı = 0.3495\n", + "Dönem 6: son toplu iş kaybı = 0.3413\n", + "Dönem 7: son toplu iş kaybı = 0.3390\n", + "Dönem 8: son toplu iş kaybı = 0.3384\n", + "Dönem 9: son toplu iş kaybı = 0.3382\n" + ] + } + ], "source": [ "batch_size = 4\n", "for epoch in range(10):\n", @@ -401,7 +516,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 42, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -409,14 +524,26 @@ "id": "US6q0nCBD-LL", "outputId": "65a79620-a3eb-445b-aafb-60a60575ab0e" }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "(,\n", + " )" + ] + }, + "execution_count": 42, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "w,b" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 43, "metadata": { "colab": { "base_uri": "https://localhost:8080/", @@ -425,7 +552,28 @@ "id": "_e6xRMZFDnyI", "outputId": "d202b7fe-4383-4d82-b98e-a20f3180093e" }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAhYAAAGdCAYAAABO2DpVAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8rg+JYAAAACXBIWXMAAA9hAAAPYQGoP6dpAABPi0lEQVR4nO3deXxU5dn/8c8kgYQtYTdBEBEB2VQWEQS1rKLW4lJbfYSiVhRkUdEKuKMooChuGBQQ6o8qbQX3ikAREA2yyyaIkU0IIluCLAEy5/fH6YQss5wz+/J9v155PZ3hTM6d03l6rnPf131dDsMwDERERESCICnSAxAREZH4ocBCREREgkaBhYiIiASNAgsREREJGgUWIiIiEjQKLERERCRoFFiIiIhI0CiwEBERkaBJCfcJnU4ne/bsoVq1ajgcjnCfXkRERPxgGAZHjhyhXr16JCV5npcIe2CxZ88eGjRoEO7TioiISBDs2rWL+vXre/z3sAcW1apVA8yBpaenh/v0IiIi4oeCggIaNGhQfB/3JOyBhWv5Iz09XYGFiIhIjPGVxqDkTREREQkaBRYiIiISNAosREREJGgUWIiIiEjQKLAQERGRoFFgISIiIkGjwEJERESCRoGFiIiIBE3YC2SJiIhI8BU5DZZvO8i+IyeoWy2NDo1qkpwU/p5cCixERERi3NwNeYz+ZBN5+SeK38vKSOPJ61rQu1VWWMeipRAREZEYNndDHoNmri4VVADszT/BoJmrmbshL6zjUWAhIiISo4qcBqM/2YTh5t9c743+ZBNFTndHhIYCCxERkRi1fNvBcjMVJRlAXv4Jlm87GLYxKbAQERGJUfuOeA4q/DkuGBRYiIiIxKi61dKCelwwKLAQERGJUR0a1SQrIw1Pm0odmLtDOjSqGbYxKbAQERGJUclJDp68rgVAueDC9frJ61qEtZ6FAgsREZEwKXIa5OQe4KO1u8nJPRCU3Rq9W2WR3bctmRmllzsyM9LI7ts27HUsVCBLREQkDEJZxKp3qyx6tsiMisqbDsMwwre5FSgoKCAjI4P8/HzS09PDeWoREZGIcBWxKnvDdd32IzGzYJfV+7eWQkREREIoGotYhZICCxERkRCKxiJWoaTAQkREJISisYhVKCmwEBERCaFoLGIVSgosREREQigai1iFkq3A4txzz8XhcJT7GTx4cKjGJyIiEtOisYhVKNkKLFasWEFeXl7xz/z58wG4+eabQzI4ERGReBBtRaxCyVaBrDp16pR6PW7cOBo3bsyVV14Z1EGJiIjEm0CLWBU5jVKfbdewBqt2HIp4Qayy/K68efLkSWbOnMnw4cNxODz/IYWFhRQWFha/Ligo8PeUIiIiMS05yUGnxrVsf85d1c4kB5QsfRGsKp6B8jt588MPP+Tw4cPcfvvtXo8bO3YsGRkZxT8NGjTw95QiIiIJx1W1s2wtjLL1tPbmn2DQzNXM3ZAXxtGV53dJ76uuuoqKFSvyySefeD3O3YxFgwYNVNJbREQSXtnljbLLGUVOgy7jF3otsFWSAzNvY+mIbkFfFrFa0tuvpZAdO3awYMEC5syZ4/PY1NRUUlNT/TmNiIhI3LLSlMxX1c6ySlbx9GfJJRj8WgqZPn06devW5dprrw32eEREROKep+WNsssZ/lbjjGQVT9uBhdPpZPr06fTv35+UFHVdFxERscNOUzJ/q3FGsoqn7cBiwYIF7Ny5kzvvvDMU4xEREYlrdpqS+araWVY0VPG0HVj06tULwzBo2rRpKMYjIiIS1+w0JfNWtbOsaKniqV4hIiIiYWS3KZmnqp1lY4doqeKpJAkREZEwci1v7M0/4TbPwrVltORyhruqnXFXeVNERETscy1vDJq5GgeUCi68LWe4q9oZqS2l3mgpREREJMziuSmZZixEREQiINCmZNFKgYWIiEiE+NuULJppKURERESCRoGFiIiIBI0CCxERkXixfz/8978RHYICCxERkVjndMK0adCsGdx4I+TlRWwoCixERERi2fr1cMUVcNddcPAgNGxo/t8IUWAhIiISi44ehYcfhrZt4euvoUoVmDABVq2Cli0jNixtNxUREYk1H30EQ4fCrl3m6xtugFdegQYNIjsuFFiIiIgEpMhphK/I1Y4dZkDxySfm64YN4fXX4fe/D835/KDAQkRExE9zN+Qx+pNN5OWfaYWelZHGk9e1CEpZblfQ8uvBI1z07+mcM2kCjmPHICUFHnoIHn8cKlcO+DzBpMBCRESkDCuzEHM35DFo5upyHUr35p9g0MzVfvX8KHne7fuP8d7ynTTYuJIx896g4f6dABxs15Gaf58a0TwKbxRYiIiIlOBrFqLIabAs9wAjZ6932/bcwOxSOvqTTfRskWl5WaTseWscy2fUoun8af0CAA5USue5rn9lTqtuZBs16R3g3xkqCixERMSWsOYUhJmvWYi7r2jEx9/llQo63DGAvPwTLN920FIvkJLndRhObl63gFGLplPjxBEA3r3oKp6/sj+HK6X7FbSEkwILERGxLNQ5BZFU5DQY/ckmj7MQAG8u2Wbrd+474j0AKXveZr9u59kvJtF+9/cAfF/nXB7tNZjV9ZuXGoudoCXcFFiIiIglocgpiCbLtx30ORNhV91qaT5neJZvO0j+r4cY9fV7/HXFh6QYTo5WSOOlLrcxo/0fKEpKdvu7rQQtkaDAQkREfPL1NB/t0/NWBPNG7QAyM9I4dPQkXcYv9DzDYxgkffwh86eO4uwjvwLwedPLeLr7APLS63g9R91qaUEbbzApsBAREZ98Pc1H+/S8FcG6UbvCqj9clMXgdz3P8MzoWocrX3+GSz/9FIBdGWfxRM+BfNn4Ep+/PzPDnPmIRgosRETEJ6tP83vzj5OTeyAmEzs7NKpJVkYae/NPuJ2ZsSozI43Hr23OM5997/b3pBSd4q8rPuLSl96DU4UYFSrwzmV/ZFy7mzhewXtw47qST17XImqvqwILERHxyerT/DOffc/BoyeLX8dSYmdykoMnr2vBoJmrcYDt4KJ6pQpMuq0tHc+r5XGGp8OuDYz54g2aHjBrUhRc0on0GVM5y1mDExbOmxkD11NNyERExCfX07yvZ+SSQQWcmfafuyFybbzt6N0qi+y+bcnMKB1IZWWkcc8VjXBAuWvgem/cTa3pfH5tkpMc5WZ4ah7L54XPXuZf746k6YGdHKiUzoPXPMCXb/4LWrTweN7M9FQe6NGEV265mPcGdGTpiG5RHVSAZixERMQCf5/mozWx09tOjd6tsujZItPtv7c5p0a57bbuZhFcMzwOw8mf1s1n5KIZJWpS9Gb8lf3Jr1SNP6ZXKv6Mt/PGEodhGIEsJdlWUFBARkYG+fn5pKenh/PUIiISIHd1LGpWqcDBo6d8fva9AR2jIrEz0FocVgqEFTkN+j8wlftnTyxdk+Kqwaw+u3lxAubSEd1iJnCwev/WjIWIiFjm7ql6b8EJHvjnWp+fjYa6C8GoxZGc5PAeIP32G8mjR/POpIkkFRWVq0kRCwmYgVBgISIitpS9sebkHrD0uUjXXQh5LQ7DgA8/hPvug127SAL29riGe9r25TvHmSf8WEjADIQCCxERCYivbZrRUnchpLU4tm+HoUPhfzUpOPdceP11Mq+9ljlx3FvFHe0KERGRgLgSO8H9jgmIjml/q0sxtpZsTp6EceOgRQszqKhQAR55BDZuhGuvBc7M8PS5+Gw6Na4V8esQagosREQkYB63S2akRU0PEatLMZaXbJYsgTZtYNQoOH4crrwSvvsOnn0WKlcOYKSxTUshIiISFNG+XTJoSza//goPPwwzZpiv69SBCROgXz9wRMffGkkKLEREJGh87piIIG+1OCwt2Tid8PbbZlBx6JD53t13w9ixUDM6+3ZEgpZCREQkYfi9ZLNuHXTpAgMGmEHFRRdBTg68+aaCijI0YyEiIgnF1pLNb7/BU0/Byy9DURFUrQpPP23uAEnRLdQdXRUREUk4PpdsXDUphg2Dn38237vpJjPAqF8/HEOMWQosREREStq2zZyR+Owz83WjRvD663DNNZEdV4ywnWOxe/du+vbtS61atahcuTIXX3wxq1atCsXYREREgqLIaZCTe4CP1u4mJ/cARU43+0JOnjQTMVu2NIMKV02KDRsUVNhga8bi0KFDdO7cma5du/L5559Tt25dcnNzqV69eoiGJyIiEhhLTccWL4ZBg+B7s2EYV14J2dnQvHkERhzbbHU3HTlyJF9//TVfffWV3ydUd1MREQkXT03HXGmaU69pSPe3J8Df/26+UacOvPgi9O2rmhRlWL1/21oK+fjjj2nfvj0333wzdevWpU2bNkyZMsXrZwoLCykoKCj1IyIiEmremo5hOLll7Vwu6X2ZGVQ4HHDPPbB5swpdBchWYPHTTz+RnZ1NkyZN+OKLLxg4cCDDhg3jnXfe8fiZsWPHkpGRUfzToEGDgActIiLhYyk/IQp5ajp2wb5tvD/zYcZ+8Trpx49wtHkr+OYbmDxZNSmCwNZSSMWKFWnfvj3ffPNN8XvDhg1jxYoV5OTkuP1MYWEhhYWFxa8LCgpo0KCBlkJERGKApfyEKFTkNJg4/wde//LH4vcqnzzO/Uvf5c6VH5FiOPmtYiVe6tKXi8c/yh/aN4zgaGOD1aUQW8mbWVlZtGjRotR7zZs3Z/bs2R4/k5qaSmpqqp3TiIhIFPCUn7A3/wSDZq6OmuZiZZULhgyDq7bm8OSCt6h3ZD8AnzXrzDPdBrA3vTbv1agawdHGH1uBRefOndmyZUup93744QcaNlSkJyIST7zlJxiYyY+jP9lEzxaZAFHTeKxsMFT/8F5GL3iT7rkrANiZcRZP9BzIosaX4MCcffHZdExssRVYPPDAA1x22WU899xz/OlPf2L58uW89dZbvPXWW6Ean4iIRICn/AQXA8jLP8HrC39k1oqdlpdKipxGyIKQksFQhaJTDFj+AUO/+SeVThdyMimFNy+9iUmdbuZEhTRrTcfEL7ZyLAA+/fRTRo0axdatW2nUqBHDhw9nwIABlj+v7aYiItHvo7W7uW/WWr8+67pNl10qCXW+Rk7uAW6dsoxLd65nzLw3aHJgl/n+Oa15rOe95NY+s3kgFvJEoo3V+7ftwCJQCixERKKf6ybtLwdmx9ClI7qRnOTwWU8iGPkany/8jmP3DeemDQsB2F85g2e7/pUPWnYttX10SNfGPNCzmWYqbApJHQsREUkMHRrVJCvjzJKBXa6lkuXbDvrM1wAzX8PvbaxOJ7z1Fj1v/B03bViIEwf/uLg33Qa8yQetupWrSdH5/DoKKkJIgYWIiJSTnOTgyevMXYBlb8F2bsn7jpywnK+xfNtB2+Pku++gSxe45x5S8g/zQ1Zjbuo3gUevGkJBWundHkrWDA8FFiIi4lbvVllk921LZkZaqfczM9J4oEcTS7+jbrU09h3xHFSUVPY4r4W5jhyBBx+Edu0gJweqVoWJE9n2ny9ZW6+Zx2BIyZqhp7bpIiLiUe9WWfRskVluJwfArBW72Jt/wu0ShyvHokOjmpZnIupWOxPAeEz0/H1zem9dBvfdBz//bP7DH/8IL78MZ5/NVUB2Skq5z2YqWTNsFFiIiIhXyUkOOjWuVe79J69rwaCZq3FAqeCi7OyAK1/DShACngtzpezYTsXrR8JPK803GjWCSZPg6qtLHecpGNJMRXgosBAREb+4lkp8zQ648jWsBCHuEj1dNSmGfTOLtNMnOZWcQvLIESQ9+ihUqlR8XChrZIh1CixERBJAqG66VmcHrAYhZRM9O+5cxzPzskvXpOh1L2PuuJlOJYKKWO1pEo8UWIiIxLlQ33Q9LZWUZSUIcSVw1jp6mEcWvV2qJsWYbnfxYYvfgcPBviMnioOl+Zv28vbX28udz05PE812BI8CCxGROBZtjcR8BSF1q1Tk1rVzGbF4BtVP/IYTB+9e3Jvnr+xfavvo9v3H6DJ+oc9trCV7mngKFDTbEVyqvCkiEqeKnIbXm2/Z6pgR9913GAMH4lhmVvzcWPc8Hr1qMGvrNSs+xAFkVK5A/rFTbhNBPXlvQEe3AU04KoLGC1XeFBFJcCEtTBVMR47A8OHQrh2OZcs4XbkKo7sPoE//ieWCClcAYPeJ2F0tjZBXBE1QCixEROKUv4WpwsYwYPZsaN4cJk6EoiK4+WZSftjCpS+Ppk6NKqUOdxXmOnzslO1TlayR4RIzgVeMUY6FiEgMspJs6O5m6o7V44Lqp59g6FD4z3/M1+edZ9ak6N0bgN5n4zbR89N1e2ydpmyNjJKiPvCKUQosRERijNVkQ1+FqQCqV6qA0zAochrhybMoLIQJE2DMGDhxAipUgBEj4JFHStWkAPeJnnaCIF9lvKM68IphWgoREYkhrmTDslP4rl0eczfkFb/nrZGYy+Hjp7ht6rd0Gb+w1GdDYtEiuPhieOwxM6jo2hXWrYNnnikXVLhT5DRwOg2qV6pg6XSZGWleky99dXBV0zL/KLAQEYkR/iQbemokVpa7wCRo9u2Dv/zFDCQ2b4a6dWHmTPjvfylq2sxzo7ES5m7Io8v4hdw27VsOH/eeY/HXzufy3oCOLB3RzeuODisdXNW0zD4thYiIxIhlPx2wnGxYcgnBVZhqWe4BBr+72u2N2WrNB1ucTpgyBUaOhMOHweGAe+6B556DGjUsL+l42hJalj+1J6xUBFXxLHsUWIiIxIC5G/IYOXu9pWPdJRsmJzlISnJ4fdr3FJj4Ze1aGDQI/leTgjZtIDsbLr0UsF64y9ssjUv1ShWYdFtbOp5Xy68bvreKoCqeZZ+WQkQkLhU5DUtT7LHAdRP2tQTg4inZMCy7IErUpGDZMqhWzWxpvnx5cVBhZ0nH15ZQMPNEkhyOgGYRXImifS4+m06NaxUHFVbzWeQMzViISNyJp6dMK0/sLt62VkKId0EYBsyZA/fdB7t3m+/dfLNZn+Lss0sdaqd+RKS2hPoKfoK+bBRHNGMhInEl3p4yrTyxl+Qt2TBkuyB++gmuvRb++EczqDjvPPj8c/jXvyjKqldu5shOsBCpLaEqnuU/zViISNyItadMK0mBVm/C1StXYNyNrS3tghg0c3Wp8tjg5y4IdzUpRo6EUaOgUiWPM0e3XNLA0q93XRNvtTh8zdL4K5CZkkRP9lRgISJxw85TZsDJiQGyulxj9Ul80q1t6dykts/jrOyCsOTLL83kzC1bzNfdusEbb0Azs7eHt+TMiQu2Ut1LI7GSwULQgyGL/J0piadlOH8psBCRuBErJZrttDK3+sTe0Uag5G0XhE+//AIPPWTWoQCzJsVLL8H//Z+5nRRrM0clx+8rWAhaMGSDPzMl0daiPlIUWIhI3IiFEs12l2usPrED5OQesBwouCuX7ZW7mhQDB8Kzz0KNGqUOtTJzdPjYKR7o0ZRZK3aWOrZGlQrccPHZZFSqWKrMeEDBkB/szpTE2jJcKCmwEJG4Ean1eDv8Wa7x9cQO0GX8wtBNv69dawYR335rvm7TBiZPhg4d3B5udUbo3NqVWTqiG8u3HWT+pr18uHYPB4+eZNrX25n29fZyf4PtYChAdmZKYmkZLtQUWIhI3IjUerwd/i7XeHpin79pb+im348cgSeegFdfNWcsqlUzEzXvvRdSPN8+7MwcJSc5yD9+kulfb4/KJQSrMyWxsgwXDgosRCSuRGI93o5AlmvKPrEHa/q93C6Gc2uQ/MEcuP/+MzUp/vQnsyZFvXo+x25n5igWlhCszJTEwjJcuCiwEJG4E+71eDuCuVwTjOn3srsYzjmUx/hFb9HphxXmAY0bw6RJcNVVPsfjYmfmKCfXv/4n0SYWluHCRQWyRCQuuSvRHA2C2VEz0On3ksXEKp4+xZBvZjHv7cF0+mEFhckp/HjP/bB+va2gwsVTV9WyrczjZQlBnVLP0IyFiEiYBWu5JpDp95JLEJ12rGPMvDdofPBnAL5ueCFP9LyXYw3PZ2lqGsmWzlKelZmjeFpCiPZluHBRYCEiEgHBWK4JZPp9+baDnNqTx0tfvs2NG78E4NfK1Xmm+1183PxKcztpEJYgfOUnxNsSQjQvw4WLAgsRkQgJdPuk37tgnE4qvz2F/04ZQ0bhUZw4mNnmGiZc0Y+CtKqlDg31EkQs7OSxK9zbYqONcixERGKY1VyGYmvWQKdOXPTcKDIKj7L+rMbc0G8CT/QaVC6ogPAsQdj+GySqOQzDsNKNN2gKCgrIyMggPz+f9PT0cJ5aRCRu+Wx8VaYmhVGtGi9d+RfeaN6LoqTyWRSuJYilI7qFbbYg0Zt3RTur928thYiIBFGkbo4ep98NA2bPhvvugz17zPf+/GccL71Ey4MOnFG0BJHoSwjxQoGFiEiQRF1ny9xcGDIE5s41XzdubHYg7dULgN710C4GCTothYiIBIGnzpau5/2w5goUFsILL5gNwk6cgIoVzeZhI0dCpUrlDtcShFihpRARkTCJqrLUCxeavTy2bDFfd+9uzlI0berxI1qCkGCytSvkqaeewuFwlPrJzMwM1dhERGKCndLaIfPLL9C3rxlIbNkCZ50F//gHzJ/vNagQCTbbMxYtW7ZkwYIFxa+Tk/2tySYiEh8iWpa6qAjeegtGjYL8fLOw1aBB5jJI9erBP5+ID7YDi5SUFM1SiIiUELGy1GvWwMCBsHy5+bptW5g8GS65JLjnEbHBdoGsrVu3Uq9ePRo1asQtt9zCTz/95PX4wsJCCgoKSv2IiMSqIqdBTu4BPlq7m5zcAxQ5jeKy1J6yJxyYu0OCVpa6oMBsad6+vRlUVKtm1qdYvlxBhUScrV0hn3/+OceOHaNp06b88ssvjBkzhs2bN7Nx40Zq1XKf+PPUU08xevTocu9rV4iIxBpv20kBBs1cDbivCRGUXSGGAe+/bwYVJWpS8NJLUK9eYL9bxAeru0IC2m569OhRGjduzMMPP8zw4cPdHlNYWEhhYWGpgTVo0ECBhYjEFCvbSYHQ1bHIzYXBg+GLL8zXZWpSiIRaWLabVqlShdatW7N161aPx6SmppKamhrIaUREwqpsXYd2DWtY2k66dES34He2LCyE5583kzELC82aFKNGmTUp0qK/lbgknoACi8LCQr7//nsuv/zyYI1HRCSi3C131KxSgYNHT3n8TMntpJ0a1wpeTYiFC80dHj/8YL7u0QMmTdL2UYlqtpI3H3roIRYvXsy2bdv49ttv+eMf/0hBQQH9+/cP1fhERMLGtdxRtiaFt6CipKBtJy1Zk+KHH8yaFO++C/PmKaiQqGdrxuLnn3/m1ltvZf/+/dSpU4eOHTuybNkyGjZsGKrxiYiEhbfqmVYFvJ3UXU2Ke++FMWNUk0Jihq3AYtasWaEah4hIRPmqnumNq8V4QNtJV682a1KsWGG+btcOsrO1fVRiju06FiIi8cjfZYyAW4wXFJgtzS+5xAwq0tPhtdfg228VVEhMUhMyERGsL2PUrFKRg0dPFr/2u8W4YcC//23WpMjLM9+75RazJkWW2pVL7FJgISICxdUz9+afcJtn4VruWPy3rqzacSiw7aQ//ghDhpypSXH++WZNip49A/0zRCJOSyEiIpitw10VNMuGCSWXOyqmJNGpcS36XHw2nRrXshdUFBbC009Dq1ZmUFGxIjz5JKxfr6BC4oZmLESkXEGogIs6xajerbLI7tu2XB0Lv5c7OHNtnQsW0Hb8o1Talmv+g2pSSJxSYCGS4Lz1vwi4DHUM6t0qK2jVM+duyOO1d5cy4KNJXL9pMQC/Vq3JVwNHknXPHXQ4rxbJwf4DRCIsoF4h/rBaa1xEQs9K/4tIBRd2Z1GibdZl7nc/8/XfnuNvS94hvfAoThy80/ZaXryiH0dSqwC+A7ho+5sksYWlCZk/FFiIRIcip0GX8Qs91m5wJSsuHdEt7Dczu7Mo0TbrUrRyFVtuuI0WP28BYF3m+TzaazDrs5qUOs5bABdtf5OI1fu3kjdFEpSvglAl+1+Ek6ey2nvzTzBo5mrmbsgL6PiQ+l9NiqRLO9Di5y0UVKzM4z0Hcn2/F8sFFXCmvfroTzZR5DzzjBdVf5OITQosRBKU1YJQQet/YYG3strubsJ2jw8Zw4B//QsuuABefRWH08nHza+g+4DJ/L+2v8eZ5DmTomwAFzV/k4ifFFiIJCirBaEC7n9hg91ZlKiYdfnxR+jdG/78Z7PQ1fnns2nG+wz7w8P8WtV6iW9XABcVf5NIABRYiCQoV0EoT9kTDsw1/YD6X9hkdxYlorMuJWtSzJtn1qR46ilYv55m/W70em3dcQVw0TiTJGKHAguRBGW1IFQ4EzftzqJEbNZlwQJo3dosblVYaBa32rDBfJ2WVura+lI2gIvGmSQROxRYiCQwV0GozIzSN6nMjLSIbDW1O4sS9lmXvXvh//7PDCS2boXMTHjvPbOKZpPSyZmua5uV4TkAcBfAReNMkogd2m4qIlFVL8G1IwIolcDoaWum3eP9UlQEkyfDo49Cfj44HDB4MIwZAxkZ3j/6v2s7f9NePly7p1QDM0/bR8PyN4nYpDoWIhKzoqqOxapVMHAgrFxpvm7Xzgwy2re3/avsBHCRrGMRTYGmRA8FFiIS0yJeeTM/Hx5/3Ozn4XRCejo895wZZCSHpxB3JG7wKswlniiwEBHxh6smxQMPmNtHAW69FV58EbLi+8YazSXeJfJUeVNExC5XTYpbbjGDiiZNYP58ePfdsAQVRU6DnNwDfLR2Nzm5B8JaBEuFuSRY1N1UROTECRg/HsaONbePpqbCqFEwYgSked/WGazlikgvQdgpzNWpca2Qj0dilwILEYkaEUkaXLAA7r3X3D4K5lbSSZPKbR91J1jBgKclCFdvkHAsQagwlwSLAgsRiQphf2LfuxeGDzfrUIBZk+Lll+FPfzK3k1oYbzCCAV9LEA7MJYieLTJDGmSpMJcEi3IsRCTiwtrNs6jInJFo1swMKpKScA4ZwvLPv+GjZl3I+emgzzyCYOYjREtvEBXmkmDRjIVIAoqmOgVhfWIvW5OifXu+eWgMD/6UQt6sTcWH+ZopCWY+QrQsQbjKkA+auRoH7gtzhbvEu8QmzViIJJi5G/LoMn4ht05Zxn2z1nLrlGV0Gb8wuLMCNoTliT0/H4YOhQ4dzKAiPR1ef525Uz/gtjWnbc+UBDMYiKYliGgr8S6xSTMWIgkkGpIEywrpE7urJsX995s5FWD2+njxRYrqnsXo8Qv9mikJZjDgWoLYm3/C7VgcmDf2cC1B9G6VRc8WmVEzoyWxRzMWIgkiWusUhOyJfetWuOoqsybF3r1nalL84x+QmRnQTEkw8xGisctscpKDTo1r0efis+nUuJaCCrFFgYVIgoiWJMGygp40eOIEjB5ttjWfP9+sSTF6NKxbBz16FB8WyExJsIMBLUFIPNFSiEiCiJYkwbKCmjQ4f75Zk+LHH83XvXqZO0DOP7/coXZmStwlu7qCgbJbZDP93CKrJQiJFwosRBJENCUJlhXwTTovz6xJMWuW+TorCyZO9FqTwmpuw6GjJ+kyfqHH+hrBDAZcSxAisUxNyEQSRJHToMv4hT5vpEtHdIvo1lNbN+miIsjOhkcfhYICSEqCwYPhmWcgI8Pn+VzJrOB+puTuKxrx1pJtasolgpqQiUgZ0ZgkWJatpMGVK+HSS81tpAUF0L49LF8Or75qKagA77kNk/6vDR9/lxd1ya5WRbKhmSQ2LYWIJJBg5wWEk2s24+CefbSd8hKZM6fhMAwziHjuObjnHkhOtv17PS1nxHJTrkg3NJPEpsBCJMHEYpLg3A15jP54I+2XzePxhVOpe/QQAJu7/Z7to54mo9E5dHAkYTWscLfkUjY4iNZkV1+isVaJJBYFFiIJKJaSBOduyGP8q5/w/LxsLt+xFoDcmmfzeM9BfHPuxbBgD7DH8hO51af5aE529SRaGppJYlOOhYh4Fcm1+qJjx/n5vhHMfXsIl+9YS2FyBV7schtX3/G6GVSUYKVhmZ1mZ7HYlCtaa5VIYtGMhUgIRVOzL39EdK1+3jxO3j2Qu3ZsA2DJuW14vNcgdtSo5/ZwX0/kdp/mY7EpV6wu30h8UWAhEiKxnkAXsbX6EjUpKgG/VK3J090G8NkFXTzWpHDxllDpTzJmrCW7xuLyjcQfBRYiIRDrCXRW+oqMnL2eamkV6HhekHpJuKlJkdfvLnrW6MFvqZVt/Sp3T+T+Ps3HUrJrtDU0k8QUUI7F2LFjcTgc3H///UEajkjsi9ZmX3b4eroHOHz8FLdN/TY4LdfL1qS45BJYsYK6b0+mWt2aHvMcPHH3RB7I03ysNOWKhVolEv/8DixWrFjBW2+9xYUXXhjM8YjEvHhIoLOzBm8ladKj/HwYMgQ6dIBVq8yaFJMmQU4OtG3r9UbpjqeEyiKngdNpUL1SBdufjTVqaCaR5tdSyG+//cZtt93GlClTGDNmTLDHJBLT4iGBzs4avF/bGA3D7OsxfLjZ0hzgtttgwgTIzCx1qKc8h7I8PZG7y3Wx+tlYFUvLNxJ//AosBg8ezLXXXkuPHj18BhaFhYUUFhYWvy4oKPDnlCIxIx4S6Hyt1Zdlqwrl1q1mB9IFC8zXTZvCG29A9+4eP1L2Rrl9/zHeW76TvQXeEyo95bqUFa3JmIGIpVolEl9sBxazZs1i9erVrFixwtLxY8eOZfTo0bYHJhKr4iGBzttWS2+8zsKcOAFjx8K4cXDyJKSmmomaDz9s/mcLYyp5oxzS7XyvT+Tecl1cqleqwKTb2gYvAVVE7OVY7Nq1i/vuu4+ZM2eSlmbtaWvUqFHk5+cX/+zatcuvgYrEinhJoPO0Vu+Nx1mYefOgdWt4+mkzqLjqKtiwAR5/3FJQ4Y6vhEqrCahJDkfU/3chEktsBRarVq1i3759tGvXjpSUFFJSUli8eDGvvvoqKSkpFBUVlftMamoq6enppX5E4l28JND1bpXF0hHd+MdfL/Uv8XHPHrjlFjOQ+PFHyMqCf/0LPv8czj8/pGOPh1wXkVhkaymke/furF+/vtR7d9xxBxdccAEjRowg2Y/OgiLxKl4S6JKTHHRuUptxN7Vm0MzVgIUqlEVFZt7Eo4/CkSOQlGRuJX36aQjTw0U85LqIxCJbgUW1atVo1apVqfeqVKlCrVq1yr0vIvGVQGe5CuXKlTBwoLl9FMyaFJMnQ9u2YR1vPOS6iMQiVd4UEcu8zsIcPgyPPWbOVBiGWZNi7Fi4+26IwGxmLPb6EIkHDsMwwlr+r6CggIyMDPLz85VvIRIPXDUpHngAfvnFfK9vX7MmxVlnRXZsxH7PFpFoYfX+rRkLEfHfDz+YNSn++1/zddOmZr+Pbt0iO64S4iXXRSRWKLAQiRFR1YLdXU2Kxx6Dv/2t1PbRaBlzPOW6iEQ7BRYiMSCqpvO/+AIGD4bcXPN1797w+uvQuHGpw6JqzCISNgF1NxWR0HOVpS5b7Cmg5l9eFDkNcnIP8NHa3eTkHjjThXXPHvjzn81AIjcX6tUza1L85z9ugworY/Z4LhGJWZqxEIlivlqw227+5YO7WYazq1Vg6m/f0nzSC5ZqUlgds9MJz3ymGQ2ReKMZC5EoZrUF+4yvtwX8tO9uluHCvB+Y/Nq9NB/3hBlUdOhg1ql4+WWPQcWMr7dZGvO974ZvFkZEwkeBhUgUs1pu+pnPvqfL+IV+35DLzjKkn/iNp+dl8+E7D9L6l1zyU6vwfJ/7KFr6NbRp4/Z3zN2QR5fxC3nms+/9GgOcqTUx+pNNWhYRiVEKLESimJ1y04E87RfPjBgGf9i0iP9OHchf1nxGEgZzWnal+4DJvHFBT5bvzC/32SKnwSsLtjLQTU6FP0q2YBeR2KMcC5Eo5qssdUmB5FzsO3KCRgd388y8N+iy4zsAcmvW57Feg8hpeFGp40qauyGPpz7eyN6CQsvnsjMmEYk9mrEQiWLeWrC749fT/vHjtJs2kblvD6bLju84kVKRFy7vx9V3vFYqqIDSMyiunAw7QYWd9FI1BxOJTQosRKKcpxbs3lh+2v/iC2jdmvqvv0hq0WkWNWpHrzsnMemyP3My5Uyb9LJt0b3t/PAmMyONN/6vDVkZaR6DDI8t2EUkJmgpRMSGSFWSdJWlnvH1NkvJkT6f9vfsMXt7/Otf5ut69Vjz4FPc8UsWOEr/Pe4advnareLO49c25/bOjUhOcpCU5FBzMJE4pcBCxKJIV5JMTnJwe+dGTF26zf9W4KdPm91HH3vsTE2KYcNg9GjapKeT7eZvLNcWHXv5D64xuYIKsNGCXURijrqbiljgyico+/8srmfq7L5tw3YzdI0F3D/texzL8uUwcCCsWWO+7tABJk8ut33UyqxMTu4Bbp2yzNJ4HV7GFC29RETEN6v3bwUWIj4UOQ26jF/ocerf9US+dES3sN0Ubc2eHD4MjzxiBhGGAdWrmw3EBgyA5GS/zu+6Jr52q6iSpkj8UNt0kSCxWv1y+baDYeugaakVuGHAu+/Cgw/CL7+Y7/XrBy+8AGedFdD5XbtV3OVJuDzQowlDujXRDIRIglFgIeKD1XyCcNdd8NoKfMsWuPdeWLjQfN2sGWRnQ9euQTu/pzwJzVKIJDYFFhK1omX93Wo9haiou3D8uLnMMX48nDwJaWlmouZDD0FqatBPZ2nmREQSigILiUqR3oFRkq/qlz53YoTL3LkwZIjZ0hzg6qvh9dfhvPNCelqvMyciknBUIEuijrsumxC5zpfeql9GRd2F3bvhT38yA4ncXKhXD95/Hz77LORBhYhIWQosJKp4q+gYyc6XnqpfZmakhXWraSmnT8Mrr0Dz5vDvf5s1Ke6/HzZvhptuKlfoSkQkHLQUIlElGndguERVPkHZmhSXXmomZ/6vJkW05KeISOJRYCFRJVp3YLhEPJ/AXU2KceMo+utdLN9xmH1rd7N9/zHeW76TvQUlKlqmp3Jrh3M4t3YVBRoiElIKLCSqxNQOjHBy1aQYPhz27TPf69cPJkxg7r4iRr+wyOtMz96CQiYu2Fr8WltCRSRUlGMhUcW1AyMRO18WOQ1ycg/w0drd5OQeOJNHsmUL9OgBffuaQcUFF5j1Kd55h7n7itwmuvoSqURYEYl/mrGQqOKtomNU7MAIEXfba8+t7GDq7vmcP+ONMzUpHn/crElRsaLfrcvBvK4OzETYni0y4+56ikjkaMZCok5U7sAIIXfba6/8aRV/n/hXzn/rZTOouPpq2LjRzK+oWBHwr3V5SSUTYUVEgkUzFhKVomoHRgiVnXU468h+nvjvFK7d8jUAeVVrMeGaQdw4Zhgdz61NyZZhwUpgjVQirIjEJwUWErUivgMjDFyzDsnOIv6y+lMe/GomVU8e57QjiRntrmNil9s4mlqZ2dOWl0u4DFYCa8IlwopISCmwEImgfUdOcPGeLTz7xSRa7vsJgDVZzXj0qsFsOqt01UxXwqVrOchXqXFfoqYUuYjEFeVYiETKoUNc+sJjzPl/D9Fy30/kp1Zh1FVDuLHfC+WCCihfedRbqXFf4jkRVkQiSzMWImFU5DRY/tMBKv7zXVpPHEPmgV8BmN2qG8/97k4OVKnu9fNlK496al1esiCW24JZqmMhIiGiwEIkTOZuyGPGtLkMm/My7XauA2B7nXP4evhoHjtcx9bvKplwaSXRdUi38+M+EVZEooMCC5EwmLfyJ7YOe4R3vp1NRedpTqRU5NXLbmFqhxs4dbgCd1/RiI+/y7O8fbRswqWvRNdESIQVkeigwEIkxIo++w8t/nIXvQ6aVS4XnteeJ3sOZFf1TMDMd/j4uzwW/60rK7YdZPC7qzl8/JTb3xXrCZdqjiYS/xRYiITK7t1w//0kv/8+9TFrUjzV4x6+aNqpVEtzV97Eqh2H6NykNuNuas2gmauL/80l1hMu3VUXVc8SkfijXSEiwXb6NLz8stnT4/33cSYnM+WS6+lxVzZfNLusVFBRkitvIh4rj7qrLgrqWSISjzRjIWGTENPg334LAwfC2rXm644dWf/oOJ5d+pvPj5bMm4inyqPeepqoZ4lI/LEVWGRnZ5Odnc327dsBaNmyJU888QRXX311KMYmcSTup8EPHTL7eLz5ptnivEYNGDcO7rqLVjjIWr/QYyErT3kT8ZJw6aunSdkttCIS22wthdSvX59x48axcuVKVq5cSbdu3ejTpw8bN24M1fgkDsT1NLhhwMyZ5rLH5Mnm67/8BTZvhrvvhqQkr4WsYj1vwgqrvUjUs0QkPtgKLK677jquueYamjZtStOmTXn22WepWrUqy5YtC9X4JMb5mgaHM5UkY87mzdC9O/TrB/v2QfPmsGgR/P3vULduqUPjMW/CKqu9SNSzRCQ++J1jUVRUxL///W+OHj1Kp06dPB5XWFhIYWFh8euCggJ/TykxKFLT4CHN5zh+HJ59Fp5/Hk6dgrQ0eOIJePDB4pbm7sRT3oQdvnqaxPoWWhEpzXZgsX79ejp16sSJEyeoWrUqH3zwAS1atPB4/NixYxk9enRAg5TYFYlpcHf5HCVLXPu6oXsNSv7zHxgyBLZtM19fcw28/jo0amRpbPGSN2GHaylo0MzVOIivLbQiUp7DMAxbc9AnT55k586dHD58mNmzZzN16lQWL17sMbhwN2PRoEED8vPzSU9PD2z0EvVycg9w6xTfS2XvDegYlBuuK5/D15faU+KopyTT5y6pTtfJY2H2bPPN+vXhlVfghhtKbR9NiJ0vfor7BF6ROFdQUEBGRobP+7ftwKKsHj160LhxY958882gDkziQ5HToMt43zsilo7oFvAN2HUuK2WxXWcqmd/gLihJdhZx+6pPeGDpP6h68jgkJ8N998FTT0G1aqV+p26cvinwEoldVu/fAdexMAyj1IyESEnhnAb3lc9RUtn6CfzvP5ccX5vdm3l23iRa7DOXPdY3aE6Lj94luc3Fxce4bpTzN+3l7a+3lzuPa+dLvCdoWpWIS0EiicZWYPHII49w9dVX06BBA44cOcKsWbNYtGgRc+fODdX4xKJofhL02No7yE/zdvM0SiaO8r//DJB+4jdGLJ7BrWu/IAmDw2lVGXfl7fzzol68m94AV6qyuxkKd+dQASgRSSS2AotffvmFfv36kZeXR0ZGBhdeeCFz586lZ8+eoRqfWBALU/Dh2BHh73bF4oDEMLhh45c8+uU0ah/LB+D9Vt0Z+7s7OFCleqljreZygApAiUhisRVYTJs2LVTjED95usFF4xR8qKfBfW1r9KRutTTScrfy3qxH6LRzPQBbazXgsV738u05rcsd6602hzcqACUiiUBNyGJYXBef8oO3CpfuOIBzKzu49O2XuPj3V9Bp53qOp6Qy/sr+XHPHq+WCiuqVKuA0DJb9dMByLkdJKgAlIolATchimHowlOcpn6MsB/C73BVMyplO0u6dAOy7ogc3Nb+Fn6tnug3WDh8/xW1Tv6V6pQq2xqQCUCKSSBRYxDD1YDijbPLq4r91ZdWOQ+w7coLt+4/x3vKd7C0wr0NmwX6eWzKNbhu/Mj9cvz68+ip1r7+eRzfu9RmUHD5+yvK4vO18ieaEWxERfymwiGHqwWDylrza5+KzARjS7XyWb91H1SnZtHhnAslHj5o1Ke6/36xJUbUqcCbJdFnuAQa/u9pWEOGOp50vsZBwKyLiDwUWMUw9GKwnryYv/5ZOAwfCd9+ZB3TqZHYjvfDCcr8zOclBUpIjoKDir53PpUeLTLezELGUcCsiYpeSN2NYvLXjLnIa5OQe4KO1u8nJPeAz6dRK8urEfy7DeffdcNllZlBRowa89RYsXeo2qHCxunxUNt8iKyONyX3b8vh1LenUuJbb5Q8l3IpIPNOMRYwLV/GpUPNnacBr8qphcMPGhTzy5dsk/a8mBf37wwsvQJ06Psdjdflo0v+1JSnJYTlPQgm3IhLvFFjEgVhvx+3v0oCnWYXG+3cxZv4bxTUpCs5rSvr0KXDFFZbHZHWZqaObWQlvlHArIvFOSyFxwlV8qs/FZ7udgo9WgSwNlJ1VSDt1goeWvMPn04eWqkmx6dNFtoIKCN0ykxJuRSTeKbCQiLKzNFCWa1bBAXTNXcH8aYMZkvMvKjpPs6DxJfS86w0+vKoflzTL9GtsrmWmzIzSN/nMjDS/EyxLjtkdB+YSUDwn3IpIfNNSiERUIEsDyUkOnrukOicGD+PqH74BYE+12jzV4x7mN+kIDgfZASavBnuZKZzdXkVEIkGBhUS0UJPfSwOnT8Orr9L1ySfht984nZTEtPbX80rnWzlWsVJQa0IEu8dJvCTcioi4o8AiwUW6UJNftThycmDQoFI1KRxvZHNhtfqMjZHk1VhPuBUR8cRhGEZYN8wXFBSQkZFBfn4+6enp4Ty1lOFpN4br1hauQk2ucYD7pYHicRw8CKNGmXUowKxJ8fzzcOedkKR0IRGRULJ6/9b/GicoX7sxDGDk7PV8/eP+kBdr8pkk2TIT3nkHLrjgTFBx++2wZQvcdZeCChGRKKKlkATlazcGnOnmGY6lEY9LA1s2Q9dbYfFi88AWLSA72/b2URERCQ896iUoOwWYXIWq5m7IC+GIytTiyKpE8mOPwkUXmUFFpUowbhysWaOgQkQkimnGIkHZKcBkYOY7jP5kEz1bZIY+wfCzz2DIENi+3Xz9+9/Da6/BueeG5HRqXy4iEjwKLBKUr90YZYWlh8WuXXDfffDBB+brBg3g1VehTx9whOZGH+ldMSIi8UZLIQnKW8lqb0LSw+LUKXjxRWje3AwqkpPhoYdg0ya4/vqQBhWDZq4ul2sSrqUfEZF4pMAigXnajeFN0HtY5ORA+/ZmIHH0qNnefPVqswtp1arBPVcJal8uIhIaCiwSXO9WWSwd0Y1//PVSqleq4PG4oPewOHgQ7r7bDCTWrYOaNWHqVPjqK7jwQp8fL3Ia5OQe4KO1u8nJPWA7AAikR4mIiHimHAshOclB5ya1GXdTa6+FqoLSw8IwzJoUDz0E+/eb791xB4wfD3XqWPoVwciLUPtyEZHQ0IyFFAtFN89SNm2Crl3N4lb790PLlrBkCbz9tq2gIhh5EWpfLiISGpqxkFLs9rCwtFXz2DEYM8bMmzh92qxJ8eST8MADULGi5bH5youwsyXWrx4lIiLikwILKcdqN09LSxKffgpDh56pSXHddeYWUj9qUtjJi/A1frUvFxEJDS2FiF98LUksWrASbrzRDCS2bzdrUnz4IXz8sd+FroKdFxHypR8RkQSkGQuxzduSRHLRae5Y9TEdJr4LJ0+YNSmGD4cnngh4+2go8iLUvlxEJLgUWIhtnpYk2v78Pc/Om0TzX7cDUNDuUtKnT4HWrQM+Z5HTwOk0qF6pAoePn3J7jL95EVaXfkRExDcFFmJb2aWG6scLGLFoBreumwfAobRqjP3dHXR+9iH6tG4Q8Pnc5XKUpbwIEZHooMBCbCteajAMbtqwkEe+nEat4wUA/Kt1D8b+7g4OVc7ghozKAZ/Llcvhq/xVpvp7iIhEBQUWYluHRjXpdOIX7p8zkUt3bQBgS+1zePSqways3zJoVTq95XK4VK9UgUm3taXjebU0UyEiEgUUWIg9x46R/Mwz/GPSBJJOn+ZYhVRe6Xwr09pfz+nklFJLEgA5uQf8Tor0tb0U4PDxUyQ5HAoqRESihAKLOGSpaJU/StSkSAJ++V0vBl7SnzVJGcWHuJYkALqMX6iy2yIiCUaBRZwJRh+NcnbuhPvuM+tQgFmT4rXXOKtPH953E8TM37TXbV6Eq8aF1RoRKrstIhJ7VCArSvnTvTNYfTSKnToFEyZAixZmUJGSAn/7m9nzo08f4MxWzT4Xn128ZTNY7chdZbc9zbUEveOqiIgETDMWAQjVkoM/sw7B7KMBwDffwMCBsH69+bpzZ8jOpqhlK/Nv/jHf7d+sstsiIolNgYWfQrLkgOftlb6WEYJ2Qz9wAEaOhKlTzdc1a5rNw26/nbmbfmG0j7yJUJXdLnuttb1URCQ6KbDwg783f18CmXUI+IZuGPD3v5tLHfv3m+/deSeMHw+1a1v+m2Oh7HbIkltFRMReYDF27FjmzJnD5s2bqVSpEpdddhnjx4+nWbNmoRpf1An6kkMJgcw6BHRD37gRBg2Cr74yX7dsCZMnQ5cugL2/OVTtyINVdjtUM00iImKylby5ePFiBg8ezLJly5g/fz6nT5+mV69eHD16NFTjizp2bv52BTLr4Fei47FjMGoUXHyxGVRUrgzPPw9r1hQHFWDvb3blRbjOWXYMELm8iKAnt4qISDm2Aou5c+dy++2307JlSy666CKmT5/Ozp07WbVqVajGF3VCWVshkFkH2zf0Tz81d3uMGwenT5u7PDZtMpdCKlQo9Xm7f3M0tiP3NesC1neriIiIZwHlWOTn5wNQs6bnae3CwkIKCwuLXxcUFARyyogLZW2FQJcRLCU6lq1Jcc458Npr8Ic/BPy3lDwu2tqRB3O3ioiIeOZ3YGEYBsOHD6dLly60atXK43Fjx45l9OjR/p4m6oQqhwCCs73S4w296LRZk+LJJ80lkJQUGD4cnngCqlTxOi5//+ZoakeuKp4iIuHhd4GsIUOGsG7dOt577z2vx40aNYr8/Pzin127dvl7yogoW6gKCGkOQTCWEcoWrUrO+QbatjWXOY4dM/Mn1qwxd3z4CCpcvy9a8yasUhVPEZHwcBiGYXtReejQoXz44YcsWbKERo0a2fpsQUEBGRkZ5Ofnk56ebvfUYeVtBwEQ0t0FQdkSeeAAjBgB06aZr2vVMpMzb78dkuzHlLG8o6LIadBl/EKfsy5LR3SL6gBJRCRSrN6/bQUWhmEwdOhQPvjgAxYtWkSTJk1CNrBI81S3wXXLye7bNqpyCEoxDJgxw5yhOGDOsuz7422suncE1c+pl7A1IFz/nYL7ZaZIJZaKiMSCkAQW9957L++++y4fffRRqdoVGRkZVKpUKagDiyTX062nZL9IPN1avqGXqUlx5PwLeKjbPXxR40wQGCuzDKEQy7MuIiKRFJLAwuFwfxOdPn06t99+e1AHFkk5uQe4dcoyn8e9N6BjWJITLd0Mjx6FZ56BF180t49WrszmgcO5Lqk9p5JL5+gm+hN6LM+6iIhEitX7t61dIX6kY0Q9dzeZcO0gsHKDs1RKe9tKGDoUduww/7FPH4pefoU73vuRU25mXQKtEBrromm3iohIvEnoXiGeZgJuuaSBpc8HsoPAyiyEr6JO9Qr2kfrHm2BLjvlmiZoUy3MPqG6DiIiEnd/bTWOdt/LOExdspXrlCvbKYwfp3CVLS3sq6pRSdJq7v53NgqmD6Lolh1NJybxzxZ+Z/++FxYWuVLdBREQiISFnLKw01XLxt1BVIOd2LVG4u+m3+3kTz34xiQv2m8sey+u34LFe97K1zrkwZzPZlSuHrMuoiIiILwkZWFgp73z42Cke6NGUWSt2ei6PHaJzu5YoSt70qx8vYOSiGdyybh4AByulM/Z3d/B+6+4YDnPiKRxdRkVERLxJyMDC6vT/ubUrs3REt1IJlu0a1mDVjkN8tHa3XzsK7CxR/P7CetSrVpHOX3/GqEXTqXnc7LMy68JejPvd7RyuVDort2zeRKDlwUVEROxKyMDCzjJByR0EczfkceULXwZUA8HWuTdt5NM5j1Fz9XIANtduyKNXDWZV/RZeP1u2y6jXpmQiIiJBlJCBhT/LBJa2fVq4UVs597mVDC59czxMnEjN06c5XakS2b/rxystr+F0su//yqK5y6iIiMS3hNwVYreplq+ESzBzG4qcvut8+Dp3j63f8p83B5L0wgtmoavrrydl82bu/XQyf7+7M9UrVfD4uz3tVinXlExBhYiIhEhCBhZgr4uonYRLf89dr2AfMz5+jilznqFS3m5o2BA+/hg++ADOOYfkJAedm9Rm3E2tcRC7XUZFRCS+JeRSiIvVZYJQ1IRwnXvFD79QbfJrXDDjZZKPH4OUFHjwQXj8cbctzZU3ISIi0SyhAwuwVt45VDUhkr/5mo6DBsGGDeYbl18O2dnQsqXXz8VL3oR6doiIxJ+EDyysCHpNiP37YcQIePtt83WtWjBhAvTvDx4avZUV6/0u1GVURCQ+JWyOhR12kz09cjrNYOKCC84EFXfdBVu2wO23Ww4qwqnIaZCTe4CP1u4mJ/eApQRVX6yWNBcRkdijGQuLAs5t2LABBg2CpUvN161bm8senTuHcNSBCcWsgp2S5loWERGJPQosbPArt+HoUXj6aXjpJXP7aJUqMHo0DBsGFTxvHY20YNXtKMvODptYXuoREUlUCixsspXb8PHHMHQo7Nxpvr7+enjlFbO9eRQL5ayCuq6KiMQ35ViEwo4d0KeP+bNzZ7maFO6EIpfBX8Gu21GSuq6KiMQ3zViUEdAWyFOnYOJEc6nj2P9qUjz0EDz2mNuaFC7h3iHh628M5ayCuq6KiMQ3BRYlBHSD/+orMzlz40bztcWaFKHKZfB2Pl9/YyCzCr6CFtcOG3VdFRGJTw7DMMI6515QUEBGRgb5+fmkp6f7/kCYeLrBu25vHm/w+/fDww/D9Onm69q14YUXLNWkKHIadBm/0OOyg+vpfemIbkG50Vr9G13j8jWrUHZcdgIz1bEQEYktVu/fmrHAz2RFp9MMJh5+GA7+L9fgrrtg3Diz4JUF4dwhYfdvtDurYHfmJV6qh4qISGlK3sSPZMX16+GKK8xA4uBBsybF0qUwZYrloALCu0PC7t9op0mbv91f1XVVRCT+xOWMhd0ETKs37gP7DsKb480EzSDUpAjnDgl/ghirswqqTSEiIi5xF1j4s3Zv5cbdc+syev5xIOz52XzjhhvMmhQNGvg91nDukPA3iLFSt0O1KURExCWulkKs9qAoWzOiXcMaZGWklesDAnB2/j6mzn6aKXPGkLrnZ7MmxSefwJw5AQUVEMQeJBa4ghhPv8mBGYD5E8SoNoWIiLjEzYyF1eREpxOe+az8jMYfLsrirSXbipMVU4pOc9eKDxn2zXtUPlWIMyWFpIcegscfh8qVgzbugHuQWBTKbZ6qTSEiIi5xs900J/cAt05Z5tdnXbfSu69oxMff5VF/w0rGzHuDZvvNUtwH23Wk5t+n+qxJEYiACnPZEKptnq7ZInAftAS7HoeIiISX1ft33AQWH63dzX2z1vr9eQfQLKWQz37+hOS/zwDgVI1aJL84gaTbfdekiCWhCmJUm0JEJH4lXB2LQNbvHYaTm9ctYNSi6SSfOGK+OWAAFcaOtbV9NFbYaqRmg2pTiIhI3AQWvtb5PWn263ae/WIS7Xd/D0B+k+ZkzJgKl10WmoHGuVAFLSIiEhviZleIlR0WJVU+eZxRX77NZ9OH0X739xytkMYzXf/Kpk++VFAhIiLip7gJLMB7tcg3/q9N8XbLnluXMX/qvdyzfA4phpPPm15Gz7uy+U/PW+nQpG5kBi8iIhIH4mYpxMXbOn+VvJ85NeQRevy4HIBdGWfxRM+BLGp8CQDZ6qopIiISkLgLLMDNOv/JkzBxIleOHg3Hj3MqOYW3LrmB1y77MycqpGnngoiISJDEZWBRypIlMGgQbNpkvr7iCpImvUHbSpmM184FERGRoIrfwOLXX82W5jNmmK9r14YJE+AvfyHZ4aBTRAcnIiISn+IqeRMApxOmToULLjgTVAwYAFu2QP/4KnQlIiISbeJrxmL9ehg4EL75xnx94YUweTJ0isz8RLjKdIuIiESL+Agsjh6Fp56CiROhqAiqVIGnn4ZhwyAlMn+iyluLiEgisr0UsmTJEq677jrq1auHw+Hgww8/DMGwbCoqgn/8w/y/N94I338Pw4cXBxVl26QXOUPbHsVq+3YREZF4Y/tx/ujRo1x00UXccccd3HTTTaEYk33p6TBlivmfr7221D+Fe+bAavv2ni0ytSwiIiJxx3ZgcfXVV3P11VeHYiyBKRNQwJmZg7I3edfMQShaeS/fdrDcTEVJBpCXf4Ll2w6qp4aIiMSdkO8KKSwspKCgoNRPOPiaOQBz5iDYyyL7jngOKvw5TkREJJaEPLAYO3YsGRkZxT8NGjQI9SkBezMHwWS1fXsgbd5FRESiVcgDi1GjRpGfn1/8s2vXrlCfEojczIGrfbun7AkHZo5Hh0Y1g3peERGRaBDywCI1NZX09PRSP+EQqZkDK+3bn1SzMxERiVPxV3nzfyIxc+Da1lp42sn9PZpyVnr59u2hSBgVERGJFrZ3hfz222/8+OOPxa+3bdvG2rVrqVmzJuecc05QBxcI18zBoJmrcUCpJM5QzBy429aamZ7KAz2acG7tKtStlka7hjVYteMQH63drUqcIiISlxyGYdjaFrFo0SK6du1a7v3+/fszw9Wbw4uCggIyMjLIz88Py7JIOOpYeNrW6goZsvu2BVAlThERiVlW79+2A4tAhTuwgND27ChyGnQZv9DjDhQHkFG5AvnHTnkNPBRciIhINLN6/46PXiE+JCc5QlaMysq21sPHTnn8N1XiFBGReBK3yZvhEuh21VDV0xAREYkEBRYBCtZ2VVXiFBGReKDAIkC+trVapUqcIiISDxRYBMhKQazqlSuoEqeIiCQEBRZB0LtVFtl925KZUb4g1uS+bRl3Y2tAlThFRCT+JcR203Dxtq01HPU0REREQkV1LKJQKOtpiIiIhJLqWEShUNbTEBERiQbKsRAREZGgiYsZCy0xiIiIRIeYDyyUFCkiIhI9YnopxNVVtGyvjr35Jxg0czVzN+RFaGQiIiKJKWYDiyKnwehPNpXrGAoUvzf6k00UOcO66UVERCShxWxgYaWrqJp7iYiIhFfMBhZWm3apuZeIiEj4xGxgYbVpl5p7iYiIhE/MBha+uoqquZeIiEj4xWxgYaWrqJp7iYiIhFfMBhbgvatodt+2qmMhIiISZjFfIKt3qyx6tshU5U0REZEoEPOBBai5l4iISLSI6aUQERERiS4KLERERCRoFFiIiIhI0CiwEBERkaBRYCEiIiJBo8BCREREgkaBhYiIiASNAgsREREJGgUWIiIiEjRhr7xpGAYABQUF4T61iIiI+Ml133bdxz0Je2Bx5MgRABo0aBDuU4uIiEiAjhw5QkZGhsd/dxi+Qo8gczqd7Nmzh2rVquFwBK9RWEFBAQ0aNGDXrl2kp6cH7ffGI10r63St7NH1sk7XyjpdK+tCea0Mw+DIkSPUq1ePpCTPmRRhn7FISkqifv36Ifv96enp+uJZpGtlna6VPbpe1ulaWadrZV2orpW3mQoXJW+KiIhI0CiwEBERkaCJm8AiNTWVJ598ktTU1EgPJerpWlmna2WPrpd1ulbW6VpZFw3XKuzJmyIiIhK/4mbGQkRERCJPgYWIiIgEjQILERERCRoFFiIiIhI0MRVYvPHGGzRq1Ii0tDTatWvHV1995fX4xYsX065dO9LS0jjvvPOYPHlymEYaeXau1aJFi3A4HOV+Nm/eHMYRR8aSJUu47rrrqFevHg6Hgw8//NDnZxL1e2X3WiXy92rs2LFccsklVKtWjbp163L99dezZcsWn59LxO+WP9cqUb9b2dnZXHjhhcXFrzp16sTnn3/u9TOR+E7FTGDxz3/+k/vvv59HH32UNWvWcPnll3P11Vezc+dOt8dv27aNa665hssvv5w1a9bwyCOPMGzYMGbPnh3mkYef3WvlsmXLFvLy8op/mjRpEqYRR87Ro0e56KKLeP311y0dn8jfK7vXyiURv1eLFy9m8ODBLFu2jPnz53P69Gl69erF0aNHPX4mUb9b/lwrl0T7btWvX59x48axcuVKVq5cSbdu3ejTpw8bN250e3zEvlNGjOjQoYMxcODAUu9dcMEFxsiRI90e//DDDxsXXHBBqffuueceo2PHjiEbY7Swe62+/PJLAzAOHToUhtFFL8D44IMPvB6TyN+rkqxcK32vzti3b58BGIsXL/Z4jL5bJivXSt+tM2rUqGFMnTrV7b9F6jsVEzMWJ0+eZNWqVfTq1avU+7169eKbb75x+5mcnJxyx1911VWsXLmSU6dOhWyskebPtXJp06YNWVlZdO/enS+//DKUw4xZifq9CoS+V5Cfnw9AzZo1PR6j75bJyrVySeTvVlFREbNmzeLo0aN06tTJ7TGR+k7FRGCxf/9+ioqKOOuss0q9f9ZZZ7F37163n9m7d6/b40+fPs3+/ftDNtZI8+daZWVl8dZbbzF79mzmzJlDs2bN6N69O0uWLAnHkGNKon6v/KHvlckwDIYPH06XLl1o1aqVx+P03bJ+rRL5u7V+/XqqVq1KamoqAwcO5IMPPqBFixZuj43Udyrs3U0DUbbNumEYXluvuzve3fvxyM61atasGc2aNSt+3alTJ3bt2sWECRO44oorQjrOWJTI3ys79L0yDRkyhHXr1rF06VKfxyb6d8vqtUrk71azZs1Yu3Ythw8fZvbs2fTv35/Fixd7DC4i8Z2KiRmL2rVrk5ycXO6Je9++feWiMZfMzEy3x6ekpFCrVq2QjTXS/LlW7nTs2JGtW7cGe3gxL1G/V8GSaN+roUOH8vHHH/Pll19Sv359r8cm+nfLzrVyJ1G+WxUrVuT888+nffv2jB07losuuohXXnnF7bGR+k7FRGBRsWJF2rVrx/z580u9P3/+fC677DK3n+nUqVO54+fNm0f79u2pUKFCyMYaaf5cK3fWrFlDVlZWsIcX8xL1exUsifK9MgyDIUOGMGfOHBYuXEijRo18fiZRv1v+XCt3EuW7VZZhGBQWFrr9t4h9p0KaGhpEs2bNMipUqGBMmzbN2LRpk3H//fcbVapUMbZv324YhmGMHDnS6NevX/HxP/30k1G5cmXjgQceMDZt2mRMmzbNqFChgvH+++9H6k8IG7vXauLEicYHH3xg/PDDD8aGDRuMkSNHGoAxe/bsSP0JYXPkyBFjzZo1xpo1awzAeOmll4w1a9YYO3bsMAxD36uS7F6rRP5eDRo0yMjIyDAWLVpk5OXlFf8cO3as+Bh9t0z+XKtE/W6NGjXKWLJkibFt2zZj3bp1xiOPPGIkJSUZ8+bNMwwjer5TMRNYGIZhTJo0yWjYsKFRsWJFo23btqW2I/Xv39+48sorSx2/aNEio02bNkbFihWNc88918jOzg7ziCPHzrUaP3680bhxYyMtLc2oUaOG0aVLF+Ozzz6LwKjDz7VtrexP//79DcPQ96oku9cqkb9X7q4TYEyfPr34GH23TP5cq0T9bt15553F/7tep04do3v37sVBhWFEz3dKbdNFREQkaGIix0JERERigwILERERCRoFFiIiIhI0CixEREQkaBRYiIiISNAosBAREZGgUWAhIiIiQaPAQkRERIJGgYWIiIgEjQILERERCRoFFiIiIhI0CixEREQkaP4/Q+joyO3U6dUAAAAASUVORK5CYII=\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "plt.scatter(train_x,train_labels)\n", "x = np.array([min(train_x),max(train_x)])\n", @@ -448,7 +596,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 44, "metadata": { "id": "HK7HPLz3Hyrl" }, @@ -481,7 +629,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 45, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -489,7 +637,31 @@ "id": "oYro9Lbr8q0M", "outputId": "78c0a6de-71bd-4eef-8819-439495b28672" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dönem 0: son toplu iş kaybı = 173.4585\n", + "Dönem 1: son toplu iş kaybı = 13.8459\n", + "Dönem 2: son toplu iş kaybı = 4.5407\n", + "Dönem 3: son toplu iş kaybı = 3.7364\n", + "Dönem 4: son toplu iş kaybı = 3.4334\n", + "Dönem 5: son toplu iş kaybı = 3.1790\n", + "Dönem 6: son toplu iş kaybı = 2.9458\n", + "Dönem 7: son toplu iş kaybı = 2.7311\n", + "Dönem 8: son toplu iş kaybı = 2.5332\n", + "Dönem 9: son toplu iş kaybı = 2.3508\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2022-11-06 18:27:07.717288: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:113] Plugin optimizer for device_type GPU is enabled.\n" + ] + } + ], "source": [ "w.assign([[10.0]])\n", "b.assign([0.0])\n", @@ -519,7 +691,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 46, "metadata": { "id": "j0OTPkGpwHl7" }, @@ -540,7 +712,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 47, "metadata": { "id": "c-_BjSHPwHl8" }, @@ -567,7 +739,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 48, "metadata": { "colab": { "base_uri": "https://localhost:8080/", @@ -576,7 +748,26 @@ "id": "tq0vFchQwHl8", "outputId": "9a5aa6a0-c92f-4d72-9e78-c0f615804bff" }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/var/folders/_l/jnklp1bj4cl95rc01tf5vx4h0000gn/T/ipykernel_36985/2482543244.py:17: UserWarning: Matplotlib is currently using module://matplotlib_inline.backend_inline, which is a non-GUI backend, so cannot show the figure.\n", + " fig.show()\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "plot_dataset(train_x, train_labels)" ] @@ -594,7 +785,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 49, "metadata": {}, "outputs": [], "source": [ @@ -609,22 +800,22 @@ "id": "SjPlpf2-wHl8" }, "source": [ - "## Training One-Layer Perceptron\n", + "## Tek Katmanlı Algılayıcı Eğitme\n", "\n", - "Let's use Tensorflow gradient computing machinery to train one-layer perceptron.\n", + "Tek katmanlı algılayıcıyı eğitmek için Tensorflow gradyan hesaplama araçlarını kullanalım.\n", "\n", - "Our neural network will have 2 inputs and 1 output. The weight matrix $W$ will have size $2\\times1$, and bias vector $b$ -- $1$.\n", + "Sinir ağımızın 2 girdisi ve 1 çıktısı olacaktır. $W$ ağırlık matrisinin boyutu $2\\times1$ ve ek girdi vektörü $b$ -- $1$ olacaktır.\n", "\n", - "Core model will be the same as in previous example, but loss function will be a logistic loss. To apply logistic loss, we need to get the value of **probability** as the output of our network, i.e. we need to bring the output $z$ to the range [0,1] using `sigmoid` activation function: $p=\\sigma(z)$.\n", + "Çekirdek model önceki örnektekiyle aynı olacaktır, ancak kayıp fonksiyonu lojistik kayıp olacaktır. Lojistik kaybı uygulamak için, ağımızın çıktısı olarak **olasılık** değerini almamız gerekiyor, yani `sigmoid` etkinleştirme işlevini kullanarak $z$ çıktısını [0,1] aralığına getirmemiz gerekiyor: $ p=\\sigma(z)$.\n", "\n", - "If we get the probability $p_i$ for the i-th input value corresponding to the actual class $y_i\\in\\{0,1\\}$, we compute the loss as $\\mathcal{L_i}=-(y_i\\log p_i + (1-y_i)log(1-p_i))$. \n", + "Gerçek $y_i\\in\\{0,1\\}$ sınıfına karşılık gelen i. girdi değeri için $p_i$ olasılığını alırsak, kaybı $\\mathcal{L_i}=-(y_i\\log p_i + (1-y_i)log(1-p_i))$ olarak hesaplarız.\n", "\n", - "In Tensorflow, both those steps (applying sigmoid and then logistic loss) can be done using one call to `sigmoid_cross_entropy_with_logits` function. Since we are training our network in minibatches, we need to average out the loss across all elements of a minibatch using `reduce_mean`: " + "Tensorflow'da, bu adımların her ikisi de (sigmoid ve ardından lojistik kayıp uygulamak), `sigmoid_cross_entropy_with_logits` işlevine bir çağrı kullanılarak yapılabilir. Ağımızı minigruplar halinde eğittiğimiz için, `reduce_mean` kullanarak bir minigrubun tüm öğelerindeki kaybın ortalamasını almamız gerekiyor:" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 50, "metadata": { "id": "kdDxWeCqwHl8" }, @@ -652,12 +843,12 @@ "id": "zAAgw0h6KzUd" }, "source": [ - "We will use minibatches of 16 elements, and do a few epochs of training:" + "16 elemandan oluşan minigrupları kullanacağız ve birkaç dönemlik eğitim yapacağız:" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 51, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -665,16 +856,40 @@ "id": "PfyqjVb2wHl8", "outputId": "308850b8-fe17-4cda-ac27-8bcda210f113" }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2022-11-06 18:27:07.945330: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:113] Plugin optimizer for device_type GPU is enabled.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dönem 0: son toplu iş kaybı = 0.6366\n", + "Dönem 1: son toplu iş kaybı = 0.7524\n", + "Dönem 2: son toplu iş kaybı = 0.7179\n", + "Dönem 3: son toplu iş kaybı = 0.6107\n", + "Dönem 4: son toplu iş kaybı = 0.6817\n", + "Dönem 5: son toplu iş kaybı = 0.6261\n", + "Dönem 6: son toplu iş kaybı = 0.6710\n", + "Dönem 7: son toplu iş kaybı = 0.5960\n", + "Dönem 8: son toplu iş kaybı = 0.6175\n", + "Dönem 9: son toplu iş kaybı = 0.5421\n" + ] + } + ], "source": [ - "# Create a tf.data.Dataset object for easy batched iteration\n", + "# Kolay toplu yineleme için bir tf.data.Dataset nesnesi oluşturun\n", "dataset = tf.data.Dataset.from_tensor_slices((train_x_norm.astype(np.float32), train_labels.astype(np.float32)))\n", "dataset = dataset.shuffle(128).batch(2)\n", "\n", "for epoch in range(10):\n", " for step, (x, y) in enumerate(dataset):\n", " loss = train_on_batch(x, tf.expand_dims(y,1))\n", - " print('Epoch %d: last batch loss = %.4f' % (epoch, float(loss)))" + " print('Dönem %d: son toplu iş kaybı = %.4f' % (epoch, float(loss)))" ] }, { @@ -683,12 +898,12 @@ "id": "s4_Atvn5K4K9" }, "source": [ - "To make sure our training worked, let's plot the line that separates two classes. Separation line is defined by the equation $W\\times x + b = 0.5$" + "Eğitimimizin işe yaradığından emin olmak için iki sınıfı ayıran doğruyu çizelim. Ayırma doğrusu $W\\times x + b = 0.5$ denklemiyle tanımlanır." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 52, "metadata": { "colab": { "base_uri": "https://localhost:8080/", @@ -697,7 +912,26 @@ "id": "PgRTHttLwHl9", "outputId": "e4407e1b-edf5-48e5-fdc2-da28120a3c6b" }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/var/folders/_l/jnklp1bj4cl95rc01tf5vx4h0000gn/T/ipykernel_36985/2482543244.py:17: UserWarning: Matplotlib is currently using module://matplotlib_inline.backend_inline, which is a non-GUI backend, so cannot show the figure.\n", + " fig.show()\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "plot_dataset(train_x,train_labels,W.numpy(),b.numpy())" ] @@ -706,12 +940,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Let's see how our model behaves on the validation data." + "Modelimizin geçerleme verileri üzerinde nasıl davrandığını görelim." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 53, "metadata": { "colab": { "base_uri": "https://localhost:8080/", @@ -720,7 +954,28 @@ "id": "oEQswfCGrmHw", "outputId": "3cf61882-60e1-4baa-8e51-0c31ea80875c" }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "pred = tf.matmul(test_x,W)+b\n", "fig,ax = plt.subplots(1,2)\n", @@ -732,12 +987,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "To compute the accuracy on the validation data, we can cast boolean type to float, and compute the mean:" + "Geçerleme verilerinin doğruluğunu hesaplamak için boole (boolean) türünü float (kayan virgüllü sayı) türüne çevirebilir ve ortalamayı hesaplayabiliriz:" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 54, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -745,7 +1000,18 @@ "id": "HUjdeIefsIsg", "outputId": "f267f505-8ba4-43ef-9ebe-df124c3c05a1" }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "tf.reduce_mean(tf.cast(((pred[0]>0.5)==test_labels),tf.float32))" ] @@ -754,12 +1020,12 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Let's explain what goes on here:\n", - "* `pred` is the values predicted by the network. They are not quite probabilities, because we have not used an activation function, but values greater than 0.5 correspond to class 1, and smaller - to class 0.\n", - "* `pred[0]>0.5` creates a boolean tensor of results, where `True` corresponds to class 1, and `False` - to class 0\n", - "* We compare that tensor to expected labels `valid_labels`, getting the boolean vector or correct predictions, where `True` corresponds to the correct prediction, and `False` - to incorrect one.\n", - "* We convert that tensor to floating point using `tf.cast`\n", - "* We then compute the mean value using `tf.reduce_mean` - that is exactly our desired accuracy " + "Burada neler olduğunu açıklayalım:\n", + "* `pred`, ağ tarafından tahmin edilen değerlerdir. Tam olasılık değiller, çünkü bir etkinleştirme işlevi kullanmadık, ancak 0.5'ten büyük değerler sınıf 1'e ve daha küçük değerler sınıf 0'a karşılık gelir.\n", + "* `pred[0]>0.5`, sonuçların bir boole tensörünü oluşturur; burada `True` sınıf 1'e ve `False` - sınıf 0'a karşılık gelir.\n", + "* Bu tensörü, `True` doğru tahmine ve `False` yanlış olana karşılık gelen beklenen boole vektörünü veya doğru tahminleri elde ederek, `valid_labels` (geçerli etiketler) etiketleriyle karşılaştırırız.\n", + "* `tf.cast` kullanarak bu tensörü kayan virgüllü sayıya dönüştürüyoruz.\n", + "* Daha sonra ortalama değeri `tf.reduce_mean` kullanarak hesaplarız - bu tam olarak bizim istediğimiz doğruluktur." ] }, { @@ -768,14 +1034,14 @@ "id": "_95qF9lY2kHp" }, "source": [ - "## Using TensorFlow/Keras Optimizers\n", + "## TensorFlow/Keras Optimize Edicileri Kullanma\n", "\n", - "Tensorflow is closely integrated with Keras, which contains a lot of useful functionality. For example, we can use different **optimization algorithms**. Let's do that, and also print obtained accuracy during training." + "Tensorflow, birçok kullanışlı işlevsellik içeren Keras ile yakından tümleştirilmiştir. Örneğin, farklı **eniyileme (optimizasyon) algoritmaları** kullanabiliriz. Bunu yapalım ve ayrıca eğitim sırasında elde edilen doğruluğu yazdıralım." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 55, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -783,7 +1049,41 @@ "id": "ups7nlV22ofp", "outputId": "aa4dff06-82b9-4b2f-ca00-33970ea2b989" }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2022-11-06 18:27:09.139136: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:113] Plugin optimizer for device_type GPU is enabled.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Dönem 0: son topluiş kaybı = 7.6350, acc = 0.5000\n", + "Dönem 1: son topluiş kaybı = 7.5484, acc = 0.5000\n", + "Dönem 2: son topluiş kaybı = 7.4980, acc = 1.0000\n", + "Dönem 3: son topluiş kaybı = 7.1606, acc = 1.0000\n", + "Dönem 4: son topluiş kaybı = 7.3958, acc = 1.0000\n", + "Dönem 5: son topluiş kaybı = 7.6092, acc = 0.5000\n", + "Dönem 6: son topluiş kaybı = 7.5016, acc = 0.5000\n", + "Dönem 7: son topluiş kaybı = 6.5573, acc = 1.0000\n", + "Dönem 8: son topluiş kaybı = 8.2018, acc = 0.5000\n", + "Dönem 9: son topluiş kaybı = 6.9698, acc = 1.0000\n", + "Dönem 10: son topluiş kaybı = 6.9775, acc = 1.0000\n", + "Dönem 11: son topluiş kaybı = 7.1308, acc = 1.0000\n", + "Dönem 12: son topluiş kaybı = 7.2976, acc = 1.0000\n", + "Dönem 13: son topluiş kaybı = 7.2084, acc = 1.0000\n", + "Dönem 14: son topluiş kaybı = 6.7165, acc = 1.0000\n", + "Dönem 15: son topluiş kaybı = 6.5100, acc = 1.0000\n", + "Dönem 16: son topluiş kaybı = 6.8080, acc = 1.0000\n", + "Dönem 17: son topluiş kaybı = 6.1264, acc = 1.0000\n", + "Dönem 18: son topluiş kaybı = 5.5414, acc = 1.0000\n", + "Dönem 19: son topluiş kaybı = 4.6002, acc = 1.0000\n" + ] + } + ], "source": [ "optimizer = tf.keras.optimizers.Adam(0.01)\n", "\n", @@ -805,7 +1105,7 @@ "for epoch in range(20):\n", " for step, (x, y) in enumerate(dataset):\n", " loss,acc = train_on_batch(tf.reshape(x,(-1,2)), tf.reshape(y,(-1,1)))\n", - " print('Epoch %d: last batch loss = %.4f, acc = %.4f' % (epoch, float(loss),acc))" + " print('Dönem %d: son toplu iş kaybı = %.4f, acc = %.4f' % (epoch, float(loss),acc))" ] }, { @@ -814,9 +1114,9 @@ "id": "dvAiaj_JndyP" }, "source": [ - "**Task 1**: Plot the graphs of loss function and accuracy on training and validation data during training\n", + "**Görev 1**: Eğitim sırasında kayıp fonksiyonu ve eğitim ve geçerleme verileri üzerindeki doğruluk grafiklerini çizin.\n", "\n", - "**Task 2**: Try to solve MNIST classificiation problem using this code. Hint: use `softmax_crossentropy_with_logits` or `sparse_softmax_cross_entropy_with_logits` as loss function. In the first case you need to feed expected output values in *one hot encoding*, and in the second case - as integer class number." + "**Görev 2**: Bu kodu kullanarak MNIST sınıflandırma problemini çözmeye çalışın. İpucu: Kayıp işlevi olarak `softmax_crossentropy_with_logits` veya `sparse_softmax_cross_entropy_with_logits` kullanın. İlk durumda, beklenen çıktı değerlerini *birebir kodlanmış* ve ikinci durumda, tamsayı sınıf numarası olarak beslemeniz gerekir." ] }, { @@ -826,31 +1126,31 @@ }, "source": [ "## Keras\n", - "### Deep Learning for Humans\n", + "### İnsanlar için Derin Öğrenme\n", "\n", - "* Keras is a library originally developed by Francois Chollet to work on top of Tensorflow, CNTK and Theano, to unify all lower-level frameworks. You can still install Keras as a separate library, but it is not advised to do so. \n", - "* Now Keras is included as part of Tensorflow library\n", - "* You can easily construct neural networks from layers\n", - "* Contains `fit` function to do all training, plus a lot of functions to work with typical data (pictures, text, etc.)\n", - "* A lot of samples\n", - "* Functional API vs. Sequential API\n", + "* Keras, başlangıçta Francois Chollet tarafından Tensorflow, CNTK ve Theano üzerinde çalışmak ve tüm alt seviye çerçeveleri birleştirmek için geliştirilmiş bir kütüphanedir. Hala Keras'ı ayrı bir kitaplık olarak kurabilirsiniz, ancak bunu yapmanız önerilmez.\n", + "* Artık Keras, Tensorflow kütüphanesinin bir parçası olarak dahil edilmiştir.\n", + "* Katmanlardan kolayca sinir ağları oluşturabilirsiniz.\n", + "* Tüm eğitimi yapmak için `fit` işlevinin yanı sıra tipik verilerle (resimler, metinler, vb.) çalışmak için birçok işlev içerir. \n", + "* Çok sayıda örnek vardır.\n", + "* İşlevsel API ve Ardışık API içerir.\n", "\n", - "Keras provides higher level abstractions for neural networks, allowing us to operate in terms of layers, models and optimizers, and not in terms of tensors and gradients. \n", + "Keras, sinir ağları için daha yüksek düzeyde soyutlamalar sağlayarak, tensörler ve gradyanlar açısından değil, katmanlar, modeller ve optimize ediciler açısından çalışmamıza olanak tanır.\n", "\n", - "Classical Deep Learning book from the creator of Keras: [Deep Learning with Python](https://www.manning.com/books/deep-learning-with-python)\n", + "Keras'ın yaratıcısından Klasik Derin Öğrenme kitabına bakabilirsiniz: [Python ile Derin Öğrenme](https://www.manning.com/books/deep-learning-with-python)\n", "\n", - "### Functional API\n", + "### İşlevsel API\n", "\n", - "When using functional API, we define the **input** to the network as `keras.Input`, and then compute the **output** by passing it through a series of computations. Finally, we define **model** as an object that transforms input into output.\n", + "İşlevsel API'yi kullanırken, ağa **girdi**yi `keras.Input` olarak tanımlarız ve ardından bir dizi hesaplamadan geçirerek **çıktı**yı hesaplarız. Son olarak, **model**i girdiyi çıktıya dönüştüren bir nesne olarak tanımlarız.\n", "\n", - "Once we obtained **model** object, we need to:\n", - "* **Compile it**, by specifying loss function and the optimizer that we want to use with our model\n", - "* **Train it** by calling `fit` function with the training (and possibly validation) data" + "**Model** nesnesini elde ettikten sonra şunları yapmamız gerekir:\n", + "* Kayıp işlevini ve modelimizde kullanmak istediğimiz optimize ediciyi belirterek **derlemek**, \n", + "* Eğitim (ve muhtemelen geçerleme) verileriyle `fit` işlevini çağırarak **eğitmek**." ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 56, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -858,7 +1158,71 @@ "id": "QJWplVfy34Eo", "outputId": "9be976f2-4f9a-495c-bddc-a7f9ec30989a" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Model: \"model_1\"\n", + "_________________________________________________________________\n", + " Layer (type) Output Shape Param # \n", + "=================================================================\n", + " input_2 (InputLayer) [(None, 2)] 0 \n", + " \n", + " dense_3 (Dense) (None, 1) 3 \n", + " \n", + "=================================================================\n", + "Total params: 3\n", + "Trainable params: 3\n", + "Non-trainable params: 0\n", + "_________________________________________________________________\n", + "Epoch 1/15\n", + "7/9 [======================>.......] - ETA: 0s - loss: 0.7315 - accuracy: 0.4107" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2022-11-06 18:27:11.824716: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:113] Plugin optimizer for device_type GPU is enabled.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "9/9 [==============================] - 0s 16ms/step - loss: 0.7176 - accuracy: 0.5000\n", + "Epoch 2/15\n", + "9/9 [==============================] - 0s 8ms/step - loss: 0.6572 - accuracy: 0.7429\n", + "Epoch 3/15\n", + "9/9 [==============================] - 0s 8ms/step - loss: 0.6184 - accuracy: 0.9143\n", + "Epoch 4/15\n", + "9/9 [==============================] - 0s 9ms/step - loss: 0.5828 - accuracy: 0.9429\n", + "Epoch 5/15\n", + "9/9 [==============================] - 0s 8ms/step - loss: 0.5538 - accuracy: 0.8571\n", + "Epoch 6/15\n", + "9/9 [==============================] - 0s 9ms/step - loss: 0.5182 - accuracy: 0.9143\n", + "Epoch 7/15\n", + "9/9 [==============================] - 0s 7ms/step - loss: 0.4968 - accuracy: 0.9429\n", + "Epoch 8/15\n", + "9/9 [==============================] - 0s 6ms/step - loss: 0.4673 - accuracy: 0.9571\n", + "Epoch 9/15\n", + "9/9 [==============================] - 0s 7ms/step - loss: 0.4494 - accuracy: 0.9286\n", + "Epoch 10/15\n", + "9/9 [==============================] - 0s 7ms/step - loss: 0.4311 - accuracy: 0.9286\n", + "Epoch 11/15\n", + "9/9 [==============================] - 0s 7ms/step - loss: 0.4169 - accuracy: 0.9429\n", + "Epoch 12/15\n", + "9/9 [==============================] - 0s 6ms/step - loss: 0.4003 - accuracy: 0.9286\n", + "Epoch 13/15\n", + "9/9 [==============================] - 0s 7ms/step - loss: 0.3950 - accuracy: 0.9000\n", + "Epoch 14/15\n", + "9/9 [==============================] - 0s 7ms/step - loss: 0.3740 - accuracy: 0.9286\n", + "Epoch 15/15\n", + "9/9 [==============================] - 0s 6ms/step - loss: 0.3659 - accuracy: 0.9429\n" + ] + } + ], "source": [ "inputs = tf.keras.Input(shape=(2,))\n", "z = tf.keras.layers.Dense(1,kernel_initializer='glorot_uniform',activation='sigmoid')(inputs)\n", @@ -871,7 +1235,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 57, "metadata": { "colab": { "base_uri": "https://localhost:8080/", @@ -880,7 +1244,28 @@ "id": "K2Kf60IrZcqs", "outputId": "b60b868d-3562-4715-f5d5-1f9764e45f09" }, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "plt.plot(h.history['accuracy'])" ] @@ -891,14 +1276,14 @@ "id": "iJruFXmb_dur" }, "source": [ - "### Sequential API\n", + "### Ardışık API\n", "\n", - "Alternatively, we can start thinking of a model as of a **sequence of layers**, and just specify those layers by adding them to the `model` object:" + "Alternatif olarak, bir modeli **katmanlar dizisi** olarak düşünmeye başlayabilir ve bu katmanları `model` nesnesine ekleyerek belirtebiliriz:" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 58, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -906,7 +1291,95 @@ "id": "iWc_kSr8_YXt", "outputId": "345dbe65-629d-468f-ed75-1d412c966340" }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Model: \"sequential_1\"\n", + "_________________________________________________________________\n", + " Layer (type) Output Shape Param # \n", + "=================================================================\n", + " dense_4 (Dense) (None, 5) 15 \n", + " \n", + " dense_5 (Dense) (None, 1) 6 \n", + " \n", + "=================================================================\n", + "Total params: 21\n", + "Trainable params: 21\n", + "Non-trainable params: 0\n", + "_________________________________________________________________\n", + "Epoch 1/15\n", + "5/9 [===============>..............] - ETA: 0s - loss: 0.6960 - accuracy: 0.4500" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2022-11-06 18:27:13.289710: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:113] Plugin optimizer for device_type GPU is enabled.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "9/9 [==============================] - 1s 39ms/step - loss: 0.6682 - accuracy: 0.5143 - val_loss: 0.7002 - val_accuracy: 0.4667\n", + "Epoch 2/15\n", + "8/9 [=========================>....] - ETA: 0s - loss: 0.6642 - accuracy: 0.5312" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2022-11-06 18:27:13.634944: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:113] Plugin optimizer for device_type GPU is enabled.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "9/9 [==============================] - 0s 11ms/step - loss: 0.6553 - accuracy: 0.5571 - val_loss: 0.5634 - val_accuracy: 1.0000\n", + "Epoch 3/15\n", + "9/9 [==============================] - 0s 12ms/step - loss: 0.5889 - accuracy: 0.7571 - val_loss: 0.5148 - val_accuracy: 1.0000\n", + "Epoch 4/15\n", + "9/9 [==============================] - 0s 12ms/step - loss: 0.5161 - accuracy: 0.9286 - val_loss: 0.4654 - val_accuracy: 0.8667\n", + "Epoch 5/15\n", + "9/9 [==============================] - 0s 9ms/step - loss: 0.4707 - accuracy: 0.8429 - val_loss: 0.3745 - val_accuracy: 1.0000\n", + "Epoch 6/15\n", + "9/9 [==============================] - 0s 10ms/step - loss: 0.4001 - accuracy: 0.9143 - val_loss: 0.2882 - val_accuracy: 1.0000\n", + "Epoch 7/15\n", + "9/9 [==============================] - 0s 10ms/step - loss: 0.3562 - accuracy: 0.9143 - val_loss: 0.2326 - val_accuracy: 1.0000\n", + "Epoch 8/15\n", + "9/9 [==============================] - 0s 9ms/step - loss: 0.3034 - accuracy: 0.9286 - val_loss: 0.1751 - val_accuracy: 1.0000\n", + "Epoch 9/15\n", + "9/9 [==============================] - 0s 10ms/step - loss: 0.2728 - accuracy: 0.9286 - val_loss: 0.1492 - val_accuracy: 1.0000\n", + "Epoch 10/15\n", + "9/9 [==============================] - 0s 9ms/step - loss: 0.2558 - accuracy: 0.9286 - val_loss: 0.1248 - val_accuracy: 1.0000\n", + "Epoch 11/15\n", + "9/9 [==============================] - 0s 9ms/step - loss: 0.2340 - accuracy: 0.9286 - val_loss: 0.1160 - val_accuracy: 1.0000\n", + "Epoch 12/15\n", + "9/9 [==============================] - 0s 9ms/step - loss: 0.2329 - accuracy: 0.9286 - val_loss: 0.0965 - val_accuracy: 1.0000\n", + "Epoch 13/15\n", + "9/9 [==============================] - 0s 9ms/step - loss: 0.2105 - accuracy: 0.9571 - val_loss: 0.1220 - val_accuracy: 1.0000\n", + "Epoch 14/15\n", + "9/9 [==============================] - 0s 10ms/step - loss: 0.2151 - accuracy: 0.9429 - val_loss: 0.0964 - val_accuracy: 1.0000\n", + "Epoch 15/15\n", + "9/9 [==============================] - 0s 11ms/step - loss: 0.2091 - accuracy: 0.9429 - val_loss: 0.0808 - val_accuracy: 1.0000\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 58, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "model = tf.keras.models.Sequential()\n", "model.add(tf.keras.layers.Dense(5,activation='sigmoid',input_shape=(2,)))\n", @@ -923,22 +1396,22 @@ "id": "BmHNhUU8bqEX" }, "source": [ - "## Classification Loss Functions\n", + "## Sınıflandırma Kaybı Fonksiyonları\n", "\n", - "It is important to correctly specify loss function and activation function on the last layer of the network. The main rules are the following:\n", - "* If the network has one output (**binary classification**), we use **sigmoid** activation function, for **multiclass classification** - **softmax**\n", - "* If the output class is represented as one-hot-encoding, the loss function will be **cross entropy loss** (categorical cross-entropy), if the output contains class number - **sparse categorical cross-entropy**. For **binary classification** - use **binary cross-entropy** (same as **log loss**)\n", - "* **Multi-label classification** is when we can have an object belonging to several classes at the same time. In this case, we need to encode labels using one-hot encoding, and use **sigmoid** as activation function, so that each class probability is between 0 and 1.\n", + "Ağın son katmanında kayıp fonksiyonunu ve etkinleştirme fonksiyonunu doğru bir şekilde belirlemek önemlidir. Ana kurallar şunlardır:\n", + "* Ağın bir çıktısı varsa (**ikili sınıflandırma**) **sigmoid**, **çok sınıflı sınıflandırma** içinse **softmax** etkinleştirme işlevini kullanırız.\n", + "* Kayıp işlevi, çıktı sınıfı birebir kodlama olarak temsil edilirse **çapraz entropi kaybı** (kategorik çapraz entropi), çıktı sınıf numarası içeriyorsa **seyrek kategorik çapraz entropi** olacaktır. **İkili sınıflandırma** için **ikili çapraz entropi** kullanın (**logaritmik kayıp** ile aynıdır).\n", + "* **Çok etiketli sınıflandırma**, aynı anda birkaç sınıfa ait bir nesneye sahip olabileceğimiz zamandır. Bu durumda, etiketleri birebir kodlama kullanarak kodlamamız ve etkinleştirme fonksiyonu olarak **sigmoid** kullanmamız gerekir, böylece her sınıf olasılığı 0 ile 1 arasında olur.\n", "\n", - "| Classification | Label Format | Activation Function | Loss |\n", + "| Sınıflandırma | Etiket Formatı | Etkinleştirme Fonksiyonu | Kayıp |\n", "|---------------|-----------------------|-----------------|----------|\n", - "| Binary | Probability of 1st class | sigmoid | binary crossentropy |\n", - "| Binary | One-hot encoding (2 outputs) | softmax | categorical crossentropy |\n", - "| Multiclass | One-hot encoding | softmax | categorical crossentropy |\n", - "| Multiclass | Class Number | softmax | sparse categorical crossentropy |\n", - "| Multilabel | One-hot encoding | sigmoid | categorical crossentropy |\n", + "| İkili | 1. sınıf olasılığı | sigmoid | ikili çapraz entropi |\n", + "| İkili | Bire bir kodlama (2 çıktılı) | softmax | kategorik çapraz entropi |\n", + "| Çok sınıflı | Bire bir kodlama | softmaks | kategorik çapraz entropi |\n", + "| Çok sınıflı | Sınıf sayısı | softmaks | seyrek kategorik çapraz entropi |\n", + "| Çok etiketli | Bire bir kodlama | sigmoid | kategorik çapraz entropi |\n", "\n", - "> Binary classification can also be handled as a special case of multi-class classification with two outputs. In this case, we need to use **softmax**.\n" + "> İkili sınıflandırma, çok sınıflı sınıflandırmanın iki çıktılı özel bir durumu olarak da ele alınabilir. Bu durumda **softmax** kullanmamız gerekir.\n" ] }, { @@ -947,12 +1420,12 @@ "id": "gZ-kWx84bMDH" }, "source": [ - "**Task 3**: \n", - "Use Keras to train MNIST classifier:\n", - "* Notice that Keras contains some standard datasets, including MNIST. To use MNIST from Keras, you only need a couple of lines of code (more information [here](https://www.tensorflow.org/api_docs/python/tf/keras/datasets/mnist))\n", - "* Try several network configuration, with different number of layers/neurons, activation functions.\n", + "**Görev 3**:\n", + "MNIST sınıflandırıcısını eğitmek için Keras'ı kullanın:\n", + "* Keras'ın MNIST dahil bazı standart veri kümesi içerdiğine dikkat edin. MNIST'i Keras'tan kullanmak için yalnızca birkaç satır koda ihtiyacınız vardır (daha fazla bilgi [burada](https://www.tensorflow.org/api_docs/python/tf/keras/datasets/mnist))\n", + "* Farklı sayıda katman/nöron, etkinleştirme işlevleriyle birkaç ağ yapılandırması deneyin.\n", "\n", - "What is the best accuracy you were able to achieve?" + "Ulaşabildiğiniz en iyi doğruluk nedir?" ] }, { @@ -961,15 +1434,15 @@ "id": "yX6hqiafwHl9" }, "source": [ - "## Takeaways\n", + "## ANA Fikirler\n", "\n", - "* Tensorflow allows you to operate on tensors at low level, you have most flexibility.\n", - "* There are convenient tools to work with data (`td.Data`) and layers (`tf.layers`)\n", - "* For beginners/typical tasks, it is recommended to use **Keras**, which allows to construct networks from layers\n", - "* If non-standard architecture is needed, you can implement your own Keras layer, and then use it in Keras models\n", - "* It is a good idea to look at PyTorch as well and compare approaches. \n", + "* Tensorflow, tensörler üzerinde düşük seviyede çalışmanıza izin verir, aşırı esnekliğe sahip olursunuz.\n", + "* Veri (`td.Data`) ve katmanlar (`tf.layers`) ile çalışmak için uygun araçlar vardır.\n", + "* Yeni başlayanlar/tipik görevler için, katmanlardan ağ oluşturmaya izin veren **Keras** kullanılması önerilir.\n", + "* Standart dışı mimari gerekiyorsa kendi Keras katmanınızı uygulayabilir ve ardından Keras modellerinde kullanabilirsiniz.\n", + "* PyTorch'a da bakmak ve yaklaşımları karşılaştırmak iyi bir fikirdir.\n", "\n", - "A good sample notebook from the creator of Keras on Keras and Tensorflow 2.0 can be found [here](https://t.co/k694J95PI8)." + "Keras yaratıcısından Keras ve Tensorflow 2.0'nin üzerine güzel bir örnek not defterini [burada](https://t.co/k694J95PI8) bulabilirsiniz." ] } ], From c487052f4c462f12cfeef10364d54ade3d7f4ef3 Mon Sep 17 00:00:00 2001 From: semercim Date: Sun, 6 Nov 2022 19:39:59 +0100 Subject: [PATCH 33/38] WIP: the Turkish translation of lesson 5 --- .../translations/IntroKeras.tr.ipynb | 407 ++++++++++++++++-- 1 file changed, 383 insertions(+), 24 deletions(-) diff --git a/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKeras.tr.ipynb b/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKeras.tr.ipynb index 149ba11f..51c93bfe 100644 --- a/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKeras.tr.ipynb +++ b/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKeras.tr.ipynb @@ -35,7 +35,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -44,7 +44,16 @@ "outputId": "2aa591b4-b647-441f-9c8e-4e0da2d517a0", "tags": [] }, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tensorflow sürümü = 2.9.0\n", + "Keras sürümü\" = 2.9.0\n" + ] + } + ], "source": [ "import tensorflow as tf\n", "from tensorflow import keras\n", @@ -86,7 +95,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 2, "metadata": { "id": "j0OTPkGpwHl7" }, @@ -107,7 +116,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": { "id": "c-_BjSHPwHl8" }, @@ -134,7 +143,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "metadata": { "colab": { "base_uri": "https://localhost:8080/", @@ -143,7 +152,26 @@ "id": "tq0vFchQwHl8", "outputId": "9a5aa6a0-c92f-4d72-9e78-c0f615804bff" }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/var/folders/_l/jnklp1bj4cl95rc01tf5vx4h0000gn/T/ipykernel_36984/3412616912.py:17: UserWarning: Matplotlib is currently using module://matplotlib_inline.backend_inline, which is a non-GUI backend, so cannot show the figure.\n", + " fig.show()\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "%matplotlib inline\n", "plot_dataset(train_x, train_labels)" @@ -162,7 +190,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ @@ -183,9 +211,44 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 6, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Metal device set to: Apple M1 Pro\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2022-11-06 19:39:09.553986: I tensorflow/core/common_runtime/pluggable_device/pluggable_device_factory.cc:305] Could not identify NUMA node of platform GPU ID 0, defaulting to 0. Your kernel may not have been built with NUMA support.\n", + "2022-11-06 19:39:09.554333: I tensorflow/core/common_runtime/pluggable_device/pluggable_device_factory.cc:271] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 0 MB memory) -> physical PluggableDevice (device: 0, name: METAL, pci bus id: )\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Model: \"sequential\"\n", + "_________________________________________________________________\n", + " Layer (type) Output Shape Param # \n", + "=================================================================\n", + " dense (Dense) (None, 1) 3 \n", + " \n", + " activation (Activation) (None, 1) 0 \n", + " \n", + "=================================================================\n", + "Total params: 3\n", + "Trainable params: 3\n", + "Non-trainable params: 0\n", + "_________________________________________________________________\n" + ] + } + ], "source": [ "model = keras.models.Sequential()\n", "model.add(keras.Input(shape=(2,)))\n", @@ -209,9 +272,27 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 7, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Model: \"sequential_1\"\n", + "_________________________________________________________________\n", + " Layer (type) Output Shape Param # \n", + "=================================================================\n", + " dense_1 (Dense) (None, 1) 3 \n", + " \n", + "=================================================================\n", + "Total params: 3\n", + "Trainable params: 3\n", + "Non-trainable params: 0\n", + "_________________________________________________________________\n" + ] + } + ], "source": [ "model = keras.models.Sequential()\n", "model.add(keras.layers.Dense(1,input_shape=(2,),activation='sigmoid'))\n", @@ -232,7 +313,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ @@ -252,9 +333,74 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 1/10\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2022-11-06 19:39:10.066835: W tensorflow/core/platform/profile_utils/cpu_utils.cc:128] Failed to get CPU frequency: 0 Hz\n", + "2022-11-06 19:39:10.202253: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:113] Plugin optimizer for device_type GPU is enabled.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "70/70 [==============================] - 2s 8ms/step - loss: 0.7261 - acc: 0.4714 - val_loss: 0.6578 - val_acc: 0.6667\n", + "Epoch 2/10\n", + "11/70 [===>..........................] - ETA: 0s - loss: 0.6590 - acc: 0.6364" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2022-11-06 19:39:11.498184: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:113] Plugin optimizer for device_type GPU is enabled.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "70/70 [==============================] - 0s 6ms/step - loss: 0.6363 - acc: 0.7000 - val_loss: 0.5965 - val_acc: 0.7667\n", + "Epoch 3/10\n", + "70/70 [==============================] - 0s 6ms/step - loss: 0.5643 - acc: 0.7857 - val_loss: 0.5456 - val_acc: 0.7667\n", + "Epoch 4/10\n", + "70/70 [==============================] - 0s 6ms/step - loss: 0.5084 - acc: 0.8143 - val_loss: 0.4868 - val_acc: 0.9333\n", + "Epoch 5/10\n", + "70/70 [==============================] - 0s 6ms/step - loss: 0.4752 - acc: 0.8857 - val_loss: 0.4628 - val_acc: 0.9000\n", + "Epoch 6/10\n", + "70/70 [==============================] - 0s 5ms/step - loss: 0.4419 - acc: 0.9286 - val_loss: 0.4313 - val_acc: 0.9000\n", + "Epoch 7/10\n", + "70/70 [==============================] - 0s 5ms/step - loss: 0.4128 - acc: 0.9143 - val_loss: 0.4014 - val_acc: 0.9000\n", + "Epoch 8/10\n", + "70/70 [==============================] - 0s 5ms/step - loss: 0.3960 - acc: 0.9143 - val_loss: 0.3805 - val_acc: 0.9333\n", + "Epoch 9/10\n", + "70/70 [==============================] - 0s 5ms/step - loss: 0.3779 - acc: 0.9143 - val_loss: 0.3646 - val_acc: 0.9333\n", + "Epoch 10/10\n", + "70/70 [==============================] - 0s 6ms/step - loss: 0.3641 - acc: 0.9286 - val_loss: 0.3525 - val_acc: 0.9000\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "model.fit(x=train_x_norm,y=train_labels,validation_data=(test_x_norm,test_labels),epochs=10,batch_size=1)" ] @@ -276,7 +422,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": { "colab": { "base_uri": "https://localhost:8080/", @@ -285,7 +431,26 @@ "id": "PgRTHttLwHl9", "outputId": "e4407e1b-edf5-48e5-fdc2-da28120a3c6b" }, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/var/folders/_l/jnklp1bj4cl95rc01tf5vx4h0000gn/T/ipykernel_36984/3412616912.py:17: UserWarning: Matplotlib is currently using module://matplotlib_inline.backend_inline, which is a non-GUI backend, so cannot show the figure.\n", + " fig.show()\n" + ] + }, + { + "data": { + "image/png": "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TTfhgQcecPZQuu2DDz7AY489hl//+tc4ePAgpk2bhnnz5iE7O9vZQ7OL6upqjB49Gq+88oqzh2J3W7duxUMPPYTdu3dj48aNaGhowOzZs1FdXe3sodlFUlIS/vSnPyEjIwMZGRm4/PLLsWDBAhw9etTZQ7O7ffv2YcWKFRg1apSzh2I/qujQ2rVr1SFDhqhHjx5VAagHDx509pAc5vPPP1cVRVGNRqOzh+IQf/7zn9V+/fo5exh2t3LlSjU8PNzZw+iWiRMnqvfff3+L7w0ZMkT95S9/6aQROQ4Adc2aNc4ehsMUFhaqANStW7c6eygOExkZqb755pvOHoZdVVZWqgMHDlQ3btyozpgxQ3300UedPSS7kAxOBy5evIh7770X//73vxEUFOTs4ThUSUkJ3n33XUyZMgV+fn7OHo5DlJeXIyoqytnDEK0YjUbs378fs2fPbvH92bNnY9euXU4aleiq8vJyAPDI95rJZMLq1atRXV2N9PR0Zw/Hrh566CFcc801uPLKK509FLuSAKcdqqrirrvuwv3334+0tDRnD8dhfvGLXyA4OBjR0dHIzs7G559/7uwhOcSZM2fw8ssv4/7773f2UEQrRUVFMJlMiIuLa/H9uLg4FBQUOGlUoitUVcUTTzyBqVOnYsSIEc4ejt1kZmYiJCQEer0e999/P9asWYNhw4Y5e1h2s3r1ahw4cADLli1z9lDszqsCnD/84Q9QFKXTS0ZGBl5++WVUVFTg6aefdvaQbWLt49M89dRTOHjwIDZs2AAfHx/ceeedUF24sbWtjw8A8vLyMHfuXNx0001YunSpk0Zuna48Pk+hKEqLr1VVbfM94doefvhhHD58GO+//76zh2JXgwcPxqFDh7B792488MADWLx4MY4dO+bsYdlFTk4OHn30UfznP/9BQECAs4djd161VUNRURGKioo6vU7fvn1x66234ssvv2zxAWsymeDj44Of/vSn+Ne//uXooXaJtY+vvRfyhQsXkJycjF27drls+tXWx5eXl4dZs2Zh0qRJWLVqFXQ6147nu/L8rVq1Co899hjKysocPDrHMBqNCAoKwkcffYTrr7++8fuPPvooDh06hK1btzpxdPanKArWrFmDhQsXOnsodvXII4/gs88+w7Zt29CvXz9nD8ehrrzySgwYMADLly939lC67bPPPsP1118PHx+fxu+Z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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "plot_dataset(train_x,train_labels,model.layers[0].weights[0],model.layers[0].weights[1])" ] @@ -305,9 +470,63 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 1/10\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2022-11-06 19:39:15.640677: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:113] Plugin optimizer for device_type GPU is enabled.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "70/70 [==============================] - 1s 7ms/step - loss: 0.7444 - acc: 0.3714 - val_loss: 0.7277 - val_acc: 0.3667\n", + "Epoch 2/10\n", + "11/70 [===>..........................] - ETA: 0s - loss: 0.6793 - acc: 0.6364" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2022-11-06 19:39:16.060911: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:113] Plugin optimizer for device_type GPU is enabled.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "70/70 [==============================] - 0s 6ms/step - loss: 0.7116 - acc: 0.4714 - val_loss: 0.7075 - val_acc: 0.4333\n", + "Epoch 3/10\n", + "70/70 [==============================] - 0s 5ms/step - loss: 0.6860 - acc: 0.5143 - val_loss: 0.6813 - val_acc: 0.5000\n", + "Epoch 4/10\n", + "70/70 [==============================] - 0s 5ms/step - loss: 0.6644 - acc: 0.5857 - val_loss: 0.6614 - val_acc: 0.6000\n", + "Epoch 5/10\n", + "70/70 [==============================] - 0s 5ms/step - loss: 0.6436 - acc: 0.7286 - val_loss: 0.6447 - val_acc: 0.7333\n", + "Epoch 6/10\n", + "70/70 [==============================] - 0s 5ms/step - loss: 0.6234 - acc: 0.7286 - val_loss: 0.6256 - val_acc: 0.8000\n", + "Epoch 7/10\n", + "70/70 [==============================] - 0s 5ms/step - loss: 0.6050 - acc: 0.8286 - val_loss: 0.6073 - val_acc: 0.8333\n", + "Epoch 8/10\n", + "70/70 [==============================] - 0s 6ms/step - loss: 0.5842 - acc: 0.7571 - val_loss: 0.5868 - val_acc: 0.9000\n", + "Epoch 9/10\n", + "70/70 [==============================] - 0s 6ms/step - loss: 0.5720 - acc: 0.9429 - val_loss: 0.5778 - val_acc: 0.8333\n", + "Epoch 10/10\n", + "70/70 [==============================] - 0s 6ms/step - loss: 0.5568 - acc: 0.9143 - val_loss: 0.5615 - val_acc: 0.9000\n" + ] + } + ], "source": [ "model = keras.models.Sequential([\n", " keras.layers.Dense(1,input_shape=(2,),activation='sigmoid')])\n", @@ -317,9 +536,30 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAiMAAAGdCAYAAADAAnMpAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjQuMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8rg+JYAAAACXBIWXMAAA9hAAAPYQGoP6dpAABYxklEQVR4nO3dd3gU5frG8W96AiShh9A7BEJLgghIE0TpoAIK0lFQURErYjnw08M5tmMF6c0GAioqlgDSRSBSBemQEAIhCaQQ0nbn98cAihRJSDK72ftzXblOZpjZfWL07M07z/u+boZhGIiIiIhYxN3qAkRERMS1KYyIiIiIpRRGRERExFIKIyIiImIphRERERGxlMKIiIiIWEphRERERCylMCIiIiKW8rS6gBtht9s5ceIE/v7+uLm5WV2OiIiI3ADDMEhNTaVixYq4u197/MMpwsiJEyeoUqWK1WWIiIhIHsTExFC5cuVr/rlThBF/f3/A/GECAgIsrkZERERuREpKClWqVLn0OX4tThFGLj6aCQgIUBgRERFxMv/UYqEGVhEREbGUwoiIiIhYSmFERERELKUwIiIiIpZSGBERERFLKYyIiIiIpRRGRERExFIKIyIiImIphRERERGxlMKIiIiIWEphRERERCylMCIiIiKWUhgRERHJg6hjZ/jw54Psjk3GMAyry3FqTrFrr4iIiCNJz8ph5LwtnEnP5o0f91GtTDG6NgqmW6NgGlYM+MddauVyCiMiIiK5tGhLDGfSs/H38STLZudYYjpTVx9i6upDVCtTjC6hwXRvrGByoxRGREREciHHZmfGuiMAPNulPnc3q8TKP+JZvjOOn/fFcywxnY/WHOKjNYeoWvrPEZPQSgom1+JmOMGDrpSUFAIDA0lOTiYgIMDqckRExIV9vT2WJz7fTpni3mx4/nZ8vTwu/dm5zBxW/RHP8l1mMMnItl/6s6qli9GlUQW6N6roMsHkRj+/FUZERERukGEYdH1vPXvjUnjqjro81rHONa89l5nDz/vMYLLqj8uDSZXSfpdGTBpVCiyywURhREREJJ+t3X+awbM34+flwS/jb6dkMe8bui89688Rk6sGk9BgujUuesFEYURERCSfDZixiY2HEhnWujqv9GiYp9dIz8rh5z9O892uE1cEk8ql/OjWKJiujYJpXNn5g4nCiIiISD7aefwsPT/Y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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], "source": [ "plt.plot(hist.history['acc'])\n", "plt.plot(hist.history['val_acc'])" @@ -350,9 +590,63 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 1/10\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2022-11-06 19:39:20.200324: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:113] Plugin optimizer for device_type GPU is enabled.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "70/70 [==============================] - 2s 11ms/step - loss: 0.8018 - acc: 0.5429 - val_loss: 0.7117 - val_acc: 0.4000\n", + "Epoch 2/10\n", + " 1/70 [..............................] - ETA: 0s - loss: 0.6854 - acc: 1.0000" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2022-11-06 19:39:21.829635: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:113] Plugin optimizer for device_type GPU is enabled.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "70/70 [==============================] - 1s 10ms/step - loss: 0.7058 - acc: 0.4286 - val_loss: 0.6920 - val_acc: 0.5333\n", + "Epoch 3/10\n", + "70/70 [==============================] - 1s 10ms/step - loss: 0.6942 - acc: 0.5429 - val_loss: 0.6883 - val_acc: 0.5000\n", + "Epoch 4/10\n", + "70/70 [==============================] - 1s 10ms/step - loss: 0.6890 - acc: 0.5286 - val_loss: 0.6836 - val_acc: 0.4667\n", + "Epoch 5/10\n", + "70/70 [==============================] - 1s 10ms/step - loss: 0.6815 - acc: 0.5286 - val_loss: 0.6752 - val_acc: 0.5667\n", + "Epoch 6/10\n", + "70/70 [==============================] - 1s 10ms/step - loss: 0.6754 - acc: 0.5429 - val_loss: 0.6652 - val_acc: 0.4667\n", + "Epoch 7/10\n", + "70/70 [==============================] - 1s 10ms/step - loss: 0.6585 - acc: 0.6714 - val_loss: 0.6493 - val_acc: 0.4667\n", + "Epoch 8/10\n", + "70/70 [==============================] - 1s 10ms/step - loss: 0.6419 - acc: 0.6286 - val_loss: 0.6240 - val_acc: 0.7667\n", + "Epoch 9/10\n", + "70/70 [==============================] - 1s 10ms/step - loss: 0.6024 - acc: 0.7571 - val_loss: 0.5896 - val_acc: 0.8000\n", + "Epoch 10/10\n", + "70/70 [==============================] - 1s 10ms/step - loss: 0.5626 - acc: 0.8143 - val_loss: 0.5576 - val_acc: 0.8000\n" + ] + } + ], "source": [ "model = keras.models.Sequential([\n", " keras.layers.Dense(5,input_shape=(2,),activation='relu'),\n", @@ -379,9 +673,74 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 1/10\n", + " 1/70 [..............................] - ETA: 18s - loss: 0.5918 - acc: 1.0000" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2022-11-06 19:39:28.237102: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:113] Plugin optimizer for device_type GPU is enabled.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "70/70 [==============================] - 1s 8ms/step - loss: 0.5351 - acc: 0.8286 - val_loss: 0.5325 - val_acc: 0.7667\n", + "Epoch 2/10\n", + "12/70 [====>.........................] - ETA: 0s - loss: 0.3990 - acc: 0.8333" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2022-11-06 19:39:28.847968: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:113] Plugin optimizer for device_type GPU is enabled.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "70/70 [==============================] - 0s 7ms/step - loss: 0.4780 - acc: 0.8143 - val_loss: 0.4772 - val_acc: 0.8333\n", + "Epoch 3/10\n", + "70/70 [==============================] - 0s 7ms/step - loss: 0.4411 - acc: 0.8571 - val_loss: 0.4366 - val_acc: 0.9000\n", + "Epoch 4/10\n", + "70/70 [==============================] - 0s 7ms/step - loss: 0.4054 - acc: 0.8571 - val_loss: 0.4014 - val_acc: 0.9000\n", + "Epoch 5/10\n", + "70/70 [==============================] - 0s 6ms/step - loss: 0.3745 - acc: 0.8714 - val_loss: 0.3893 - val_acc: 0.8667\n", + "Epoch 6/10\n", + "70/70 [==============================] - 0s 6ms/step - loss: 0.3534 - acc: 0.8571 - val_loss: 0.3512 - val_acc: 0.9000\n", + "Epoch 7/10\n", + "70/70 [==============================] - 0s 6ms/step - loss: 0.3263 - acc: 0.9000 - val_loss: 0.3430 - val_acc: 0.9333\n", + "Epoch 8/10\n", + "70/70 [==============================] - 0s 6ms/step - loss: 0.3072 - acc: 0.8857 - val_loss: 0.3165 - val_acc: 0.9333\n", + "Epoch 9/10\n", + "70/70 [==============================] - 0s 6ms/step - loss: 0.2857 - acc: 0.8714 - val_loss: 0.2885 - val_acc: 0.9333\n", + "Epoch 10/10\n", + "70/70 [==============================] - 0s 6ms/step - loss: 0.2774 - acc: 0.8857 - val_loss: 0.2887 - val_acc: 0.9333\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "model.compile(keras.optimizers.Adam(0.01),'sparse_categorical_crossentropy',['acc'])\n", "model.fit(x=train_x_norm,y=train_labels,validation_data=[test_x_norm,test_labels],batch_size=1,epochs=10)" From af74b0c7c356095943c0604ce79dee6d3a4d9947 Mon Sep 17 00:00:00 2001 From: semercim Date: Mon, 7 Nov 2022 20:48:37 +0100 Subject: [PATCH 34/38] WIP: the Turkish translation of lesson 5 --- .../translations/Overfitting.tr.md | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 lessons/3-NeuralNetworks/05-Frameworks/translations/Overfitting.tr.md diff --git a/lessons/3-NeuralNetworks/05-Frameworks/translations/Overfitting.tr.md b/lessons/3-NeuralNetworks/05-Frameworks/translations/Overfitting.tr.md new file mode 100644 index 00000000..aade8301 --- /dev/null +++ b/lessons/3-NeuralNetworks/05-Frameworks/translations/Overfitting.tr.md @@ -0,0 +1,75 @@ +# Aşırı Öğrenme + +Aşırı öğrenme, makine öğrenmesinde son derece önemli bir kavramdır ve bunu doğru yapmak çok önemlidir! + +Aşağıdaki 5 noktayı (aşağıdaki grafiklerde `x` ile temsil edilen) yaklaşıklama problemini göz önünde bulundurun: + +![doğrusal](../../images/overfit1.jpg) | ![aşırı öğrenme](../../images/overfit2.jpg) +-------------------------|-------------------------- +**Doğrusal model, 2 parametre** | **Doğrusal olmayan model, 7 parametre** +Eğitim hatası = 5.3 | Eğitim hatası = 0 +Geçerleme hatası = 5.1 | Geçerleme hatası = 20 + +* Solda iyi bir düz doğru yaklaşımı görüyoruz. Parametre sayısı yeterli olduğundan, model nokta dağılımının arkasındaki fikri doğru alır. +* Sağdaki model çok güçlüdür. Sadece 5 noktamız ve modelin 7 parametresi olduğu için, kendisini tüm noktalardan geçecek şekilde ayarlayabilir ve hatayı 0 yapar. Ancak bu, modelin verinin arkasındaki doğru örüntüyü anlamasını engeller, dolayısıyla geçerleme hatası çok yüksektir. + +Modelin zenginliği (parametre sayısı) ile eğitim örneklerinin sayısı arasında doğru bir denge kurmak çok önemlidir. + +## Aşırı öğrenme neden olur? + + * Yeterli eğitim verisi yoktur. + * Model çok güçlüdür. + * Girdi verisinde çok fazla gürültü vardır. + +## Aşırı öğrenme nasıl tespit edilir? + +Yukarıdaki şekilden de görebileceğiniz gibi, aşırı öğrenme, çok düşük bir eğitim hatası ve yüksek bir geçerleme hatası ile tespit edilebilir. Normalde eğitim sırasında hem eğitim hem de geçerleme hatalarının azalmaya başladığını görürüz ve ardından bir noktada geçerleme hatası azalmayı durdurabilir ve yükselmeye başlayabilir. Bu, aşırı öğrenmenin bir işaretidir ve muhtemelen bu noktada eğitimi durdurmamız (veya en azından modelin anlık görüntüsünü almamız) gerektiğinin göstergesi olacaktır. + +![aşırı öğrenme](../../images/Overfitting.png) + +## Aşırı öğrenme nasıl önlenir? + +Aşırı öğrenmenin meydana geldiğini görüyorsanız, aşağıdakilerden birini yapabilirsiniz: + + * Eğitim verisinin miktarını artırın + * Modelin karmaşıklığını azaltın + * [Hattan düşürme](../../../4-ComputerVision/08-TransferLearning/TrainingTricks.md#Dropout) gibi bazı [düzenlileştirme teknikleri](../../../4-ComputerVision/08-TransferLearning/TrainingTricks.md), ki daha sonra ele alacağız, kullanın. + +## Aşırı öğrenme ve yanlılık-varyans ödünleşmesi + +Aşırı öğrenme aslında istatistikte [yanlılık-varyans ödünleşmesi](https://en.wikipedia.org/wiki/Bias%E2%80%93variance_tradeoff) adı verilen daha genel bir sorundur. Modelimizde olası hata kaynaklarını göz önüne alırsak iki tür hata görebiliriz: + +* **Yanlılık hataları**, algoritmamızın eğitim verileri arasındaki ilişkiyi doğru şekilde yakalayamamasından kaynaklanır. Modelimizin yeterince güçlü olmamasından (**eksik öğrenme**) kaynaklanabilir. +* **Varyans hataları**, modelin anlamlı ilişki yerine girdi verilerindeki gürültüyü yaklaşıklamasından (**aşırı öğrenme**) kaynaklanır. + +Eğitim esnasında, yanlılık hatası azalır (modelimiz verilere yaklaşmayı öğrenirken) ve varyans hatası artar. Aşırı öğrenmeyi önlemek için eğitimi - manuel olarak (aşırı öğrenmeyi tespit ettiğimizde) veya otomatik olarak (düzenlileştirmeyi katarak) durdurmak önemlidir. + +## Vargılar + +Bu derste, en popüler iki YZ çerçevesi olan TensorFlow ve PyTorch için çeşitli API'ler arasındaki farkları öğrendiniz. Ayrıca, çok önemli bir konuyu da öğrendiniz, aşırı öğrenme. + +## 🚀 Kendini Sınama + +Ekli defterlerde alt kısımda 'görevler'i bulacaksınız; defterler üzerinden çalışın ve görevleri tamamlayın. + +## [Ders sonrası sınavı](https://red-field-0a6ddfd03.1.azurestaticapps.net/quiz/205) + +## Gözden Geçirme ve Bireysel Çalışma + +Aşağıdaki konularda biraz araştırma yapın: + +- TensorFlow +- PyTorch +- Aşırı öğrenme + +Kendinize şu soruları sorun: + +- TensorFlow ve PyTorch arasındaki fark nedir? +- Aşırı öğrenme ile eksik öğrenme arasındaki fark nedir? + +## [Ödev](../lab/README.md) + +Bu laboratuvar çalışmasında, PyTorch veya TensorFlow kullanarak tek ve çok katmanlı tam bağlı ağları kullanarak iki tane sınıflandırma problemini çözmeniz isteniyor. + +* [Talimatlar](../lab/README.md) +* [Not defteri](../lab/LabFrameworks.ipynb) From 7aa31d2b1562f044c4c654849c6e0b7077a94619 Mon Sep 17 00:00:00 2001 From: semercim Date: Mon, 7 Nov 2022 21:59:22 +0100 Subject: [PATCH 35/38] WIP: the Turkish translation of lesson 5 --- .../translations/IntroPyTorch.tr.ipynb | 1718 +++++++++++++++++ 1 file changed, 1718 insertions(+) create mode 100644 lessons/3-NeuralNetworks/05-Frameworks/translations/IntroPyTorch.tr.ipynb diff --git a/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroPyTorch.tr.ipynb b/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroPyTorch.tr.ipynb new file mode 100644 index 00000000..f772971c --- /dev/null +++ b/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroPyTorch.tr.ipynb @@ -0,0 +1,1718 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "En2vX4FuwHlu" + }, + "source": [ + "## PyTorch'a Giriş\n", + "\n", + "> Bu not defteri, [Yeni Başlayanlar için YZ Müfredatı](http://github.com/microsoft/ai-for-beginners)'nın bir parçasıdır. Eksiksiz öğrenme materyalleri kümesi için kaynak deposunu ziyaret edin.\n", + "\n", + "### Sinir Çerçeveleri\n", + "\n", + "Sinir ağlarını eğitmek için şunlara ihtiyacınız olduğunu öğrendik:\n", + "* Matrisleri hızla çarpın (tensörler).\n", + "* Gradyan inişi optimizasyonunu gerçekleştirmek için gradyanları hesaplayın.\n", + "\n", + "Sinir ağı çerçeveleri şunları yapmanıza izin verir:\n", + "* Mevcut herhangi bir hesaplamada, CPU veya GPU'da ve hatta TPU'da, tensörlerle çalışın.\n", + "* Gradyanları otomatik olarak hesaplayın (tüm yerleşik tensör işlevleri için açıkça programlanmışlardır).\n", + "\n", + "İsteğe bağlı olarak:\n", + "* Sinir Ağı yapıcısı / daha üst seviye API (ağı bir dizi katman olarak tanımlamak)\n", + "* Basit eğitim işlevleri (Scikit Learn'de olduğu gibi `fit`)\n", + "* Gradyan inişine ek olarak bir dizi optimizasyon algoritması\n", + "* Veri işleme soyutlamaları (bu ideal olarak GPU'da da çalışır)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "8cACQoFMwHl3" + }, + "source": [ + "### En Popüler Çerçeveler\n", + "\n", + "* Tensorflow 1.x - yaygın olarak kullanılabilen ilk çerçevedir (Google). Statik hesaplama çizgesini tanımlamaya, GPU'ya göndermeye ve açıkça değerlendirmeye izin verir.\n", + "* PyTorch - Facebook'tan popülaritesi artan bir çerçevedir.\n", + "* Keras - sinir ağlarını (Francois Chollet) kullanarak birleştirmek ve basitleştirmek için Tensorflow/PyTorch'un üzerüne daha üst seviye API'dir.\n", + "* Tensorflow 2.x + Keras - **dinamik hesaplama çizgesini** destekleyen ve numpy'ye (ve PyTorch) çok benzer tensör işlemleri gerçekleştirmeye olanak tanıyan tümleşik Keras işlevselliğine sahip Tensorflow'un yeni sürümüdür.\n", + "\n", + "Bu Defterde PyTorch kullanmayı öğreneceğiz. PyTorch'un en son sürümünün kurulu olduğundan emin olmanız gerekir - bunu yapmak için [sitelerindeki talimatları](https://pytorch.org/get-started/locally/) izleyin. Normalde bunu yapmak bu kadar basittir\n", + "```\n", + "pip install torch torchvision\n", + "```\n", + "veya\n", + "```\n", + "conda install pytorch -c pytorch\n", + "```" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 35 + }, + "id": "xwqVx9-bwHl3", + "outputId": "38564a63-0567-4406-ee1a-1d3618f27351", + "tags": [] + }, + "outputs": [ + { + "data": { + "text/plain": [ + "'1.11.0'" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import torch\n", + "torch.__version__" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6tp2xGV7wHl4" + }, + "source": [ + "## Temel Kavramlar: Tensör\n", + "\n", + "**Tensör** çok boyutlu bir dizidir. Farklı veri türlerini temsil etmek için tensör kullanmak çok uygundur:\n", + "* 400x400 - siyah beyaz resim\n", + "* 400x400x3 - renkli resim \n", + "* 16x400x400x3 - 16 adet renkli resimden minigrup\n", + "* 25x400x400x3 - 25 fps'lik videonun bir saniyesi\n", + "* 8x25x400x400x3 - 8 adet 1 saniyelik videodan minigrup" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "qG2bsaR7wHl4" + }, + "source": [ + "### Basit Tensörler\n", + "\n", + "Np dizilimleri listelerinden kolayca basit tensörler oluşturabilir veya rastgele üretebilirsiniz:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ybpnk08HwHl4", + "outputId": "54e2c89b-b373-4389-b285-49b0510be931" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor([[1, 2],\n", + " [3, 4]])\n", + "tensor([[ 0.3039, -0.6590, -1.0034],\n", + " [-0.6935, 0.7224, -1.4946],\n", + " [ 1.9349, 1.1315, 1.7867],\n", + " [ 2.2123, 0.2299, -0.0887],\n", + " [-0.1980, -0.2772, -0.2522],\n", + " [-0.4922, 1.1748, -0.0307],\n", + " [ 0.1680, 0.1391, -1.3474],\n", + " [ 1.8574, 0.1533, 0.5403],\n", + " [-1.0163, -0.4252, -0.6593],\n", + " [ 0.7413, -0.2241, 1.4884]])\n" + ] + } + ], + "source": [ + "a = torch.tensor([[1,2],[3,4]])\n", + "print(a)\n", + "a = torch.randn(size=(10,3))\n", + "print(a)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "AXFMsV3r09Ux" + }, + "source": [ + "Numpy'de olduğu gibi eleman bazında gerçekleştirilen tensörlerde aritmetik işlemleri kullanabilirsiniz. Gerekirse, tensörler otomatik olarak gerekli boyuta genişletilir. Tensörden numpy-dizilimini çıkarmak için `.numpy()` kullanın:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "e5Nu5Xgj1DnQ", + "outputId": "c1fbcd86-dde6-40b6-8edf-7a37f9d60901" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor([[ 0.0000, 0.0000, 0.0000],\n", + " [-0.9974, 1.3814, -0.4913],\n", + " [ 1.6310, 1.7905, 2.7901],\n", + " [ 1.9083, 0.8889, 0.9147],\n", + " [-0.5019, 0.3817, 0.7511],\n", + " [-0.7961, 1.8338, 0.9727],\n", + " [-0.1359, 0.7981, -0.3441],\n", + " [ 1.5535, 0.8122, 1.5437],\n", + " [-1.3203, 0.2338, 0.3440],\n", + " [ 0.4373, 0.4349, 2.4917]])\n", + "[1.3551546 0.5173858 0.3666444]\n" + ] + } + ], + "source": [ + "print(a-a[0])\n", + "print(torch.exp(a)[0].numpy())" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "uQ5zN6cVyrG7" + }, + "source": [ + "## Yerinde ve Hizası Dışında İşlemler\n", + "\n", + "`+`/`add` gibi tensör işlemleri yeni tensörler döndürür. Ancak bazen mevcut tensörü yerinde değiştirmeniz gerekir. İşlemlerin çoğunun `_` ile biten yerinde karşılıkları vardır:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "Mjkbcw3-ACKS", + "outputId": "ca021008-9ab6-4b09-c5a5-bbe854cd1493" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Hizası dışında toplarken sonuç: tensor(8)\n", + "Yerinde topladıktan sonra sonuç: tensor(8)\n" + ] + } + ], + "source": [ + "u = torch.tensor(5)\n", + "print(\"Hizası dışında toplarken sonuç:\",u.add(torch.tensor(3)))\n", + "u.add_(torch.tensor(3))\n", + "print(\"Yerinde topladıktan sonra sonuç:\", u)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "DLPUcVsXACKT" + }, + "source": [ + "Bir matristeki tüm satırların toplamını saf bir şekilde şöyle hesaplayabiliriz:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "7pu0UZ-_yqfB", + "outputId": "bd2e8c6a-39e1-4f29-990b-9591e866936c" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor([ 4.8177, 1.9657, -1.0610])\n" + ] + } + ], + "source": [ + "s = torch.zeros_like(a[0])\n", + "for i in a:\n", + " s.add_(i)\n", + "\n", + "print(s)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "rIh1EHcezlNo" + }, + "source": [ + "Ama aşağıdakini kullanmak çok daha iyidir:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "aQIdWZ1kzn6P", + "outputId": "89000bb4-f45e-493b-a7b0-39fa4e7d92c1" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor([ 4.8177, 1.9657, -1.0610])" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "torch.sum(a,axis=0)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5UzUmEZhACKT" + }, + "source": [ + "[Resmi dokümantasyonda](https://pytorch.org/tutorials/beginner/basics/tensorqs_tutorial.html) PyTorch tensörleri hakkında daha fazla bilgi edinebilirsiniz." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "U-auwezDwHl6" + }, + "source": [ + "## Gradyanları Hesaplama\n", + "\n", + "Geri yayma için gradyanları hesaplamanız gerekir. Herhangi bir PyTorch tensörünün `requires_grad` özelliğini `True` olarak ayarlayabiliriz; bu, tüm işlemlerde gradyan hesaplamaları için bu tensörün izlenmesiyle sonuçlanacaktır. Gradyanları hesaplamak için `backward()` yöntemini çağırmanız gerekir, ardından gradyan `grad` özelliği kullanılarak mevcut hale gelir:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "m8vFOXr7wHl6", + "outputId": "7054c2b1-0b61-4938-937d-813f75f0b195" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor([[ 0.2473, 0.1115],\n", + " [-0.0769, 0.2500]])\n" + ] + } + ], + "source": [ + "a = torch.randn(size=(2, 2), requires_grad=True)\n", + "b = torch.randn(size=(2, 2))\n", + "\n", + "c = torch.mean(torch.sqrt(torch.square(a) + torch.square(b))) # Do some math using `a`\n", + "c.backward() # call backward() to compute all gradients\n", + "# What's the gradient of `c` with respect to `a`?\n", + "print(a.grad)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "nPj3rtrtACKU" + }, + "source": [ + "To be more precise, PyTorch automatically **accumulates** gradients. If you specify `retain_graph=True` when calling `backward`, computational graph will be preserved, and new gradient is added to the `grad` field. In order to restart computing gradients from scratch, we need to reset `grad` field to 0 explicitly by calling `zero_()`: " + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "z_VIw8MoACKU", + "outputId": "36a28b11-6919-47ab-c3f9-c7f1d8500423" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor([[ 0.7418, 0.3345],\n", + " [-0.2307, 0.7499]])\n", + "tensor([[ 0.2473, 0.1115],\n", + " [-0.0769, 0.2500]])\n" + ] + } + ], + "source": [ + "c = torch.mean(torch.sqrt(torch.square(a) + torch.square(b)))\n", + "c.backward(retain_graph=True)\n", + "c.backward(retain_graph=True)\n", + "print(a.grad)\n", + "a.grad.zero_()\n", + "c.backward()\n", + "print(a.grad)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "HM9sUkVgCiG9" + }, + "source": [ + "To compute gradients, PyTorch creates and maintains **compute graph**. For each tensor that has the `requires_grad` flag set to `True`, PyTorch maintains a special function called `grad_fn`, which computes the derivative of the expression according to chain differentiation rule:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "PcxHb-7jC7Vv", + "outputId": "3b3fa138-6d09-4636-8a71-f4a4051c7827" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor(1.4370, grad_fn=)\n" + ] + } + ], + "source": [ + "print(c)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "rvLfNiblACKV" + }, + "source": [ + "Here `c` is computed using `mean` function, thus `grad_fn` point to a function called `MeanBackward`.\n", + "\n", + "In most of the cases, we want PyTorch to compute gradient of a scalar function (such as loss function). However, if we want to compute the gradient of a tensor with respect to another tensor, PyTorch allows us to compute the product of a Jacobian matrix and a given vector.\n", + "\n", + "Suppose we have a vector function $\\vec{y}=f(\\vec{x})$, where\n", + "$\\vec{x}=\\langle x_1,\\dots,x_n\\rangle$ and\n", + "$\\vec{y}=\\langle y_1,\\dots,y_m\\rangle$, then a gradient of $\\vec{y}$ with respect to $\\vec{x}$ is defined by a **Jacobian**:\n", + "\n", + "$$\n", + "\\begin{align}J=\\left(\\begin{array}{ccc}\n", + " \\frac{\\partial y_{1}}{\\partial x_{1}} & \\cdots & \\frac{\\partial y_{1}}{\\partial x_{n}}\\\\\n", + " \\vdots & \\ddots & \\vdots\\\\\n", + " \\frac{\\partial y_{m}}{\\partial x_{1}} & \\cdots & \\frac{\\partial y_{m}}{\\partial x_{n}}\n", + "\\end{array}\\right)\\end{align}\n", + "$$\n", + "\n", + "Instead of giving us access to the whole Jacobian, PyTorch computes the product $v^T\\cdot J$ of Jacobian with some vector\n", + "$v=(v_1 \\dots v_m)$. In order to do that, we need to call ``backward`` and pass `v` as an argument. The size of `v` should be the same as the size of the original tensor, with respect to which we compute the gradient.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "VUNYiQCOACKV", + "outputId": "e3127c21-fce6-420d-f347-ec40cc827e7e" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor([[ 1.2363, 0.1115],\n", + " [-0.0769, 1.2499]])\n" + ] + } + ], + "source": [ + "c = torch.sqrt(torch.square(a) + torch.square(b))\n", + "c.backward(torch.eye(2)) # eye(2) means 2x2 identity matrix\n", + "print(a.grad)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dGHlkVlvACKV" + }, + "source": [ + "More on computing Jacobians in PyTorch can be found in [official documentation](https://pytorch.org/tutorials/beginner/basics/autogradqs_tutorial.html)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "FnVvj4LkD15r" + }, + "source": [ + "# Example 0: Optimization Using Gradient Descent\n", + "\n", + "Let's try to use automatic differentiation to find a minimum of a simple two-variable function $f(x_1,x_2)=(x_1-3)^2+(x_2+2)^2$. Let tensor `x` hold the current coordinates of a point. We start with some starting point $x^{(0)}=(0,0)$, and compute the next point in a sequence using gradient descent formula:\n", + "$$\n", + "x^{(n+1)} = x^{(n)} - \\eta\\nabla f\n", + "$$\n", + "Here $\\eta$ is so-called **learning rage** (we will denote it by `lr` in the code), and $\\nabla f = (\\frac{\\partial f}{\\partial x_1},\\frac{\\partial f}{\\partial x_2})$ - gradient of $f$.\n", + "\n", + "To begin, let's define starting value of `x` and the function `f`:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "id": "nDw5mV9KEeOa" + }, + "outputs": [], + "source": [ + "x = torch.zeros(2,requires_grad=True)\n", + "f = lambda x : (x-torch.tensor([3,-2])).pow(2).sum()\n", + "lr = 0.1" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Wt815LWdEj77" + }, + "source": [ + "Now let's do 15 iterations of gradient descent. In each iteration, we will update `x` coordinates and print them, to make sure that we are approaching the minimum point at (3,-2):" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "KfwMf555EyWJ", + "outputId": "67e2199c-61ff-4ad1-9c48-b4a646bf8bbd" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Step 0: x[0]=0.6000000238418579, x[1]=-0.4000000059604645\n", + "Step 1: x[0]=1.0800000429153442, x[1]=-0.7200000286102295\n", + "Step 2: x[0]=1.4639999866485596, x[1]=-0.9760000705718994\n", + "Step 3: x[0]=1.7711999416351318, x[1]=-1.1808000802993774\n", + "Step 4: x[0]=2.0169599056243896, x[1]=-1.3446400165557861\n", + "Step 5: x[0]=2.2135679721832275, x[1]=-1.4757120609283447\n", + "Step 6: x[0]=2.370854377746582, x[1]=-1.5805696249008179\n", + "Step 7: x[0]=2.4966835975646973, x[1]=-1.6644556522369385\n", + "Step 8: x[0]=2.597346782684326, x[1]=-1.7315645217895508\n", + "Step 9: x[0]=2.677877426147461, x[1]=-1.7852516174316406\n", + "Step 10: x[0]=2.7423019409179688, x[1]=-1.8282012939453125\n", + "Step 11: x[0]=2.793841600418091, x[1]=-1.8625609874725342\n", + "Step 12: x[0]=2.835073232650757, x[1]=-1.8900487422943115\n", + "Step 13: x[0]=2.868058681488037, x[1]=-1.912039041519165\n", + "Step 14: x[0]=2.894446849822998, x[1]=-1.929631233215332\n" + ] + } + ], + "source": [ + "for i in range(15):\n", + " y = f(x)\n", + " y.backward()\n", + " gr = x.grad\n", + " x.data.add_(-lr*gr)\n", + " x.grad.zero_()\n", + " print(\"Step {}: x[0]={}, x[1]={}\".format(i,x[0],x[1]))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "8sfjBMBu59B5" + }, + "source": [ + "## Example 1: Linear Regression\n", + "\n", + "Now we know enough to solve the classical problem of **Linear regression**. Let's generate small synthetic dataset:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "id": "j723455WwHl7" + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "from sklearn.datasets import make_classification, make_regression\n", + "from sklearn.model_selection import train_test_split\n", + "import random" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 282 + }, + "id": "WJNK_J6v6I-Z", + "outputId": "09e6386e-a6d4-4b81-c8d2-153f0acf9696" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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duxY3uOPHDmiL37xi7rjjju0b98+Pf7443r00Ue1du1an8/cf3avlendd99VY2Nj+8+wYcN8OuPgnD9/XqNGjdKPf/xjS8cn+Xtl91qZkvi92rJli+bOnasdO3Zow4YN+uSTTzR16lSdP3++4GuS+t1ycq1MSftuDRo0SEuXLtXu3bu1e/duTZo0Sffee6/efvvtvMcH9p0yIuK2224zHnrooU6/u+GGG4yFCxfmPf573/ueccMNN3T63be//W1j3Lhxnp1jWNi9Vq+99pohyThz5owPZxdekox169YVPSbJ36uOrFwrvld/duLECUOSsWXLloLH8N1qY+Va8d36s6uuusp4+umn8/5dUN+pSGQsLl26pD179mjq1Kmdfj916lT99re/zfua7du3dzn+C1/4gnbv3q3Lly97dq5Bc3KtTLfccovq6up0991367XXXvPyNCMrqd+rcvC9kjKZjCSpb9++BY/hu9XGyrUyJfm71dLSojVr1uj8+fMaP3583mOC+k5FIrA4efKkWlpa9KlPfarT7z/1qU+pqakp72uampryHv/JJ5/o5MmTnp1r0Jxcq7q6Oq1YsUJr167V888/rxEjRujuu+/W1q1b/TjlSEnq98oJvldtDMPQ/PnzNXHiRI0cObLgcXy3rF+rJH+33nrrLV155ZWqqqrSQw89pHXr1qmhoSHvsUF9p3yfblqO3DHrhmEUHb2e7/h8v48jO9dqxIgRGjFiRPufx48fr+PHj+tf//Vfdeedd3p6nlGU5O+VHXyv2jz88MN68803tW3btpLHJv27ZfVaJfm7NWLECO3fv19nz57V2rVrNXv2bG3ZsqVgcBHEdyoSGYv+/furW7duXZ64T5w40SUaM9XW1uY9vnv37urXr59n5xo0J9cqn3HjxunQoUNun17kJfV75Zakfa8eeeQRvfTSS3rttdc0aNCgoscm/btl51rlk5TvVo8ePXT99dfr1ltv1ZIlSzRq1Cj96Ec/yntsUN+pSAQWPXr00NixY7Vhw4ZOv9+wYYNuv/32vK8ZP358l+N//etf69Zbb1VlZaVn5xo0J9cqn3379qmurs7t04u8pH6v3JKU75VhGHr44Yf1/PPPa9OmTRoyZEjJ1yT1u+XkWuWTlO9WLsMw1NzcnPfvAvtOeVoa6qI1a9YYlZWVxjPPPGMcPHjQeOyxx4xevXoZR48eNQzDMBYuXGh89atfbT/+/fffN6644gpj3rx5xsGDB41nnnnGqKysNP7rv/4rqI/gG7vX6sknnzTWrVtnvPfee8aBAweMhQsXGpKMtWvXBvURfHPu3Dlj3759xr59+wxJxr/9278Z+/btMz744APDMPhedWT3WiX5ezVnzhwjnU4bmzdvNhobG9t/Lly40H4M3602Tq5VUr9bixYtMrZu3WocOXLEePPNN43HH3/cqKioMH79618bhhGe71RkAgvDMIynnnrKGDx4sNGjRw9jzJgxnbYjzZ492/j85z/f6fjNmzcbt9xyi9GjRw/j2muvNZYvX+7zGQfHzrVatmyZMXToUKO6utq46qqrjIkTJxqvvPJKAGftP3PbWu7P7NmzDcPge9WR3WuV5O9VvuskyVi1alX7MXy32ji5Vkn9bn39619v///1q6++2rj77rvbgwrDCM93irHpAADANZGosQAAANFAYAEAAFxDYAEAAFxDYAEAAFxDYAEAAFxDYAEAAFxDYAEAAFxDYAEAAFxDYAEAAFxDYAEAAFxDYAEAAFxDYAEAAFzz/wG0npXX5xSjowAAAABJRU5ErkJggg==\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "np.random.seed(13) # pick the seed for reproducibility - change it to explore the effects of random variations\n", + "\n", + "train_x = np.linspace(0, 3, 120)\n", + "train_labels = 2 * train_x + 0.9 + np.random.randn(*train_x.shape) * 0.5\n", + "\n", + "plt.scatter(train_x,train_labels)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "Ng4rZmGc6oxk" + }, + "source": [ + "Linear regression is defined by a straight line $f_{W,b}(x) = Wx+b$, where $W, b$ are model parameters that we need to find. An error on our dataset $\\{x_i,y_u\\}_{i=1}^N$ (also called **loss function**) can be defined as mean square error:\n", + "$$\n", + "\\mathcal{L}(W,b) = {1\\over N}\\sum_{i=1}^N (f_{W,b}(x_i)-y_i)^2\n", + "$$\n", + "\n", + "Let's define our model and loss function:" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "id": "QxhI4GlB6aiH" + }, + "outputs": [], + "source": [ + "input_dim = 1\n", + "output_dim = 1\n", + "learning_rate = 0.1\n", + "\n", + "# This is our weight matrix\n", + "w = torch.tensor([100.0],requires_grad=True,dtype=torch.float32)\n", + "# This is our bias vector\n", + "b = torch.zeros(size=(output_dim,),requires_grad=True)\n", + "\n", + "def f(x):\n", + " return torch.matmul(x,w) + b\n", + "\n", + "def compute_loss(labels, predictions):\n", + " return torch.mean(torch.square(labels - predictions))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "JUxwj3367gD2" + }, + "source": [ + "We will train the model on a series of minibatches. We will use gradient descent, adjusting model parameters using the following formulae:\n", + "$$\n", + "\\begin{array}{l}\n", + "W^{(n+1)}=W^{(n)}-\\eta\\frac{\\partial\\mathcal{L}}{\\partial W} \\\\\n", + "b^{(n+1)}=b^{(n)}-\\eta\\frac{\\partial\\mathcal{L}}{\\partial b} \\\\\n", + "\\end{array}\n", + "$$" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "id": "-991PErM7fJU" + }, + "outputs": [], + "source": [ + "def train_on_batch(x, y):\n", + " predictions = f(x)\n", + " loss = compute_loss(y, predictions)\n", + " loss.backward()\n", + " w.data.sub_(learning_rate * w.grad)\n", + " b.data.sub_(learning_rate * b.grad)\n", + " w.grad.zero_()\n", + " b.grad.zero_()\n", + " return loss" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "idr2VEWb9rr0" + }, + "source": [ + "Let's do the training. We will do several passes through the dataset (so-called **epochs**), divide it into minibatches and call the function defined above:" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "id": "nOuu0qpx-wAp" + }, + "outputs": [], + "source": [ + "# Shuffle the data.\n", + "indices = np.random.permutation(len(train_x))\n", + "features = torch.tensor(train_x[indices],dtype=torch.float32)\n", + "labels = torch.tensor(train_labels[indices],dtype=torch.float32)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "3zdIf6c_85Ht", + "outputId": "6520288c-da59-4a9f-c37e-cd99779c3073" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 0: last batch loss = 94.5247\n", + "Epoch 1: last batch loss = 9.3428\n", + "Epoch 2: last batch loss = 1.4166\n", + "Epoch 3: last batch loss = 0.5224\n", + "Epoch 4: last batch loss = 0.3807\n", + "Epoch 5: last batch loss = 0.3495\n", + "Epoch 6: last batch loss = 0.3413\n", + "Epoch 7: last batch loss = 0.3390\n", + "Epoch 8: last batch loss = 0.3384\n", + "Epoch 9: last batch loss = 0.3382\n" + ] + } + ], + "source": [ + "batch_size = 4\n", + "for epoch in range(10):\n", + " for i in range(0,len(features),batch_size):\n", + " loss = train_on_batch(features[i:i+batch_size].view(-1,1),labels[i:i+batch_size])\n", + " print('Epoch %d: last batch loss = %.4f' % (epoch, float(loss)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We now have obtained optimized parameters $W$ and $b$. Note that their values are similar to the original values used when generating the dataset ($W=2, b=1$)" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "US6q0nCBD-LL", + "outputId": "c804b779-3231-4f6f-c854-032d211b2853" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "(tensor([1.8617], requires_grad=True), tensor([1.0711], requires_grad=True))" + ] + }, + "execution_count": 19, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "w,b" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 282 + }, + "id": "_e6xRMZFDnyI", + "outputId": "79e6c360-265a-401d-ce39-8f211917a13d" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.scatter(train_x,train_labels)\n", + "x = np.array([min(train_x),max(train_x)])\n", + "with torch.no_grad():\n", + " y = w.numpy()*x+b.numpy()\n", + "plt.plot(x,y,color='red')" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0giuwC9GHzi8" + }, + "source": [ + "## Computations on GPU\n", + "\n", + "To use GPU for computations, PyTorch supports moving tensors to GPU and building computational graph for GPU. Traditionally, in the beginning of our code we define available computation device `device` (which is either `cpu` or `cuda`), and then move all tensors to this device using a call `.to(device)`. We can also create tensors on the specified device upfront, by passing the parameter `device=...` to tensor creation code. Such code works without changes both on CPU and GPU: " + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "HK7HPLz3Hyrl", + "outputId": "7e14cccb-d376-4e59-be66-4ab3f5c3f6f4" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Doing computations on cpu\n", + "Epoch 0: last batch loss = 94.5247\n", + "Epoch 1: last batch loss = 9.3428\n", + "Epoch 2: last batch loss = 1.4166\n", + "Epoch 3: last batch loss = 0.5224\n", + "Epoch 4: last batch loss = 0.3807\n", + "Epoch 5: last batch loss = 0.3495\n", + "Epoch 6: last batch loss = 0.3413\n", + "Epoch 7: last batch loss = 0.3390\n", + "Epoch 8: last batch loss = 0.3384\n", + "Epoch 9: last batch loss = 0.3382\n" + ] + } + ], + "source": [ + "device = 'cuda' if torch.cuda.is_available() else 'cpu'\n", + "\n", + "print('Doing computations on '+device)\n", + "\n", + "### Changes here: indicate device\n", + "w = torch.tensor([100.0],requires_grad=True,dtype=torch.float32,device=device)\n", + "b = torch.zeros(size=(output_dim,),requires_grad=True,device=device)\n", + "\n", + "def f(x):\n", + " return torch.matmul(x,w) + b\n", + "\n", + "def compute_loss(labels, predictions):\n", + " return torch.mean(torch.square(labels - predictions))\n", + "\n", + "def train_on_batch(x, y):\n", + " predictions = f(x)\n", + " loss = compute_loss(y, predictions)\n", + " loss.backward()\n", + " w.data.sub_(learning_rate * w.grad)\n", + " b.data.sub_(learning_rate * b.grad)\n", + " w.grad.zero_()\n", + " b.grad.zero_()\n", + " return loss\n", + "\n", + "batch_size = 4\n", + "for epoch in range(10):\n", + " for i in range(0,len(features),batch_size):\n", + " ### Changes here: move data to required device\n", + " loss = train_on_batch(features[i:i+batch_size].view(-1,1).to(device),labels[i:i+batch_size].to(device))\n", + " print('Epoch %d: last batch loss = %.4f' % (epoch, float(loss)))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "A10prCPowHl7" + }, + "source": [ + "## Example 2: Classification\n", + "\n", + "Now we will consider binary classification problem. A good example of such a problem would be a tumour classification between malignant and benign based on it's size and age.\n", + "\n", + "The core model is similar to regression, but we need to use different loss function. Let's start by generating sample data:\n" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "id": "j0OTPkGpwHl7" + }, + "outputs": [], + "source": [ + "np.random.seed(0) # pick the seed for reproducibility - change it to explore the effects of random variations\n", + "\n", + "n = 100\n", + "X, Y = make_classification(n_samples = n, n_features=2,\n", + " n_redundant=0, n_informative=2, flip_y=0.1,class_sep=1.5)\n", + "X = X.astype(np.float32)\n", + "Y = Y.astype(np.int32)\n", + "\n", + "split = [ 70*n//100, (15+70)*n//100 ]\n", + "train_x, valid_x, test_x = np.split(X, split)\n", + "train_labels, valid_labels, test_labels = np.split(Y, split)" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "id": "c-_BjSHPwHl8" + }, + "outputs": [], + "source": [ + "def plot_dataset(features, labels, W=None, b=None):\n", + " # prepare the plot\n", + " fig, ax = plt.subplots(1, 1)\n", + " ax.set_xlabel('$x_i[0]$ -- (feature 1)')\n", + " ax.set_ylabel('$x_i[1]$ -- (feature 2)')\n", + " colors = ['r' if l else 'b' for l in labels]\n", + " ax.scatter(features[:, 0], features[:, 1], marker='o', c=colors, s=100, alpha = 0.5)\n", + " if W is not None:\n", + " min_x = min(features[:,0])\n", + " max_x = max(features[:,1])\n", + " min_y = min(features[:,1])*(1-.1)\n", + " max_y = max(features[:,1])*(1+.1)\n", + " cx = np.array([min_x,max_x],dtype=np.float32)\n", + " cy = (0.5-W[0]*cx-b)/W[1]\n", + " ax.plot(cx,cy,'g')\n", + " ax.set_ylim(min_y,max_y)\n", + " fig.show()" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 283 + }, + "id": "tq0vFchQwHl8", + "outputId": "919f1922-f789-4779-cbdc-4f9e742c358b" + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/var/folders/_l/jnklp1bj4cl95rc01tf5vx4h0000gn/T/ipykernel_78802/2721537645.py:17: UserWarning: Matplotlib is currently using module://matplotlib_inline.backend_inline, which is a non-GUI backend, so cannot show the figure.\n", + " fig.show()\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot_dataset(train_x, train_labels)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "SjPlpf2-wHl8" + }, + "source": [ + "## Training One-Layer Perceptron\n", + "\n", + "Let's use PyTorch gradient computing machinery to train one-layer perceptron.\n", + "\n", + "Our neural network will have 2 inputs and 1 output. The weight matrix $W$ will have size $2\\times1$, and bias vector $b$ -- $1$.\n", + "\n", + "To make our code more structured, let's group all parameters into a single class:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "id": "J1KaixW-cMWJ" + }, + "outputs": [], + "source": [ + "class Network():\n", + " def __init__(self):\n", + " self.W = torch.randn(size=(2,1),requires_grad=True)\n", + " self.b = torch.zeros(size=(1,),requires_grad=True)\n", + "\n", + " def forward(self,x):\n", + " return torch.matmul(x,self.W)+self.b\n", + "\n", + " def zero_grad(self):\n", + " self.W.data.zero_()\n", + " self.b.data.zero_()\n", + "\n", + " def update(self,lr=0.1):\n", + " self.W.data.sub_(lr*self.W.grad)\n", + " self.b.data.sub_(lr*self.b)\n", + "\n", + "net = Network()" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "rQ7W6TOacIAI" + }, + "source": [ + "> Note that we use `W.data.zero_()` instead of `W.zero_()`. We need to do this, because we cannot directly modify a tensor that is being tracked using *Autograd* mechanism.\n", + "\n", + "Core model will be the same as in previous example, but loss function will be a logistic loss. To apply logistic loss, we need to get the value of **probability** as the output of our network, i.e. we need to bring the output $z$ to the range [0,1] using `sigmoid` activation function: $p=\\sigma(z)$.\n", + "\n", + "If we get the probability $p_i$ for the i-th input value corresponding to the actual class $y_i\\in\\{0,1\\}$, we compute the loss as $\\mathcal{L_i}=-(y_i\\log p_i + (1-y_i)log(1-p_i))$. \n", + "\n", + "In PyTorch, both those steps (applying sigmoid and then logistic loss) can be done using one call to `binary_cross_entropy_with_logits` function. Since we are training our network in minibatches, we need to average out the loss across all elements of a minibatch - and that is also done automatically by `binary_cross_entropy_with_logits` function: \n", + "\n", + "> The call to `binary_crossentropy_with_logits` is equivalent to a call to `sigmoid`, followed by a call to `binary_crossentropy`" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "id": "kdDxWeCqwHl8" + }, + "outputs": [], + "source": [ + "def train_on_batch(net, x, y):\n", + " z = net.forward(x).flatten()\n", + " loss = torch.nn.functional.binary_cross_entropy_with_logits(input=z,target=y)\n", + " net.zero_grad()\n", + " loss.backward()\n", + " net.update()\n", + " return loss" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "zAAgw0h6KzUd" + }, + "source": [ + "To loop through our data, we will use built-in PyTorch mechanism for managing datasets. It is based on two concepts:\n", + "* **Dataset** is the main source of data, it can be either **Iterable** or **Map-style**\n", + "* **Dataloader** is responsible for loading the data from a dataset and splitting it into minibatches.\n", + "\n", + "In our case, we will define a dataset based on a tensor, and split it into minibatches of 16 elements. Each minibatch contains two tensors, input data (size=16x2) and labels (a vector of length 16 of integer type - class number)." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "PfyqjVb2wHl8", + "outputId": "b3a685a9-304c-4e7e-adf9-2858cc47c3a5" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[tensor([[ 1.5442, 2.5290],\n", + " [-1.6284, 0.0772],\n", + " [-1.7141, 2.4770],\n", + " [-1.4951, 0.7320],\n", + " [-1.6899, 0.9243],\n", + " [-0.9474, -0.7681],\n", + " [ 3.8597, -2.2951],\n", + " [-1.3944, 1.4300],\n", + " [ 4.3627, 3.1333],\n", + " [-1.0973, -1.7011],\n", + " [-2.5532, -0.0777],\n", + " [-1.2661, -0.3167],\n", + " [ 0.3921, 1.8406],\n", + " [ 2.2091, -1.6045],\n", + " [ 1.8383, -1.4861],\n", + " [ 0.7173, -0.9718]]),\n", + " tensor([1., 0., 0., 0., 0., 0., 1., 0., 1., 0., 0., 0., 1., 1., 1., 1.])]" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Create a tf.data.Dataset object for easy batched iteration\n", + "dataset = torch.utils.data.TensorDataset(torch.tensor(train_x),torch.tensor(train_labels,dtype=torch.float32))\n", + "dataloader = torch.utils.data.DataLoader(dataset,batch_size=16)\n", + "\n", + "list(dataloader)[0]" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "xrwgkbQjhkEp" + }, + "source": [ + "Now we can loop through the whole dataset to train our network for 15 epochs:" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "QGchp9D6gVJa", + "outputId": "b4c4751d-cb56-4104-d5b5-f1ae9d3d858d" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 0: last batch loss = 0.5801\n", + "Epoch 1: last batch loss = 0.4727\n", + "Epoch 2: last batch loss = 0.4072\n", + "Epoch 3: last batch loss = 0.3630\n", + "Epoch 4: last batch loss = 0.3309\n", + "Epoch 5: last batch loss = 0.3064\n", + "Epoch 6: last batch loss = 0.2869\n", + "Epoch 7: last batch loss = 0.2710\n", + "Epoch 8: last batch loss = 0.2577\n", + "Epoch 9: last batch loss = 0.2464\n", + "Epoch 10: last batch loss = 0.2366\n", + "Epoch 11: last batch loss = 0.2281\n", + "Epoch 12: last batch loss = 0.2205\n", + "Epoch 13: last batch loss = 0.2137\n", + "Epoch 14: last batch loss = 0.2076\n" + ] + } + ], + "source": [ + "for epoch in range(15):\n", + " for (x, y) in dataloader:\n", + " loss = train_on_batch(net,x,y)\n", + " print('Epoch %d: last batch loss = %.4f' % (epoch, float(loss)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Obtained parameters:" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "5QaDiCQUkFOT", + "outputId": "45b4a66b-1222-40f4-c758-d58f1c7daf8c" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "tensor([[1.3843],\n", + " [0.3519]], requires_grad=True) tensor([0.], requires_grad=True)\n" + ] + } + ], + "source": [ + "print(net.W,net.b)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "s4_Atvn5K4K9" + }, + "source": [ + "To make sure our training worked, let's plot the line that separates two classes. Separation line is defined by the equation $W\\times x + b = 0.5$" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 283 + }, + "id": "PgRTHttLwHl9", + "outputId": "d9abf92f-cb70-4c56-ccd0-5e027239da58" + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/var/folders/_l/jnklp1bj4cl95rc01tf5vx4h0000gn/T/ipykernel_78802/2721537645.py:17: UserWarning: Matplotlib is currently using module://matplotlib_inline.backend_inline, which is a non-GUI backend, so cannot show the figure.\n", + " fig.show()\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot_dataset(train_x,train_labels,net.W.detach().numpy(),net.b.detach().numpy())" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "1W4TZfXOmIlS" + }, + "source": [ + "Not let's compute the accuracy on the validation dataset:" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "HUjdeIefsIsg", + "outputId": "a1a363d4-a307-4769-9ccf-fe8a857b62af" + }, + "outputs": [ + { + "data": { + "text/plain": [ + "tensor(0.8000)" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "pred = torch.sigmoid(net.forward(torch.tensor(valid_x)))\n", + "torch.mean(((pred.view(-1)>0.5)==(torch.tensor(valid_labels)>0.5)).type(torch.float32))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's explain what is going on here:\n", + "* `pred` is the vector of predicted probabilities for the whole validation dataset. We compute it by running original validation data `valid_x` through our network, and applying `sigmoid` to get probabilities.\n", + "* `pred.view(-1)` creates a flattened view of the original tensor. `view` is similar to `reshape` function in numpy.\n", + "* `pred.view(-1)>0.5` returns a boolean tensor or truth value showing the predicted class (False = class 0, True = class 1)\n", + "* Similarly, `torch.tensor(valid_labels)>0.5)` creates the boolean tensor of truth values for validation labels\n", + "* We compare those two tensors element-wise, and get another boolean tensor, where `True` corresponds to correct prediction, and `False` - to incorrect.\n", + "* We convert that tensor to floating point, and take it's mean value using `torch.mean` - that is the desired accuracy " + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "_95qF9lY2kHp" + }, + "source": [ + "## Neural Networks and Optimizers\n", + "\n", + "In PyTorch, a special module `torch.nn.Module` is defined to represent a neural network. There are two methods to define your own neural network:\n", + "* **Sequential**, where you just specify a list of layers that comprise your network\n", + "* As a **class** inherited from `torch.nn.Module`\n", + "\n", + "First method allows you to specify standard networks with sequential composition of layers, while the second one is more flexible, and gives an opportunity to express networks of arbitrary complex architectures. \n", + "\n", + "Inside modules, you can use standard **layers**, such as:\n", + "* `Linear` - dense linear layer, equivalent to one-layered perceptron. It has the same architecture as we have defined above for our network\n", + "* `Softmax`, `Sigmoid`, `ReLU` - layers that correspond to activation functions \n", + "* There are also other layers for special network types - convolution, recurrent, etc. We will revisit many of them later in the course.\n", + "\n", + "> Most of the activation function and loss functions in PyTorch are available in two form: as a **function** (inside `torch.nn.functional` namespace) and **as a layer** (inside `torch.nn` namespace). For activation functions, it is often easier to use functional elements from `torch.nn.functional`, without creating separate layer object.\n", + "\n", + "If we want to train one-layer perceptron, we can just use one built-in `Linear` layer:" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "D77pXPR6oFRs", + "outputId": "efa49e5c-72d4-4781-89d4-4ab6597d2b0e" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[Parameter containing:\n", + "tensor([[ 0.2255, -0.6099]], requires_grad=True), Parameter containing:\n", + "tensor([0.7046], requires_grad=True)]\n" + ] + } + ], + "source": [ + "net = torch.nn.Linear(2,1) # 2 inputs, 1 output\n", + "\n", + "print(list(net.parameters()))" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "0tbe0Et_oiNo" + }, + "source": [ + "As you can see, `parameters()` method returns all the parameters that need to be adjusted during training. They correspond to weight matrix $W$ and bias $b$. You may note that they have `requires_grad` set to `True`, because we need to compute gradients with respect to parameters.\n", + "\n", + "PyTorch also contains built-in **optimizers**, which implement optimization methods such as **gradient descent**. Here is how we can define a **stochastic gradient descent optimizer**:" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "id": "B4AxyrFMozh0" + }, + "outputs": [], + "source": [ + "optim = torch.optim.SGD(net.parameters(),lr=0.05)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "6eB8v58eo9pp" + }, + "source": [ + "Using the optimizer, our training loop will look like this:" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ups7nlV22ofp", + "outputId": "503d8ae9-35f3-4ecb-e2ff-4da2ec2914eb" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 0: last batch loss = 0.7838571667671204, val acc = 0.6000000238418579\n", + "Epoch 1: last batch loss = 0.6847705841064453, val acc = 0.6666666865348816\n", + "Epoch 2: last batch loss = 0.6084134578704834, val acc = 0.6666666865348816\n", + "Epoch 3: last batch loss = 0.5488442182540894, val acc = 0.7333333492279053\n", + "Epoch 4: last batch loss = 0.5015578866004944, val acc = 0.7333333492279053\n", + "Epoch 5: last batch loss = 0.4633162021636963, val acc = 0.7333333492279053\n", + "Epoch 6: last batch loss = 0.4318276345729828, val acc = 0.7333333492279053\n", + "Epoch 7: last batch loss = 0.4054690897464752, val acc = 0.800000011920929\n", + "Epoch 8: last batch loss = 0.3830794394016266, val acc = 0.800000011920929\n", + "Epoch 9: last batch loss = 0.36381515860557556, val acc = 0.800000011920929\n" + ] + } + ], + "source": [ + "val_x = torch.tensor(valid_x)\n", + "val_lab = torch.tensor(valid_labels)\n", + "\n", + "for ep in range(10):\n", + " for (x,y) in dataloader:\n", + " z = net(x).flatten()\n", + " loss = torch.nn.functional.binary_cross_entropy_with_logits(z,y)\n", + " optim.zero_grad()\n", + " loss.backward()\n", + " optim.step()\n", + " acc = ((torch.sigmoid(net(val_x).flatten())>0.5).float()==val_lab).float().mean()\n", + " print(f\"Epoch {ep}: last batch loss = {loss}, val acc = {acc}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "vRLXEQ4Qrcvx" + }, + "source": [ + "> You may notice that to apply our network to input data we can use `net(x)` instead of `net.forward(x)`, because `nn.Module` implements Python `__call__()` function\n", + "\n", + "Taking this into account, we can define generic `train` function:" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "5c6WsBhlrlIs", + "outputId": "54de8404-4170-4a15-abba-039d06d5e946" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 0: last batch loss = 0.35061463713645935, val acc = 0.800000011920929\n", + "Epoch 1: last batch loss = 0.3105311989784241, val acc = 0.800000011920929\n", + "Epoch 2: last batch loss = 0.27806898951530457, val acc = 0.800000011920929\n", + "Epoch 3: last batch loss = 0.25174298882484436, val acc = 0.800000011920929\n", + "Epoch 4: last batch loss = 0.23032109439373016, val acc = 0.800000011920929\n", + "Epoch 5: last batch loss = 0.2128313183784485, val acc = 0.800000011920929\n", + "Epoch 6: last batch loss = 0.1984984427690506, val acc = 0.800000011920929\n", + "Epoch 7: last batch loss = 0.186697319149971, val acc = 0.800000011920929\n", + "Epoch 8: last batch loss = 0.176921546459198, val acc = 0.800000011920929\n", + "Epoch 9: last batch loss = 0.16876190900802612, val acc = 0.800000011920929\n" + ] + } + ], + "source": [ + "def train(net, dataloader, val_x, val_lab, epochs=10, lr=0.05):\n", + " optim = torch.optim.Adam(net.parameters(),lr=lr)\n", + " for ep in range(epochs):\n", + " for (x,y) in dataloader:\n", + " z = net(x).flatten()\n", + " loss = torch.nn.functional.binary_cross_entropy_with_logits(z,y)\n", + " optim.zero_grad()\n", + " loss.backward()\n", + " optim.step()\n", + " acc = ((torch.sigmoid(net(val_x).flatten())>0.5).float()==val_lab).float().mean()\n", + " print(f\"Epoch {ep}: last batch loss = {loss}, val acc = {acc}\")\n", + "\n", + "net = torch.nn.Linear(2,1)\n", + "\n", + "train(net,dataloader,val_x,val_lab,lr=0.03)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "KzuIDqJ8sFYm" + }, + "source": [ + "## Defining Network as a Sequence of Layers\n", + "\n", + "Now let's train multi-layered perceptron. It can be defined just by specifying a sequence of layers. The resulting object will automatically inherit from `Module`, e.g. it will also have `parameters` method that will return all parameters of the whole network." + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "tBtytmEAsq-O", + "outputId": "06ad840b-c2b7-409e-e01e-a9170548151d" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Sequential(\n", + " (0): Linear(in_features=2, out_features=5, bias=True)\n", + " (1): Sigmoid()\n", + " (2): Linear(in_features=5, out_features=1, bias=True)\n", + ")\n" + ] + } + ], + "source": [ + "net = torch.nn.Sequential(torch.nn.Linear(2,5),torch.nn.Sigmoid(),torch.nn.Linear(5,1))\n", + "print(net)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "5r5RbLB1s6YB" + }, + "source": [ + "We can train this multi-layered network using the function `train` that we have defined above:" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "ogXKdcfIs_ND", + "outputId": "957ccd8d-0076-4e9b-89f1-edc1de75f18e" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 0: last batch loss = 0.6326006054878235, val acc = 0.6666666865348816\n", + "Epoch 1: last batch loss = 0.5457456111907959, val acc = 0.7333333492279053\n", + "Epoch 2: last batch loss = 0.4622190296649933, val acc = 0.800000011920929\n", + "Epoch 3: last batch loss = 0.383121132850647, val acc = 0.800000011920929\n", + "Epoch 4: last batch loss = 0.3107181191444397, val acc = 0.800000011920929\n", + "Epoch 5: last batch loss = 0.24700605869293213, val acc = 0.800000011920929\n", + "Epoch 6: last batch loss = 0.19325126707553864, val acc = 0.800000011920929\n", + "Epoch 7: last batch loss = 0.15045680105686188, val acc = 0.800000011920929\n", + "Epoch 8: last batch loss = 0.11867871880531311, val acc = 0.800000011920929\n", + "Epoch 9: last batch loss = 0.09648200869560242, val acc = 0.800000011920929\n" + ] + } + ], + "source": [ + "train(net,dataloader,val_x,val_lab)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "jY4R1XEGtEzJ" + }, + "source": [ + "## Defining a Network as a Class\n", + "\n", + "Using a class inherited from `torch.nn.Module` is a more flexible method, because we can define any computations inside it. `Module` automates a lot of things, eg. it automatically understands all internal variables that are PyTorch layers, and gathers their parameters for optimization. You just need to define all layers of the network as members of the class:" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "SlsJmGu0tMsZ", + "outputId": "240d5c89-096c-4392-99cd-1ade5ff3e3e1" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "MyNet(\n", + " (fc1): Linear(in_features=2, out_features=10, bias=True)\n", + " (func): ReLU()\n", + " (fc2): Linear(in_features=10, out_features=1, bias=True)\n", + ")\n" + ] + } + ], + "source": [ + "class MyNet(torch.nn.Module):\n", + " def __init__(self,hidden_size=10,func=torch.nn.Sigmoid()):\n", + " super().__init__()\n", + " self.fc1 = torch.nn.Linear(2,hidden_size)\n", + " self.func = func\n", + " self.fc2 = torch.nn.Linear(hidden_size,1)\n", + "\n", + " def forward(self,x):\n", + " x = self.fc1(x)\n", + " x = self.func(x)\n", + " x = self.fc2(x)\n", + " return x\n", + " \n", + "net = MyNet(func=torch.nn.ReLU())\n", + "print(net)" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "HwdapRxft-7M", + "outputId": "6eb900cf-4902-4a04-c62b-497b68455406" + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Epoch 0: last batch loss = 0.7660725712776184, val acc = 0.46666666865348816\n", + "Epoch 1: last batch loss = 0.728505551815033, val acc = 0.5333333611488342\n", + "Epoch 2: last batch loss = 0.6944690346717834, val acc = 0.5333333611488342\n", + "Epoch 3: last batch loss = 0.6628866791725159, val acc = 0.5333333611488342\n", + "Epoch 4: last batch loss = 0.6324793696403503, val acc = 0.5333333611488342\n", + "Epoch 5: last batch loss = 0.6026090979576111, val acc = 0.6000000238418579\n", + "Epoch 6: last batch loss = 0.5736637711524963, val acc = 0.6666666865348816\n", + "Epoch 7: last batch loss = 0.543581485748291, val acc = 0.7333333492279053\n", + "Epoch 8: last batch loss = 0.5133266448974609, val acc = 0.7333333492279053\n", + "Epoch 9: last batch loss = 0.4830652177333832, val acc = 0.800000011920929\n" + ] + } + ], + "source": [ + "train(net,dataloader,val_x,val_lab,lr=0.005)" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "id": "dvAiaj_JndyP" + }, + "source": [ + "**Task 1**: Plot the graphs of loss function and accuracy on training and validation data during training\n", + "\n", + "**Task 2**: Try to solve MNIST classificiation problem using this code. Hint: use `crossentropy_with_logits` as a loss function." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Takeaways\n", + "\n", + "* PyTorch allows you to operate on tensors at low level, you have most flexibility.\n", + "* There are convenient tools to work with data, such as Datasets and Dataloaders.\n", + "* You can define neural network architectures using `Sequential` syntax, or inheriting a class from `torch.nn.Module`\n", + "* For even simpler approach to defining and training a network - look into PyTorch Lightning" + ] + } + ], + "metadata": { + "accelerator": "GPU", + "celltoolbar": "Slideshow", + "colab": { + "collapsed_sections": [], + "name": "IntroPyTorch.ipynb", + "provenance": [] + }, + "interpreter": { + "hash": "0cb620c6d4b9f7a635928804c26cf22403d89d98d79684e4529119355ee6d5a5" + }, + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + }, + "livereveal": { + "start_slideshow_at": "selected" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} From 797b54a77627915f20ff23b4c7d3ae65d8ab75af Mon Sep 17 00:00:00 2001 From: semercim Date: Mon, 14 Nov 2022 19:04:42 +0100 Subject: [PATCH 36/38] The Turkish translation of lesson 5 --- .../translations/IntroKerasTF.tr.ipynb | 2 +- .../translations/IntroPyTorch.tr.ipynb | 446 +++++++++--------- 2 files changed, 223 insertions(+), 225 deletions(-) diff --git a/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKerasTF.tr.ipynb b/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKerasTF.tr.ipynb index d5d1150d..e2191012 100644 --- a/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKerasTF.tr.ipynb +++ b/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroKerasTF.tr.ipynb @@ -1434,7 +1434,7 @@ "id": "yX6hqiafwHl9" }, "source": [ - "## ANA Fikirler\n", + "## Ana Fikirler\n", "\n", "* Tensorflow, tensörler üzerinde düşük seviyede çalışmanıza izin verir, aşırı esnekliğe sahip olursunuz.\n", "* Veri (`td.Data`) ve katmanlar (`tf.layers`) ile çalışmak için uygun araçlar vardır.\n", diff --git a/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroPyTorch.tr.ipynb b/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroPyTorch.tr.ipynb index f772971c..57b116c0 100644 --- a/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroPyTorch.tr.ipynb +++ b/lessons/3-NeuralNetworks/05-Frameworks/translations/IntroPyTorch.tr.ipynb @@ -123,16 +123,16 @@ "text": [ "tensor([[1, 2],\n", " [3, 4]])\n", - "tensor([[ 0.3039, -0.6590, -1.0034],\n", - " [-0.6935, 0.7224, -1.4946],\n", - " [ 1.9349, 1.1315, 1.7867],\n", - " [ 2.2123, 0.2299, -0.0887],\n", - " [-0.1980, -0.2772, -0.2522],\n", - " [-0.4922, 1.1748, -0.0307],\n", - " [ 0.1680, 0.1391, -1.3474],\n", - " [ 1.8574, 0.1533, 0.5403],\n", - " [-1.0163, -0.4252, -0.6593],\n", - " [ 0.7413, -0.2241, 1.4884]])\n" + "tensor([[ 0.9740, 1.1339, 0.9433],\n", + " [-0.6964, -1.0682, -0.3335],\n", + " [-0.5078, 0.4401, 0.3818],\n", + " [-0.0231, 0.4968, -0.8708],\n", + " [-0.2964, -0.5230, 1.0721],\n", + " [-1.0783, -0.6082, 0.3048],\n", + " [-0.6351, 1.7860, 0.0811],\n", + " [-0.0606, 0.4921, 0.0091],\n", + " [-0.5768, -0.4674, -1.4946],\n", + " [ 0.7530, -0.7547, 0.0091]])\n" ] } ], @@ -168,16 +168,16 @@ "output_type": "stream", "text": [ "tensor([[ 0.0000, 0.0000, 0.0000],\n", - " [-0.9974, 1.3814, -0.4913],\n", - " [ 1.6310, 1.7905, 2.7901],\n", - " [ 1.9083, 0.8889, 0.9147],\n", - " [-0.5019, 0.3817, 0.7511],\n", - " [-0.7961, 1.8338, 0.9727],\n", - " [-0.1359, 0.7981, -0.3441],\n", - " [ 1.5535, 0.8122, 1.5437],\n", - " [-1.3203, 0.2338, 0.3440],\n", - " [ 0.4373, 0.4349, 2.4917]])\n", - "[1.3551546 0.5173858 0.3666444]\n" + " [-1.6703, -2.2020, -1.2768],\n", + " [-1.4818, -0.6938, -0.5614],\n", + " [-0.9971, -0.6370, -1.8141],\n", + " [-1.2703, -1.6569, 0.1288],\n", + " [-2.0523, -1.7420, -0.6384],\n", + " [-1.6091, 0.6522, -0.8621],\n", + " [-1.0346, -0.6417, -0.9341],\n", + " [-1.5508, -1.6012, -2.4378],\n", + " [-0.2210, -1.8885, -0.9341]])\n", + "[2.6484823 3.1076026 2.5683248]\n" ] } ], @@ -248,7 +248,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "tensor([ 4.8177, 1.9657, -1.0610])\n" + "tensor([-2.1476, 0.9275, 0.1025])\n" ] } ], @@ -283,7 +283,7 @@ { "data": { "text/plain": [ - "tensor([ 4.8177, 1.9657, -1.0610])" + "tensor([-2.1476, 0.9275, 0.1025])" ] }, "execution_count": 6, @@ -330,8 +330,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "tensor([[ 0.2473, 0.1115],\n", - " [-0.0769, 0.2500]])\n" + "tensor([[0.2352, 0.0731],\n", + " [0.2213, 0.2482]])\n" ] } ], @@ -339,9 +339,9 @@ "a = torch.randn(size=(2, 2), requires_grad=True)\n", "b = torch.randn(size=(2, 2))\n", "\n", - "c = torch.mean(torch.sqrt(torch.square(a) + torch.square(b))) # Do some math using `a`\n", - "c.backward() # call backward() to compute all gradients\n", - "# What's the gradient of `c` with respect to `a`?\n", + "c = torch.mean(torch.sqrt(torch.square(a) + torch.square(b))) # `a` kullanarak biraz matematik yapın\n", + "c.backward() # tüm gradyanlari hesaplamak için backward() çağırın\n", + "# `c`'nin `a`'ya göre gradyanı nedir?\n", "print(a.grad)" ] }, @@ -351,7 +351,7 @@ "id": "nPj3rtrtACKU" }, "source": [ - "To be more precise, PyTorch automatically **accumulates** gradients. If you specify `retain_graph=True` when calling `backward`, computational graph will be preserved, and new gradient is added to the `grad` field. In order to restart computing gradients from scratch, we need to reset `grad` field to 0 explicitly by calling `zero_()`: " + "Daha kesin olmak gerekirse, PyTorch gradyanları otomatik olarak **biriktirir**. `backward` işlevi çağrılırken `retain_graph=True` değerini belirtirseniz, hesaplamalı çizge korunur ve `grad` alanına yeni gradyan eklenir. Hesaplama gradyanlarını sıfırdan yeniden başlatmak için, `zero_()` çağırarak `grad` alanını açıkça 0'a kurmamız gerekiyor:" ] }, { @@ -369,10 +369,10 @@ "name": "stdout", "output_type": "stream", "text": [ - "tensor([[ 0.7418, 0.3345],\n", - " [-0.2307, 0.7499]])\n", - "tensor([[ 0.2473, 0.1115],\n", - " [-0.0769, 0.2500]])\n" + "tensor([[0.7055, 0.2193],\n", + " [0.6638, 0.7445]])\n", + "tensor([[0.2352, 0.0731],\n", + " [0.2213, 0.2482]])\n" ] } ], @@ -392,7 +392,7 @@ "id": "HM9sUkVgCiG9" }, "source": [ - "To compute gradients, PyTorch creates and maintains **compute graph**. For each tensor that has the `requires_grad` flag set to `True`, PyTorch maintains a special function called `grad_fn`, which computes the derivative of the expression according to chain differentiation rule:" + "PyTorch, gradyanları hesaplamak için **hesaplama çizgesi** oluşturur ve bakımını yapar. `requires_grad` bayrağı `True` olarak ayarlanmış her tensör için PyTorch, ifadenin türevini zincir türev alma kuralına göre hesaplayan `grad_fn` adlı özel bir işlevinin bakımını yapar:" ] }, { @@ -410,7 +410,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "tensor(1.4370, grad_fn=)\n" + "tensor(0.8781, grad_fn=)\n" ] } ], @@ -424,13 +424,13 @@ "id": "rvLfNiblACKV" }, "source": [ - "Here `c` is computed using `mean` function, thus `grad_fn` point to a function called `MeanBackward`.\n", + "Burada `c`, `mean` ('ortalama') işlevi kullanılarak hesaplanır, bu nedenle `grad_fn`, `MeanBackward` adlı bir işleve işaret eder.\n", "\n", - "In most of the cases, we want PyTorch to compute gradient of a scalar function (such as loss function). However, if we want to compute the gradient of a tensor with respect to another tensor, PyTorch allows us to compute the product of a Jacobian matrix and a given vector.\n", + "Çoğu durumda, PyTorch'un bir skaler fonksiyonun (kayıp fonksiyonu gibi) gradyanını hesaplamasını isteriz. Bununla birlikte, bir tensörün gradyanını başka bir tensöre göre hesaplamak istiyorsak, PyTorch bize bir Jacobian matrisinin ve belirli bir vektörün çarpımını hesaplamamıza izin verir.\n", "\n", - "Suppose we have a vector function $\\vec{y}=f(\\vec{x})$, where\n", - "$\\vec{x}=\\langle x_1,\\dots,x_n\\rangle$ and\n", - "$\\vec{y}=\\langle y_1,\\dots,y_m\\rangle$, then a gradient of $\\vec{y}$ with respect to $\\vec{x}$ is defined by a **Jacobian**:\n", + "Varsayalım $\\vec{y}=f(\\vec{x})$ vektörümüz olsun, öyleki\n", + "$\\vec{x}=\\langle x_1,\\dots,x_n\\rangle$ ve\n", + "$\\vec{y}=\\langle y_1,\\dots,y_m\\rangle$, o zaman $\\vec{y}$ gradyanı $\\vec{x}$'e göre bir **Jacobian** ile tanımlanır:\n", "\n", "$$\n", "\\begin{align}J=\\left(\\begin{array}{ccc}\n", @@ -440,8 +440,7 @@ "\\end{array}\\right)\\end{align}\n", "$$\n", "\n", - "Instead of giving us access to the whole Jacobian, PyTorch computes the product $v^T\\cdot J$ of Jacobian with some vector\n", - "$v=(v_1 \\dots v_m)$. In order to do that, we need to call ``backward`` and pass `v` as an argument. The size of `v` should be the same as the size of the original tensor, with respect to which we compute the gradient.\n" + "Bize Jacobian'ın tamamına erişim vermek yerine, PyTorch Jacobian'ın $v^T\\cdot J$ çarpımını $v=(v_1 \\dots v_m)$ vektörü ile hesaplar. Bunu yapmak için ``backward``'ı çağırmamız ve argüman olarak `v`'yi geçmemiz gerekiyor. `v`'nin boyutu, gradyanı hesapladığımız orijinal tensörün boyutuyla aynı olmalıdır." ] }, { @@ -459,14 +458,14 @@ "name": "stdout", "output_type": "stream", "text": [ - "tensor([[ 1.2363, 0.1115],\n", - " [-0.0769, 1.2499]])\n" + "tensor([[1.1758, 0.0731],\n", + " [0.2213, 1.2409]])\n" ] } ], "source": [ "c = torch.sqrt(torch.square(a) + torch.square(b))\n", - "c.backward(torch.eye(2)) # eye(2) means 2x2 identity matrix\n", + "c.backward(torch.eye(2)) # eye(2) 2x2 birim matris anlamına gelir\n", "print(a.grad)" ] }, @@ -476,7 +475,7 @@ "id": "dGHlkVlvACKV" }, "source": [ - "More on computing Jacobians in PyTorch can be found in [official documentation](https://pytorch.org/tutorials/beginner/basics/autogradqs_tutorial.html)" + "PyTorch'ta Jacobian hesaplama hakkında daha fazla bilgiyi [resmi dokümantasyon](https://pytorch.org/tutorials/beginner/basics/autogradqs_tutorial.html)da bulabilirsiniz." ] }, { @@ -485,15 +484,15 @@ "id": "FnVvj4LkD15r" }, "source": [ - "# Example 0: Optimization Using Gradient Descent\n", + "# Örnek 0: Gradyan İnişi Kullanarak Eniyileme\n", "\n", - "Let's try to use automatic differentiation to find a minimum of a simple two-variable function $f(x_1,x_2)=(x_1-3)^2+(x_2+2)^2$. Let tensor `x` hold the current coordinates of a point. We start with some starting point $x^{(0)}=(0,0)$, and compute the next point in a sequence using gradient descent formula:\n", + "İki değişkenli basit bir fonksiyonun, $f(x_1,x_2)=(x_1-3)^2+(x_2+2)^2$, minimumunu bulmak için otomatik türev almayı deneyelim. Tensör `x` bir noktanın mevcut koordinatlarını tutsun. Bir başlangıç noktası $x^{(0)}=(0,0)$ ile başlıyoruz ve gradyan inişi formülünü kullanarak bir dizideki sonraki noktayı hesaplıyoruz:\n", "$$\n", "x^{(n+1)} = x^{(n)} - \\eta\\nabla f\n", "$$\n", - "Here $\\eta$ is so-called **learning rage** (we will denote it by `lr` in the code), and $\\nabla f = (\\frac{\\partial f}{\\partial x_1},\\frac{\\partial f}{\\partial x_2})$ - gradient of $f$.\n", + "Burada $\\eta$ sözde **öğrenme oranı** (kodda `lr` ile göstereceğiz) ve $\\nabla f = (\\frac{\\partial f}{\\partial x_1},\\frac{\\partial f}{\\partial x_2})$, $f$'in gradyanıdır.\n", "\n", - "To begin, let's define starting value of `x` and the function `f`:" + "Başlamak için, `x`'in başlangıç değerini ve `f` fonksiyonunu tanımlayalım:" ] }, { @@ -515,7 +514,7 @@ "id": "Wt815LWdEj77" }, "source": [ - "Now let's do 15 iterations of gradient descent. In each iteration, we will update `x` coordinates and print them, to make sure that we are approaching the minimum point at (3,-2):" + "Şimdi 15 gradyan inişi yinelemesi yapalım. Her yinelemede, (3,-2)'deki minimum noktaya yaklaştığımızdan emin olmak için `x` koordinatlarını güncelleyeceğiz ve yazdıracağız:" ] }, { @@ -533,21 +532,21 @@ "name": "stdout", "output_type": "stream", "text": [ - "Step 0: x[0]=0.6000000238418579, x[1]=-0.4000000059604645\n", - "Step 1: x[0]=1.0800000429153442, x[1]=-0.7200000286102295\n", - "Step 2: x[0]=1.4639999866485596, x[1]=-0.9760000705718994\n", - "Step 3: x[0]=1.7711999416351318, x[1]=-1.1808000802993774\n", - "Step 4: x[0]=2.0169599056243896, x[1]=-1.3446400165557861\n", - "Step 5: x[0]=2.2135679721832275, x[1]=-1.4757120609283447\n", - "Step 6: x[0]=2.370854377746582, x[1]=-1.5805696249008179\n", - "Step 7: x[0]=2.4966835975646973, x[1]=-1.6644556522369385\n", - "Step 8: x[0]=2.597346782684326, x[1]=-1.7315645217895508\n", - "Step 9: x[0]=2.677877426147461, x[1]=-1.7852516174316406\n", - "Step 10: x[0]=2.7423019409179688, x[1]=-1.8282012939453125\n", - "Step 11: x[0]=2.793841600418091, x[1]=-1.8625609874725342\n", - "Step 12: x[0]=2.835073232650757, x[1]=-1.8900487422943115\n", - "Step 13: x[0]=2.868058681488037, x[1]=-1.912039041519165\n", - "Step 14: x[0]=2.894446849822998, x[1]=-1.929631233215332\n" + "Adım 0: x[0]=0.6000000238418579, x[1]=-0.4000000059604645\n", + "Adım 1: x[0]=1.0800000429153442, x[1]=-0.7200000286102295\n", + "Adım 2: x[0]=1.4639999866485596, x[1]=-0.9760000705718994\n", + "Adım 3: x[0]=1.7711999416351318, x[1]=-1.1808000802993774\n", + "Adım 4: x[0]=2.0169599056243896, x[1]=-1.3446400165557861\n", + "Adım 5: x[0]=2.2135679721832275, x[1]=-1.4757120609283447\n", + "Adım 6: x[0]=2.370854377746582, x[1]=-1.5805696249008179\n", + "Adım 7: x[0]=2.4966835975646973, x[1]=-1.6644556522369385\n", + "Adım 8: x[0]=2.597346782684326, x[1]=-1.7315645217895508\n", + "Adım 9: x[0]=2.677877426147461, x[1]=-1.7852516174316406\n", + "Adım 10: x[0]=2.7423019409179688, x[1]=-1.8282012939453125\n", + "Adım 11: x[0]=2.793841600418091, x[1]=-1.8625609874725342\n", + "Adım 12: x[0]=2.835073232650757, x[1]=-1.8900487422943115\n", + "Adım 13: x[0]=2.868058681488037, x[1]=-1.912039041519165\n", + "Adım 14: x[0]=2.894446849822998, x[1]=-1.929631233215332\n" ] } ], @@ -558,7 +557,7 @@ " gr = x.grad\n", " x.data.add_(-lr*gr)\n", " x.grad.zero_()\n", - " print(\"Step {}: x[0]={}, x[1]={}\".format(i,x[0],x[1]))" + " print(\"Adım {}: x[0]={}, x[1]={}\".format(i,x[0],x[1]))" ] }, { @@ -567,9 +566,9 @@ "id": "8sfjBMBu59B5" }, "source": [ - "## Example 1: Linear Regression\n", + "## Örnek 1: Doğrusal Bağlanım\n", "\n", - "Now we know enough to solve the classical problem of **Linear regression**. Let's generate small synthetic dataset:" + "Artık klasik **doğrusal bağlanım** problemini çözecek kadar bilgimiz var. Küçük sentetik veri kümesi oluşturalım:" ] }, { @@ -602,7 +601,7 @@ { "data": { "text/plain": [ - "" + "" ] }, "execution_count": 14, @@ -621,7 +620,7 @@ } ], "source": [ - "np.random.seed(13) # pick the seed for reproducibility - change it to explore the effects of random variations\n", + "np.random.seed(13) # yeniden üretilebilirlik için tohumu seçin - rastgele değişimlerin etkilerini keşfetmek için değiştirin\n", "\n", "train_x = np.linspace(0, 3, 120)\n", "train_labels = 2 * train_x + 0.9 + np.random.randn(*train_x.shape) * 0.5\n", @@ -635,12 +634,11 @@ "id": "Ng4rZmGc6oxk" }, "source": [ - "Linear regression is defined by a straight line $f_{W,b}(x) = Wx+b$, where $W, b$ are model parameters that we need to find. An error on our dataset $\\{x_i,y_u\\}_{i=1}^N$ (also called **loss function**) can be defined as mean square error:\n", + "Doğrusal bağlanım, $f_{W,b}(x) = Wx+b$ doğrusuyla tanımlanır, burada $W$ ve $b$ bulmamız gereken model parametreleridir. $\\{x_i,y_u\\}_{i=1}^N$ (**kayıp işlevi** olarak da adlandırılır) veri kümemizdeki hata, ortalama kare hatası olarak tanımlanabilir:\n", "$$\n", "\\mathcal{L}(W,b) = {1\\over N}\\sum_{i=1}^N (f_{W,b}(x_i)-y_i)^2\n", "$$\n", - "\n", - "Let's define our model and loss function:" + "Modelimizi ve kayıp fonksiyonumuzu tanımlayalım:" ] }, { @@ -673,7 +671,7 @@ "id": "JUxwj3367gD2" }, "source": [ - "We will train the model on a series of minibatches. We will use gradient descent, adjusting model parameters using the following formulae:\n", + "Modeli bir dizi minigrup üzerinde eğiteceğiz. Aşağıdaki formülleri kullanarak model parametrelerini ayarlayarak gradyan inişini kullanacağız:\n", "$$\n", "\\begin{array}{l}\n", "W^{(n+1)}=W^{(n)}-\\eta\\frac{\\partial\\mathcal{L}}{\\partial W} \\\\\n", @@ -707,7 +705,7 @@ "id": "idr2VEWb9rr0" }, "source": [ - "Let's do the training. We will do several passes through the dataset (so-called **epochs**), divide it into minibatches and call the function defined above:" + "Eğitimi yapalım. Veri kümesinden (**dönemler** olarak adlandırılır) birkaç geçiş yapacağız, onu minigruplara ayıracağız ve yukarıda tanımlanan işlevi çağıracağız:" ] }, { @@ -739,16 +737,16 @@ "name": "stdout", "output_type": "stream", "text": [ - "Epoch 0: last batch loss = 94.5247\n", - "Epoch 1: last batch loss = 9.3428\n", - "Epoch 2: last batch loss = 1.4166\n", - "Epoch 3: last batch loss = 0.5224\n", - "Epoch 4: last batch loss = 0.3807\n", - "Epoch 5: last batch loss = 0.3495\n", - "Epoch 6: last batch loss = 0.3413\n", - "Epoch 7: last batch loss = 0.3390\n", - "Epoch 8: last batch loss = 0.3384\n", - "Epoch 9: last batch loss = 0.3382\n" + "Dönem 0: son toplu iş kaybı = 94.5247\n", + "Dönem 1: son toplu iş kaybı = 9.3428\n", + "Dönem 2: son toplu iş kaybı = 1.4166\n", + "Dönem 3: son toplu iş kaybı = 0.5224\n", + "Dönem 4: son toplu iş kaybı = 0.3807\n", + "Dönem 5: son toplu iş kaybı = 0.3495\n", + "Dönem 6: son toplu iş kaybı = 0.3413\n", + "Dönem 7: son toplu iş kaybı = 0.3390\n", + "Dönem 8: son toplu iş kaybı = 0.3384\n", + "Dönem 9: son toplu iş kaybı = 0.3382\n" ] } ], @@ -757,14 +755,14 @@ "for epoch in range(10):\n", " for i in range(0,len(features),batch_size):\n", " loss = train_on_batch(features[i:i+batch_size].view(-1,1),labels[i:i+batch_size])\n", - " print('Epoch %d: last batch loss = %.4f' % (epoch, float(loss)))" + " print('Dönem %d: son toplu iş kaybı = %.4f' % (epoch, float(loss)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "We now have obtained optimized parameters $W$ and $b$. Note that their values are similar to the original values used when generating the dataset ($W=2, b=1$)" + "Şimdi optimize edilmiş $W$ ve $b$ parametrelerini elde ettik. Değerlerinin, veri kümesi oluşturulurken kullanılan orijinal değerlere benzer olduğuna dikkat edin ($W=2, b=1$)" ] }, { @@ -808,7 +806,7 @@ { "data": { "text/plain": [ - "[]" + "[]" ] }, "execution_count": 20, @@ -840,9 +838,9 @@ "id": "0giuwC9GHzi8" }, "source": [ - "## Computations on GPU\n", + "## GPU'daki Hesaplamalar\n", "\n", - "To use GPU for computations, PyTorch supports moving tensors to GPU and building computational graph for GPU. Traditionally, in the beginning of our code we define available computation device `device` (which is either `cpu` or `cuda`), and then move all tensors to this device using a call `.to(device)`. We can also create tensors on the specified device upfront, by passing the parameter `device=...` to tensor creation code. Such code works without changes both on CPU and GPU: " + "Hesaplamalar için GPU'yu kullanmak için PyTorch, tensörleri GPU'ya taşımayı ve GPU için hesaplamalı çizgeyi oluşturmayı destekler. Geleneksel olarak, kodumuzun başında mevcut hesaplama cihazı `device` (`cpu` veya `cuda`'dır) tanımlarız ve ardından `.to(device)` çağrısını kullanarak tüm tensörleri bu cihaza taşırız. Ayrıca, `device=...` parametresini tensör oluşturma koduna ileterek, belirtilen cihaz üzerinde önceden tensörler oluşturabiliriz. Bu kod, hem CPU'da hem de GPU'da değişiklik yapmadan çalışır:" ] }, { @@ -860,24 +858,24 @@ "name": "stdout", "output_type": "stream", "text": [ - "Doing computations on cpu\n", - "Epoch 0: last batch loss = 94.5247\n", - "Epoch 1: last batch loss = 9.3428\n", - "Epoch 2: last batch loss = 1.4166\n", - "Epoch 3: last batch loss = 0.5224\n", - "Epoch 4: last batch loss = 0.3807\n", - "Epoch 5: last batch loss = 0.3495\n", - "Epoch 6: last batch loss = 0.3413\n", - "Epoch 7: last batch loss = 0.3390\n", - "Epoch 8: last batch loss = 0.3384\n", - "Epoch 9: last batch loss = 0.3382\n" + "Hesaplamaları şurada yapıyor cpu\n", + "Dönem 0: son toplu iş kaybı = 94.5247\n", + "Dönem 1: son toplu iş kaybı = 9.3428\n", + "Dönem 2: son toplu iş kaybı = 1.4166\n", + "Dönem 3: son toplu iş kaybı = 0.5224\n", + "Dönem 4: son toplu iş kaybı = 0.3807\n", + "Dönem 5: son toplu iş kaybı = 0.3495\n", + "Dönem 6: son toplu iş kaybı = 0.3413\n", + "Dönem 7: son toplu iş kaybı = 0.3390\n", + "Dönem 8: son toplu iş kaybı = 0.3384\n", + "Dönem 9: son toplu iş kaybı = 0.3382\n" ] } ], "source": [ "device = 'cuda' if torch.cuda.is_available() else 'cpu'\n", "\n", - "print('Doing computations on '+device)\n", + "print('Hesaplamaları şurada yapıyor '+device)\n", "\n", "### Changes here: indicate device\n", "w = torch.tensor([100.0],requires_grad=True,dtype=torch.float32,device=device)\n", @@ -904,7 +902,7 @@ " for i in range(0,len(features),batch_size):\n", " ### Changes here: move data to required device\n", " loss = train_on_batch(features[i:i+batch_size].view(-1,1).to(device),labels[i:i+batch_size].to(device))\n", - " print('Epoch %d: last batch loss = %.4f' % (epoch, float(loss)))" + " print('Dönem %d: son toplu iş kaybı = %.4f' % (epoch, float(loss)))" ] }, { @@ -913,11 +911,11 @@ "id": "A10prCPowHl7" }, "source": [ - "## Example 2: Classification\n", + "## Örnek 2: Sınıflandırma\n", "\n", - "Now we will consider binary classification problem. A good example of such a problem would be a tumour classification between malignant and benign based on it's size and age.\n", + "Şimdi ikili sınıflandırma problemini ele alacağız. Böyle bir soruna iyi bir örnek, boyutuna ve yaşına göre habis ve iyi huylu arasında tümör sınıflandırması olabilir.\n", "\n", - "The core model is similar to regression, but we need to use different loss function. Let's start by generating sample data:\n" + "Çekirdek model regresyona benzer, ancak farklı kayıp fonksiyonu kullanmamız gerekiyor. Örnek veriler üreterek başlayalım:" ] }, { @@ -984,7 +982,7 @@ "name": "stderr", "output_type": "stream", "text": [ - "/var/folders/_l/jnklp1bj4cl95rc01tf5vx4h0000gn/T/ipykernel_78802/2721537645.py:17: UserWarning: Matplotlib is currently using module://matplotlib_inline.backend_inline, which is a non-GUI backend, so cannot show the figure.\n", + "/var/folders/_l/jnklp1bj4cl95rc01tf5vx4h0000gn/T/ipykernel_37297/2721537645.py:17: UserWarning: Matplotlib is currently using module://matplotlib_inline.backend_inline, which is a non-GUI backend, so cannot show the figure.\n", " fig.show()\n" ] }, @@ -1009,13 +1007,13 @@ "id": "SjPlpf2-wHl8" }, "source": [ - "## Training One-Layer Perceptron\n", + "## Tek Katmanlı Algılayıcı Eğitme\n", "\n", - "Let's use PyTorch gradient computing machinery to train one-layer perceptron.\n", + "Tek katmanlı algılayıcı eğitmek için PyTorch gradyan hesaplama makinelerini kullanalım.\n", "\n", - "Our neural network will have 2 inputs and 1 output. The weight matrix $W$ will have size $2\\times1$, and bias vector $b$ -- $1$.\n", + "Sinir ağımızın 2 girdisi ve 1 çıktısı olacaktır. $W$ ağırlık matrisinin boyutu $2\\times1$ ve ek girdi vektörünün, $b$, $1$ olacaktır.\n", "\n", - "To make our code more structured, let's group all parameters into a single class:" + "Kodumuzu daha yapılandırılmış hale getirmek için tüm parametreleri tek bir sınıfta gruplandıralım:" ] }, { @@ -1051,15 +1049,15 @@ "id": "rQ7W6TOacIAI" }, "source": [ - "> Note that we use `W.data.zero_()` instead of `W.zero_()`. We need to do this, because we cannot directly modify a tensor that is being tracked using *Autograd* mechanism.\n", + "> `W.zero_()` yerine `W.data.zero_()` kullandığımızı unutmayın. Bunu yapmamız gerekiyor çünkü *Autograd* mekanizması kullanılarak izlenen bir tensörü doğrudan değiştiremeyiz.\n", "\n", - "Core model will be the same as in previous example, but loss function will be a logistic loss. To apply logistic loss, we need to get the value of **probability** as the output of our network, i.e. we need to bring the output $z$ to the range [0,1] using `sigmoid` activation function: $p=\\sigma(z)$.\n", + "Çekirdek model önceki örnektekiyle aynı olacaktır, ancak kayıp fonksiyonu bir lojistik kaybı olacaktır. Lojistik kaybı uygulamak için, ağımızın çıktısı olarak **olasılık** değerini almamız gerekiyor, yani `sigmoid` etkinleştirme fonksiyonunu kullanarak $z$ çıktısını [0,1] aralığına getirmemiz gerekiyor: $ p=\\sigma(z)$.\n", "\n", - "If we get the probability $p_i$ for the i-th input value corresponding to the actual class $y_i\\in\\{0,1\\}$, we compute the loss as $\\mathcal{L_i}=-(y_i\\log p_i + (1-y_i)log(1-p_i))$. \n", + "Gerçek $y_i\\in\\{0,1\\}$ sınıfına karşılık gelen i. girdi değeri için $p_i$ olasılığını alırsak, kaybı $\\mathcal{L_i}=-(y_i\\log p_i + (1-y_i)\\log(1-p_i))$ olarak hesaplarız.\n", "\n", - "In PyTorch, both those steps (applying sigmoid and then logistic loss) can be done using one call to `binary_cross_entropy_with_logits` function. Since we are training our network in minibatches, we need to average out the loss across all elements of a minibatch - and that is also done automatically by `binary_cross_entropy_with_logits` function: \n", + "PyTorch'ta, bu adımların her ikisi de (sigmoid ve ardından lojistik kayıp uygulamak) `binary_cross_entropy_with_logits` işlevine yapılan bir çağrı kullanılarak yapılabilir. Ağımızı minigruplar halinde eğittiğimiz için, bir minigrubun tüm öğelerindeki kaybın ortalamasını almamız gerekiyor ve bu aynı zamanda `binary_cross_entropy_with_logits` işlevi tarafından otomatik olarak yapılır:\n", "\n", - "> The call to `binary_crossentropy_with_logits` is equivalent to a call to `sigmoid`, followed by a call to `binary_crossentropy`" + "> `binary_crossentropy_with_logits` çağrısı, `sigmoid` çağrısına ve ardından `binary_crossentropy` çağrısına eşdeğerdir." ] }, { @@ -1085,11 +1083,11 @@ "id": "zAAgw0h6KzUd" }, "source": [ - "To loop through our data, we will use built-in PyTorch mechanism for managing datasets. It is based on two concepts:\n", - "* **Dataset** is the main source of data, it can be either **Iterable** or **Map-style**\n", - "* **Dataloader** is responsible for loading the data from a dataset and splitting it into minibatches.\n", + "Verilerimizde dolaşırken veri kümelerini yönetmek için yerleşik PyTorch mekanizmasını kullanacağız. İki kavram üzerine kuruludur:\n", + "* **Veri kümesi (Dataset)** ana veri kaynağıdır, **Yinelenebilir (Iterable)** veya **Harita tarzı (Map-style)** olabilir.\n", + "* **Veri yükleyici (Dataloader)**, bir veri kümesindeki verilerin yüklenmesinden ve minigruplara bölünmesinden sorumludur.\n", "\n", - "In our case, we will define a dataset based on a tensor, and split it into minibatches of 16 elements. Each minibatch contains two tensors, input data (size=16x2) and labels (a vector of length 16 of integer type - class number)." + "Bizim durumumuzda, bir tensöre dayalı bir veri kümesi tanımlayacağız ve onu 16 elemanlı minigruplara ayıracağız. Her minigrup iki tensör; girdi verileri (boyut=16x2) ve etiketler (sınıf numarası - 16 uzunluğunda tamsayı tipli bir vektördür) içerir." ] }, { @@ -1144,7 +1142,7 @@ "id": "xrwgkbQjhkEp" }, "source": [ - "Now we can loop through the whole dataset to train our network for 15 epochs:" + "Artık ağımızı 15 dönem eğitmek için tüm veri kümesinde dolaşabiliriz:" ] }, { @@ -1162,21 +1160,21 @@ "name": "stdout", "output_type": "stream", "text": [ - "Epoch 0: last batch loss = 0.5801\n", - "Epoch 1: last batch loss = 0.4727\n", - "Epoch 2: last batch loss = 0.4072\n", - "Epoch 3: last batch loss = 0.3630\n", - "Epoch 4: last batch loss = 0.3309\n", - "Epoch 5: last batch loss = 0.3064\n", - "Epoch 6: last batch loss = 0.2869\n", - "Epoch 7: last batch loss = 0.2710\n", - "Epoch 8: last batch loss = 0.2577\n", - "Epoch 9: last batch loss = 0.2464\n", - "Epoch 10: last batch loss = 0.2366\n", - "Epoch 11: last batch loss = 0.2281\n", - "Epoch 12: last batch loss = 0.2205\n", - "Epoch 13: last batch loss = 0.2137\n", - "Epoch 14: last batch loss = 0.2076\n" + "Dönem 0: son toplu iş kaybı = 0.5761\n", + "Dönem 1: son toplu iş kaybı = 0.4701\n", + "Dönem 2: son toplu iş kaybı = 0.4053\n", + "Dönem 3: son toplu iş kaybı = 0.3614\n", + "Dönem 4: son toplu iş kaybı = 0.3296\n", + "Dönem 5: son toplu iş kaybı = 0.3053\n", + "Dönem 6: son toplu iş kaybı = 0.2859\n", + "Dönem 7: son toplu iş kaybı = 0.2702\n", + "Dönem 8: son toplu iş kaybı = 0.2570\n", + "Dönem 9: son toplu iş kaybı = 0.2457\n", + "Dönem 10: son toplu iş kaybı = 0.2360\n", + "Dönem 11: son toplu iş kaybı = 0.2275\n", + "Dönem 12: son toplu iş kaybı = 0.2200\n", + "Dönem 13: son toplu iş kaybı = 0.2133\n", + "Dönem 14: son toplu iş kaybı = 0.2072\n" ] } ], @@ -1184,14 +1182,14 @@ "for epoch in range(15):\n", " for (x, y) in dataloader:\n", " loss = train_on_batch(net,x,y)\n", - " print('Epoch %d: last batch loss = %.4f' % (epoch, float(loss)))" + " print('Dönem %d: son toplu iş kaybı = %.4f' % (epoch, float(loss)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Obtained parameters:" + "Elde ettiğimiz parametreler aşağıdadır:" ] }, { @@ -1209,8 +1207,8 @@ "name": "stdout", "output_type": "stream", "text": [ - "tensor([[1.3843],\n", - " [0.3519]], requires_grad=True) tensor([0.], requires_grad=True)\n" + "tensor([[1.3857],\n", + " [0.3547]], requires_grad=True) tensor([0.], requires_grad=True)\n" ] } ], @@ -1224,7 +1222,7 @@ "id": "s4_Atvn5K4K9" }, "source": [ - "To make sure our training worked, let's plot the line that separates two classes. Separation line is defined by the equation $W\\times x + b = 0.5$" + "Eğitimimizin işe yaradığından emin olmak için iki sınıfı ayıran doğruyu çizelim. Ayırma doğrusu $W\\times x + b = 0.5$ denklemiyle tanımlanır." ] }, { @@ -1243,13 +1241,13 @@ "name": "stderr", "output_type": "stream", "text": [ - "/var/folders/_l/jnklp1bj4cl95rc01tf5vx4h0000gn/T/ipykernel_78802/2721537645.py:17: UserWarning: Matplotlib is currently using module://matplotlib_inline.backend_inline, which is a non-GUI backend, so cannot show the figure.\n", + "/var/folders/_l/jnklp1bj4cl95rc01tf5vx4h0000gn/T/ipykernel_37297/2721537645.py:17: UserWarning: Matplotlib is currently using module://matplotlib_inline.backend_inline, which is a non-GUI backend, so cannot show the figure.\n", " fig.show()\n" ] }, { "data": { - "image/png": "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\n", + "image/png": "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\n", "text/plain": [ "
" ] @@ -1268,7 +1266,7 @@ "id": "1W4TZfXOmIlS" }, "source": [ - "Not let's compute the accuracy on the validation dataset:" + "Şimdi doğrulama veri kümesindeki doğruluğu hesaplayalım:" ] }, { @@ -1302,13 +1300,13 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Let's explain what is going on here:\n", - "* `pred` is the vector of predicted probabilities for the whole validation dataset. We compute it by running original validation data `valid_x` through our network, and applying `sigmoid` to get probabilities.\n", - "* `pred.view(-1)` creates a flattened view of the original tensor. `view` is similar to `reshape` function in numpy.\n", - "* `pred.view(-1)>0.5` returns a boolean tensor or truth value showing the predicted class (False = class 0, True = class 1)\n", - "* Similarly, `torch.tensor(valid_labels)>0.5)` creates the boolean tensor of truth values for validation labels\n", - "* We compare those two tensors element-wise, and get another boolean tensor, where `True` corresponds to correct prediction, and `False` - to incorrect.\n", - "* We convert that tensor to floating point, and take it's mean value using `torch.mean` - that is the desired accuracy " + "Burada neler olduğunu açıklayalım:\n", + "* `pred`, tüm geçerleme veri kümesi için tahmin edilen olasılıkların vektörüdür. Onu ağımız üzerinden `valid_x` orijinal geçerleme verilerini çalıştırarak ve olasılıkları elde etmek için `sigmoid` uygulayarak hesaplıyoruz.\n", + "* `pred.view(-1)` orijinal tensörün düzleştirilmiş bir görünümünü oluşturur. `view` (görünüm), numpy'deki `reshape` (yeniden şekillendir) işlevine benzer.\n", + "* `pred.view(-1)>0.5`, tahmin edilen sınıfı gösteren bir boole tensörü veya doğruluk değeri döndürür (False (Yanlış) = sınıf 0, True (Doğru) = sınıf 1).\n", + "* Benzer şekilde, `torch.tensor(valid_labels)>0.5)` geçerleme etiketleri için doğruluk değerlerinin boole tensörünü oluşturur.\n", + "* Bu iki tensörü eleman bazında karşılaştırırız ve `True` doğru tahmine ve `False` yanlışa karşılık gelen başka bir boole tensörü elde ederiz.\n", + "* Bu tensörü kayan virgüllü sayıya çeviririz ve `torch.mean` kullanarak ortalama değerini alırız, istenen doğruluk budur." ] }, { @@ -1317,22 +1315,22 @@ "id": "_95qF9lY2kHp" }, "source": [ - "## Neural Networks and Optimizers\n", + "## Sinir Ağları ve Optimize Ediciler\n", "\n", - "In PyTorch, a special module `torch.nn.Module` is defined to represent a neural network. There are two methods to define your own neural network:\n", - "* **Sequential**, where you just specify a list of layers that comprise your network\n", - "* As a **class** inherited from `torch.nn.Module`\n", + "PyTorch'ta, bir sinir ağını temsil etmek için özel bir `torch.nn.Module` modülü tanımlanmıştır. Kendi sinir ağınızı tanımlamanın iki yöntemi vardır:\n", + "* **Ardışık (Sequential)** olarak, yalnızca ağınızı oluşturan katmanların bir listesini belirtirsiniz.\n", + "* `torch.nn.Module`'den devralınan bir **sınıf** olarak tanımlarsınız.\n", "\n", - "First method allows you to specify standard networks with sequential composition of layers, while the second one is more flexible, and gives an opportunity to express networks of arbitrary complex architectures. \n", + "İlk yöntem, ardışık katman bileşimine sahip standart ağları belirtmenize izin verirken, ikincisi daha esnektir ve gelişigüzel karmaşık mimarilerden oluşan ağları ifade etme fırsatı verir.\n", "\n", - "Inside modules, you can use standard **layers**, such as:\n", - "* `Linear` - dense linear layer, equivalent to one-layered perceptron. It has the same architecture as we have defined above for our network\n", - "* `Softmax`, `Sigmoid`, `ReLU` - layers that correspond to activation functions \n", - "* There are also other layers for special network types - convolution, recurrent, etc. We will revisit many of them later in the course.\n", + "Modüllerin içinde standart **katmanları** kullanabilirsiniz, örneğin:\n", + "* `Linear` (Doğrusal), tek katmanlı algılayıcıya eşdeğer yoğun doğrusal katman. Ağımız için yukarıda tanımladığımızla aynı mimariye sahiptir.\n", + "* `Softmax`, `Sigmoid`, `ReLU`, etkinleştirme işlevlerine karşılık gelen katmanlar.\n", + "* Özel ağ türleri için başka katmanlar da vardır - evrişim, yinelemeli, vb. Kursun ilerleyen bölümlerinde bunların çoğuna yeniden değineceğiz.\n", "\n", - "> Most of the activation function and loss functions in PyTorch are available in two form: as a **function** (inside `torch.nn.functional` namespace) and **as a layer** (inside `torch.nn` namespace). For activation functions, it is often easier to use functional elements from `torch.nn.functional`, without creating separate layer object.\n", + "> PyTorch'taki etkinleştirme işlevinin ve kayıp işlevlerinin çoğu iki biçimde mevcuttur: **İşlev** (`torch.nn.functional` ad alanının içinde) ve **katman olarak** (`torch.nn` ad alanının içinde). Etkinleştirme işlevleri için, ayrı katman nesnesi oluşturmadan `torch.nn.functional` öğesinden işlevsel öğeleri kullanmak genellikle daha kolaydır.\n", "\n", - "If we want to train one-layer perceptron, we can just use one built-in `Linear` layer:" + "Tek katmanlı algılayıcıyı eğitmek istiyorsak, yalnızca bir yerleşik `Linear` katmanı kullanabiliriz:" ] }, { @@ -1351,13 +1349,13 @@ "output_type": "stream", "text": [ "[Parameter containing:\n", - "tensor([[ 0.2255, -0.6099]], requires_grad=True), Parameter containing:\n", - "tensor([0.7046], requires_grad=True)]\n" + "tensor([[-0.3171, 0.3296]], requires_grad=True), Parameter containing:\n", + "tensor([0.6366], requires_grad=True)]\n" ] } ], "source": [ - "net = torch.nn.Linear(2,1) # 2 inputs, 1 output\n", + "net = torch.nn.Linear(2,1) # 2 girdi, 1 çıktı\n", "\n", "print(list(net.parameters()))" ] @@ -1368,9 +1366,9 @@ "id": "0tbe0Et_oiNo" }, "source": [ - "As you can see, `parameters()` method returns all the parameters that need to be adjusted during training. They correspond to weight matrix $W$ and bias $b$. You may note that they have `requires_grad` set to `True`, because we need to compute gradients with respect to parameters.\n", + "Gördüğünüz gibi `parameters()` yöntemi, eğitim sırasında ayarlanması gereken tüm parametreleri döndürür. $W$ ağırlık matrisine ve $b$ ek girdiye karşılık gelirler. Gradyanları parametrelere göre hesaplamamız gerektiğinden, `requires_grad` öğesinin `True` olarak ayarlandığını fark edebilirsiniz.\n", "\n", - "PyTorch also contains built-in **optimizers**, which implement optimization methods such as **gradient descent**. Here is how we can define a **stochastic gradient descent optimizer**:" + "PyTorch ayrıca **gradyan inişi** gibi optimizasyon yöntemlerini uygulayan yerleşik **eniyileyiciler** içerir. Bir **rasgele gradyan inişi eniyileyiciyi** şu şekilde tanımlayabiliriz:" ] }, { @@ -1390,7 +1388,7 @@ "id": "6eB8v58eo9pp" }, "source": [ - "Using the optimizer, our training loop will look like this:" + "Eniyileyiciyi kullanınca, eğitim döngümüz şöyle görünecektir:" ] }, { @@ -1408,16 +1406,16 @@ "name": "stdout", "output_type": "stream", "text": [ - "Epoch 0: last batch loss = 0.7838571667671204, val acc = 0.6000000238418579\n", - "Epoch 1: last batch loss = 0.6847705841064453, val acc = 0.6666666865348816\n", - "Epoch 2: last batch loss = 0.6084134578704834, val acc = 0.6666666865348816\n", - "Epoch 3: last batch loss = 0.5488442182540894, val acc = 0.7333333492279053\n", - "Epoch 4: last batch loss = 0.5015578866004944, val acc = 0.7333333492279053\n", - "Epoch 5: last batch loss = 0.4633162021636963, val acc = 0.7333333492279053\n", - "Epoch 6: last batch loss = 0.4318276345729828, val acc = 0.7333333492279053\n", - "Epoch 7: last batch loss = 0.4054690897464752, val acc = 0.800000011920929\n", - "Epoch 8: last batch loss = 0.3830794394016266, val acc = 0.800000011920929\n", - "Epoch 9: last batch loss = 0.36381515860557556, val acc = 0.800000011920929\n" + "Dönem 0: son toplu iş kaybı = 0.9087961316108704, geçerleme doğruluğu = 0.4000000059604645\n", + "Dönem 1: son toplu iş kaybı = 0.7703850865364075, geçerleme doğruluğu = 0.46666666865348816\n", + "Dönem 2: son toplu iş kaybı = 0.6663016676902771, geçerleme doğruluğu = 0.6000000238418579\n", + "Dönem 3: son toplu iş kaybı = 0.587394654750824, geçerleme doğruluğu = 0.7333333492279053\n", + "Dönem 4: son toplu iş kaybı = 0.5265983939170837, geçerleme doğruluğu = 0.7333333492279053\n", + "Dönem 5: son toplu iş kaybı = 0.4788611829280853, geçerleme doğruluğu = 0.800000011920929\n", + "Dönem 6: son toplu iş kaybı = 0.44066122174263, geçerleme doğruluğu = 0.800000011920929\n", + "Dönem 7: son toplu iş kaybı = 0.4095434844493866, geçerleme doğruluğu = 0.8666666746139526\n", + "Dönem 8: son toplu iş kaybı = 0.38377830386161804, geçerleme doğruluğu = 0.8666666746139526\n", + "Dönem 9: son toplu iş kaybı = 0.3621285855770111, geçerleme doğruluğu = 0.800000011920929\n" ] } ], @@ -1433,7 +1431,7 @@ " loss.backward()\n", " optim.step()\n", " acc = ((torch.sigmoid(net(val_x).flatten())>0.5).float()==val_lab).float().mean()\n", - " print(f\"Epoch {ep}: last batch loss = {loss}, val acc = {acc}\")" + " print(f\"Dönem {ep}: son toplu iş kaybı = {loss}, geçerleme doğruluğu = {acc}\")" ] }, { @@ -1442,9 +1440,9 @@ "id": "vRLXEQ4Qrcvx" }, "source": [ - "> You may notice that to apply our network to input data we can use `net(x)` instead of `net.forward(x)`, because `nn.Module` implements Python `__call__()` function\n", + "> Ağımızı girdi verilerine uygulamak için `net.forward(x)` yerine `net(x)` kullanabileceğimizi fark edebilirsiniz, çünkü `nn.Module` Python '__call__()' işlevini uygular.\n", "\n", - "Taking this into account, we can define generic `train` function:" + "Bunu dikkate alarak, genel `train` (eğitim) fonksiyonunu tanımlayabiliriz:" ] }, { @@ -1462,16 +1460,16 @@ "name": "stdout", "output_type": "stream", "text": [ - "Epoch 0: last batch loss = 0.35061463713645935, val acc = 0.800000011920929\n", - "Epoch 1: last batch loss = 0.3105311989784241, val acc = 0.800000011920929\n", - "Epoch 2: last batch loss = 0.27806898951530457, val acc = 0.800000011920929\n", - "Epoch 3: last batch loss = 0.25174298882484436, val acc = 0.800000011920929\n", - "Epoch 4: last batch loss = 0.23032109439373016, val acc = 0.800000011920929\n", - "Epoch 5: last batch loss = 0.2128313183784485, val acc = 0.800000011920929\n", - "Epoch 6: last batch loss = 0.1984984427690506, val acc = 0.800000011920929\n", - "Epoch 7: last batch loss = 0.186697319149971, val acc = 0.800000011920929\n", - "Epoch 8: last batch loss = 0.176921546459198, val acc = 0.800000011920929\n", - "Epoch 9: last batch loss = 0.16876190900802612, val acc = 0.800000011920929\n" + "Dönem 0: son toplu iş kaybı = 0.9851850867271423, geçerleme doğruluğu = 0.4000000059604645\n", + "Dönem 1: son toplu iş kaybı = 0.8353211879730225, geçerleme doğruluğu = 0.46666666865348816\n", + "Dönem 2: son toplu iş kaybı = 0.709876298904419, geçerleme doğruluğu = 0.46666666865348816\n", + "Dönem 3: son toplu iş kaybı = 0.6093153953552246, geçerleme doğruluğu = 0.6666666865348816\n", + "Dönem 4: son toplu iş kaybı = 0.530561625957489, geçerleme doğruluğu = 0.800000011920929\n", + "Dönem 5: son toplu iş kaybı = 0.46913135051727295, geçerleme doğruluğu = 0.7333333492279053\n", + "Dönem 6: son toplu iş kaybı = 0.4209415018558502, geçerleme doğruluğu = 0.800000011920929\n", + "Dönem 7: son toplu iş kaybı = 0.382853239774704, geçerleme doğruluğu = 0.800000011920929\n", + "Dönem 8: son toplu iş kaybı = 0.3525124490261078, geçerleme doğruluğu = 0.800000011920929\n", + "Dönem 9: son toplu iş kaybı = 0.3280949890613556, geçerleme doğruluğu = 0.800000011920929\n" ] } ], @@ -1486,7 +1484,7 @@ " loss.backward()\n", " optim.step()\n", " acc = ((torch.sigmoid(net(val_x).flatten())>0.5).float()==val_lab).float().mean()\n", - " print(f\"Epoch {ep}: last batch loss = {loss}, val acc = {acc}\")\n", + " print(f\"Dönem {ep}: son toplu iş kaybı = {loss}, geçerleme doğruluğu = {acc}\")\n", "\n", "net = torch.nn.Linear(2,1)\n", "\n", @@ -1499,9 +1497,9 @@ "id": "KzuIDqJ8sFYm" }, "source": [ - "## Defining Network as a Sequence of Layers\n", + "## Ağı Ardışık Katmanlar Olarak Tanımlama\n", "\n", - "Now let's train multi-layered perceptron. It can be defined just by specifying a sequence of layers. The resulting object will automatically inherit from `Module`, e.g. it will also have `parameters` method that will return all parameters of the whole network." + "Şimdi çok katmanlı algılayıcıyı eğitelim. Sadece bir katman dizisi belirterek tanımlanabilir. Ortaya çıkan nesne otomatik olarak `Module`'den devralır, ör. ayrıca tüm ağın tüm parametrelerini döndürecek `parameters` yöntemine sahip olacaktır." ] }, { @@ -1538,7 +1536,7 @@ "id": "5r5RbLB1s6YB" }, "source": [ - "We can train this multi-layered network using the function `train` that we have defined above:" + "Bu çok katmanlı ağı yukarıda tanımladığımız `train` fonksiyonunu kullanarak eğitebiliriz:" ] }, { @@ -1556,16 +1554,16 @@ "name": "stdout", "output_type": "stream", "text": [ - "Epoch 0: last batch loss = 0.6326006054878235, val acc = 0.6666666865348816\n", - "Epoch 1: last batch loss = 0.5457456111907959, val acc = 0.7333333492279053\n", - "Epoch 2: last batch loss = 0.4622190296649933, val acc = 0.800000011920929\n", - "Epoch 3: last batch loss = 0.383121132850647, val acc = 0.800000011920929\n", - "Epoch 4: last batch loss = 0.3107181191444397, val acc = 0.800000011920929\n", - "Epoch 5: last batch loss = 0.24700605869293213, val acc = 0.800000011920929\n", - "Epoch 6: last batch loss = 0.19325126707553864, val acc = 0.800000011920929\n", - "Epoch 7: last batch loss = 0.15045680105686188, val acc = 0.800000011920929\n", - "Epoch 8: last batch loss = 0.11867871880531311, val acc = 0.800000011920929\n", - "Epoch 9: last batch loss = 0.09648200869560242, val acc = 0.800000011920929\n" + "Dönem 0: son toplu iş kaybı = 0.6021518111228943, geçerleme doğruluğu = 0.6000000238418579\n", + "Dönem 1: son toplu iş kaybı = 0.505835235118866, geçerleme doğruluğu = 0.6000000238418579\n", + "Dönem 2: son toplu iş kaybı = 0.4291416108608246, geçerleme doğruluğu = 0.7333333492279053\n", + "Dönem 3: son toplu iş kaybı = 0.35532107949256897, geçerleme doğruluğu = 0.800000011920929\n", + "Dönem 4: son toplu iş kaybı = 0.2888007164001465, geçerleme doğruluğu = 0.800000011920929\n", + "Dönem 5: son toplu iş kaybı = 0.23157590627670288, geçerleme doğruluğu = 0.800000011920929\n", + "Dönem 6: son toplu iş kaybı = 0.1831870824098587, geçerleme doğruluğu = 0.800000011920929\n", + "Dönem 7: son toplu iş kaybı = 0.1437370777130127, geçerleme doğruluğu = 0.800000011920929\n", + "Dönem 8: son toplu iş kaybı = 0.11355496197938919, geçerleme doğruluğu = 0.800000011920929\n", + "Dönem 9: son toplu iş kaybı = 0.09217184782028198, geçerleme doğruluğu = 0.800000011920929\n" ] } ], @@ -1579,9 +1577,9 @@ "id": "jY4R1XEGtEzJ" }, "source": [ - "## Defining a Network as a Class\n", + "## Ağı Sınıf Olarak Tanımlamak\n", "\n", - "Using a class inherited from `torch.nn.Module` is a more flexible method, because we can define any computations inside it. `Module` automates a lot of things, eg. it automatically understands all internal variables that are PyTorch layers, and gathers their parameters for optimization. You just need to define all layers of the network as members of the class:" + "`torch.nn.Module`'den miras alınan bir sınıfı kullanmak daha esnek bir yöntemdir, çünkü onun içinde herhangi bir hesaplama tanımlayabiliriz. `Module` birçok şeyi otomatikleştirir, örn. PyTorch katmanları olan tüm dahili değişkenleri otomatik olarak anlar ve eniyileme için parametrelerini toplar. Ağın tüm katmanlarını sınıfın üyeleri olarak tanımlamanız yeterlidir:" ] }, { @@ -1640,16 +1638,16 @@ "name": "stdout", "output_type": "stream", "text": [ - "Epoch 0: last batch loss = 0.7660725712776184, val acc = 0.46666666865348816\n", - "Epoch 1: last batch loss = 0.728505551815033, val acc = 0.5333333611488342\n", - "Epoch 2: last batch loss = 0.6944690346717834, val acc = 0.5333333611488342\n", - "Epoch 3: last batch loss = 0.6628866791725159, val acc = 0.5333333611488342\n", - "Epoch 4: last batch loss = 0.6324793696403503, val acc = 0.5333333611488342\n", - "Epoch 5: last batch loss = 0.6026090979576111, val acc = 0.6000000238418579\n", - "Epoch 6: last batch loss = 0.5736637711524963, val acc = 0.6666666865348816\n", - "Epoch 7: last batch loss = 0.543581485748291, val acc = 0.7333333492279053\n", - "Epoch 8: last batch loss = 0.5133266448974609, val acc = 0.7333333492279053\n", - "Epoch 9: last batch loss = 0.4830652177333832, val acc = 0.800000011920929\n" + "Dönem 0: son toplu iş kaybı = 0.7364251017570496, geçerleme doğruluğu = 0.46666666865348816\n", + "Dönem 1: son toplu iş kaybı = 0.7092168927192688, geçerleme doğruluğu = 0.5333333611488342\n", + "Dönem 2: son toplu iş kaybı = 0.6822843551635742, geçerleme doğruluğu = 0.5333333611488342\n", + "Dönem 3: son toplu iş kaybı = 0.6552965044975281, geçerleme doğruluğu = 0.5333333611488342\n", + "Dönem 4: son toplu iş kaybı = 0.6281629800796509, geçerleme doğruluğu = 0.6000000238418579\n", + "Dönem 5: son toplu iş kaybı = 0.5996261835098267, geçerleme doğruluğu = 0.6666666865348816\n", + "Dönem 6: son toplu iş kaybı = 0.5690117478370667, geçerleme doğruluğu = 0.7333333492279053\n", + "Dönem 7: son toplu iş kaybı = 0.5358816981315613, geçerleme doğruluğu = 0.8666666746139526\n", + "Dönem 8: son toplu iş kaybı = 0.5006707310676575, geçerleme doğruluğu = 0.8666666746139526\n", + "Dönem 9: son toplu iş kaybı = 0.46446147561073303, geçerleme doğruluğu = 0.800000011920929\n" ] } ], @@ -1663,21 +1661,21 @@ "id": "dvAiaj_JndyP" }, "source": [ - "**Task 1**: Plot the graphs of loss function and accuracy on training and validation data during training\n", + "**Görev 1**: Eğitim sırasında kayıp fonksiyonunun ve doğruluğun, eğitim ve geçerleme verilerindeki grafiğini çizin.\n", "\n", - "**Task 2**: Try to solve MNIST classificiation problem using this code. Hint: use `crossentropy_with_logits` as a loss function." + "**Görev 2**: Bu kodu kullanarak MNIST sınıflandırma problemini çözmeye çalışın. İpucu: Kayıp işlevi olarak `crossentropy_with_logits` kullanın." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## Takeaways\n", + "## Ana Fikirler\n", "\n", - "* PyTorch allows you to operate on tensors at low level, you have most flexibility.\n", - "* There are convenient tools to work with data, such as Datasets and Dataloaders.\n", - "* You can define neural network architectures using `Sequential` syntax, or inheriting a class from `torch.nn.Module`\n", - "* For even simpler approach to defining and training a network - look into PyTorch Lightning" + "* PyTorch, düşük seviyede tensörler üzerinde çalışmanıza izin verir, en fazla esnekliğe sahip olursunuz.\n", + "* Datasets (Veri Kümeleri) ve Dataloaders (Veri Yükleyiciler) gibi verilerle çalışmak için uygun araçlar vardır.\n", + "* `Sequential` (Ardışık) sözdizimini kullanarak veya `torch.nn.Module`'den bir sınıf miras alarak sinir ağı mimarilerini tanımlayabilirsiniz.\n", + "* Bir ağı tanımlamaya ve eğitmeye daha da basit bir yaklaşım için PyTorch Lightning'e bakın." ] } ], From fa6aa494a363f7a158b6e778f7a8fd1b56946d5d Mon Sep 17 00:00:00 2001 From: semercim Date: Mon, 14 Nov 2022 20:37:39 +0100 Subject: [PATCH 37/38] The Turkish translation of lesson 5 --- .../lab/translations/LabFrameworks.tr.ipynb | 418 ++++++++++++++++++ .../lab/translations/README.tr.md | 16 + 2 files changed, 434 insertions(+) create mode 100644 lessons/3-NeuralNetworks/05-Frameworks/lab/translations/LabFrameworks.tr.ipynb create mode 100644 lessons/3-NeuralNetworks/05-Frameworks/lab/translations/README.tr.md diff --git a/lessons/3-NeuralNetworks/05-Frameworks/lab/translations/LabFrameworks.tr.ipynb b/lessons/3-NeuralNetworks/05-Frameworks/lab/translations/LabFrameworks.tr.ipynb new file mode 100644 index 00000000..141b85ee --- /dev/null +++ b/lessons/3-NeuralNetworks/05-Frameworks/lab/translations/LabFrameworks.tr.ipynb @@ -0,0 +1,418 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# PyTorch/TensorFlow ile Sınıflandırma\n", + "\n", + "[Yeni Başlayanlar için YZ Müfredatı](https://github.com/microsoft/ai-for-beginners)'ndan Laboratuvar Ödevi.\n", + "\n", + "## Bölüm 1: Süsen Sınıflandırma\n", + "\n", + "Süsen (Iris) veri kümesi, 3 farklı süsen sınıfının 150 kaydını içerir. Her kayıt 4 sayısal parametre içerir: Çanak yaprağı uzunluğu/genişliği ve taç yaprağı uzunluğu/genişliği. Güçlü bir sinir ağına ihtiyacınız olmayan basit bir veri kümesi örneğidir.\n", + "\n", + "### Veri Kümesini Alma\n", + "\n", + "Süsen veri kümesi, Scikit Learn'de yerleşiktir, böylece onu kolayca alabiliriz:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Öznitelikler: ['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)'], Sınıflar: ['setosa' 'versicolor' 'virginica']\n" + ] + } + ], + "source": [ + "from sklearn.datasets import load_iris\n", + "from sklearn.model_selection import train_test_split\n", + "\n", + "iris = load_iris()\n", + "features = iris['data']\n", + "labels = iris['target']\n", + "class_names = iris['target_names']\n", + "feature_names = iris['feature_names']\n", + "\n", + "print(f\"Öznitelikler: {feature_names}, Sınıflar: {class_names}\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Veriyi Görselleştirme\n", + "\n", + "Çoğu durumda, ayrılabilir görünüp görünmediklerini görmek için verileri görselleştirmek mantıklıdır; bu bize iyi bir sınıflandırma modeli oluşturabilmemiz gerektiğini garanti eder. Birkaç özniteliğimiz olduğundan, farklı sınıfları farklı nokta renkleriyle gösteren bir dizi ikili 2B dağılım grafiği oluşturabiliriz. Bu, **seaborn** adlı bir paket tarafından otomatik olarak yapılabilir:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
sepal length (cm)sepal width (cm)petal length (cm)petal width (cm)Label
05.13.51.40.20
14.93.01.40.20
24.73.21.30.20
34.63.11.50.20
45.03.61.40.20
..................
1456.73.05.22.32
1466.32.55.01.92
1476.53.05.22.02
1486.23.45.42.32
1495.93.05.11.82
\n", + "

150 rows × 5 columns

\n", + "
" + ], + "text/plain": [ + " sepal length (cm) sepal width (cm) petal length (cm) petal width (cm) \\\n", + "0 5.1 3.5 1.4 0.2 \n", + "1 4.9 3.0 1.4 0.2 \n", + "2 4.7 3.2 1.3 0.2 \n", + "3 4.6 3.1 1.5 0.2 \n", + "4 5.0 3.6 1.4 0.2 \n", + ".. ... ... ... ... \n", + "145 6.7 3.0 5.2 2.3 \n", + "146 6.3 2.5 5.0 1.9 \n", + "147 6.5 3.0 5.2 2.0 \n", + "148 6.2 3.4 5.4 2.3 \n", + "149 5.9 3.0 5.1 1.8 \n", + "\n", + " Label \n", + "0 0 \n", + "1 0 \n", + "2 0 \n", + "3 0 \n", + "4 0 \n", + ".. ... \n", + "145 2 \n", + "146 2 \n", + "147 2 \n", + "148 2 \n", + "149 2 \n", + "\n", + "[150 rows x 5 columns]" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import seaborn as sns\n", + "import pandas as pd\n", + "\n", + "df = pd.DataFrame(features,columns=feature_names).join(pd.DataFrame(labels,columns=['Label']))\n", + "\n", + "df" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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586dcxgT6bgo8dDGJCUl1VqgQ0ND2bp162TL3njjDRYXF8cYu34xqVp5m81mFhISwhYtWuTwuE899RT7xz/+YXvd0MRDfHw8W7BggWydL774ggUFBdleA2AvvfSS7XVJSQnjOI799NNPjDHG5syZw2644QbZPubNmyerHKoft1J4eDh78MEHba8lSWL+/v5s2bJlDj/DmDFj2OTJk2XLXnzxRRYZGclMJpPdbSZNmsTCw8NtlRFjjPXs2ZPFx8fbXlssFubu7s7Wr18v2/bZZ5+lHzntSFspqx9++KGtXH3//fcsNjaWjR07li1dupQxxtiIESPYnDlzbOtX/WH06aefMh8fH1ZaWmp7f9myZbbEA2OOb+ASEhLY0KFDZcsGDRokO1Z1M2bMYLfeeqts2aeffsr0er0tQVndK6+8wtzc3FhRUZFt2ciRI1lERESNcrpw4ULZth988AGLiIhwGA9pexISElivXr2YJEm2ZXPmzGG9evVijDF25swZxnEcy87Olm132223sRdffJEx5rieqe7vv/9mAGw/dhqaeFi5ciXr2bOnLFaj0ci0Wi375ZdfGGPX6xyLxWJbZ/z48WzChAmMMcZOnTrFALADBw7Y3k9LS2MAbImH6setZK/svPDCC7JEZHWbNm1igiDIYk5JSWEA2Pbt2+1uU3lefv31V9uyhQsXMgDs7NmztmVPPvkkGzlypGzbo0eP0o+cdqo1l9Vr164xnufZwYMHmSRJzNfXly1cuJANGjSIMcbYunXrWEBAgG39qvVwcXExU6lUtsQbY9ZEg1artSUeGLPet1Yto5WfBwA7c+aMbdnSpUtlx6quMhlY9WFXUVERU6vVtkRDdZX3H5999plt2fr16xkAtmPHDtuyhQsXsp49e8q2LSwsZADYzp07HcZEOi7qatHG9OvXD7fddhuio6Mxfvx4rFixwjYuQF5eHrKysvDYY49Bp9PZ/r355pu2rgCVqnYfUCgUiI2NlfVl/uSTTxAbGws/Pz/odDqsWLECmZmZjY47KSkJr7/+uiyuJ554Ajk5ObKmk3379rX9393dHXq93tb8LSUlBYMGDZLt98Ybb6x3DFX3zXEcAgMDa21aV15eDo1GI1t25MgRxMfHQ6lUOtyuT58+4PnrRSsgIADR0dG214IgwNfXt8axtVptjWakpO1qK2U1MTERycnJyM/P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\n", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "sns.pairplot(df,hue='Label')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Veriyi Normalleştirme ve Kodlama\n", + "\n", + "Veriyi sinir ağı eğitimine hazırlamak için girdileri [0..1] aralığında normalleştirmemiz gerekiyor. Bu, düz `numpy` işlemleri veya [Scikit Learn yöntemleri](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.normalize.html) kullanılarak yapılabilir.\n", + "\n", + "Ayrıca, hedef etiketin birebir olarak kodlanmasını isteyip istemediğinize karar vermeniz gerekir. PyTorch ve TensorFlow, sınıf numarasını bir tamsayı (0'dan N-1'e kadar) veya birebir kodlanmış vektör olarak besleme yapmanızı sağlar. Sinir ağı yapısı oluştururken, buna göre kayıp fonksiyonunu belirtmeniz gerekir (örn. sayısal gösterim için *seyrek kategorik çapraz-entropi* ve birebir kodlama için *çapraz-entropi kaybı*). Birebir kodlama [Sklearn kullanılarak](https://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.OneHotEncoder.html) veya bu kod parçası kullanılarak da yapılabilir:\n", + "\n", + "```python\n", + "n_values = np.max(labels) + 1\n", + "labels_onehot = np.eye(n_values)[labels]\n", + "``` " + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "# Verileri normalleştirmek ve kodlamak için kod" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Veriyi Eğitim ve Test Olarak Bölme\n", + "\n", + "Ayrı eğitim ve test veri kümemiz olmadığı için, bunu eğitim ve test veri kümesini [Sklearn kullanarak](https://scikit-learn.org/stable/modules/generated/sklearn.model_selection.train_test_split.html) ayırmamız gerekiyor." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "# Veriyi Bölme" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Sinir Ağını Tanımlama ve Eğitme\n", + "\n", + "Artık yola çıkmaya hazırsınız, tercih ettiğiniz çerçeveyi içe aktarın, sinir ağını tanımlayın ve eğitimin davranışını ve geçerleme doğruluğunu gözlemleyerek eğitime başlayın." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "# Ağı tanımla" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "# Ağı eğit" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "# Eğitim/geçerleme doğruluk grafiğini görselleştirin" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Deney\n", + "\n", + "Artık sonucu nasıl etkilediğini görmek için farklı ağ mimarilerini deneyebilirsiniz. Deneyin:\n", + "1. 3 nöronlu tek katmanlı ağ (sınıf sayısına eşit)\n", + "1. Küçük/orta/büyük gizli katmana sahip iki katmanlı ağ\n", + "1. Daha fazla katman kullanma\n", + "\n", + "Çok sayıda nöron (parametre) içeren zengin modeli kullanırken, aşırı öğrenmeyi gözlemlediğinizden emin olun." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "# Deney" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Bölüm 2: MNIST Eğitimi\n", + "\n", + "Hem Keras hem de PyTorch yerleşik veri kümesi olarak MNIST'i içerir, bu nedenle onu birkaç satır kodla kolayca elde edebilirsiniz ([Keras](https://keras.io/api/datasets/mnist/), [PyTorch](https://pytorch.org/vision/stable/datasets.html)). Ayrıca hem eğitim hem de test veri kümelerini manuel olarak bölmeden yükleyebileceksiniz." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "# Veri kümesini yükleme" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Şimdi, veri kümesinin normalleştirildiğinden emin olmak (muhtemelen zaten olacaktır), bir sinir ağı tanımlayıp eğitmek için yukarıdaki adımları uygulamanız gerekir.\n", + "\n", + "## Ana Fikirler\n", + "\n", + "1. Sinir ağları, geleneksel makine öğrenmesi görevleri için kullanılabilir. Ancak, çoğu durumda çok güçlüdürler ve aşırı öğrenmeye neden olabilirler.\n", + "1. Bu ödevde aşırı öğrenme davranışını gözlemlemeniz ve bundan kaçınmaya çalışmanız önemlidir.\n", + "1. Keras gibi çerçevelerle, bazen bir sinir ağını eğitmek oldukça basittir. Ama neler olduğunu anlamalısınız." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.13" + }, + "vscode": { + "interpreter": { + "hash": "b0fa6594d8f4cbf19f97940f81e996739fb7646882a419484c72d19e05852a7e" + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/lessons/3-NeuralNetworks/05-Frameworks/lab/translations/README.tr.md b/lessons/3-NeuralNetworks/05-Frameworks/lab/translations/README.tr.md new file mode 100644 index 00000000..2c02ec1e --- /dev/null +++ b/lessons/3-NeuralNetworks/05-Frameworks/lab/translations/README.tr.md @@ -0,0 +1,16 @@ +# PyTorch/TensorFlow ile Sınıflandırma + +[Yeni Başlayanlar için YZ Müfredatı](https://github.com/microsoft/ai-for-beginners)'dan Laboratuvar Ödevi. + +## Görev + +PyTorch veya TensorFlow kullanarak tek ve çok katmanlı tam bağlı ağları kullanarak iki sınıflandırma sorununu çözün: + +1. **[Süsen (iris) sınıflandırması](https://en.wikipedia.org/wiki/Iris_flower_data_set)** problemi - klasik makine öğrenmesi tarafından ele alınabilen tablo girdi verileriyle ilgili bir problem örneği. Amacınız, süsenleri 4 sayısal parametreye dayalı olarak 3 sınıfa sınıflandırmak olacaktır. +1. Daha önce gördüğümüz **MNIST** el yazısı rakam sınıflandırma problemi. + +Elde edebileceğiniz en iyi doğruluğu elde etmek için farklı ağ mimarilerini deneyin. + +## Not Defteri Başlatma + +[LabFrameworks.tr.ipynb](LabFrameworks.tr.ipynb)'yi açarak laboratuvarı başlatın. From 309f35ae0201a753845b575cb3aff40b26c1387f Mon Sep 17 00:00:00 2001 From: semercim Date: Mon, 14 Nov 2022 21:10:00 +0100 Subject: [PATCH 38/38] Updated the quizzes --- .../src/assets/translations/tr/index.js | 4 +- .../src/assets/translations/tr/lesson-4.json | 2 +- .../src/assets/translations/tr/lesson-5.json | 115 ++++++++++++++++++ 3 files changed, 119 insertions(+), 2 deletions(-) create mode 100644 etc/quiz-app/src/assets/translations/tr/lesson-5.json diff --git a/etc/quiz-app/src/assets/translations/tr/index.js b/etc/quiz-app/src/assets/translations/tr/index.js index 0bea43ce..f75db058 100644 --- a/etc/quiz-app/src/assets/translations/tr/index.js +++ b/etc/quiz-app/src/assets/translations/tr/index.js @@ -2,12 +2,14 @@ import tr1 from './lesson-1.json'; import tr2 from './lesson-2.json'; import tr3 from './lesson-3.json'; import tr4 from './lesson-4.json'; +import tr5 from './lesson-5.json'; //add items here const quiz = { 0: tr1[0], 1: tr2[0], 2: tr3[0], - 3: tr4[0] + 3: tr4[0], + 4: tr5[0] }; export default quiz; diff --git a/etc/quiz-app/src/assets/translations/tr/lesson-4.json b/etc/quiz-app/src/assets/translations/tr/lesson-4.json index 16aa8be0..a6ba3bfb 100644 --- a/etc/quiz-app/src/assets/translations/tr/lesson-4.json +++ b/etc/quiz-app/src/assets/translations/tr/lesson-4.json @@ -59,7 +59,7 @@ }, { "id": 204, - "title": "Sinir Aşları: Ders Sonrası Sınavı", + "title": "Sinir Ağları: Ders Sonrası Sınavı", "quiz": [ { "questionText": "Bağlanım kaybı fonksiyonları için ____ kullanıyoruz", diff --git a/etc/quiz-app/src/assets/translations/tr/lesson-5.json b/etc/quiz-app/src/assets/translations/tr/lesson-5.json new file mode 100644 index 00000000..c28fdaf7 --- /dev/null +++ b/etc/quiz-app/src/assets/translations/tr/lesson-5.json @@ -0,0 +1,115 @@ +[ + { + "title": "Yeni Başlayanlar İçin YZ: Sınavlar", + "complete": "Tebrikler, sınavı tamamladınız!", + "error": "Üzgünüz, tekrar deneyin", + "quizzes": [ + { + "id": 105, + "title": "Sinir Ağları: Ön Sınav", + "quiz": [ + { + "questionText": "Derin sinir ağı eğitimi çok sayıda hesaplama gerektirir", + "answerOptions": [ + { + "answerText": "Doğru", + "isCorrect": true + }, + { + "answerText": "Yanlış", + "isCorrect": false + } + ] + }, + { + "questionText": "Aşırı öğrenme olmasının nedeni ____", + "answerOptions": [ + { + "answerText": "yetersiz test verisi", + "isCorrect": false + }, + { + "answerText": "çok güçlü model", + "isCorrect": true + }, + { + "answerText": "çıktı verisindeki çok fazla gürültü", + "isCorrect": false + } + ] + }, + { + "questionText": "Yanlılık hataları, ____ eğitim verileri arasındaki ilişkiyi doğru bir şekilde yakalayamadığından kaynaklanır.", + "answerOptions": [ + { + "answerText": "model", + "isCorrect": false + }, + { + "answerText": "algoritma", + "isCorrect": true + }, + { + "answerText": "bilgisayar", + "isCorrect": false + } + ] + } + ] + }, + { + "id": 205, + "title": "Çerçeveler: Ders Sonrası Sınavı", + "quiz": [ + { + "questionText": "Model nesnemizi derledikten sonra ____ fonksiyonunu çağırarak eğitiyoruz.", + "answerOptions": [ + { + "answerText": "fit (uydur)", + "isCorrect": true + }, + { + "answerText": "train (eğit)", + "isCorrect": false + }, + { + "answerText": "teach (öğret)", + "isCorrect": false + } + ] + }, + { + "questionText": "İkili çapraz entropi aynı zamanda logaritme kaybı olarak da adlandırılır.", + "answerOptions": [ + { + "answerText": "Doğru", + "isCorrect": true + }, + { + "answerText": "Yanlış", + "isCorrect": false + } + ] + }, + { + "questionText": "TensorFlow ____ PyTorch ____ tarafından geliştirilmiştir.", + "answerOptions": [ + { + "answerText": "Facebook, Google", + "isCorrect": false + }, + { + "answerText": "Google, Facebook", + "isCorrect": true + }, + { + "answerText": "Microsoft, Google", + "isCorrect": false + } + ] + } + ] + } + ] + } +] \ No newline at end of file