Commit 0dcbd2a1 authored by Loic Huder's avatar Loic Huder
Browse files

Pages

parent 94641abf
image: python
stages:
- deploy
......@@ -5,14 +7,17 @@ pages:
stage: deploy
script:
- pip3 install rst2html5 jupyter
- make presentations
- mkdir .public
- cp ipnyb/*.html .public
- cp ipynb/*.html .public
- cp -rt .public ipynb/fig ipynb/reveal.js
- mv .public public
artifacts:
paths:
- .public
- public
only:
- master
- web
- web
\ No newline at end of file
......@@ -10,7 +10,7 @@
"source": [
"# Pandas : Python Data Analysis Library\n",
"\n",
"<div><img style=\"float: left;margin-left : 70px\" src='images/pandas_logo.png' height=\"500\" width=\"500\"/>"
"<div><img style=\"float: left;margin-left : 70px\" src='fig/pandas_logo.png' height=\"500\" width=\"500\"/>"
]
},
{
......
%% Cell type:markdown id: tags:
# Pandas : Python Data Analysis Library
<div><img style="float: left;margin-left : 70px" src='images/pandas_logo.png' height="500" width="500"/>
<div><img style="float: left;margin-left : 70px" src='fig/pandas_logo.png' height="500" width="500"/>
%% Cell type:markdown id: tags:
# Pandas, a Data Analysis Library
pandas is an open source, BSD-licensed library providing high-performance, easy-to-use data structures and data analysis tools for the Python programming language.
GeoExtension : geopandas
%% Cell type:markdown id: tags:
# Webography
- Online Doc: https://pandas.pydata.org/
- CheatSheet : https://pandas.pydata.org/Pandas_Cheat_Sheet.pdf
- Tutorials:
- https://www.dataschool.io/easier-data-analysis-with-pandas/
- https://www.dataschool.io/data-science-best-practices-with-pandas/
- Pandas PySciDataGre Talk : https://python.univ-grenoble-alpes.fr/working-session-librairie-pandas.html
- GeoPandas : http://geopandas.org/
%% Cell type:markdown id: tags:
Code using pandas usually starts with the import statement
%% Cell type:code id: tags:
``` python
import pandas as pd
```
%% Cell type:markdown id: tags:
Pandas
- 2 data structures (Series, DataFrame) for data analysis
- multiple methods for convenient data filtering.
- toolkit utilities to perform input/output operations.
It can read data from a variety of formats such as CSV, TSV, MS Excel, etc.
%% Cell type:markdown id: tags:
Pandas has two main data structures for data storage
- Series
- DataFrame
%% Cell type:code id: tags:
``` python
## Series structure
import pandas as pd
import numpy as np
series1 = pd.Series([1,2,3,4])
print(series1)
print(series1.sum())
print(series1.mean())
print(series1.to_csv())
fruits = np.array(['kiwi','orange','mango','apple'])
series2 = pd.Series(fruits)
print(series2)
```
%%%% Output: stream
0 1
1 2
2 3
3 4
dtype: int64
10
2.5
0,1
1,2
2,3
3,4
0 kiwi
1 orange
2 mango
3 apple
dtype: object
%%%% Output: stream
/home/huderl/.local/lib/python3.6/site-packages/ipykernel_launcher.py:12: FutureWarning: The signature of `Series.to_csv` was aligned to that of `DataFrame.to_csv`, and argument 'header' will change its default value from False to True: please pass an explicit value to suppress this warning.
if sys.path[0] == '':
%% Cell type:markdown id: tags:
# Dataframe
A dictionnary of series where keys are column name
<div><img style="float: left;margin-left : 70px" src='fig/dataframe_type.png' height="800" width="800"/>
%% Cell type:markdown id: tags:
## How to create a data frame ?
%% Cell type:markdown id: tags:
### From scratch
%% Cell type:code id: tags:
``` python
## DataFrame structure
import pandas as pd
# Intialise data: dictionnary of lists.
data = {'Name':['John', 'Paul', 'Debby', 'Laura'], 'Sex':['Male','Male','Female','Female'], 'Age':[20, 40, 19, 30]}
# Create DataFrame
df = pd.DataFrame(data)
print(df)
type(df.Age)
```
%%%% Output: stream
Name Sex Age
0 John Male 20
1 Paul Male 40
2 Debby Female 19
3 Laura Female 30
%%%% Output: execute_result
pandas.core.series.Series
%% Cell type:markdown id: tags:
### From a file
%% Cell type:code id: tags:
``` python
import pandas as pd
df_person = pd.read_csv('files/person.txt', sep = ',', encoding="utf-8", header=0)
print(df_person)
```
%%%% Output: stream
Name Sex Age
0 John Male 20
1 Paul Male 40
2 Debby Female 19
3 Laura Female 30
%% Cell type:markdown id: tags:
By default, a new index is created
If you want use a field-based index, you have to specify it in the `read_csv` function:
```python
df_person = pd.read_csv('files/person.txt', sep = ',', index_col='Name', encoding="utf-8", header=0)
```
%% Cell type:markdown id: tags:
## Basic commands
%% Cell type:code id: tags:
``` python
# display simple statistics
print(df_person.describe())
```
%%%% Output: stream
Age
count 4.000000
mean 27.250000
std 9.844626
min 19.000000
25% 19.750000
50% 25.000000
75% 32.500000
max 40.000000
%% Cell type:code id: tags:
``` python
# display the dataframe columns
print(df_person.columns)
```
%%%% Output: stream
Index(['Name', 'Sex', 'Age'], dtype='object')
%% Cell type:code id: tags:
``` python
# query one column
print(df_person["Age"])
# another method to query one column
print(df_person.Age)
```
%%%% Output: stream
0 20
1 40
2 19
3 30
Name: Age, dtype: int64
0 20
1 40
2 19
3 30
Name: Age, dtype: int64
%% Cell type:code id: tags:
``` python
# query multiple columns
print(df_person[['Name','Age']])
```
%%%% Output: stream
Name Age
0 John 20
1 Paul 40
2 Debby 19
3 Laura 30
%% Cell type:code id: tags:
``` python
# display unique value of a column
print(df_person.Sex.unique())
```
%%%% Output: stream
['Male' 'Female']
%% Cell type:code id: tags:
``` python
# display the 5 first rows
print(df_person.head())
# display the 5 last rows
print(df_person.tail())
# display 2 first rows
print(df_person[:2])
# display by position number
print(df_person.iloc[2])
print(df_person.iloc[:])
```
%%%% Output: stream
Name Sex Age
0 John Male 20
1 Paul Male 40
2 Debby Female 19
3 Laura Female 30
Name Sex Age
0 John Male 20
1 Paul Male 40
2 Debby Female 19
3 Laura Female 30
Name Sex Age
0 John Male 20
1 Paul Male 40
Name Debby
Sex Female
Age 19
Name: 2, dtype: object
Name Sex Age
0 John Male 20
1 Paul Male 40
2 Debby Female 19
3 Laura Female 30
%% Cell type:code id: tags:
``` python
print(df_person.loc[2])
```
%%%% Output: stream
Name Debby
Sex Female
Age 19
Name: 2, dtype: object
%% Cell type:code id: tags:
``` python
# Basic operations on columns
df_person.Age = df_person.Age + 2
print(df_person.Age)
```
%%%% Output: stream
0 22
1 42
2 21
3 32
Name: Age, dtype: int64
%% Cell type:markdown id: tags:
### Add a row
%% Cell type:code id: tags:
``` python
df_person = df_person.append({'Name':'Glenn', 'Sex':'Male', 'Age':10}, ignore_index=True)
df_person
```
%%%% Output: execute_result
Name Sex Age
0 John Male 22
1 Paul Male 42
2 Debby Female 21
3 Laura Female 32
4 Glenn Male 10
%% Cell type:markdown id: tags:
### Add some rows
%% Cell type:code id: tags:
``` python
data = {'Name':['Marguerite', 'Annie', 'Stephen', 'Ava'], 'Sex':['Female','Female','Male','Female'], 'Age':[34, 23, 49, 22]}
df_person = df_person.append(pd.DataFrame(data), ignore_index=True)
df_person
```
%%%% Output: execute_result
Name Sex Age
0 John Male 22
1 Paul Male 42
2 Debby Female 21
3 Laura Female 32
4 Glenn Male 10
5 Marguerite Female 34
6 Annie Female 23
7 Stephen Male 49
8 Ava Female 22
%% Cell type:markdown id: tags:
### Add a column
%% Cell type:code id: tags:
``` python
df_person["Nationality"] = 'USA'
df_person
```
%%%% Output: execute_result
Name Sex Age Nationality
0 John Male 22 USA
1 Paul Male 42 USA
2 Debby Female 21 USA
3 Laura Female 32 USA
4 Glenn Male 10 USA
5 Marguerite Female 34 USA
6 Annie Female 23 USA
7 Stephen Male 49 USA
8 Ava Female 22 USA
%% Cell type:markdown id: tags:
## Basic statistics
%% Cell type:code id: tags:
``` python
type(df_person.Age)
```
%%%% Output: execute_result
pandas.core.series.Series
%% Cell type:code id: tags:
``` python
## Mean
print(df_person.Age.mean())
## Min and Max
print(df_person.Age.min())
print(df_person.Age.max())
print(df_person.Age.count())
```
%%%% Output: stream
28.333333333333332
10
49
9
%% Cell type:markdown id: tags:
## How to sort data ?
%% Cell type:code id: tags:
``` python
df_person_sorted = df_person.sort_values(['Age'], ascending=True)
print(df_person_sorted)
```
%%%% Output: stream
Name Sex Age Nationality
4 Glenn Male 10 USA
2 Debby Female 21 USA
0 John Male 22 USA
8 Ava Female 22 USA
6 Annie Female 23 USA
3 Laura Female 32 USA
5 Marguerite Female 34 USA
1 Paul Male 42 USA
7 Stephen Male 49 USA
%% Cell type:markdown id: tags:
## Selection
%% Cell type:code id: tags:
``` python
# selection with one criterion
print(df_person[df_person['Sex'] == 'Female'])
print("--------------------")
print(df_person[df_person['Age'] < 20])
print("--------------------")
# selection with 2 criteria
print(df_person[(df_person['Sex'] == 'Male') & (df_person['Age'] > 30)])
```
%%%% Output: stream
Name Sex Age Nationality
2 Debby Female 21 USA
3 Laura Female 32 USA
5 Marguerite Female 34 USA
6 Annie Female 23 USA
8 Ava Female 22 USA
--------------------
Name Sex Age Nationality
4 Glenn Male 10 USA
--------------------
Name Sex Age Nationality
1 Paul Male 42 USA
7 Stephen Male 49 USA
%% Cell type:markdown id: tags:
## Update data
%% Cell type:code id: tags:
``` python
# change one value by index
df_person.loc[7, "Name"] = "Stephane"
print(df_person)
# change one value after a selection
df_person.loc[df_person["Name"] == 'Stephane', "Name"] = "Eric"
print(df_person)
```
%%%% Output: stream
Name Sex Age Nationality
0 John Male 22 USA
1 Paul Male 42 USA
2 Debby Female 21 USA
3 Laura Female 32 USA
4 Glenn Male 10 USA
5 Marguerite Female 34 USA
6 Annie Female 23 USA
7 Stephane Male 49 USA
8 Ava Female 22 USA
Name Sex Age Nationality
0 John Male 22 USA
1 Paul Male 42 USA
2 Debby Female 21 USA
3 Laura Female 32 USA
4 Glenn Male 10 USA
5 Marguerite Female 34 USA
6 Annie Female 23 USA
7 Eric Male 49 USA
8 Ava Female 22 USA
%% Cell type:code id: tags:
``` python
## Add a column
df_person["City"] = "City"
print(df_person)
## Delete a column
df_person = df_person.drop("City", axis=1)
print(df_person)
```
%%%% Output: stream
Name Sex Age Nationality City
0 John Male 22 USA City
1 Paul Male 42 USA City
2 Debby Female 21 USA City
3 Laura Female 32 USA City
4 Glenn Male 10 USA City
5 Marguerite Female 34 USA City
6 Annie Female 23 USA City
7 Eric Male 49 USA City
8 Ava Female 22 USA City
Name Sex Age Nationality
0 John Male 22 USA
1 Paul Male 42 USA
2 Debby Female 21 USA
3 Laura Female 32 USA
4 Glenn Male 10 USA
5 Marguerite Female 34 USA
6 Annie Female 23 USA
7 Eric Male 49 USA
8 Ava Female 22 USA
%% Cell type:markdown id: tags:
## Concat
<div><img style="float: left;margin-left : 70px" src='fig/concat-example.png' height="600" width="600"/>
%% Cell type:code id: tags:
``` python
data = {'Name':['Benedicte', 'Bernard', 'Nicolas', 'Anne'], 'Sex':['Female','Male','Male','Female'], 'Age':[24, 34, 49, 42],'Nationality':['FR','FR','FR','FR']}
df_person_fr = pd.DataFrame(data)
list_person = [df_person,df_person_fr]
result = pd.concat(list_person)
print(result)
```
%%%% Output: stream
Name Sex Age Nationality
0 John Male 22 USA
1 Paul Male 42 USA
2 Debby Female 21 USA
3 Laura Female 32 USA
4 Glenn Male 10 USA
5 Marguerite Female 34 USA
6 Annie Female 23 USA
7 Eric Male 49 USA
8 Ava Female 22 USA
0 Benedicte Female 24 FR
1 Bernard Male 34 FR
2 Nicolas Male 49 FR
3 Anne Female 42 FR
%% Cell type:markdown id: tags:
## Join
<div><img style="float: left;margin-left : 70px" src='fig/join-example.png' height="600" width="600"/>
%% Cell type:code id: tags:
``` python
import random
data = {'id_Address':[0, 1, 2, 3], 'Address':['gordon street', 'aqua boulevard', 'st georges street', '5th street'], 'City':['Boston', 'Chicago', 'Charlotte', 'San Francisco']}
# Create DataFrame
df_address = pd.DataFrame(data)
print(df_address)
df_person["id_Address"] = ""
nb_elements = df_person.Name.count()
cpt = 0
while(cpt < nb_elements):
df_person.loc[cpt,"id_Address"] = random.randint(0, 3)
cpt = cpt + 1
print(df_person)
result = pd.merge(df_person, df_address, how='left', on='id_Address')
print(result)
```
%%%% Output: stream
id_Address Address City
0 0 gordon street Boston
1 1 aqua boulevard Chicago
2 2 st georges street Charlotte
3 3 5th street San Francisco
Name Sex Age Nationality id_Address
0 John Male 22 USA 3
1 Paul Male 42 USA 2
2 Debby Female 21 USA 3
3 Laura Female 32 USA 0
4 Glenn Male 10 USA 3
5 Marguerite Female 34 USA 0
6 Annie Female 23 USA 0
7 Eric Male 49 USA 3
8 Ava Female 22 USA 1
Name Sex Age Nationality id_Address Address \
0 John Male 22 USA 3 5th street
1 Paul Male 42 USA 2 st georges street
2 Debby Female 21 USA 3 5th street
3 Laura Female 32 USA 0 gordon street
4 Glenn Male 10 USA 3 5th street
5 Marguerite Female 34 USA 0 gordon street
6 Annie Female 23 USA 0 gordon street
7 Eric Male 49 USA 3 5th street
8 Ava Female 22 USA 1 aqua boulevard
City
0 San Francisco
1 Charlotte
2 San Francisco
3 Boston
4 San Francisco
5 Boston
6 Boston
7 San Francisco
8 Chicago
%% Cell type:markdown id: tags:
## Group By
- Splitting the data into groups based on some criteria.
- Applying a function to each group independently.
- Combining the results into a data structure.
<div><img style="float: left;margin-left : 70px" src='fig/groupby-example.png' height="800" width="800"/>
%% Cell type:code id: tags:
``` python
print(df_person.groupby('Sex')['Sex'].count())
print(df_person.groupby('Sex')['Age'].mean())
```
%%%% Output: stream
Sex
Female 5
Male 4
Name: Sex, dtype: int64
Sex
Female 26.40
Male 30.75
Name: Age, dtype: float64
%% Cell type:markdown id: tags:
## Export data
%% Cell type:code id: tags:
``` python
export_csv = df_person.to_csv(r'./files/export_person.csv', index=None, header=True)
```
%% Cell type:markdown id: tags:
## Plot data
%% Cell type:code id: tags:
``` python
%matplotlib inline
df_person.groupby('Sex')['Sex'].count().plot.bar()
```
%%%% Output: execute_result
<matplotlib.axes._subplots.AxesSubplot at 0x7febf9fdf9b0>
%%%% Output: display_data
[Hidden Image Output]
%% Cell type:markdown id: tags:
# DIY
%% Cell type:markdown id: tags:
## Goals : Compute light statistics on IMDB Movies files
The goal of this session is to end up with a script that computes some simple statistics from IMDB Movies files. The file was modified and reduced for this exercice
Material
Data are in 2 files Directory named "files"
- name.tsv
This file contains the actors, the separation character is tabulation '\t'. The first line is the header.
```
nconst primaryName birthYear deathYear primaryProfession knownForTitles
```
- title.tsv
This file contains the movies, the separation character is ','. The first line is the header.
```
tconst,titleType,primaryTitle,originalTitle,isAdult,startYear,endYear,runtimeMinutes,genres
```
We want to
- load data from tsv file
- compute some basic statistics
- save data to tsv file
%% Cell type:markdown id: tags:
## Compute some basic statistics
1. Count the number of movies
2. Display the latest movies
3. Display the movies between 1939 and 1940
4. Diplay all the available titleType
5. Count the number of movies by titleType
6. Display Humphrey Bogart movies
7. Plot movie count by year between 1950 and 1960
%% Cell type:markdown id: tags:
## A possible correction
%% Cell type:code id: tags:
``` python
# load data
df_title = pd.read_csv('files/diy_12_pandas/title.tsv', sep = ',', encoding = "utf-8", header=0)
print(df_title.index)
print(df_title.head())
#1
print(df_title.primaryTitle.count())
#2
print(df_title.sort_values(['startYear'], ascending=False).head())
#3
print(df_title[(df_title.startYear>=1939) & (df_title.startYear<=1940)]['originalTitle'])
#4
print(df_title["titleType"].unique())
#5
print(df_title.groupby("titleType")["titleType"].count())
#6
df_name = pd.read_csv('files/diy_12_pandas/name.tsv', sep = '\t', encoding = "utf-8", header=0)
author_titles = df_name.loc[df_name['primaryName']=='Humphrey Bogart']['knownForTitles']
print(df_title.loc[df_title['tconst'].isin(author_titles.tolist()[0].split(','))])
#7
df_title[(df_title['startYear']>=1950) & (df_title['startYear']<=1960)].groupby("startYear")["startYear"].count().plot.bar()
```
%%%% Output: stream
RangeIndex(start=0, stop=135460, step=1)
tconst titleType primaryTitle \
0 tt0000009 movie Miss Jerry
1 tt0000020 short The Derby 1895
2 tt0000024 short Opening of the Kiel Canal
3 tt0000025 short The Oxford and Cambridge University Boat Race
4 tt0000165 short Riña en un café
originalTitle isAdult startYear endYear \
0 Miss Jerry 0 1894.0 NaN
1 The Derby 1895 0 1895.0 NaN
2 Opening of the Kiel Canal 0 1895.0 NaN
3 The Oxford and Cambridge University Boat Race 0 1895.0 NaN
4 Riña en un café 0 1897.0 NaN
runtimeMinutes genres
0 45.0 Romance
1 1.0 Documentary,Short,Sport
2 NaN News,Short
3 NaN News,Short,Sport
4 1.0 Short
135460
tconst titleType primaryTitle originalTitle \
123383 tt3554046 movie Space Jam 2 Space Jam 2
112158 tt1630029 movie Avatar 2 Avatar 2
132762 tt7304824 movie Ofrenda a la tormenta Ofrenda a la tormenta
134753 tt8984382 movie Jagdzeit Jagdzeit
131619 tt6615224 movie HeadShop HeadShop
isAdult startYear endYear runtimeMinutes \
123383 0 2021.0 NaN NaN
112158 0 2021.0 NaN NaN
132762 0 2020.0 NaN NaN
134753 0 2020.0 NaN NaN
131619 0 2020.0 NaN NaN
genres
123383 Action,Adventure,Animation
112158 Action,Adventure,Fantasy
132762 Crime,Thriller
134753 Drama
131619 Comedy
3530 Así es la vida
5342 Alhambra
5438 Dernière jeunesse
5484 El genio alegre
5577 María de la O
5611 Olympic Honeymoon
5648 El rayo
5756 Usted tiene ojos de mujer fatal
5780 3:1 a szerelem javára
5792 Allegri masnadieri
5933 Ho perduto mio marito
6024 Molinos de viento
6033 My Favorite Wife
6145 L'ultima nemica
6196 Aldeia da Roupa Branca
6216 La bestia negra
6253 Cossacks in Exile
6270 Le due madri
6274 Der Edelweißkönig
6277 Eravamo 7 sorelle
6281 Farinet ou l'or dans la montagne
6288 I figli del marchese Lucera
6335 Io, suo padre
6383 Marionette
6399 Napoli che non muore
6401 Narcisse
6424 Piccoli naufraghi
6433 Prinzessin Sissy
6495 Suspiros de España
6507 Terra di fuoco
...
106234 Swinguette
107773 Hatsukoi
107803 Shamisen bushi
111182 Stranger Than Fiction, #69
112706 Patriot
115430 Elnémult harangok
116809 Sai shang feng yun
117975 The Brown Bomber
121499 The Green Goddess
121557 Stozhary
122719 Yesterday Is Over Your Shoulder
122967 Sabakaruru onna
124321 Verena Stadler
125342 Boevye stranitsy
125380 Death at Newtown-Stewart
125391 The Sleeping Princess
125455 Chances Fair and Choosers True
125490 Plain Jane
127362 United Action Means Victory
127519 Salute to America
127520 Living in Hollywood
127874 Cavalcade of Variety
129070 The Tempest/II
129406 NBC News
131267 World in Flames
131626 Hirurgiya
131807 Hurricane Special
131951 Då länkarna smiddes
133077 En correctionnelle
134454 Hollywood Funtime, Program 2
Name: originalTitle, Length: 1004, dtype: object
['movie' 'short' 'tvMovie' 'tvSeries' 'tvMiniSeries' 'tvShort' 'tvSpecial'
'tvEpisode' 'video' 'videoGame']
titleType
movie 86687
short 12624
tvEpisode 13
tvMiniSeries 2651
tvMovie 9199
tvSeries 17863
tvShort 410
tvSpecial 695
video 4465
videoGame 853
Name: titleType, dtype: int64
tconst titleType primaryTitle originalTitle \
7458 tt0033870 movie The Maltese Falcon The Maltese Falcon
7678 tt0034583 movie Casablanca Casablanca
8620 tt0037382 movie To Have and Have Not To Have and Have Not
10879 tt0043265 movie The African Queen The African Queen
isAdult startYear endYear runtimeMinutes genres
7458 0 1941.0 NaN 100.0 Film-Noir,Mystery
7678 0 1942.0 NaN 102.0 Drama,Romance,War
8620 0 1944.0 NaN 100.0 Adventure,Comedy,Romance
10879 0 1951.0 NaN 105.0 Adventure,Drama,Romance
%%%% Output: execute_result
<matplotlib.axes._subplots.AxesSubplot at 0x7febf58d2ac8>
%%%% Output: display_data
[Hidden Image Output]
......
......@@ -307,7 +307,7 @@
"source": [
"## Anatomy of a Matplotlib figure\n",
"\n",
"![Anatomy of a figure](images/anatomy.png)\n",
"![Anatomy of a figure](fig/anatomy.png)\n",
"\n",
"For consistent figure changes, define your own stylesheets that are basically a list of parameters to tune the aspect of the figure elements.\n",
"See https://matplotlib.org/tutorials/introductory/customizing.html for more info."
%% Cell type:markdown id: tags:
 
# Python training UGA 2017
 
**A training to acquire strong basis in Python to use it efficiently**
 
Pierre Augier (LEGI), Cyrille Bonamy (LEGI), Eric Maldonado (Irstea), Franck Thollard (ISTerre), Oliver Henriot (GRICAD), Christophe Picard (LJK), Loïc Huder (ISTerre)
 
# Python scientific ecosystem
# A short introduction to Matplotlib ([gallery](http://matplotlib.org/gallery.html))
 
%% Cell type:markdown id: tags:
 
The default library to plot data is `Matplotlib`.
It allows one the creation of graphs that are ready for publications with the same functionality than Matlab.
 
%% Cell type:code id: tags:
 
``` python
# these ipython commands load special backend for notebooks
# (do not use "notebook" outside jupyter)
# %matplotlib notebook
# for jupyter-lab:
# %matplotlib ipympl
%matplotlib inline
```
 
%% Cell type:markdown id: tags:
 
When running code using matplotlib, it is highly recommended to start ipython with the option `--matplotlib` (or to use the magic ipython command `%matplotlib`).
 
%% Cell type:code id: tags:
 
``` python
import numpy as np
import matplotlib.pyplot as plt
```
 
%% Cell type:code id: tags:
 
``` python
A = np.random.random([5,5])
```
 
%% Cell type:markdown id: tags:
 
You can plot any kind of numerical data.
 
%% Cell type:code id: tags:
 
``` python
lines = plt.plot(A)
```
 
%%%% Output: display_data
 
[Hidden Image Output]
 
%% Cell type:markdown id: tags:
 
In scripts, the `plt.show` method needs to be invoked at the end of the script.
 
%% Cell type:markdown id: tags:
 
We can plot data by giving specific coordinates.
 
%% Cell type:code id: tags:
 
``` python
x = np.linspace(0, 2, 20)
y = x**2
```
 
%% Cell type:code id: tags:
 
``` python
plt.figure()
plt.plot(x,y, label='Square function')
plt.xlabel('x')
plt.ylabel('y')
plt.legend()
```
 
%%%% Output: execute_result
 
<matplotlib.legend.Legend at 0x7f39e3136d68>
 
%%%% Output: display_data
 
[Hidden Image Output]
 
%% Cell type:markdown id: tags:
 
We can associate the plot with an object figure. This object will allow us to add labels, subplot, modify the axis or save it as an image.
 
%% Cell type:code id: tags:
 
``` python
fig = plt.figure()
ax = fig.add_subplot(111)
res = ax.plot(x, y, color="red", linestyle='dashed', linewidth=3, marker='o',
markerfacecolor='blue', markersize=5)
 
ax.set_xlabel('$Re$')
ax.set_ylabel('$\Pi / \epsilon$')
```
 
%%%% Output: execute_result
 
Text(0, 0.5, '$\\Pi / \\epsilon$')
 
%%%% Output: display_data
 
[Hidden Image Output]
 
%% Cell type:markdown id: tags:
 
We can also recover the plotted matplotlib object to get info on it.
 
%% Cell type:code id: tags:
 
``` python
line_object = res[0]
print(type(line_object))
print('Color of the line is', line_object.get_color())
print('X data of the plot:', line_object.get_xdata())
```
 
%%%% Output: stream
 
<class 'matplotlib.lines.Line2D'>
Color of the line is red
X data of the plot: [0. 0.10526316 0.21052632 0.31578947 0.42105263 0.52631579
0.63157895 0.73684211 0.84210526 0.94736842 1.05263158 1.15789474
1.26315789 1.36842105 1.47368421 1.57894737 1.68421053 1.78947368
1.89473684 2. ]
 
%% Cell type:markdown id: tags:
 
### Example of multiple subplots
 
%% Cell type:code id: tags:
 
``` python
fig = plt.figure()
ax1 = fig.add_subplot(211) # First, number of subplots along X (2), then along Y (1), then the id of the subplot (1)
ax2 = fig.add_subplot(212, sharex=ax1) # It is possible to share axes between subplots
X = np.arange(0, 2*np.pi, 0.1)
ax1.plot(X, np.cos(2*X), color="red")
ax2.plot(X, np.sin(2*X), color="magenta")
ax2.set_xlabel('Angle (rad)')
```
 
%%%% Output: execute_result
 
Text(0.5, 0, 'Angle (rad)')
 
%%%% Output: display_data
 
[Hidden Image Output]
 
%% Cell type:markdown id: tags:
 
## Anatomy of a Matplotlib figure
 
![Anatomy of a figure](images/anatomy.png)
![Anatomy of a figure](fig/anatomy.png)
 
For consistent figure changes, define your own stylesheets that are basically a list of parameters to tune the aspect of the figure elements.
See https://matplotlib.org/tutorials/introductory/customizing.html for more info.
 
%% Cell type:markdown id: tags:
 
We can also plot 2D data arrays.
 
%% Cell type:code id: tags:
 
``` python
noise = np.random.random((256,256))
plt.figure()
plt.imshow(noise)
```
 
%%%% Output: execute_result
 
<matplotlib.image.AxesImage at 0x7f39e2ef9438>
 
%%%% Output: display_data
 
[Hidden Image Output]
 
%% Cell type:markdown id: tags:
 
We can also add a colorbar and adjust the colormap.
 
%% Cell type:code id: tags:
 
``` python
plt.figure()
plt.imshow(noise, cmap=plt.cm.gray)
plt.colorbar()
```
 
%%%% Output: execute_result
 
<matplotlib.colorbar.Colorbar at 0x7f39e167e780>
 
%%%% Output: display_data
 
[Hidden Image Output]
 
%% Cell type:markdown id: tags:
 
#### Choose your colormaps wisely !
When doing such colorplots, it is easy to lose the interesting features by setting a colormap that is not adapted to the data.
 
Also, when producing scientific figures, think about how will your plot will look like to colorblind people or in greyscales (as it can happen in printed articles...).
 
See the interesting discussion on matplotlib website: https://matplotlib.org/users/colormaps.html.
 
%% Cell type:markdown id: tags:
 
## Other plot types
Matplotlib also allows to plot:
- Histograms
- Plots with error bars
- Box plots
- Contours
- in 3D
- ...
 
See the [gallery](http://matplotlib.org/gallery.html) to see what suits you the most.
 
%% Cell type:markdown id: tags:
 
## Do it yourself:
 
With miscellaneous routines of scipy we can get an example image:
 
%% Cell type:code id: tags:
 
``` python
import scipy.misc
raccoon = np.array(scipy.misc.face())
```
 
%% Cell type:markdown id: tags:
 
Write a script to print shape and dtype the raccoon image. Next plot the image using matplotlib.
 
%% Cell type:code id: tags:
 
``` python
print("shape of raccoon = ", raccoon.shape)
print("dtype of raccoon = ", raccoon.dtype)
```
 
%%%% Output: stream
 
shape of raccoon = (768, 1024, 3)
dtype of raccoon = uint8
 
%% Cell type:code id: tags:
 
``` python
plt.imshow(raccoon)
```
 
%%%% Output: execute_result
 
<matplotlib.image.AxesImage at 0x7f39e00aba58>
 
%%%% Output: display_data
 
[Hidden Image Output]
 
%% Cell type:markdown id: tags:
 
0. Write a script to generate a border around the raccoon image (for example a 20 pixel size black border; black color code is 0 0 0)
 
1. Do it again without losing pixels and generate then a raccoon1 array/image
 
2. 1. Mask the face of the raccoon with a grey circle (centered of radius 240 at location 690 260 of the raccoon1 image; grey color code is for example (120 120 120))
2. Mask the face of the raccon with a grey square by using NumPy broadcast capabilities (height and width 480 and same center as before)
 
3. We propose to smooth the image : the value of a pixel of the smoothed image is the the average of the values of its neighborhood (ie the 8 neighbors + itself).
 
%% Cell type:markdown id: tags:
 
### Solution 0
 
Write a script to generate a border around the raccoon image (for example a 20 pixel size black border; black color code is 0 0 0)
 
%% Cell type:code id: tags:
 
``` python
raccoon[0:20, :, :] = 0
raccoon[-20:-1, :, :] = 0
raccoon[:, 0:20, :] = 0
raccoon[:, -20:-1, :] = 0
plt.imshow(raccoon)
```
 
%%%% Output: execute_result
 
<matplotlib.image.AxesImage at 0x7f39ce79dbe0>
 
%%%% Output: display_data
 
[Hidden Image Output]
 
%% Cell type:markdown id: tags:
 
### Solution 1
 
Do it again without losing pixels and generate then a raccoon1 array/image
 
%% Cell type:code id: tags:
 
``` python
raccoon = np.array(scipy.misc.face())
print("shape of raccoon = ", raccoon.shape)
n0, n1, n2 = raccoon.shape
raccoon1 = np.zeros((n0+40, n1+40, n2), dtype = np.uint8)
raccoon1[20:20+n0, 20:20+n1, :] = raccoon[:,:,:]
print("shape of raccoon1 = ", raccoon1.shape)
plt.imshow(raccoon1)
```
 
%%%% Output: stream
 
shape of raccoon = (768, 1024, 3)
shape of raccoon1 = (808, 1064, 3)
 
%%%% Output: execute_result
 
<matplotlib.image.AxesImage at 0x7f39ce6ffa90>
 
%%%% Output: display_data
 
[Hidden Image Output]
 
%% Cell type:markdown id: tags:
 
### Solution 2.A
 
Mask the face of the raccoon with a grey circle (centered of radius 240 at location 690 260 of the raccoon1 image; grey color code is for example (120 120 120))
 
%% Cell type:code id: tags:
 
``` python
raccoon2A = raccoon1.copy()
x_center = 260
y_center = 690
radius = 240
x_max, y_max, z = raccoon2A.shape
for i in range(x_max):
for j in range(y_max):
if ((j - y_center)**2 + (i-x_center)**2) <= radius**2:
raccoon2A[i, j, :] = 120
plt.imshow(raccoon2A)
```
 
%%%% Output: execute_result
 
<matplotlib.image.AxesImage at 0x7f39ce6e65f8>
 
%%%% Output: display_data
 
[Hidden Image Output]
 
%% Cell type:markdown id: tags:
 
### Solution 2.B
 
Mask the face of the raccon with a grey square by using NumPy broadcast capabilities (height and width 480 and same center as before)
 
%% Cell type:code id: tags:
 
``` python
raccoon2B = raccoon1.copy()
 
raccoon2B[x_center-radius:x_center+radius, y_center-radius:y_center+radius, :] = 120
 
plt.imshow(raccoon2B)
```
 
%%%% Output: execute_result
 
<matplotlib.image.AxesImage at 0x7f39ce6410b8>
 
%%%% Output: display_data
 
[Hidden Image Output]
 
%% Cell type:markdown id: tags:
 
### Solution 3
 
We propose to smooth the image : the value of a pixel of the smoothed image is the
the average of the values of its neighborhood (ie the 8 neighbors + itself).
 
%% Cell type:code id: tags:
 
``` python
import scipy.misc
raccoon = scipy.misc.face().astype(np.uint16)
n0, n1, n2 = raccoon.shape
raccoon1 = np.zeros((n0, n1, n2), dtype = np.uint8)
for i in range(n0):
for j in range(n1):
if ((i!=0) and (i!=n0-1) and (j!=0) and (j!=n1-1)):
tmp = (
raccoon[i, j] + raccoon[i+1, j] + raccoon[i-1, j] + raccoon[i, j+1] + raccoon[i, j-1]
+ raccoon[i+1, j+1] + raccoon[i-1, j-1] + raccoon[i+1, j-1] + raccoon[i-1, j+1])
raccoon1[i, j] = tmp/9
plt.imshow(raccoon1)
```
 
%%%% Output: execute_result
 
<matplotlib.image.AxesImage at 0x7f39ce629278>
 
%%%% Output: display_data
 
[Hidden Image Output]
 
%% Cell type:markdown id: tags:
 
## Extra :
- Try to optimize (vectorization can be a solution)
 
 
- You can check what is a "sum area table" (or integral image) https://en.wikipedia.org/wiki/Summed-area_table and how to use it in our example.
- compute the area image (check the "cumsum" numpy function)
- use it to smooth your image.
 
%% Cell type:markdown id: tags:
 
### Solution extra
 
%% Cell type:code id: tags:
 
``` python
def smooth(img):
img = img.astype(np.uint16)
n0, n1, n2 = img.shape
img1 = np.zeros((n0, n1, n2), dtype=np.uint16)
for i in range(n0):
for j in range(n1):
if ((i!=0) and (i!=n0-1) and (j!=0) and (j!=n1-1)):
tmp = (
img[i, j] + img[i+1, j] + img[i-1, j] + img[i, j+1] + img[i, j-1] +
img[i+1, j+1] + img[i-1, j-1] + img[i+1, j-1] + img[i-1, j+1])
img1[i, j] = tmp/9
return img1.astype(np.uint8)
 
 
def smooth1(img):
img = img.astype(np.uint16)
n0, n1, n2 = img.shape
img1 = np.zeros((n0, n1, n2), dtype=np.uint16)
img1[1:n0-1, 1:n1-1] = (
img[1:n0-1,1:n1-1] + img[2:n0, 1:n1-1] + img[0:n0-2, 1:n1-1] + img[1:n0-1, 2:n1] +
img[1:n0-1, 0:n1-2] + img[2:n0, 2:n1] + img[0:n0-2, 0:n1-2] + img[2:n0, 0:n1-2] +
img[0:n0-2, 2:n1])
img1 = img1/9
return img1.astype(np.uint8)
 
 
def smooth2(img):
from scipy import signal
img = img.astype(np.uint16)
square8 = np.ones((3, 3), dtype=np.uint16)
for i in range(3):
img[:, :, i] = signal.fftconvolve(img[:, :, i], square8, mode='same')/9
return img.astype(np.uint8)
 
 
def smooth3(img):
from scipy import signal
img = img.astype(np.uint16)
n0, n1, n2 = img.shape
img1 = np.zeros((n0, n1, n2), dtype=np.uint16)
square8 = np.ones((3, 3), dtype=np.uint16)
for i in range(3):
img1[:, :, i] = signal.convolve2d(img[:, :, i], square8, mode='same')/9
return img1.astype(np.uint8)
 
 
def smooth4(img):
img = img.astype(np.uint16)
n0, n1, n2 = img.shape
img1 = np.zeros((n0, n1, n2), dtype=np.uint16)
sum_area = np.cumsum(np.cumsum(img, axis=0), axis=1)
img1[2:n0-1, 2:n1-1] = (
sum_area[3:n0, 3:n1] + sum_area[0:n0-3, 0:n1-3] -
sum_area[3:n0, 0:n1-3] - sum_area[0:n0-3, 3:n1])
img1 = img1/9
return img1.astype(np.uint8)
 
 
def smooth_loop(method, niter, img):
for i in range(niter):
img = method(img)
return img
 
import scipy.misc
raccoon = scipy.misc.face()
%timeit smooth_loop(smooth, 1, raccoon)
%timeit smooth_loop(smooth1, 1, raccoon)
%timeit smooth_loop(smooth2, 1, raccoon)
%timeit smooth_loop(smooth3, 1, raccoon)
%timeit smooth_loop(smooth4, 1, raccoon)
 
raccoon = smooth_loop(smooth1, 20, raccoon)
plt.imshow(raccoon)
```
 
%%%% Output: stream
 
5.71 s ± 178 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
25.3 ms ± 96.6 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
233 ms ± 640 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
78.7 ms ± 442 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
106 ms ± 370 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
 
%%%% Output: execute_result
 
<matplotlib.image.AxesImage at 0x7f39c9a936d8>
 
%%%% Output: display_data
 
[Hidden Image Output]
......@@ -61,7 +61,7 @@
"## Object-oriented plots\n",
"\n",
"While doing the job, the previous example does not allow to unveil the power of matplotlib. For that, we need to keep in mind that in matplotlib plots, **everything** is an object.\n",
"<img src='images/anatomy.png' alt='https://matplotlib.org/gallery/showcase/anatomy.html' />\n",
"<img src='fig/anatomy.png' alt='https://matplotlib.org/gallery/showcase/anatomy.html' />\n",
"\n",
"It is therefore possible to change any aspect of the figure by acting on the appropriate objects. "
]
......
%% Cell type:markdown id: tags:
# Advanced matplotlib
Pierre Augier (LEGI), Cyrille Bonamy (LEGI), Eric Maldonado (Irstea), Franck Thollard (ISTerre), Christophe Picard (LJK), Loïc Huder (ISTerre)
%% Cell type:markdown id: tags:
## Introduction
This is the second part of the introductive presentation given in the [Python initiation training](https://gricad-gitlab.univ-grenoble-alpes.fr/python-uga/py-training-2017/blob/master/ipynb/pres111_intro_matplotlib.ipynb).
The aim is to present more advanced usecases of matplotlib.
%% Cell type:markdown id: tags:
## Quick reminders
%% Cell type:code id: tags:
``` python
import numpy as np
import matplotlib.pyplot as plt
```
%% Cell type:code id: tags:
``` python
X = np.arange(0, 2, 0.01)
Y = np.exp(X) - 1
plt.plot(X, X, linewidth=3)
plt.plot(X, Y)
plt.plot(X, X**2)
plt.xlabel('Abscisse')
plt.ylabel('Ordinate')
```
%% Cell type:markdown id: tags:
## Object-oriented plots
While doing the job, the previous example does not allow to unveil the power of matplotlib. For that, we need to keep in mind that in matplotlib plots, **everything** is an object.
<img src='images/anatomy.png' alt='https://matplotlib.org/gallery/showcase/anatomy.html' />
<img src='fig/anatomy.png' alt='https://matplotlib.org/gallery/showcase/anatomy.html' />
It is therefore possible to change any aspect of the figure by acting on the appropriate objects.
%% Cell type:markdown id: tags:
### The same example with objects
%% Cell type:code id: tags:
``` python
fig = plt.figure()
print('Fig is an instance of', type(fig))
ax = fig.add_subplot(111) # More on subplots later...
print('Ax is an instance of', type(ax))
X = np.arange(0, 2, 0.01)
Y = np.exp(X) - 1
# Storing results of the plot
l1 = ax.plot(X, X, linewidth=3, label='Linear')
l2 = ax.plot(X, X**2, label='Square')
l3 = ax.plot(X, Y, label='$y = e^{x} - 1$')
xlab = ax.set_xlabel('Abscissa')
ylab = ax.set_ylabel('Ordinate')
ax.set_xlim(0, 2)
ax.legend()
```
%% Cell type:code id: tags:
``` python
# ax.plot returns in fact a list of the lines plotted by the instruction
print(type(l3))
# In this case, we plotted the lines one by one so l3 contains only the line corresponding to the exp function
exp_line = l3[0]
print(type(exp_line))
```
%% Cell type:markdown id: tags:
This way, we can have access to the `Line2D` objects and therefore to all their attributes (and change them!). This includes:
- **get_data/set_data**: to get/set the numerical xdata, ydata of the line
- **get_color/set_color**: to get/set the color of the line
- **get_marker/set_marker**: to get/set the markers
- ...
See https://matplotlib.org/api/_as_gen/matplotlib.lines.Line2D.html for the complete list.
_Note: `Line2D` is based on the `Artist` class from which any graphical element inherits (lines, ticks, axes...)._
%% Cell type:markdown id: tags:
### An application: ticks
A common manipulation when designing figures for articles is to change the ticks location. Matplotlib provides several ways to do this
#### Direct manipulation
%% Cell type:code id: tags:
``` python
from calendar import day_name
weekdays = list(day_name)
print(weekdays)
temperatures = [20., 22., 16., 18., 17., 19., 20.]
fig, ax = plt.subplots()
ax.plot(temperatures, marker='o', markersize=10)
ax.set_xlabel('Weekday')
ax.set_ylabel('Temperature ($^{\circ}C$)')
```
%% Cell type:code id: tags:
``` python
# Change locations
ax.set_yticks(np.arange(15, 25, 0.5))
# Change locations AND labels
ax.set_xticks(range(7))
ax.set_xticklabels(weekdays)
ax.set_xlabel('')
# Show the updated figure
fig
```
%% Cell type:markdown id: tags:
#### With `Locators`
`Locators` are objects that give rules to generate the tick locations. See https://matplotlib.org/api/ticker_api.html.
<img src='images/tick_locators.png' alt='https://matplotlib.org/gallery/ticks_and_spines/tick-locators.html' />
%% Cell type:markdown id: tags:
For example, for the yticks in the previous example, we could have done
%% Cell type:code id: tags:
``` python
import matplotlib.ticker as ticker
# Change locator for the major ticks of yaxis
ax.yaxis.set_major_locator(ticker.MultipleLocator(0.5))
fig
```
%% Cell type:markdown id: tags:
#### Major and minor ticks
matplotlib provides two types of ticks: major and minor. The parameters and aspect of the two kinds can be handled separately.
%% Cell type:code id: tags:
``` python
import matplotlib.ticker as ticker
# Change locator for the major ticks of yaxis
ax.yaxis.set_major_locator(ticker.MultipleLocator(1.))
ax.yaxis.set_minor_locator(ticker.MultipleLocator(0.5))
fig
```
%% Cell type:markdown id: tags:
### An application: subplots
%% Cell type:code id: tags:
``` python
fig, axes = plt.subplots(nrows=1, ncols=3, sharey=True)
"""
# Equivalent to
fig = plt.figure()
axes = []
axes.append(fig.add_subplot(131))
axes.append(fig.add_subplot(132, sharey=axes[0]))
axes.append(fig.add_subplot(133, sharey=axes[0]))
"""
# This is only to have the same colors as before
color_cycle = plt.rcParams['axes.prop_cycle'].by_key()['color']
X = np.arange(0, 2, 0.01)
Y = np.exp(X) - 1
axes[0].set_title('Linear')
axes[0].plot(X, X, linewidth=3, color=color_cycle[0])
axes[1].set_title('Square')
axes[1].plot(X, X**2, label='Square', color=color_cycle[1])
axes[2].set_title('$y = e^{x} - 1$')
axes[2].plot(X, Y, label='$y = e^{x} - 1$', color=color_cycle[2])
axes[0].set_ylabel('Ordinate')
for ax in axes:
ax.set_xlabel('Abscissa')
ax.set_xlim(0, 2)
```
%% Cell type:markdown id: tags:
### Fancier subplots with gridspec
%% Cell type:code id: tags:
``` python
import matplotlib.gridspec as gridspec
fig = plt.figure()
gs = gridspec.GridSpec(2, 2, figure=fig) # 2 rows and 2 columns
X = np.arange(-3, 3, 0.01)*np.pi
ax1 = fig.add_subplot(gs[0,0]) # 1st row, 1st column
ax2 = fig.add_subplot(gs[1,0]) # 2nd row, 1st column
ax3 = fig.add_subplot(gs[:,1]) # all rows, 2nd column
ax1.plot(X, np.cos(2*X), color="red")
ax2.plot(X, np.sin(2*X), color="magenta")
ax3.plot(X, X**2)
```
%% Cell type:markdown id: tags:
## Interactivity (https://matplotlib.org/users/event_handling.html)
Know first that other plotting libraries offers interactions more smoothly (`plotly`, `bokeh`, ...). Nevertheless, `matplotlib` gives access to backend-independent methods to add interactivity to plots.
These methods use [`Events`](https://matplotlib.org/api/backend_bases_api.html#matplotlib.backend_bases.Event) to catch user interactions (mouse clicks, key presses, mouse hovers, etc...).
These events must be connected to callback functions using the `mpl_connect` method of `Figure.Canvas`:
```python
fig = plt.figure()
fig.canvas.mpl_connect(self, event_name, callback_func)
```
The signature of `callback_func` is:
```python
def callback_func(event)
```
where event is a `matplotlib.backend_bases.Event`. The following events are recognized
- **'button_press_event'**
- 'button_release_event'
- 'draw_event'
- **'key_press_event'**
- 'key_release_event'
- 'motion_notify_event'
- 'pick_event'
- 'resize_event'
- 'scroll_event'
- 'figure_enter_event',
- 'figure_leave_event',
- 'axes_enter_event',
- 'axes_leave_event'
- **'close_event'**
N.B. : `Figure.Canvas` takes care of the rendering of the figure (independent of the used backend) which is why it is used to handle events.
%% Cell type:markdown id: tags:
### A simple example: changing the color of a line
%% Cell type:code id: tags:
``` python
# Jupyter command to enable interactivity
%matplotlib notebook
f = plt.figure()
ax = f.add_subplot(111)
X = np.arange(0, 10, 0.01)
l, = plt.plot(X, X**2)
def change_color(event):
l.set_color('green')
f.canvas.mpl_connect('button_press_event', change_color)
```
%% Cell type:markdown id: tags:
### Enhanced interactivity: a drawing tool
%% Cell type:code id: tags:
``` python
f2 = plt.figure()
ax2 = f2.add_subplot(111)
ax2.set_aspect('equal')
x_data = []
y_data = []
l, = ax2.plot(x_data, y_data, marker='o')
def add_datapoint(event):
x_data.append(event.xdata)
y_data.append(event.ydata)
l.set_data(x_data, y_data)
f2.canvas.mpl_connect('button_press_event', add_datapoint)
```
%% Cell type:markdown id: tags:
But, here we are referencing `x_data` and `y_data` in `add_datapoint` that are defined outside the function : this breaks encapsulation !
A nicer solution would be to use an object to handle the interactivity. We can also take advantage of this to add more functionality (such as clearing of the figure when the mouse exits) :
%% Cell type:code id: tags:
``` python
class InteractivePlot():
def __init__(self, figure):
self.ax = figure.add_subplot(111)
self.ax.set_aspect('equal')
self.x_data = []
self.y_data = []
self.interactive_line, = self.ax.plot(self.x_data, self.y_data, marker='o')
# Need to keep the callbacks references in memory to have the interactivity
self.button_callback = figure.canvas.mpl_connect('button_press_event', self.add_datapoint)
self.clear_callback = figure.canvas.mpl_connect('figure_leave_event', self.clear)
def add_datapoint(self, event):
if event.button == 1: # Left click
self.x_data.append(event.xdata)
self.y_data.append(event.ydata)
self.update_line()
elif event.button == 3: # Right click
self.x_data = []
self.y_data = []
self.interactive_line, = self.ax.plot(self.x_data, self.y_data, marker='o')
def clear(self, event):
self.ax.clear()
self.x_data = []
self.y_data = []
self.interactive_line, = self.ax.plot(self.x_data, self.y_data, marker='o')
def update_line(self):
self.interactive_line.set_data(self.x_data, self.y_data)
f = plt.figure()
ip = InteractivePlot(f)
```
%% Cell type:markdown id: tags:
More examples could be shown but it always revolves around the same process: connecting an `Event` to a callback function.
Note that the connection can be severed using `mpl_disconnect` that takes the callback id in arg (in the previous case `self.button_callback` or `self.clear_callback`.
Some usages of interactivity:
- Print the value of a point on click
- Trigger a plot in the third dimension of a 3D plot displayed in 2D
- Save a figure on closing
- Ideas ?
%% Cell type:markdown id: tags:
## Animations
From the matplotlib page (https://matplotlib.org/api/animation_api.html):
> The easiest way to make a live animation in matplotlib is to use one of the Animation classes.
><table>
<tr><td>FuncAnimation</td><td>Makes an animation by repeatedly calling a function func.</td></tr>
<tr><td>ArtistAnimation</td><td>Animation using a fixed set of Artist objects.</td></tr>
</table>
%% Cell type:markdown id: tags:
### Example from matplotlib page
This example uses `FuncAnimation` to animate the plot of a sin function.
The animation consists in making repeated calls to the `update` function that adds at each frame a datapoint to the plot.
%% Cell type:code id: tags:
``` python
%matplotlib inline
from matplotlib import animation
fig, ax = plt.subplots()
xdata, ydata = [], []
ln, = plt.plot([], [], 'ro')
def init():
ax.set_xlim(0, 2*np.pi)
ax.set_ylim(-1, 1)
return ln,
def update(frame):
xdata.append(frame)
ydata.append(np.sin(frame))
ln.set_data(xdata, ydata)
return ln,
ani = animation.FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
init_func=init, blit=True)
plt.show()
```
%% Cell type:markdown id: tags:
The previous code executed in a regular Python script should display the animation without problem. In a Jupyter Notebook, if we use `%matplotlib inline`, we can use IPython to display it in HTML.
%% Cell type:code id: tags:
``` python
from IPython.display import HTML
HTML(ani.to_jshtml())
```
%% Cell type:markdown id: tags:
### Stroop test
The [Stroop effect](http://en.wikipedia.org/wiki/Stroop_effect) is when a psychological cause inteferes with the reaction time of a task.
A common demonstration of this effect (called a Stroop test) is naming the color in which a word is written if the word describes another color. This usually takes longer than for a word that is not a color.
Ex: Naming blue for <div style='text-align:center; font-size:36px'><span style='color:blue'>RED</span> vs. <span style='color:blue'>BIRD</span></div>
_Funfact: As this test relies on the significance of the words, people that are more used to English should find the test more difficult !_
In this part, we show how `matplotlib` animations can generate a Stroop test that shows random color words in random colors at random positions.
#### With `FuncAnimation`
We will generate a single object `word` whose position, color and text will be updated by the repeatedly called function.
%% Cell type:code id: tags:
``` python
import random
def generate_random_colored_word(words, colors):
displayed_text = random.choice(words).upper()
text_color = random.choice(colors)
xy_position = (random.random(), random.random())
return xy_position, displayed_text, text_color
def update(frame):
xy_position, displayed_text, text_color = generate_random_colored_word(wordset, colorset)
word.set_position(xy_position)
word.set_color(text_color)
word.set_text(displayed_text)
return word
fig, ax = plt.subplots()
colorset = ['red', 'blue', 'yellow', 'green', 'purple']
wordset = colorset
xy_position, displayed_text, text_color = generate_random_colored_word(wordset, colorset)
word = ax.annotate(displayed_text, xy_position, xycoords='axes fraction', color=text_color, size=36)
ani = animation.FuncAnimation(fig, update, interval=1000)
plt.show()
```
%% Cell type:code id: tags:
``` python
from IPython.display import HTML
HTML(ani.to_jshtml())
```
%% Cell type:markdown id: tags:
#### With `ArtistAnimation`
Rather than updating through a function, `ArtistAnimation` requires to generate first all the `Artists` that will be displayed during the whole animation.
A list of `Artists` must therefore be supplied for each frame. Then, all frame lists must be compiled in a single list (of lists) that will be given in argument of `ArtistAnimation`.
In our case, to reproduce the behaviour above, we need to have only one word per frame. Each frame will therefore have a list of a single element (the colored word for this frame).
%% Cell type:code id: tags:
``` python
fig, ax = plt.subplots()
N_frames = 200
words = []
colorset = ['red', 'blue', 'yellow', 'green', 'purple']
wordset = colorset
# Generate the list of lists of Artists.
for i in range(N_frames):
xy_position, displayed_text, text_color = generate_random_colored_word(wordset, colorset)
# The list of the frame contains only a single word
frame_artists = [ax.annotate(displayed_text, xy_position, xycoords='axes fraction', color=text_color, size=36)]
words.append(frame_artists)
ani = animation.ArtistAnimation(fig, words, interval=1000)
plt.show()
```
%% Cell type:code id: tags:
``` python
from IPython.display import HTML
HTML(ani.to_jshtml())
```
%% Cell type:markdown id: tags:
#### Example with multiple `Artists`: two words at once from two wordsets !
%% Cell type:code id: tags:
``` python
# We can remove the axes for a cleaner test
fig = plt.figure()
ax = fig.add_subplot(111, frameon=False)
ax.set_xticks([])
ax.set_yticks([])
N_frames = 200
words = []
colorset = ['red', 'blue', 'yellow', 'green', 'purple']
wordset = colorset
wordset2 = ['bed', 'glue', 'mellow', 'grain', 'people']
# Generate the list of lists of Artists.
for i in range(N_frames):
xy_position, displayed_text, text_color = generate_random_colored_word(wordset, colorset)
xy_position2, displayed_text2, text_color2 = generate_random_colored_word(wordset2, colorset)
# The list of the frame contains only a single word
frame_artists = [ax.annotate(displayed_text, xy_position, xycoords='axes fraction', color=text_color, size=36),
ax.annotate(displayed_text2, xy_position2, xycoords='axes fraction', color=text_color2, size=36)]
words.append(frame_artists)
ani = animation.ArtistAnimation(fig, words, interval=1000)
plt.show()
```
%% Cell type:code id: tags:
``` python
from IPython.display import HTML
HTML(ani.to_jshtml())
```
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment