Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
5 views

Python Lab

The document outlines a workshop course (PCC-CS393) focused on programming with Python, covering topics such as scripting, data types, control statements, and functions. It includes prerequisites, course outcomes, and a detailed syllabus that guides learners through various programming concepts and Python syntax. The course aims to equip students with the skills to solve real-life problems using Python and other scripting languages.

Uploaded by

SG
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views

Python Lab

The document outlines a workshop course (PCC-CS393) focused on programming with Python, covering topics such as scripting, data types, control statements, and functions. It includes prerequisites, course outcomes, and a detailed syllabus that guides learners through various programming concepts and Python syntax. The course aims to equip students with the skills to solve real-life problems using Python and other scripting languages.

Uploaded by

SG
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 108

IT Workshop (Sci Lab/MATLAB/Python/R) Code: PCC-CS393 Contacts: 4P

Course Outcomes:
1 To master an understanding of scripting & the contributions of scripting
languages
2 Design real life problems and think creatively about solutions
3 Apply a solution in a program using R/Matlab/Python.
4 To be exposed to advanced applications of mathematics, engineering and
natural sciences to program real life problems.

Pre-Requisite:
1. Knowledge of Programming Logic
2. Experience with a high level language (C/C++,) is suggested.
3. Prior knowledge of a scripting language and Object-Oriented concepts is
helpful but not mandatory.

Syllabus:

Programming with Python


Introduction History, Features, Setting up path, Working with Python, Basic Syntax, Variable and Data
Types, Operator

Conditional Statements
If, If- else, Nested if-else, Looping, For, While, Nested loops

Control Statements
Break, Continue, Pass String Manipulation Accessing Strings, Basic Operations, String slices, Function
and Methods

Lists
Introduction, Accessing list, Operations, Working with lists, Function and Methods

Tuple
Introduction, Accessing tuples, Operations, Working, Functions and Methods

Dictionaries
Introduction, Accessing values in dictionaries, Working with dictionaries, Properties

Functions
Defining a function, Calling a function, Types of functions, Function Arguments, Anonymous
functions, Global and local variables

Modules
Importing module, Math module, Random module, Packages, Composition, Input-Output Printing on
screen, Reading data from keyboard, Opening and closing file, Reading and writing files, Functions

Exception Handling
Exception, Exception Handling, Except clause, Try? finally clause, User Defined Exceptions.
What is Python?

Python is a popular programming language. It was created by Guido van Rossum, and released in
1991.

It is used for:

● web development (server-side),


● software development,
● mathematics,
● system scripting.
What can Python do?
● Python can be used on a server to create web applications.
● Python can be used alongside software to create workflows.
● Python can connect to database systems. It can also read and modify files.
● Python can be used to handle big data and perform complex mathematics.
● Python can be used for rapid prototyping, or for production-ready software development.
Why Python?
● Python works on different platforms (Windows, Mac, Linux, Raspberry Pi, etc).
● Python has a simple syntax similar to the English language.
● Python has syntax that allows developers to write programs with fewer lines than some other
programming languages.
● Python runs on an interpreter system, meaning that code can be executed as soon as it is
written. This means that prototyping can be very quick.
● Python can be treated in a procedural way, an object-orientated way or a functional way.
Python Syntax compared to other programming languages
● Python was designed for readability, and has some similarities to the English language with
influence from mathematics.
● Python uses new lines to complete a command, as opposed to other programming languages
which often use semicolons or parentheses.
● Python relies on indentation, using whitespace, to define scope; such as the scope of loops,
functions and classes. Other programming languages often use curly-brackets for this purpose.

Lab 1
● How to print in python

print("Hello, World!")

● Python Comments

Comments can be used to explain Python code.


Comments can be used to make the code more readable.
Comments can be used to prevent execution when testing code.

#This is a comment
print("Hello, World!")

print("Hello, World!") #This is a comment

"""
This is a comment
written in
more than just one line
"""
print("Hello, World!")

● Creating Variables
Variables are containers for storing data values.
Unlike other programming languages, Python has no command for declaring a variable.
A variable is created the moment you first assign a value to it.

x=5
y = "John"
print(x)
print(y)

x = 4 # x is of type int
x = "Sally" # x is now of type str
print(x)

● Variable Names

A variable can have a short name (like x and y) or a more descriptive name (age, carname,
total_volume). Rules for Python variables:
A variable name must start with a letter or the underscore character
A variable name cannot start with a number
A variable name can only contain alpha-numeric characters and underscores (A-z, 0-9, and _ )
Variable names are case-sensitive (age, Age and AGE are three different variables)
Remember that variable names are case-sensitive

● Python allows you to assign values to multiple variables in one line:

x, y, z = "Orange", "Banana", "Cherry"


print(x)
print(y)
print(z)

● Output Variables
The Python print statement is often used to output variables.
To combine both text and a variable, Python uses the + character:

x = "awesome"
print("Python is " + x)

● Built-in Data Types

In programming, data type is an important concept.


Variables can store data of different types, and different types can do different things.
Python has the following data types built-in by default, in these categories:

Text Type: str


Numeric Types: int, float, complex
Sequence Types: list, tuple, range
Mapping Type: dict
Set Types: set, frozenset
Boolean Type: bool
Binary Types: bytes, bytearray, memoryview

x=5
print(type(x))

x = str("Hello World")str
x = int(20)int
x = float(20.5)float
x = complex(1j)complex
x = list(("apple", "banana", "cherry"))list
x = tuple(("apple", "banana", "cherry"))tuple
x = range(6)range
x = dict(name="John", age=36)dict
x = set(("apple", "banana", "cherry"))set
x = frozenset(("apple", "banana", "cherry"))frozenset
x = bool(5)bool
x = bytes(5)bytes
x = bytearray(5)bytearray
x = memoryview(bytes(5))memoryview

Python Casting

Specify a Variable Type

There may be times when you want to specify a type on to a variable. This can be done with casting.
Python is an object-orientated language, and as such it uses classes to define data types, including
its primitive types.
Casting in python is therefore done using constructor functions:
int() - constructs an integer number from an integer literal, a float literal (by rounding down to the
previous whole number), or a string literal (providing the string represents a whole number)
float() - constructs a float number from an integer literal, a float literal or a string literal (providing the
string represents a float or an integer)
str() - constructs a string from a wide variety of data types, including strings, integer literals and float
literals
x = int(1) # x will be 1
y = int(2.8) # y will be 2
z = int("3") # z will be 3

● Inputs in Python 3

name = input("What's your name? ")


print("Nice to meet you " + name + "!")
age = input("Your age? ")
print("So, you are already " + age + " years old, " + name + "!")

● Python Operators

Operators are used to perform operations on variables and values.

Python divides the operators in the following groups:


Arithmetic operators
Assignment operators
Comparison operators
Logical operators
Identity operators
Membership operators
Bitwise operators
Lab 2

Python Conditions and If statements

Python supports the usual logical conditions from mathematics:

Equals: a == b
Not Equals: a != b
Less than: a < b
Less than or equal to: a <= b
Greater than: a > b
Greater than or equal to: a >= b
These conditions can be used in several ways, most commonly in "if statements" and loops.
An "if statement" is written by using the if keyword.

a = 33
b = 200
if b > a:
print("b is greater than a")

Elif
The elif keyword is pythons way of saying "if the previous conditions were not true, then try this
condition".

a = 33
b = 33
if b > a:
print("b is greater than a")
elif a == b:
print("a and b are equal")

Else
The else keyword catches anything which isn't caught by the preceding conditions.

a = 200
b = 33
if b > a:
print("b is greater than a")
elif a == b:
print("a and b are equal")
else:
print("a is greater than b")

And
The and keyword is a logical operator, and is used to combine conditional statements:

a = 200
b = 33
c = 500
if a > b and c > a:
print("Both conditions are True")

Or
The or keyword is a logical operator, and is used to combine conditional statements:
a = 200
b = 33
c = 500
if a > b or a > c:
print("At least one of the conditions is True")
Nested If
You can have if statements inside if statements, this is called nested if statements.

x = 41

if x > 10:
print("Above ten,")
if x > 20:
print("and also above 20!")
else:
print("but not above 20.")

Python Loops
Python has two primitive loop commands:
while loops
for loops

The while Loop


With the while loop we can execute a set of statements as long as a condition is true.

i=1
while i < 6:
print(i)
i += 1

The break Statement


With the break statement we can stop the loop even if the while condition is true:

i=1
while i < 6:
print(i)
if i == 3:
break
i += 1

The continue Statement


With the continue statement we can stop the current iteration, and continue with the next:

i=0
while i < 6:
i += 1
if i == 3:
continue
print(i)

The else Statement


With the else statement we can run a block of code once when the condition no longer is true:

Python For Loops


A for loop is used for iterating over a sequence (that is either a list, a tuple, a dictionary, a set, or a
string).
This is less like the for keyword in other programming languages, and works more like an iterator
method as found in other object-orientated programming languages.
With the for loop we can execute a set of statements, once for each item in a list, tuple, set etc.

fruits = ["apple", "banana", "cherry"]


for x in fruits:
print(x)

for x in "banana":
print(x)

fruits = ["apple", "banana", "cherry"]


for x in fruits:
print(x)
if x == "banana":
break

fruits = ["apple", "banana", "cherry"]


for x in fruits:
if x == "banana":
break
print(x)

fruits = ["apple", "banana", "cherry"]


for x in fruits:
if x == "banana":
continue
print(x)

The range() Function


To loop through a set of code a specified number of times, we can use the range() function,
The range() function returns a sequence of numbers, starting from 0 by default, and increments by 1
(by default), and ends at a specified number.

for x in range(6):
print(x)

for x in range(2, 6):


print(x)

for x in range(2, 30, 3):


print(x)

for x in range(6):
print(x)
else:
print("Finally finished!")

Nested Loops
A nested loop is a loop inside a loop.
The "inner loop" will be executed one time for each iteration of the "outer loop":

adj = ["red", "big", "tasty"]


fruits = ["apple", "banana", "cherry"]
for x in adj:
for y in fruits:
print(x, y)

The pass Statement


for loops cannot be empty, but if you for some reason have a for loop with no content, put in
the pass statement to avoid getting an error.

for x in [0, 1, 2]:


pass

Lab 3

Strings are Arrays


Like many other popular programming languages, strings in Python are arrays of bytes representing
unicode characters.
However, Python does not have a character data type, a single character is simply a string with a
length of 1.
Square brackets can be used to access elements of the string.

a = "Hello, World!"
print(a[1])

Slicing
You can return a range of characters by using the slice syntax.
Specify the start index and the end index, separated by a colon, to return a part of the string.

Get the characters from position 2 to position 5 (not included):


b = "Hello, World!"
print(b[2:5])

Negative Indexing
Use negative indexes to start the slice from the end of the string:

Get the characters from position 5 to position 1, starting the count from the end of the string:

b = "Hello, World!"
print(b[-5:-2])

String Length
To get the length of a string, use the len() function.

a = "Hello, World!"
print(len(a))

String Methods
Python has a set of built-in methods that you can use on strings.

The strip() method removes any whitespace from the beginning or the end:
a = " Hello, World! "
print(a.strip()) # returns "Hello, World!"

The lower() method returns the string in lower case:


a = "Hello, World!"
print(a.lower())

The upper() method returns the string in upper case:


a = "Hello, World!"
print(a.upper())

The replace() method replaces a string with another string:


a = "Hello, World!"
print(a.replace("H", "J"))

The split() method splits the string into substrings if it finds instances of the separator:
a = "Hello, World!"
print(a.split(",")) # returns ['Hello', ' World!']

MethodDescription
capitalize()Converts the first character to upper case
casefold()Converts string into lower case
center()Returns a centered string
count()Returns the number of times a specified value occurs in a string
encode()Returns an encoded version of the string
endswith()Returns true if the string ends with the specified value
expandtabs()Sets the tab size of the string
find()Searches the string for a specified value and returns the position of where it was found
format()Formats specified values in a string
format_map()Formats specified values in a string
index()Searches the string for a specified value and returns the position of where it was found
isalnum()Returns True if all characters in the string are alphanumeric
isalpha()Returns True if all characters in the string are in the alphabet
isdecimal()Returns True if all characters in the string are decimals
isdigit()Returns True if all characters in the string are digits
isidentifier()Returns True if the string is an identifier
islower()Returns True if all characters in the string are lower case
isnumeric()Returns True if all characters in the string are numeric
isprintable()Returns True if all characters in the string are printable
isspace()Returns True if all characters in the string are whitespaces
istitle()Returns True if the string follows the rules of a title
isupper()Returns True if all characters in the string are upper case
join()Joins the elements of an iterable to the end of the string
ljust()Returns a left justified version of the string
lower()Converts a string into lower case
lstrip()Returns a left trim version of the string
maketrans()Returns a translation table to be used in translations
partition()Returns a tuple where the string is parted into three parts
replace()Returns a string where a specified value is replaced with a specified value
rfind()Searches the string for a specified value and returns the last position of where it was found
rindex()Searches the string for a specified value and returns the last position of where it was found
rjust()Returns a right justified version of the string
rpartition()Returns a tuple where the string is parted into three parts
rsplit()Splits the string at the specified separator, and returns a list
rstrip()Returns a right trim version of the string
split()Splits the string at the specified separator, and returns a list
splitlines()Splits the string at line breaks and returns a list
startswith()Returns true if the string starts with the specified value
strip()Returns a trimmed version of the string
swapcase()Swaps cases, lower case becomes upper case and vice versa
title()Converts the first character of each word to upper case
translate()Returns a translated string
upper()Converts a string into upper case
zfill()Fills the string with a specified number of 0 values at the beginning

Check String
To check if a certain phrase or character is present in a string, we can use the keywords in or not in.
Example

Check if the phrase "ain" is present in the following text:

txt = "The rain in Spain stays mainly in the plain"


x = "ain" in txt
print(x)

To Check if the phrase "ain" is NOT present in the following text:


txt = "The rain in Spain stays mainly in the plain"
x = "ain" not in txt
print(x)

String Concatenation
To concatenate, or combine, two strings you can use the + operator.
Example
Merge variable a with variable b into variable c:
a = "Hello"
b = "World"
c=a+b
print(c)

To add a space between them, add a " ":


a = "Hello"
b = "World"
c=a+""+b
print(c)

String Format

age = 36
txt = "My name is John, I am " + age
print(txt)

The format() method takes the passed arguments, formats them, and places them in the string where
the placeholders {} are:
Example
Use the format() method to insert numbers into strings:
age = 36
txt = "My name is John, and I am {}"
print(txt.format(age))

The format() method takes unlimited number of arguments, and are placed into the respective
placeholders:

quantity = 3
itemno = 567
price = 49.95
myorder = "I want {} pieces of item {} for {} dollars."
print(myorder.format(quantity, itemno, price))

You can use index numbers {0} to be sure the arguments are placed in the correct placeholders:
Example
quantity = 3
itemno = 567
price = 49.95
myorder = "I want to pay {2} dollars for {0} pieces of item {1}."
print(myorder.format(quantity, itemno, price))

CodeResult
\'Single Quote
\\Backslash
\nNew Line
\rCarriage Return
\tTab
\bBackspace
\fForm Feed
\oooOctal value
\xhhHex value

Lab 4

Lists are just like the arrays, declared in other languages. Lists need not be homogeneous always
which makes it a most powerful tool in Python. A single list may contain DataTypes like Integers,
Strings, as well as Objects. Lists are mutable, and hence, they can be altered even after their creation.
List in Python are ordered and have a definite count. The elements in a list are indexed according to a
definite sequence and the indexing of a list is done with 0 being the first index. Each element in the
list has its definite place in the list, which allows duplicating of elements in the list, with each element
having its own distinct place and credibility.
Note- Lists are a useful tool for preserving a sequence of data and further iterating over it.

Create a List:
thislist = ["apple", "banana", "cherry"]
print(thislist)

Print the second item of the list:


thislist = ["apple", "banana", "cherry"]
print(thislist[1])

Change the second item:


thislist = ["apple", "banana", "cherry"]
thislist[1] = "blackcurrant"
print(thislist)

Loop Through a List


thislist = ["apple", "banana", "cherry"]
for x in thislist:
print(x)

Check if Item Exists


To determine if a specified item is present in a list use the in keyword:
thislist = ["apple", "banana", "cherry"]
if "apple" in thislist:
print("Yes, 'apple' is in the fruits list")

List Length
thislist = ["apple", "banana", "cherry"]
print(len(thislist))

Add Items
To add an item to the end of the list, use the append() method:
thislist = ["apple", "banana", "cherry"]
thislist.append("orange")
print(thislist)

To add an item at the specified index, use the insert() method:

Insert an item as the second position:


thislist = ["apple", "banana", "cherry"]
thislist.insert(1, "orange")
print(thislist)

The remove() method removes the specified item:


thislist = ["apple", "banana", "cherry"]
thislist.remove("banana")
print(thislist)

The pop() method removes the specified index, (or the last item if index is not specified):
thislist = ["apple", "banana", "cherry"]
thislist.pop()
print(thislist)

The del keyword removes the specified index:


thislist = ["apple", "banana", "cherry"]
del thislist[0]
print(thislist)

The del keyword can also delete the list completely:


thislist = ["apple", "banana", "cherry"]
del thislist

The clear() method empties the list:


thislist = ["apple", "banana", "cherry"]
thislist.clear()
print(thislist)

Copy a List
You cannot copy a list simply by typing list2 = list1, because: list2 will only be a reference to list1, and
changes made in list1 will automatically also be made in list2.
There are ways to make a copy, one way is to use the built-in List method copy().
Make a copy of a list with the copy() method:
thislist = ["apple", "banana", "cherry"]
mylist = thislist.copy()
print(mylist)

Make a copy of a list with the list() method:


thislist = ["apple", "banana", "cherry"]
mylist = list(thislist)
print(mylist)

The list() Constructor


It is also possible to use the list() constructor to make a new list.

Using the list() constructor to make a List:


thislist = list(("apple", "banana", "cherry")) # note the double round-brackets
print(thislist)

Extend
fruits = ['apple', 'banana', 'cherry']
cars = ['Ford', 'BMW', 'Volvo']
fruits.extend(cars)
print(fruits)

index() Method
fruits = ['apple', 'banana', 'cherry']
x = fruits.index("cherry")

fruits = ['apple', 'banana', 'cherry']


x = fruits.pop(1)
print(x)

fruits = ['apple', 'banana', 'cherry']


fruits.pop(1)
print(fruits)

fruits = ['apple', 'banana', 'cherry']


fruits.reverse()

***********************************************************************************************

Tuple
A tuple is a collection which is ordered and unchangeable. In Python tuples are written with round
brackets.
The sequence of values stored in a tuple can be of any type, and they are indexed by integers. The
important difference between a list and a tuple is that tuples are immutable. Also, Tuples are
hashable whereas lists are not.
Values of a tuple are syntactically separated by ‘commas’. Although it is not necessary, it is more
common to define a tuple by closing the sequence of values in parentheses. This helps in
understanding the Python tuples more easily.
Tuples are immutable, and usually, they contain a sequence of heterogeneous elements that are
accessed via unpacking or indexing (or even by attribute in the case of named tuples). Lists are
mutable, and their elements are usually homogeneous and are accessed by iterating over the list.

thistuple = ("apple", "banana", "cherry")


print(thistuple)

thistuple = ("apple", "banana", "cherry")


print(thistuple[1])
thistuple = ("apple", "banana", "cherry")
for x in thistuple:
print(x)

thistuple = ("apple", "banana", "cherry")


if "apple" in thistuple:
print("Yes, 'apple' is in the fruits tuple")

thistuple = ("apple", "banana", "cherry")


print(len(thistuple))

Add Items
Once a tuple is created, you cannot add items to it. Tuples are unchangeable.
Example
You cannot add items to a tuple:
thistuple = ("apple", "banana", "cherry")
thistuple[3] = "orange" # This will raise an error
print(thistuple)

Remove Items
Note: You cannot remove items in a tuple.
Tuples are unchangeable, so you cannot remove items from it, but you can delete the tuple
completely:

The tuple() Constructor


It is also possible to use the tuple() constructor to make a tuple.
Example: Using the tuple() method to make a tuple:
thistuple = tuple(("apple", "banana", "cherry")) # note the double round-brackets
print(thistuple)

thistuple = (1, 3, 7, 8, 7, 5, 4, 6, 8, 5)
x = thistuple.count(5) #2
print(x)

Search for the first occurrence of the value 8, and return its position:

thistuple = (1, 3, 7, 8, 7, 5, 4, 6, 8, 5)
x = thistuple.index(8)
print(x)

****************************************************************************************
Set
A set is a collection which is unordered and unindexed. In Python sets are written with curly brackets.

Example

Create a Set:
thisset = {"apple", "banana", "cherry"}
print(thisset)

Note: Sets are unordered, so you cannot be sure in which order the items will appear.

Access Items
thisset = {"apple", "banana", "cherry"}
for x in thisset:
print(x)

Check if "banana" is present in the set:


thisset = {"apple", "banana", "cherry"}
print("banana" in thisset) #True

Change Items
Once a set is created, you cannot change its items, but you can add new items.
Add Items
To add one item to a set use the add() method.
To add more than one item to a set use the update() method.
Example
Add an item to a set, using the add() method:
thisset = {"apple", "banana", "cherry"}
thisset.add("orange")
print(thisset)

thisset = {"apple", "banana", "cherry"}


thisset.update(["orange", "mango", "grapes"])
print(thisset)

Get the Length of a Set


To determine how many items a set has, use the len() method.

Example
Get the number of items in a set:
thisset = {"apple", "banana", "cherry"}
print(len(thisset))

Remove Item
To remove an item in a set, use the remove(), or the discard() method.
Example
Remove "banana" by using the remove() method:
thisset = {"apple", "banana", "cherry"}
thisset.remove("banana")
print(thisset)

Remove "banana" by using the discard() method:


thisset = {"apple", "banana", "cherry"}
thisset.discard("banana")
print(thisset)

If the item to remove does not exist, discard() will NOT raise an error.

You can also use the pop(), method to remove an item, but this method will remove the last item.
Remember that sets are unordered, so you will not know what item that gets removed.

The return value of the pop() method is the removed item.

Remove the last item by using the pop() method:

thisset = {"apple", "banana", "cherry"}


x = thisset.pop()
print(x)
print(thisset)
The clear() method empties the set:
thisset = {"apple", "banana", "cherry"}
thisset.clear()
print(thisset)

The del keyword will delete the set completely:


thisset = {"apple", "banana", "cherry"}
del thisset
print(thisset)

The set() Constructor


It is also possible to use the set() constructor to make a set.
Example
Using the set() constructor to make a set:
thisset = set(("apple", "banana", "cherry")) # note the double round-brackets
print(thisset)

MethodDescription
add()Adds an element to the set
clear()Removes all the elements from the set
copy()Returns a copy of the set
difference()Returns a set containing the difference between two or more sets
difference_update()Removes the items in this set that are also included in another, specified set
discard()Remove the specified item
intersection()Returns a set, that is the intersection of two other sets
intersection_update()Removes the items in this set that are not present in other, specified set(s)
isdisjoint()Returns whether two sets have a intersection or not
issubset()Returns whether another set contains this set or not
issuperset()Returns whether this set contains another set or not
pop()Removes an element from the set
remove()Removes the specified element
symmetric_difference()Returns a set with the symmetric differences of two sets
symmetric_difference_update()inserts the symmetric differences from this set and another
union()Return a set containing the union of sets
update()Update the set with the union of this set and others

******************************************************************************************************
***********************************************
A dictionary is a collection which is unordered, changeable and indexed. In Python dictionaries are
written with curly brackets, and they have keys and values.

Create and print a dictionary:


thisdict ={
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
print(thisdict)

Accessing Items
x = thisdict["model"]
There is also a method called get() that will give you the same result:
x = thisdict.get("model")

Change Values
thisdict ={
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
thisdict["year"] = 2018

Loop Through a Dictionary


You can loop through a dictionary by using a for loop.
When looping through a dictionary, the return value are the keys of the dictionary, but there are
methods to return the values as well.
Print all key names in the dictionary, one by one:
thisdict ={
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
for x in thisdict:
print(x)

Print all values in the dictionary, one by one:


thisdict ={
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
for x in thisdict:
print(thisdict[x])

You can also use the values() function to return values of a dictionary:
thisdict ={
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
for x in thisdict.values():
print(x)

Loop through both keys and values, by using the items() function:
thisdict ={
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
for x, y in thisdict.items():
print(x, y)
brand Ford
model Mustang
year 1964

To determine if a specified key is present in a dictionary use the in keyword:


thisdict ={
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
if "model" in thisdict:
print("Yes, 'model' is one of the keys in the thisdict dictionary")

Dictionary Length
To determine how many items (key-value pairs) a dictionary has, use the len() method.
thisdict ={
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
print(len(thisdict))

Adding Items
Adding an item to the dictionary is done by using a new index key and assigning a value to it:
thisdict ={
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
thisdict["color"] = "red"
print(thisdict)

Removing Items
The pop() method removes the item with the specified key name:

thisdict ={
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
thisdict.pop("model")
print(thisdict)

The popitem() method removes the last inserted item (in versions before 3.7, a random item is
removed instead):
thisdict ={
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
thisdict.popitem()
print(thisdict)

The del keyword removes the item with the specified key name:
thisdict ={
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
del thisdict["model"]
print(thisdict)

The del keyword can also delete the dictionary completely:


thisdict ={
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
del thisdict
print(thisdict) #this will cause an error because "thisdict" no longer exists.

The clear() keyword empties the dictionary:


thisdict ={
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
thisdict.clear()
print(thisdict)

Copy a Dictionary
thisdict ={
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
mydict = thisdict.copy()
print(mydict)

Make a copy of a dictionary with the dict() method:


thisdict ={
"brand": "Ford",
"model": "Mustang",
"year": 1964
}
mydict = dict(thisdict)
print(mydict)

The dict() Constructor


It is also possible to use the dict() constructor to make a new dictionary:
thisdict = dict(brand="Ford", model="Mustang", year=1964)
# note that keywords are not string literals
# note the use of equals rather than colon for the assignment
print(thisdict)

Dictionary Methods
Python has a set of built-in methods that you can use on dictionaries.

MethodDescription
clear()Removes all the elements from the dictionary
copy()Returns a copy of the dictionary
fromkeys()Returns a dictionary with the specified keys and values
get()Returns the value of the specified key
items()Returns a list containing the a tuple for each key value pair
keys()Returns a list containing the dictionary's keys
pop()Removes the element with the specified key
popitem()Removes the last inserted key-value pair
setdefault()Returns the value of the specified key. If the key does not exist: insert the key, with the
specified value
update()Updates the dictionary with the specified key-value pairs
values()Returns a list of all the values in the dictionary

Function
def my_function():
print("Hello from a function")
my_function()

function with parameters:


def my_function(fname):
print(fname + " Donkey")
my_function("You")
my_function("Are")
my_function("a")

default parameter value:


def my_function(country = "Norway"):
print("I am from " + country)
my_function("Sweden")
my_function("India")
my_function()
my_function("Brazil")

Passing a List as a Parameter

You can send any data types of parameter to a function (string, number, list, dictionary etc.), and it
will be treated as the same data type inside the function.

E.g. if you send a List as a parameter, it will still be a List when it reaches the function:

Example
def my_function(food):
for x in food:
print(x)
fruits = ["apple", "banana", "cherry"]
my_function(fruits)

Return Values
To let a function return a value, use the return statement:

def my_function(x):
return 5 * x
print(my_function(3))
print(my_function(5))
print(my_function(9))

Recursion:

def tri_recursion(k):
if(k>0):
result = k+tri_recursion(k-1)
print(result)
else:
result = 0
return result

print("\n\nRecursion Example Results")


tri_recursion(6)
Global variable:

x = "global"
def foo():
print("x inside :", x)
foo()
print("x outside:", x)

Python Dates

import datetime
x = datetime.datetime.now()
print(x)

Return the year and name of weekday:

import datetime
x = datetime.datetime.now()
print(x.year)
print(x.strftime("%A"))

Creating Date Objects


To create a date, we can use the datetime() class (constructor) of the datetime module.
The datetime() class requires three parameters to create a date: year, month, day.
Create a date object:

import datetime
x = datetime.datetime(2020, 5, 17)
print(x)

The strftime() Method


The datetime object has a method for formatting date objects into readable strings.
The method is called strftime(), and takes one parameter, format, to specify the format of the returned
string:
Display the name of the month:
import datetime
x = datetime.datetime(2018, 6, 1)
print(x.strftime("%B"))

DirectiveDescriptionExampleTry it
%aWeekday, short versionWed
%AWeekday, full versionWednesday
%wWeekday as a number 0-6, 0 is Sunday3
%dDay of month 01-3131
%bMonth name, short versionDec
%BMonth name, full versionDecember
%mMonth as a number 01-1212
%yYear, short version, without century18
%YYear, full version2018
%HHour 00-2317
%IHour 00-1205
%pAM/PMPM
%MMinute 00-5941
%SSecond 00-5908
%fMicrosecond 000000-999999548513
%zUTC offset+0100
%ZTimezoneCST
%jDay number of year 001-366365
%UWeek number of year, Sunday as the first day of week, 00-5352
%WWeek number of year, Monday as the first day of week, 00-5352
%cLocal version of date and timeMon Dec 31 17:41:00 2018
%xLocal version of date12/31/18
%XLocal version of time17:41:00
%%A % character%

Lab 5 (Numerical)

# -*- coding: utf-8 -*-


"""
Created on Tue Sep 10 18:15:14 2019

@author: USER
"""
import numpy as np
#Our first simple Numpy example deals with temperatures. Given is a list with values, e.g.
temperatures in Celsius:

cvalues = [20.1, 20.8, 21.9, 22.5, 22.7, 22.3, 21.8, 21.2, 20.9, 20.1]
#We will turn our list "cvalues" into a one-dimensional numpy array:

C = np.array(cvalues)
print(C)
#Let's assume, we want to turn the values into degrees Fahrenheit. This is very easy to accomplish
with a #numpy array. The solution to our problem can be achieved by simple scalar multiplication:
print(C * 9 / 5 + 32)
fvalues = [ x*9/5 + 32 for x in cvalues]
print(fvalues)
#So far, we referred to C as an array. The internal type is "ndarray" or to be even more precise "C is an
instance #of the class numpy.ndarray":
print(type(C))

#Graphical Representation of the Values


import matplotlib.pyplot as plt
plt.plot(C)
plt.show()
'''
Memory Consumption: ndarray and list
The main benefits of using numpy arrays should be smaller memory consumption
and better runtime behaviour.
We want to look at the memory usage of numpy arrays in this subchapter of our
turorial and compare it to
the memory consumption of Python lists.
'''
from sys import getsizeof as size

lst = [24, 12, 57]

size_of_list_object = size(lst) # only green box


size_of_elements = len(lst) * size(lst[0]) # 24, 12, 57

total_list_size = size_of_list_object + size_of_elements


print("Size without the size of the elements: ", size_of_list_object)
print("Size of all the elements: ", size_of_elements)
print("Total size of list, including elements: ", total_list_size)

'''
The size of a Python list consists of the general list information, the size needed for the references to
the elements and the size of all the elements of the list. If we apply sys.getsizeof to a list, we get only
the size without the size of the elements. In the previous example, we made the assumption that all
the integer elements of our list have the same size. Of course, this is not valid in general, because
memory consumption will be higher for larger integers.

We will check now, how the memory usage changes, if we add another integer element to the list. We
also look at an empty list:
'''

lst = [24, 12, 57, 42]

size_of_list_object = size(lst) # only green box


size_of_elements = len(lst) * size(lst[0]) # 24, 12, 57, 42

total_list_size = size_of_list_object + size_of_elements


print("Size without the size of the elements: ", size_of_list_object)
print("Size of all the elements: ", size_of_elements)
print("Total size of list, including elements: ", total_list_size)

lst = []
print("Emtpy list size: ", size(lst))

#arange returns evenly spaced values within a given interval.


a = np.arange(1, 10)
print(a)

x = range(1, 10)
print(x) # x is an iterator
print(list(x))

# further arange examples:


a = np.arange(1, 10)
print(a)

x = range(1, 10)
print(x) # x is an iterator
print(list(x))
import numpy as np
x = np.arange(10.4)
print(x)
x = np.arange(0.5, 10.4, 0.8)
print(x)
x = np.arange(0.5, 10.4, 0.8, int)
print(x)

#linspace returns an ndarray, consisting of 'num' equally spaced samples


#in the closed interval [start, stop] or the half-open interval [start, stop).
# 50 values between 1 and 10:
print(np.linspace(1, 10))
# 7 values between 1 and 10:
print(np.linspace(1, 10, 7))
# excluding the endpoint:
print(np.linspace(1, 10, 7, endpoint=False))

samples, spacing = np.linspace(1, 10, retstep=True)


print(samples)
print(spacing)
samples, spacing = np.linspace(1, 10, 20, endpoint=True, retstep=True)
print(samples)
print(spacing)
samples, spacing = np.linspace(1, 10, 20, endpoint=False, retstep=True)
print(samples)
print(spacing)
#One-dimensional Arrays
import numpy as np
F = np.array([1, 1, 2, 3, 5, 8, 13, 21])
V = np.array([3.4, 6.9, 99.8, 12.8])
print("F: ", F)
print("V: ", V)
print("Type of F: ", F.dtype)
print("Type of V: ", V.dtype)
print("Dimension of F: ", np.ndim(F))
print("Dimension of V: ", np.ndim(V))
#Two- and Multidimensional Arrays
A = np.array([ [3.4, 8.7, 9.9],
[1.1, -7.8, -0.7],
[4.1, 12.3, 4.8]])
print(A)
print(A.ndim)
B = np.array([ [[111, 112], [121, 122]],
[[211, 212], [221, 222]],
[[311, 312], [321, 322]] ])
print(B)
print(B.ndim)
#Shape of an Array
x = np.array([ [67, 63, 87],
[77, 69, 59],
[85, 87, 99],
[79, 72, 71],
[63, 89, 93],
[68, 92, 78]])

print(np.shape(x))
print(x.shape)
#"shape" can also be used to change the shape of an array.
x.shape = (3, 6)
print(x)
x.shape = (2, 9)
print(x)

#Indexing and Slicing


F = np.array([1, 1, 2, 3, 5, 8, 13, 21])
# print the first element of F
print(F[0])
# print the last element of F
print(F[-1])

A = np.array([ [3.4, 8.7, 9.9],


[1.1, -7.8, -0.7],
[4.1, 12.3, 4.8]])
print(A[1][0])

#We illustrate the operating principle of "slicing" with some examples. We start with the easiest case,
i.e. the slicing of a one-dimensional array:

S = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
print(S[2:5])
print(S[:4])
print(S[6:])
print(S[:])

A = np.array([
[11, 12, 13, 14, 15],
[21, 22, 23, 24, 25],
[31, 32, 33, 34, 35],
[41, 42, 43, 44, 45],
[51, 52, 53, 54, 55]])

print(A[:3, 2:])
print(A[3:, :])
print(A[:, 4:])
#The following two examples use the third
#parameter "step". The reshape function is used
#to construct the two-dimensional array.
#We will explain reshape in the following
#subchapter:
import numpy as np
X = np.arange(28).reshape(4, 7)
print(X)

print(X[::2, ::3])

print(X[::, ::3])
#Creating Arrays with Ones, Zeros and Empty
#import numpy as np

E = np.ones((2,3))
print(E)
#
F = np.ones((3,4),dtype=int)
print(F)
#
Z = np.zeros((2,4))
print(Z)
#
x = np.array([2,5,18,14,4])
E = np.ones_like(x)
print(E)
#
Z = np.zeros_like(x)
print(Z)

#Copying Arrays

#numpy.copy()
import numpy as np

x = np.array([[42,22,12],[44,53,66]], order='F')
y = x.copy()

x[0,0] = 1001
print(x)

print(y)
print(x.flags['C_CONTIGUOUS'])
print(y.flags['C_CONTIGUOUS'])

#ndarray.copy()
import numpy as np
x = np.array([[42,22,12],[44,53,66]], order='F')
y = x.copy()
x[0,0] = 1001
print(x)

print(y)

print(x.flags['C_CONTIGUOUS'])
print(y.flags['C_CONTIGUOUS'])
'''
Identity Array
In linear algebra, the identity matrix, or unit matrix, of size n is the n × n square matrix with ones on
the main diagonal and zeros elsewhere.

There are two ways in Numpy to create identity arrays:

identy
eye
The identity Function
We can create identity arrays with the function identity:

identity(n, dtype=None)

The parameters:

ParameterMeaning
nAn integer number defining the number of rows and columns of the output, i.e. 'n' x 'n'
dtypeAn optional argument, defining the data-type of the output. The default is 'float'
The output of identity is an 'n' x 'n' array with its main diagonal set to one, and all other elements are 0.
'''
np.identity(4)

np.identity(4, dtype=int) # equivalent to np.identity(3, int)

'''
The eye Function
Another way to create identity arrays provides the function eye. This function creates also diagonal
arrays consisting solely of ones.

It returns a 2-D array with ones on the diagonal and zeros elsewhere.

eye(N, M=None, k=0, dtype=float)

ParameterMeaning
NAn integer number defining the rows of the output array.
MAn optional integer for setting the number of columns in the output. If it is None, it defaults to 'N'.
kDefining the position of the diagonal. The default is 0. 0 refers to the main diagonal. A positive value
refers to an upper diagonal, and a negative value to a lower diagonal.
dtypeOptional data-type of the returned array.
eye returns an ndarray of shape (N,M). All elements of this array are equal to zero, except for the 'k'-th
diagonal, whose values are equal to one.
'''
#import numpy as np

np.eye(5, 8, k=1, dtype=int)


#dtype
import numpy as np

i16 = np.dtype(np.int16)
print(i16)

lst = [ [3.4, 8.7, 9.9],


[1.1, -7.8, -0.7],
[4.1, 12.3, 4.8] ]

A = np.array(lst, dtype=i16)

print(A)
#
dt = np.dtype([('country', 'S20'), ('density', 'i4'), ('area', 'i4'), ('population', 'i4')])
population_table = np.array([
('Netherlands', 393, 41526, 16928800),
('Belgium', 337, 30510, 11007020),
('United Kingdom', 256, 243610, 62262000),
('Germany', 233, 357021, 81799600),
('Liechtenstein', 205, 160, 32842),
('Italy', 192, 301230, 59715625),
('Switzerland', 177, 41290, 7301994),
('Luxembourg', 173, 2586, 512000),
('France', 111, 547030, 63601002),
('Austria', 97, 83858, 8169929),
('Greece', 81, 131940, 11606813),
('Ireland', 65, 70280, 4581269),
('Sweden', 20, 449964, 9515744),
('Finland', 16, 338424, 5410233),
('Norway', 13, 385252, 5033675)],
dtype=dt)
print(population_table[:12])

#We can acces every column individually:

print(population_table['density'])
print(population_table['country'])
print(population_table['area'][2:5])

#
lst = [2,3, 7.9, 3.3, 6.9, 0.11, 10.3, 12.9]
v = np.array(lst)
v=v+2
print(v)

print(v * 2.2)

print(v - 1.38)
#
print(v ** 2)
print(v ** 1.5)
#
lst = [2,3, 7.9, 3.3, 6.9, 0.11, 10.3, 12.9]
res = []
for val in lst:
res.append(val + 2)

print(res)
#
res = [ val + 2 for val in lst]
print(res)
#
v = np.random.randint(0, 100, 1000)

%timeit v + 1

#
lst = list(v)

%timeit [ val + 2 for val in lst]

#Arithmetic Operations with two Arrays


import numpy as np

A = np.array([ [11, 12, 13], [21, 22, 23], [31, 32, 33] ])
B = np.ones((3,3))

print("Adding to arrays: ")


print(A + B)

print("\nMultiplying two arrays: ")


print(A * (B + 1))
#Matrix Multiplication:
#For this purpose, we can use the dot product. Using the previous arrays, we can calculate the matrix
multiplication:

np.dot(A, B)
#Examples of Using the dot Product
#We will begin with the cases in which both arguments are scalars or one-dimensional array:
print(np.dot(3, 4))
x = np.array([3])
y = np.array([4])
print(x.ndim)
print(np.dot(x, y))

x = np.array([3, -2])
y = np.array([-4, 1])
print(np.dot(x, y))
#Let's go to the two-dimensional use case:
A = np.array([ [1, 2, 3],
[3, 2, 1] ])
B = np.array([ [2, 3, 4, -2],
[1, -1, 2, 3],
[1, 2, 3, 0] ])

# es muss gelten:
print(A.shape[-1] == B.shape[-2], A.shape[1])
print(np.dot(A, B))
#The dot Product in the 3-dimensional Case
import numpy as np
X = np.array( [[[3, 1, 2],
[4, 2, 2],
[2, 4, 1]],

[[3, 2, 2],
[4, 4, 3],
[4, 1, 1]],

[[2, 2, 1],
[3, 1, 3],
[3, 2, 3]]])

Y = np.array( [[[2, 3, 1],


[2, 2, 4],
[3, 4, 4]],

[[1, 4, 1],
[4, 1, 2],
[4, 1, 2]],

[[1, 2, 3],
[4, 1, 1],
[3, 1, 4]]])

R = np.dot(X, Y)

print("The shapes:")
print(X.shape)
print(Y.shape)
print(R.shape)

print("\nThe Result R:")


print(R)
#To demonstrate how the dot product in the three-dimensional case works, we will use different
arrays with non-symmetrical shapes in the following example:
import numpy as np
X = np.array(
[[[3, 1, 2],
[4, 2, 2]],

[[-1, 0, 1],
[1, -1, -2]],

[[3, 2, 2],
[4, 4, 3]],

[[2, 2, 1],
[3, 1, 3]]])

Y = np.array(
[[[2, 3, 1, 2, 1],
[2, 2, 2, 0, 0],
[3, 4, 0, 1, -1]],

[[1, 4, 3, 2, 2],
[4, 1, 1, 4, -3],
[4, 1, 0, 3, 0]]])

R = np.dot(X, Y)

print("X.shape: ", X.shape, " X.ndim: ", X.ndim)


print("Y.shape: ", Y.shape, " Y.ndim: ", Y.ndim)
print("R.shape: ", R.shape, "R.ndim: ", R.ndim)

print("\nThe result array R:\n")


print(R)
#Let's have a look at the following sum products:
i=0
for j in range(X.shape[1]):
for k in range(Y.shape[0]):
for m in range(Y.shape[2]):
fmt = " sum(X[{}, {}, :] * Y[{}, :, {}] : {}"
arguments = (i, j, k, m, sum(X[i, j, :] * Y[k, :, m]))
print(fmt.format(*arguments))
#Hopefully, you have noticed that we have created the elements of R[0], one ofter the other.

print(R[0])

#This means that we could have created the array R by applying the sum products in the way above.
To "prove" this, we will create an array R2 by using the sum product, which is equal to R in the
following example:

R2 = np.zeros(R.shape, dtype=np.int)

for i in range(X.shape[0]):
for j in range(X.shape[1]):
for k in range(Y.shape[0]):
for m in range(Y.shape[2]):
R2[i, j, k, m] = sum(X[i, j, :] * Y[k, :, m])

print( np.array_equal(R, R2) )


#Matrices vs. Two-Dimensional Arrays
import numpy as np

A = np.array([ [1, 2, 3], [2, 2, 2], [3, 3, 3] ])


B = np.array([ [3, 2, 1], [1, 2, 3], [-1, -2, -3] ])

R=A*B
print(R)
#
MA = np.mat(A)
MB = np.mat(B)

R = MA * MB
print(R)
#Comparison Operators
import numpy as np

A = np.array([ [11, 12, 13], [21, 22, 23], [31, 32, 33] ])
B = np.array([ [11, 102, 13], [201, 22, 203], [31, 32, 303] ])

A == B

#It is possible to compare complete arrays for equality as well. We use array_equal for this purpose.
array_equal returns True if two arrays have the same shape and elements, otherwise False will be
returned.

print(np.array_equal(A, B))
print(np.array_equal(A, A))
#Logical Operators
a = np.array([ [True, True], [False, False]])
b = np.array([ [True, False], [True, False]])

print(np.logical_or(a, b))
print(np.logical_and(a, b))
'''
Broadcasting
Numpy provides a powerful mechanism, called Broadcasting, which allows to perform arithmetic
operations on arrays of different shapes. This means that we have a smaller array and a larger array,
and we transform or apply the smaller array multiple times to perform some operation on the larger
array. In other words: Under certain conditions, the smaller array is "broadcasted" in a way that it has
the same shape as the larger array.

With the aid of broadcasting we can avoid loops in our Python program. The looping occurs implicitly
in the Numpy implementations, i.e. in C. We also avoid creating unnecessary copies of our data.
'''
import numpy as np

A = np.array([ [11, 12, 13], [21, 22, 23], [31, 32, 33] ])
B = np.array([1, 2, 3])

print("Multiplication with broadcasting: ")


print(A * B)
print("... and now addition with broadcasting: ")
print(A + B)
#
B = np.array([[1, 2, 3],] * 3)
print(B)

#The previous code returned the following result:


B = np.array([1, 2, 3])
B[:, np.newaxis]
#Now we are capable of doing the multipliplication using broadcasting:

A * B[:, np.newaxis]
#
A = np.array([10, 20, 30])
B = np.array([1, 2, 3])
A[:, np.newaxis]
#
A[:, np.newaxis] * B
#Distance Matrix
'''
In mathematics, computer science and especially graph theory, a distance matrix is a matrix or a
two-dimensional array, which contains the distances between the elements of a set, pairwise taken.
The size of this two-dimensional array in n x n, if the set consists of n elements.
'''
cities = ["Barcelona", "Berlin", "Brussels", "Bucharest",
"Budapest", "Copenhagen", "Dublin", "Hamburg", "Istanbul",
"Kiev", "London", "Madrid", "Milan", "Moscow", "Munich",
"Paris", "Prague", "Rome", "Saint Petersburg",
"Stockholm", "Vienna", "Warsaw"]

dist2barcelona = [0, 1498, 1063, 1968,


1498, 1758, 1469, 1472, 2230,
2391, 1138, 505, 725, 3007, 1055,
833, 1354, 857, 2813,
2277, 1347, 1862]

dists = np.array(dist2barcelona[:12])
print(dists)
print(np.abs(dists - dists[:, np.newaxis]))
#3-Dimensional Broadcasting
A = np.array([ [[3, 4, 7], [5, 0, -1] , [2, 1, 5]],
[[1, 0, -1], [8, 2, 4], [5, 2, 1]],
[[2, 1, 3], [1, 9, 4], [5, -2, 4]]])

B = np.array([ [[3, 4, 7], [1, 0, -1], [1, 2, 3]] ])

B*A

'''
Flatten and Reshape Arrays
There are two methods to flatten a multidimensional array:

flatten()
ravel()
flatten
'''
import numpy as np

A = np.array([[[ 0, 1],
[ 2, 3],
[ 4, 5],
[ 6, 7]],
[[ 8, 9],
[10, 11],
[12, 13],
[14, 15]],
[[16, 17],
[18, 19],
[20, 21],
[22, 23]]])

Flattened_X = A.flatten()
print(Flattened_X)
print(A.flatten(order="C"))
print(A.flatten(order="F"))
print(A.flatten(order="A"))
'''
ravel
The order of the elements in the array returned by ravel() is normally "C-style".

ravel(a, order='C')

ravel returns a flattened one-dimensional array. A copy is made only if needed.

The optional keyword parameter "order" can be 'C','F', 'A', or 'K'

'C': C-like order, with the last axis index changing fastest, back to the first axis index changing slowest.
"C" is the default!

'F': Fortran-like index order with the first index changing fastest, and the last index changing slowest.

'A': Fortran-like index order if the array "a" is Fortran contiguous in memory, C-like order otherwise.

'K': read the elements in the order they occur in memory, except for reversing the data when strides are
negative.
'''
print(A.ravel())

print(A.ravel(order="A"))

print(A.ravel(order="F"))

print(A.ravel(order="A"))

print(A.ravel(order="K"))
'''
reshape
The method reshape() gives a new shape to an array without changing its data, i.e. it returns a new
array with a new shape.

reshape(a, newshape, order='C')

ParameterMeaning
aarray_like, Array to be reshaped.
newshapeint or tuple of ints
order'C', 'F', 'A', like in flatten or ravel
'''
X = np.array(range(24))
Y = X.reshape((3,4,2))
Y
'''
Concatenating Arrays
In the following example we concatenate three one-dimensional arrays to one array. The elements of
the second array are appended to the first array. After this the elements of the third array are
appended:
'''
x = np.array([11,22])
y = np.array([18,7,6])
z = np.array([1,3,5])
c = np.concatenate((x,y,z))
print(c)

'''
If we are concatenating multidimensional arrays, we can concatenate the arrays according to axis.
Arrays must have the same shape to be concatenated with concatenate().
In the case of multidimensional arrays, we can arrange them according to the axis.
The default value is axis = 0:
'''
x = np.array(range(24))
x = x.reshape((3,4,2))
y = np.array(range(100,124))
y = y.reshape((3,4,2))
z = np.concatenate((x,y))
print(z)
#We do the same concatenation now with axis=1:

z = np.concatenate((x,y),axis = 1)
print(z)

#Adding New Dimensions


'''
New dimensions can be added to an array by using slicing and np.newaxis.
We illustrate this technique with an example:
'''
x = np.array([2,5,18,14,4])
y = x[:, np.newaxis]
print(y)
[[ 2]
[ 5]
[18]
[14]
[ 4]]
'''Repeating Patterns, The "tile" Method
Sometimes, you want to or have to create a new matrix by repeating an existing matrix multiple times
to create a new matrix with a different shape or even dimension. You may have for example a one-
dimensional array array([ 3.4]) and you want to turn it into an array array([ 3.4, 3.4, 3.4, 3.4, 3.4])

In another usecase you may have a two-dimensional array like np.array([ [1, 2], [3, 4]]),
which you intend to use as a building block to construe the array with the shape (6, 8):
'''
array([[1, 2, 1, 2, 1, 2, 1, 2],
[3, 4, 3, 4, 3, 4, 3, 4],
[1, 2, 1, 2, 1, 2, 1, 2],
[3, 4, 3, 4, 3, 4, 3, 4],
[1, 2, 1, 2, 1, 2, 1, 2],
[3, 4, 3, 4, 3, 4, 3, 4]])
#
x = np.array([ [1, 2], [3, 4]])
np.tile(x, (3,4))

#
x = np.array([ 3.4])
y = np.tile(x, (5,))
print(y)
#
import numpy as np
x = np.array([[1, 2], [3, 4]])
print(np.tile(x, 2))
#
import numpy as np
x = np.array([[1, 2], [3, 4]])
print(np.tile(x, (2, 1)))
#
import numpy as np
x = np.array([[1, 2], [3, 4]])
print(np.tile(x, (2, 2)))

#
import random
random_number = random.random()
print(random_number)
#
from random import SystemRandom
crypto = SystemRandom()
print(crypto.random())
#Generate a list of Random Numbers
import random

def random_list(n, secure=True):


random_floats = []
if secure:
crypto = random.SystemRandom()
random_float = crypto.random
else:
random_float = random.random
for _ in range(n):
random_floats.append(random_float())
return random_floats

print(random_list(10, secure=False))

#
import random

outcome = random.randint(1,6)
print(outcome)
#
import random

[ random.randint(1, 6) for _ in range(10) ]


#
import numpy as np

outcome = np.random.randint(1, 7, size=10)


print(outcome)
#Random Choices with Python
from random import choice
possible_destinations = ["Berlin", "Hamburg", "Munich",
"Amsterdam", "London", "Paris",
"Zurich", "Heidelberg", "Strasbourg",
"Augsburg", "Milan", "Rome"]

print(choice(possible_destinations))
#Random Samples with Python
import numpy as np

x = np.random.random_sample((3, 4))
print(x)
#Random seed
import random

random.seed(42)

for _ in range(10):
print(random.randint(1, 10), end=", ")

print("\nLet's create the same random numbers again:")


random.seed(42)
for _ in range(10):
print(random.randint(1, 10), end=", ")
#Random Numbers in Python with Gaussian and Normalvariate Distribution
#We want to create now 1000 random numbers between 130 and 230 that have a gaussian
distribution
#with the mean value mu set to 550 and the standard deviation sigma is set to 30.

from random import gauss

n = 1000

values = []
frequencies = {}

while len(values) < n:


value = gauss(180, 30)
if 130 < value < 230:
frequencies[int(value)] = frequencies.get(int(value), 0) + 1
values.append(value)

print(values[:10])
#The following program plots the random values, which we have created before.
#We haven't covered matplotlib so far, so it's not necessary to understand the code:

%matplotlib inline

import matplotlib.pyplot as plt

freq = list(frequencies.items())
freq.sort()

plt.plot(*list(zip(*freq)))
import bk_random

firstnames = ["John", "Eve", "Jane", "Paul",


"Frank", "Laura", "Robert",
"Kathrin", "Roger", "Simone",
"Bernard", "Sarah", "Yvonne"]
surnames = ["Singer", "Miles", "Moore",
"Looper", "Rampman", "Chopman",
"Smiley", "Bychan", "Smith",
"Baker", "Miller", "Cook"]

number_of_specialists = 15

employees = set()
while len(employees) < number_of_specialists:
employee = bk_random.cartesian_choice(firstnames, surnames)
employees.add(" ".join(employee))

print(employees)

#Numpy: Boolean Indexing


import numpy as np

A = np.array([4, 7, 3, 4, 2, 8])

print(A == 4)
print(A < 5)

#
B = np.array([[42,56,89,65],
[99,88,42,12],
[55,42,17,18]])

print(B>=42)
'''
Extract from the array np.array([3,4,6,10,24,89,45,43,46,99,100]) with Boolean masking all the number

which are not divisible by 3

which are divisible by 5

which are divisible by 3 and 5

which are divisible by 3 and set them to 42

'''
import numpy as np
A = np.array([3,4,6,10,24,89,45,43,46,99,100])

div3 = A[A%3!=0]
print("Elements of A not divisible by 3:")
print(div3)

div5 = A[A%5==0]
print("Elements of A divisible by 5:")
print(div5)

print("Elements of A, which are divisible by 3 and 5:")


print(A[(A%3==0) & (A%5==0)])
print("------------------")

A[A%3==0] = 42
print("""New values of A after setting the elements of A,
which are divisible by 3, to 42:""")
print(A)

#
import matplotlib.pyplot as plt

plt.plot([-1, -4.5, 16, 23])


plt.show()
#
import matplotlib.pyplot as plt

plt.plot([-1, -4.5, 16, 23], "ob")


plt.show()
#
import matplotlib.pyplot as plt

# our X values:
days = list(range(0, 22, 3))
print(days)
# our Y values:
celsius_values = [25.6, 24.1, 26.7, 28.3, 27.5, 30.5, 32.8, 33.1]

plt.plot(days, celsius_values)
plt.show()
plt.plot(days, celsius_values, 'bo')
plt.show()
#
import matplotlib.pyplot as plt

fig, ax = plt.subplots()

print(type(fig))
print(type(ax))
#
import matplotlib.pyplot as plt

# Data for plotting


X = [2, 4, 6, 8, 10]
Y = [1, 4, 9, 19, 39]

fig, ax = plt.subplots()
ax.plot(X, Y)
#Labels on Axes
import matplotlib.pyplot as plt
days = list(range(1,9))
celsius_values = [25.6, 24.1, 26.7, 28.3, 27.5, 30.5, 32.8, 33.1]

fig, ax = plt.subplots()
ax.plot(days, celsius_values)
ax.set(xlabel='Day',
ylabel='Temperature in Celsius',
title='Temperature Graph')

plt.show()
#The plot Function
import matplotlib.pyplot as plt

days = list(range(1,9))
celsius_min = [19.6, 24.1, 26.7, 28.3, 27.5, 30.5, 32.8, 33.1]
celsius_max = [24.8, 28.9, 31.3, 33.0, 34.9, 35.6, 38.4, 39.2]

fig, ax = plt.subplots()

ax.set(xlabel='Day',
ylabel='Temperature in Celsius',
title='Temperature Graph')

ax.plot(days, celsius_min,
days, celsius_min, "oy",
days, celsius_max,
days, celsius_max, "or")

plt.show()
#
import matplotlib.pyplot as plt

days = list(range(1, 9))


celsius_min = [19.6, 24.1, 26.7, 28.3, 27.5, 30.5, 32.8, 33.1]
celsius_max = [24.8, 28.9, 31.3, 33.0, 34.9, 35.6, 38.4, 39.2]

fig, ax = plt.subplots()

ax.set(xlabel='Day',
ylabel='Temperature in Celsius',
title='Temperature Graph')

ax.plot(days, celsius_min)
ax.plot(days, celsius_min, "oy")
ax.plot(days, celsius_max)
ax.plot(days, celsius_max, "or")

plt.show()
#Checking and Defining the Range of Axes
import matplotlib.pyplot as plt

days = list(range(1, 9))


celsius_values = [25.6, 24.1, 26.7, 28.3, 27.5, 30.5, 32.8, 33.1]

fig, ax = plt.subplots()
ax.plot(days, celsius_values)
ax.set(xlabel='Day',
ylabel='Temperature in Celsius',
title='Temperature Graph')

print("The current limits for the axes are:")


print(ax.axis())
print("We set the axes to the following values:")
xmin, xmax, ymin, ymax = 0, 10, 14, 45
print(xmin, xmax, ymin, ymax)
ax.axis([xmin, xmax, ymin, ymax])
plt.show()
#"linspace" to Define X Values
import matplotlib.pyplot as plt

X = np.linspace(-2 * np.pi, 2 * np.pi, 50, endpoint=True)


F1 = 3 * np.sin(X)
F2 = np.sin(2*X)
F3 = 0.3 * np.sin(X)

fig, ax = plt.subplots()

startx, endx = -2 * np.pi - 0.1, 2*np.pi + 0.1


starty, endy = -3.1, 3.1
ax.axis([startx, endx, starty, endy])

ax.plot(X, F1, X, F2, X, F3)


plt.show()
#
import matplotlib.pyplot as plt

X = np.linspace(-2 * np.pi, 2 * np.pi, 50, endpoint=True)


F1 = 3 * np.sin(X)
F2 = np.sin(2*X)
F3 = 0.3 * np.sin(X)

fig, ax = plt.subplots()
startx, endx = -2 * np.pi - 0.1, 2*np.pi + 0.1
starty, endy = -3.1, 3.1

ax.axis([startx, endx, starty, endy])


ax.plot(X, F1, X, F2, X, F3)
ax.plot(X, F1, 'ro', X, F2, 'bx')
plt.show()
#
'''
Changing the Line Style
The linestyle of a plot can be influenced with the linestyle or ls parameter of the plot function. It can
be set to one of the following values:
'-', '--', '-.', ':', 'None', ' ', ''

We can use linewidth to set the width of a line as the name implies.
'''
import matplotlib.pyplot as plt

X = np.linspace(0, 2 * np.pi, 50, endpoint=True)


F1 = 3 * np.sin(X)
F2 = np.sin(2*X)
F3 = 0.3 * np.sin(X)
F4 = np.cos(X)

fig, ax = plt.subplots()
ax.plot(X, F1, color="blue", linewidth=2.5, linestyle="-")
ax.plot(X, F2, color="red", linewidth=1.5, linestyle="--")
ax.plot(X, F3, color="green", linewidth=2, linestyle=":")
ax.plot(X, F4, color="grey", linewidth=2, linestyle="-.")
plt.show()
'''
Draw LPoints in Matplotlib
We will learn now how to draw single points in Matplotlib.
'''
import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.scatter(3, 7, s=42)
#
import matplotlib.pyplot as plt
import numpy as np

X = np.random.randint(0, 100, (20,))


Y = np.random.randint(0, 100, (20,))
fig, ax = plt.subplots()
ax.scatter(X, Y, s=42)
'''
Shading Regions with fill_between()
It is possible to shade or colorize regions between two curves.
We are filling the region between the X axis and the graph of sin(2*X) in the following example:
'''
import numpy as np
import matplotlib.pyplot as plt
n = 256
X = np.linspace(-np.pi,np.pi,n,endpoint=True)
Y = np.sin(2*X)

fig, ax = plt.subplots()
ax.plot (X, Y, color='blue', alpha=1.00)
ax.fill_between(X, 0, Y, color='blue', alpha=.1)
plt.show()
#
import numpy as np
import matplotlib.pyplot as plt

n = 256
X = np.linspace(-np.pi,np.pi,n,endpoint=True)
Y = np.sin(2*X)

fig, ax = plt.subplots()

ax.plot (X, Y, color='blue', alpha=1.00)


ax.fill_between(X, Y, 1, color='blue', alpha=.1)
plt.show()
#
import numpy as np
import matplotlib.pyplot as plt

X = np.linspace(-2 * np.pi, 2 * np.pi, 70, endpoint=True)


F1 = np.sin(2* X)
F2 = (2*X**5 + 4*X**4 - 4.8*X**3 + 1.2*X**2 + X + 1)*np.exp(-X**2)

fig, ax = plt.subplots()

# making the top and right spine invisible:


ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')

# moving bottom spine up to y=0 position:


ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data',0))

# moving left spine to the right to position x == 0:


ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data',0))

ax.plot(X, F1, X, F2)

plt.show()
'''
Customizing Ticks
Matplotlib has so far - in all our previous examples - automatically taken over the task of
spacing points on the axis. We can see for example that the X axis in our previous example was
numbered -6. -4, -2, 0, 2, 4, 6, whereas the Y axis was numbered -1.0, 0, 1.0, 2.0, 3.0

xticks is a method, which can be used to get or to set the current tick locations and the labels.
The same is true for yticks:
'''
import matplotlib.pyplot as plt
fig, ax = plt.subplots()

xticks = ax.get_xticks()
xticklabels = ax.get_xticklabels()
print(xticks, xticklabels)
for i in range(6):
print(xticklabels[i])

yticks = ax.get_yticks()
print(yticks)
#As we said before, we can also use xticks to set the location of xticks:

import matplotlib.pyplot as plt


fig, ax = plt.subplots()

ax.set_xticks([7, 13, 19, 33, 42])


#Now, we will set both the locations and the labels of the xticks:

import matplotlib.pyplot as plt


fig, ax = plt.subplots()

ax.set_xticks([7, 13, 19, 33, 42])


ax.set_xticklabels(['Berlin', 'London', 'Hamburg', 'Toronto'])
#Let's get back to our previous example with the trigonometric functions. Most people might consider
factors of Pi to be more appropriate for the X axis than the integer labels:

import numpy as np
import matplotlib.pyplot as plt

X = np.linspace(-2 * np.pi, 2 * np.pi, 70, endpoint=True)


X = np.linspace(-2 * np.pi, 2 * np.pi, 70, endpoint=True)
F1 = np.sin(X**2)
F2 = X * np.sin(X)

fig, ax = plt.subplots()

# making the top and right spine invisible:


ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
# moving bottom spine up to y=0 position:
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data',0))
# moving left spine to the right to position x == 0:
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data',0))

ax.set_xticks( [-6.28, -3.14, 3.14, 6.28])


ax.set_yticks([-3, -1, 0, +1, 3])
ax.plot(X, F1)
ax.plot(X, F2)

plt.show()
#There is an easier way to set the values of the xticks so that we do not have to caculate them
manually. We use plt.MultipleLocator with np.pi/2 as argument:

import numpy as np
import matplotlib.pyplot as plt

X = np.linspace(-2 * np.pi, 2 * np.pi, 100)


F1 = np.sin(X)
F2 = 3 * np.sin(X)
fig, ax = plt.subplots()

ax.xaxis.set_major_locator(plt.MultipleLocator(np.pi / 2))

ax.plot(X, F1, X, F2)

plt.show()
#Adding a Legend
from polynomials import Polynomial
import numpy as np
import matplotlib.pyplot as plt

p = Polynomial(-0.8, 2.3, 0.5, 1, 0.2)


p_der = p.derivative()

fig, ax = plt.subplots()
X = np.linspace(-2, 3, 50, endpoint=True)
F = p(X)
F_derivative = p_der(X)
ax.plot(X, F)
ax.plot(X, F_derivative)

ax.legend(['p', 'derivation of p'])


#
from polynomials import Polynomial
import numpy as np
import matplotlib.pyplot as plt

p = Polynomial(2, 3, -4, 6)
p_der = p.derivative()

fig, ax = plt.subplots()
X = np.linspace(-2, 3, 50, endpoint=True)
F = p(X)
F_derivative = p_der(X)
ax.plot(X, F, label="$2x^{3} + 3x^{2} - 4x + 6$")
ax.plot(X, F_derivative, label="$6x^{2} - 6x -4$")

ax.legend(loc='upper left')
'''
Annotations
The visualizations of function plots often makes annotations necessary.
This means we draw the readers attentions to important points and areas of the plot.
To this purpose we use texts, labels and arrows. We have already used axis labels and titles for
this purpose, but these are 'annotations' for the whole plot. We can easily annotate points inside
the axis or on the graph with the annotate method of an axes object. In an annotation,
there are two points to consider: the location being annotated represented by the argument
xy and the location of the text xytext. Both of these arguments are (x,y) tuples.

We demonstrate how easy it is in matplotlib to to annotate plots in matplotlib with the


annotate method. We will annotate the local maximum and the local minimum of a function.
In its simplest form annotate method needs two arguments annotate(s, xy), where s is the
text string for the annotation and xx is the position of the point to be annotated:
'''
from polynomials import Polynomial
import numpy as np
import matplotlib.pyplot as plt

p = Polynomial(1, 0, -12, 0)
p_der = p.derivative()

fig, ax = plt.subplots()
X = np.arange(-5, 5, 0.1)
F = p(X)

F_derivative = p_der(X)
ax.grid()

maximum = (-2, p(-2))


minimum = (2, p(2))
ax.annotate("local maximum", maximum)
ax.annotate("local minimum", minimum)
ax.plot(X, F, label="p")
ax.plot(X, F_derivative, label="derivation of p")

ax.legend(loc='best')
plt.show()
#If you are not satisfied with the automatic positioning of the text, you can assign a tuple with a
position for the text to the keyword parameter xytext:

from polynomials import Polynomial


import numpy as np
import matplotlib.pyplot as plt

p = Polynomial(1, 0, -12, 0)
p_der = p.derivative()

fig, ax = plt.subplots()
X = np.arange(-5, 5, 0.1)
F = p(X)

F_derivative = p_der(X)
ax.grid()

ax.annotate("local maximum",
xy=(-2, p(-2)),
xytext=(-1, p(-2)+35),
arrowprops=dict(facecolor='orange'))
ax.annotate("local minimum",
xy=(2, p(2)),
xytext=(-2, p(2)-40),
arrowprops=dict(facecolor='orange', shrink=0.05))
ax.annotate("inflection point",
xy=(0, p(0)),
xytext=(-3, -30),
arrowprops=dict(facecolor='orange', shrink=0.05))

ax.plot(X, F, label="p")
ax.plot(X, F_derivative, label="derivation of p")

ax.legend(loc='best')
plt.show()
#
import matplotlib.pyplot as plt

def demo_con_style(ax, connectionstyle):


x1, y1 = 0.3, 0.2
x2, y2 = 0.8, 0.6

ax.plot([x1, x2], [y1, y2], ".")


ax.annotate("",
xy=(x1, y1), xycoords='data',
xytext=(x2, y2), textcoords='data',
arrowprops=dict(arrowstyle="->", color="0.5",
shrinkA=5, shrinkB=5,
patchA=None, patchB=None,
connectionstyle=connectionstyle))

ax.text(.05, .95, connectionstyle.replace(",", ",\n"),


transform=ax.transAxes, ha="left", va="top")

fig, axs = plt.subplots(3, 5, figsize=(8, 4.8))


demo_con_style(axs[0, 0], "angle3,angleA=90,angleB=0")
demo_con_style(axs[1, 0], "angle3,angleA=0,angleB=90")
demo_con_style(axs[0, 1], "arc3,rad=0.")
demo_con_style(axs[1, 1], "arc3,rad=0.3")
demo_con_style(axs[2, 1], "arc3,rad=-0.3")
demo_con_style(axs[0, 2], "angle,angleA=-90,angleB=180,rad=0")
demo_con_style(axs[1, 2], "angle,angleA=-90,angleB=180,rad=5")
demo_con_style(axs[2, 2], "angle,angleA=-90,angleB=10,rad=5")
demo_con_style(axs[0, 3], "arc,angleA=-90,angleB=0,armA=30,armB=30,rad=0")
demo_con_style(axs[1, 3], "arc,angleA=-90,angleB=0,armA=30,armB=30,rad=5")
demo_con_style(axs[2, 3], "arc,angleA=-90,angleB=0,armA=0,armB=40,rad=0")
demo_con_style(axs[0, 4], "bar,fraction=0.3")
demo_con_style(axs[1, 4], "bar,fraction=-0.3")
demo_con_style(axs[2, 4], "bar,angle=180,fraction=-0.2")

for ax in axs.flat:
ax.set(xlim=(0, 1), ylim=(0, 1), xticks=[], yticks=[], aspect=1)
fig.tight_layout(pad=0.2)

plt.show()
#Multiple Plots and Double Axes
#Working with Multiple Figures and Axes
import matplotlib.pyplot as plt

python_course_green = "#476042"
plt.figure(figsize=(6, 4))
plt.subplot(221) # equivalent to: plt.subplot(2, 2, 1)

plt.text(0.5, # x coordinate, 0 leftmost positioned, 1 rightmost


0.5, # y coordinate, 0 topmost positioned, 1 bottommost
'subplot(2,2,1)', # the text which will be printed
horizontalalignment='center', # shortcut 'ha'
verticalalignment='center', # shortcut 'va'
fontsize=20, # can be named 'font' as well
alpha=.5 # float (0.0 transparent through 1.0 opaque)
)
plt.subplot(224, axisbg=python_course_green)
plt.text(0.5, 0.5,
'subplot(2,2,4)',
ha='center', va='center',
fontsize=20,
color="y")
#Histograms
import matplotlib.pyplot as plt
import numpy as np
gaussian_numbers = np.random.normal(size=10000)
plt.hist(gaussian_numbers)
plt.title("Gaussian Histogram")
plt.xlabel("Value")
plt.ylabel("Frequency")
plt.show()
#
n, bins, patches = plt.hist(gaussian_numbers)
print("n: ", n, sum(n))
print("bins: ", bins)
for i in range(len(bins)-1):
print(bins[i+1] -bins[i])
print("patches: ", patches)
print(patches[1])
#Bar Plots
bars = plt.bar([1,2,3,4], [1,4,9,16])
bars[0].set_color('green')
plt.show()
#Contour Plot
import numpy as np

xlist = np.linspace(-3.0, 3.0, 3)


ylist = np.linspace(-3.0, 3.0, 4)
X, Y = np.meshgrid(xlist, ylist)
print(xlist)
print(ylist)
print(X)
print(Y)
#
import matplotlib.pyplot as plt

plt.figure()
cp = plt.contour(X, Y,Z)
plt.clabel(cp, inline=True,
fontsize=10)
plt.title('Contour Plot')
plt.xlabel('x (cm)')
plt.ylabel('y (cm)')
plt.show()
#
import matplotlib.pyplot as plt

plt.figure()
cp = plt.contour(X, Y, Z, colors='black', linestyles='dashed')
plt.clabel(cp, inline=True,
fontsize=10)
plt.title('Contour Plot')
plt.xlabel('x (cm)')
plt.ylabel('y (cm)')
plt.show()
#Filled Contours
import numpy as np
import matplotlib.pyplot as plt

xlist = np.linspace(-3.0, 3.0, 100)


ylist = np.linspace(-3.0, 3.0, 100)
X, Y = np.meshgrid(xlist, ylist)
Z = np.sqrt(X**2 + Y**2)

plt.figure()
cp = plt.contourf(X, Y, Z)
plt.colorbar(cp)

plt.title('Filled Contours Plot')


plt.xlabel('x (cm)')
plt.ylabel('y (cm)')
plt.show()
#Individual Colours
import numpy as np
import matplotlib.pyplot as plt

xlist = np.linspace(-3.0, 3.0, 100)


ylist = np.linspace(-3.0, 3.0, 100)
X, Y = np.meshgrid(xlist, ylist)
Z = np.sqrt(X**2 + Y**2)

plt.figure()

contour = plt.contourf(X, Y, Z)
plt.clabel(contour, colors = 'k', fmt = '%2.1f', fontsize=12)
c = ('#ff0000', '#ffff00', '#0000FF', '0.6', 'c', 'm')
contour_filled = plt.contourf(X, Y, Z, colors=c)
plt.colorbar(contour)

plt.title('Filled Contours Plot')


plt.xlabel('x (cm)')
plt.ylabel('y (cm)')
plt.show()
'''
Levels
The levels were decided automatically by contour and contourf so far.
They can be defined manually, by providing a list of levels as a fourth parameter.
Contour lines will be drawn for each value in the list, if we use contour.
For contourf, there will be filled colored regions between the values in the list.
'''
import numpy as np
import matplotlib.pyplot as plt

xlist = np.linspace(-3.0, 3.0, 100)


ylist = np.linspace(-3.0, 3.0, 100)
X, Y = np.meshgrid(xlist, ylist)

Z = np.sqrt(X ** 2 + Y ** 2 )
plt.figure()

levels = [0.0, 0.2, 0.5, 0.9, 1.5, 2.5, 3.5]


contour = plt.contour(X, Y, Z, levels, colors='k')
plt.clabel(contour, colors = 'k', fmt = '%2.1f', fontsize=12)
contour_filled = plt.contourf(X, Y, Z, levels)
plt.colorbar(contour_filled)

plt.title('Plot from level list')


plt.xlabel('x (cm)')
plt.ylabel('y (cm)')
plt.show()
#Lovely
import matplotlib.pyplot as plt
import numpy as np

y, x = np.ogrid[-1:2:100j, -1:1:100j]
plt.contour(x.ravel(),
y.ravel(),
x**2 + (y-((x**2)**(1.0/3)))**2,
[1],
colors='red',)
plt.axis('equal')
plt.show()
#Introduction into Pandas
#Data Structures
import pandas as pd
S = pd.Series([11, 28, 72, 3, 5, 8])
S
print(S.index)
print(S.values)
#
fruits = ['apples', 'oranges', 'cherries', 'pears']
quantities = [20, 33, 52, 10]
S = pd.Series(quantities, index=fruits)
S
#If we add two series with the same indices, we get a new series with the same index and the
correponding values will be added:

fruits = ['apples', 'oranges', 'cherries', 'pears']

S = pd.Series([20, 33, 52, 10], index=fruits)


S2 = pd.Series([17, 13, 31, 32], index=fruits)
print(S + S2)
print("sum of S: ", sum(S))
#The indices do not have to be the same for the Series addition. The index will be the "union" of both
indices. If an index doesn't occur in both Series, the value for this Series will be NaN:

fruits = ['peaches', 'oranges', 'cherries', 'pears']


fruits2 = ['raspberries', 'oranges', 'cherries', 'pears']

S = pd.Series([20, 33, 52, 10], index=fruits)


S2 = pd.Series([17, 13, 31, 32], index=fruits2)
print(S + S2)
#Indexing
print(S[['apples', 'oranges', 'cherries']])
#
import pandas as pd
years = range(2014, 2018)
shop1 = pd.Series([2409.14, 2941.01, 3496.83, 3119.55], index=years)
shop2 = pd.Series([1203.45, 3441.62, 3007.83, 3619.53], index=years)
shop3 = pd.Series([3412.12, 3491.16, 3457.19, 1963.10], index=years)
pd.concat([shop1, shop2, shop3])
shops_df = pd.concat([shop1, shop2, shop3], axis=1)
shops_df

cities = ["Zürich", "Winterthur", "Freiburg"]


shops_df.columns = cities
print(shops_df)
# alternative way: give names to series:
shop1.name = "Zürich"
shop2.name = "Winterthur"
shop3.name = "Freiburg"
print("------")
shops_df2 = pd.concat([shop1, shop2, shop3], axis=1)
print(shops_df2)
#DataFrames from Dictionaries
#A DataFrame has a row and column index; it's like a dict of Series with a common index.

cities = {"name": ["London", "Berlin", "Madrid", "Rome",


"Paris", "Vienna", "Bucharest", "Hamburg",
"Budapest", "Warsaw", "Barcelona",
"Munich", "Milan"],
"population": [8615246, 3562166, 3165235, 2874038,
2273305, 1805681, 1803425, 1760433,
1754000, 1740119, 1602386, 1493900,
1350680],
"country": ["England", "Germany", "Spain", "Italy",
"France", "Austria", "Romania",
"Germany", "Hungary", "Poland", "Spain",
"Germany", "Italy"]}
city_frame = pd.DataFrame(cities)
city_frame
#
import pandas as pd

exchange_rates = pd.read_csv("dollar_euro.txt",
sep="\t")
print(exchange_rates)
#
import pandas as pd

exchange_rates = pd.read_csv("dollar_euro.txt",
sep="\t",
header=0,
names=["year", "min", "max", "days"])
print(exchange_rates)

# -*- coding: utf-8 -*-


"""
Created on Tue Sep 10 18:15:14 2019

@author: USER
"""
import numpy as np
#Our first simple Numpy example deals with temperatures. Given is a list with values, e.g.
temperatures in Celsius:

cvalues = [20.1, 20.8, 21.9, 22.5, 22.7, 22.3, 21.8, 21.2, 20.9, 20.1]
#We will turn our list "cvalues" into a one-dimensional numpy array:

C = np.array(cvalues)
print(C)
#Let's assume, we want to turn the values into degrees Fahrenheit. This is very easy to accomplish
with a numpy array. The solution to our problem can be achieved by simple scalar multiplication:
print(C * 9 / 5 + 32)
fvalues = [ x*9/5 + 32 for x in cvalues]
print(fvalues)
#So far, we referred to C as an array. The internal type is "ndarray" or to be even more precise "C is an
instance of the class numpy.ndarray":

print(type(C))

#Graphical Representation of the Values


import matplotlib.pyplot as plt

plt.plot(C)
plt.show()
'''
Memory Consumption: ndarray and list
The main benefits of using numpy arrays should be smaller memory consumption
and better runtime behaviour.
We want to look at the memory usage of numpy arrays in this subchapter of our
turorial and compare it to
the memory consumption of Python lists.
'''
from sys import getsizeof as size

lst = [24, 12, 57]

size_of_list_object = size(lst) # only green box


size_of_elements = len(lst) * size(lst[0]) # 24, 12, 57

total_list_size = size_of_list_object + size_of_elements


print("Size without the size of the elements: ", size_of_list_object)
print("Size of all the elements: ", size_of_elements)
print("Total size of list, including elements: ", total_list_size)

'''
The size of a Python list consists of the general list information, the size needed for the references to
the elements and the size of all the elements of the list. If we apply sys.getsizeof to a list, we get only
the size without the size of the elements. In the previous example, we made the assumption that all
the integer elements of our list have the same size. Of course, this is not valid in general, because
memory consumption will be higher for larger integers.

We will check now, how the memory usage changes, if we add another integer element to the list. We
also look at an empty list:
'''

lst = [24, 12, 57, 42]


size_of_list_object = size(lst) # only green box
size_of_elements = len(lst) * size(lst[0]) # 24, 12, 57, 42

total_list_size = size_of_list_object + size_of_elements


print("Size without the size of the elements: ", size_of_list_object)
print("Size of all the elements: ", size_of_elements)
print("Total size of list, including elements: ", total_list_size)

lst = []
print("Emtpy list size: ", size(lst))

#arange returns evenly spaced values within a given interval.


a = np.arange(1, 10)
print(a)

x = range(1, 10)
print(x) # x is an iterator
print(list(x))

# further arange examples:


a = np.arange(1, 10)
print(a)

x = range(1, 10)
print(x) # x is an iterator
print(list(x))
import numpy as np
x = np.arange(10.4)
print(x)
x = np.arange(0.5, 10.4, 0.8)
print(x)
x = np.arange(0.5, 10.4, 0.8, int)
print(x)

#linspace returns an ndarray, consisting of 'num' equally spaced samples


#in the closed interval [start, stop] or the half-open interval [start, stop).
# 50 values between 1 and 10:
print(np.linspace(1, 10))
# 7 values between 1 and 10:
print(np.linspace(1, 10, 7))
# excluding the endpoint:
print(np.linspace(1, 10, 7, endpoint=False))

samples, spacing = np.linspace(1, 10, retstep=True)


print(samples)
print(spacing)
samples, spacing = np.linspace(1, 10, 20, endpoint=True, retstep=True)
print(samples)
print(spacing)
samples, spacing = np.linspace(1, 10, 20, endpoint=False, retstep=True)
print(samples)
print(spacing)
#One-dimensional Arrays
import numpy as np
F = np.array([1, 1, 2, 3, 5, 8, 13, 21])
V = np.array([3.4, 6.9, 99.8, 12.8])
print("F: ", F)
print("V: ", V)
print("Type of F: ", F.dtype)
print("Type of V: ", V.dtype)
print("Dimension of F: ", np.ndim(F))
print("Dimension of V: ", np.ndim(V))
#Two- and Multidimensional Arrays
A = np.array([ [3.4, 8.7, 9.9],
[1.1, -7.8, -0.7],
[4.1, 12.3, 4.8]])
print(A)
print(A.ndim)
B = np.array([ [[111, 112], [121, 122]],
[[211, 212], [221, 222]],
[[311, 312], [321, 322]] ])
print(B)
print(B.ndim)
#Shape of an Array
x = np.array([ [67, 63, 87],
[77, 69, 59],
[85, 87, 99],
[79, 72, 71],
[63, 89, 93],
[68, 92, 78]])

print(np.shape(x))
print(x.shape)
#"shape" can also be used to change the shape of an array.
x.shape = (3, 6)
print(x)
x.shape = (2, 9)
print(x)

#Indexing and Slicing


F = np.array([1, 1, 2, 3, 5, 8, 13, 21])
# print the first element of F
print(F[0])
# print the last element of F
print(F[-1])

A = np.array([ [3.4, 8.7, 9.9],


[1.1, -7.8, -0.7],
[4.1, 12.3, 4.8]])
print(A[1][0])

#We illustrate the operating principle of "slicing" with some examples. We start with the easiest case,
i.e. the slicing of a one-dimensional array:

S = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
print(S[2:5])
print(S[:4])
print(S[6:])
print(S[:])

A = np.array([
[11, 12, 13, 14, 15],
[21, 22, 23, 24, 25],
[31, 32, 33, 34, 35],
[41, 42, 43, 44, 45],
[51, 52, 53, 54, 55]])

print(A[:3, 2:])
print(A[3:, :])
print(A[:, 4:])
#The following two examples use the third
#parameter "step". The reshape function is used
#to construct the two-dimensional array.
#We will explain reshape in the following
#subchapter:
import numpy as np
X = np.arange(28).reshape(4, 7)
print(X)

print(X[::2, ::3])

print(X[::, ::3])
#Creating Arrays with Ones, Zeros and Empty
#import numpy as np

E = np.ones((2,3))
print(E)
#
F = np.ones((3,4),dtype=int)
print(F)
#
Z = np.zeros((2,4))
print(Z)
#
x = np.array([2,5,18,14,4])
E = np.ones_like(x)
print(E)
#
Z = np.zeros_like(x)
print(Z)

#Copying Arrays

#numpy.copy()
import numpy as np

x = np.array([[42,22,12],[44,53,66]], order='F')
y = x.copy()

x[0,0] = 1001
print(x)

print(y)
print(x.flags['C_CONTIGUOUS'])
print(y.flags['C_CONTIGUOUS'])
#ndarray.copy()
import numpy as np

x = np.array([[42,22,12],[44,53,66]], order='F')
y = x.copy()
x[0,0] = 1001
print(x)

print(y)

print(x.flags['C_CONTIGUOUS'])
print(y.flags['C_CONTIGUOUS'])
'''
Identity Array
In linear algebra, the identity matrix, or unit matrix, of size n is the n × n square matrix with ones on
the main diagonal and zeros elsewhere.

There are two ways in Numpy to create identity arrays:

identy
eye
The identity Function
We can create identity arrays with the function identity:

identity(n, dtype=None)

The parameters:

ParameterMeaning
nAn integer number defining the number of rows and columns of the output, i.e. 'n' x 'n'
dtypeAn optional argument, defining the data-type of the output. The default is 'float'
The output of identity is an 'n' x 'n' array with its main diagonal set to one, and all other elements are 0.
'''
np.identity(4)

np.identity(4, dtype=int) # equivalent to np.identity(3, int)

'''
The eye Function
Another way to create identity arrays provides the function eye. This function creates also diagonal
arrays consisting solely of ones.

It returns a 2-D array with ones on the diagonal and zeros elsewhere.

eye(N, M=None, k=0, dtype=float)

ParameterMeaning
NAn integer number defining the rows of the output array.
MAn optional integer for setting the number of columns in the output. If it is None, it defaults to 'N'.
kDefining the position of the diagonal. The default is 0. 0 refers to the main diagonal. A positive value
refers to an upper diagonal, and a negative value to a lower diagonal.
dtypeOptional data-type of the returned array.
eye returns an ndarray of shape (N,M). All elements of this array are equal to zero, except for the 'k'-th
diagonal, whose values are equal to one.
'''
#import numpy as np
np.eye(5, 8, k=1, dtype=int)

#dtype
import numpy as np

i16 = np.dtype(np.int16)
print(i16)

lst = [ [3.4, 8.7, 9.9],


[1.1, -7.8, -0.7],
[4.1, 12.3, 4.8] ]

A = np.array(lst, dtype=i16)

print(A)
#
dt = np.dtype([('country', 'S20'), ('density', 'i4'), ('area', 'i4'), ('population', 'i4')])
population_table = np.array([
('Netherlands', 393, 41526, 16928800),
('Belgium', 337, 30510, 11007020),
('United Kingdom', 256, 243610, 62262000),
('Germany', 233, 357021, 81799600),
('Liechtenstein', 205, 160, 32842),
('Italy', 192, 301230, 59715625),
('Switzerland', 177, 41290, 7301994),
('Luxembourg', 173, 2586, 512000),
('France', 111, 547030, 63601002),
('Austria', 97, 83858, 8169929),
('Greece', 81, 131940, 11606813),
('Ireland', 65, 70280, 4581269),
('Sweden', 20, 449964, 9515744),
('Finland', 16, 338424, 5410233),
('Norway', 13, 385252, 5033675)],
dtype=dt)
print(population_table[:12])

#We can acces every column individually:

print(population_table['density'])
print(population_table['country'])
print(population_table['area'][2:5])

#
lst = [2,3, 7.9, 3.3, 6.9, 0.11, 10.3, 12.9]
v = np.array(lst)
v=v+2
print(v)

print(v * 2.2)

print(v - 1.38)
#
print(v ** 2)
print(v ** 1.5)
#
lst = [2,3, 7.9, 3.3, 6.9, 0.11, 10.3, 12.9]
res = []
for val in lst:
res.append(val + 2)

print(res)
#
res = [ val + 2 for val in lst]
print(res)
#
v = np.random.randint(0, 100, 1000)

%timeit v + 1

#
lst = list(v)

%timeit [ val + 2 for val in lst]

#Arithmetic Operations with two Arrays


import numpy as np

A = np.array([ [11, 12, 13], [21, 22, 23], [31, 32, 33] ])
B = np.ones((3,3))

print("Adding to arrays: ")


print(A + B)

print("\nMultiplying two arrays: ")


print(A * (B + 1))
#Matrix Multiplication:
#For this purpose, we can use the dot product. Using the previous arrays, we can calculate the matrix
multiplication:

np.dot(A, B)
#Examples of Using the dot Product
#We will begin with the cases in which both arguments are scalars or one-dimensional array:
print(np.dot(3, 4))
x = np.array([3])
y = np.array([4])
print(x.ndim)
print(np.dot(x, y))

x = np.array([3, -2])
y = np.array([-4, 1])
print(np.dot(x, y))
#Let's go to the two-dimensional use case:
A = np.array([ [1, 2, 3],
[3, 2, 1] ])
B = np.array([ [2, 3, 4, -2],
[1, -1, 2, 3],
[1, 2, 3, 0] ])

# es muss gelten:
print(A.shape[-1] == B.shape[-2], A.shape[1])
print(np.dot(A, B))
#The dot Product in the 3-dimensional Case
import numpy as np
X = np.array( [[[3, 1, 2],
[4, 2, 2],
[2, 4, 1]],

[[3, 2, 2],
[4, 4, 3],
[4, 1, 1]],

[[2, 2, 1],
[3, 1, 3],
[3, 2, 3]]])

Y = np.array( [[[2, 3, 1],


[2, 2, 4],
[3, 4, 4]],

[[1, 4, 1],
[4, 1, 2],
[4, 1, 2]],

[[1, 2, 3],
[4, 1, 1],
[3, 1, 4]]])

R = np.dot(X, Y)

print("The shapes:")
print(X.shape)
print(Y.shape)
print(R.shape)

print("\nThe Result R:")


print(R)
#To demonstrate how the dot product in the three-dimensional case works, we will use different
arrays with non-symmetrical shapes in the following example:
import numpy as np
X = np.array(
[[[3, 1, 2],
[4, 2, 2]],

[[-1, 0, 1],
[1, -1, -2]],

[[3, 2, 2],
[4, 4, 3]],

[[2, 2, 1],
[3, 1, 3]]])

Y = np.array(
[[[2, 3, 1, 2, 1],
[2, 2, 2, 0, 0],
[3, 4, 0, 1, -1]],
[[1, 4, 3, 2, 2],
[4, 1, 1, 4, -3],
[4, 1, 0, 3, 0]]])

R = np.dot(X, Y)

print("X.shape: ", X.shape, " X.ndim: ", X.ndim)


print("Y.shape: ", Y.shape, " Y.ndim: ", Y.ndim)
print("R.shape: ", R.shape, "R.ndim: ", R.ndim)

print("\nThe result array R:\n")


print(R)
#Let's have a look at the following sum products:
i=0
for j in range(X.shape[1]):
for k in range(Y.shape[0]):
for m in range(Y.shape[2]):
fmt = " sum(X[{}, {}, :] * Y[{}, :, {}] : {}"
arguments = (i, j, k, m, sum(X[i, j, :] * Y[k, :, m]))
print(fmt.format(*arguments))
#Hopefully, you have noticed that we have created the elements of R[0], one ofter the other.

print(R[0])

#This means that we could have created the array R by applying the sum products in the way above.
To "prove" this, we will create an array R2 by using the sum product, which is equal to R in the
following example:

R2 = np.zeros(R.shape, dtype=np.int)

for i in range(X.shape[0]):
for j in range(X.shape[1]):
for k in range(Y.shape[0]):
for m in range(Y.shape[2]):
R2[i, j, k, m] = sum(X[i, j, :] * Y[k, :, m])

print( np.array_equal(R, R2) )


#Matrices vs. Two-Dimensional Arrays
import numpy as np

A = np.array([ [1, 2, 3], [2, 2, 2], [3, 3, 3] ])


B = np.array([ [3, 2, 1], [1, 2, 3], [-1, -2, -3] ])

R=A*B
print(R)
#
MA = np.mat(A)
MB = np.mat(B)

R = MA * MB
print(R)
#Comparison Operators
import numpy as np

A = np.array([ [11, 12, 13], [21, 22, 23], [31, 32, 33] ])
B = np.array([ [11, 102, 13], [201, 22, 203], [31, 32, 303] ])

A == B

#It is possible to compare complete arrays for equality as well. We use array_equal for this purpose.
array_equal returns True if two arrays have the same shape and elements, otherwise False will be
returned.

print(np.array_equal(A, B))
print(np.array_equal(A, A))
#Logical Operators
a = np.array([ [True, True], [False, False]])
b = np.array([ [True, False], [True, False]])

print(np.logical_or(a, b))
print(np.logical_and(a, b))
'''
Broadcasting
Numpy provides a powerful mechanism, called Broadcasting, which allows to perform arithmetic
operations on arrays of different shapes. This means that we have a smaller array and a larger array,
and we transform or apply the smaller array multiple times to perform some operation on the larger
array. In other words: Under certain conditions, the smaller array is "broadcasted" in a way that it has
the same shape as the larger array.

With the aid of broadcasting we can avoid loops in our Python program. The looping occurs implicitly
in the Numpy implementations, i.e. in C. We also avoid creating unnecessary copies of our data.
'''
import numpy as np

A = np.array([ [11, 12, 13], [21, 22, 23], [31, 32, 33] ])
B = np.array([1, 2, 3])

print("Multiplication with broadcasting: ")


print(A * B)
print("... and now addition with broadcasting: ")
print(A + B)
#
B = np.array([[1, 2, 3],] * 3)
print(B)

#The previous code returned the following result:


B = np.array([1, 2, 3])
B[:, np.newaxis]
#Now we are capable of doing the multipliplication using broadcasting:

A * B[:, np.newaxis]
#
A = np.array([10, 20, 30])
B = np.array([1, 2, 3])
A[:, np.newaxis]
#
A[:, np.newaxis] * B

#Distance Matrix
'''
In mathematics, computer science and especially graph theory, a distance matrix is a matrix or a
two-dimensional array, which contains the distances between the elements of a set, pairwise taken.
The size of this two-dimensional array in n x n, if the set consists of n elements.
'''
cities = ["Barcelona", "Berlin", "Brussels", "Bucharest",
"Budapest", "Copenhagen", "Dublin", "Hamburg", "Istanbul",
"Kiev", "London", "Madrid", "Milan", "Moscow", "Munich",
"Paris", "Prague", "Rome", "Saint Petersburg",
"Stockholm", "Vienna", "Warsaw"]

dist2barcelona = [0, 1498, 1063, 1968,


1498, 1758, 1469, 1472, 2230,
2391, 1138, 505, 725, 3007, 1055,
833, 1354, 857, 2813,
2277, 1347, 1862]

dists = np.array(dist2barcelona[:12])
print(dists)
print(np.abs(dists - dists[:, np.newaxis]))
#3-Dimensional Broadcasting
A = np.array([ [[3, 4, 7], [5, 0, -1] , [2, 1, 5]],
[[1, 0, -1], [8, 2, 4], [5, 2, 1]],
[[2, 1, 3], [1, 9, 4], [5, -2, 4]]])

B = np.array([ [[3, 4, 7], [1, 0, -1], [1, 2, 3]] ])

B*A

'''
Flatten and Reshape Arrays
There are two methods to flatten a multidimensional array:

flatten()
ravel()
flatten
'''
import numpy as np

A = np.array([[[ 0, 1],
[ 2, 3],
[ 4, 5],
[ 6, 7]],
[[ 8, 9],
[10, 11],
[12, 13],
[14, 15]],
[[16, 17],
[18, 19],
[20, 21],
[22, 23]]])
Flattened_X = A.flatten()
print(Flattened_X)

print(A.flatten(order="C"))
print(A.flatten(order="F"))
print(A.flatten(order="A"))
'''
ravel
The order of the elements in the array returned by ravel() is normally "C-style".

ravel(a, order='C')

ravel returns a flattened one-dimensional array. A copy is made only if needed.

The optional keyword parameter "order" can be 'C','F', 'A', or 'K'

'C': C-like order, with the last axis index changing fastest, back to the first axis index changing slowest.
"C" is the default!

'F': Fortran-like index order with the first index changing fastest, and the last index changing slowest.

'A': Fortran-like index order if the array "a" is Fortran contiguous in memory, C-like order otherwise.

'K': read the elements in the order they occur in memory, except for reversing the data when strides are
negative.
'''
print(A.ravel())

print(A.ravel(order="A"))

print(A.ravel(order="F"))

print(A.ravel(order="A"))

print(A.ravel(order="K"))
'''
reshape
The method reshape() gives a new shape to an array without changing its data, i.e. it returns a new
array with a new shape.

reshape(a, newshape, order='C')

ParameterMeaning
aarray_like, Array to be reshaped.
newshapeint or tuple of ints
order'C', 'F', 'A', like in flatten or ravel
'''
X = np.array(range(24))
Y = X.reshape((3,4,2))
Y
'''
Concatenating Arrays
In the following example we concatenate three one-dimensional arrays to one array. The elements of
the second array are appended to the first array. After this the elements of the third array are
appended:
'''
x = np.array([11,22])
y = np.array([18,7,6])
z = np.array([1,3,5])
c = np.concatenate((x,y,z))
print(c)

'''
If we are concatenating multidimensional arrays, we can concatenate the arrays according to axis.
Arrays must have the same shape to be concatenated with concatenate().
In the case of multidimensional arrays, we can arrange them according to the axis.
The default value is axis = 0:
'''
x = np.array(range(24))
x = x.reshape((3,4,2))
y = np.array(range(100,124))
y = y.reshape((3,4,2))
z = np.concatenate((x,y))
print(z)
#We do the same concatenation now with axis=1:

z = np.concatenate((x,y),axis = 1)
print(z)

#Adding New Dimensions


'''
New dimensions can be added to an array by using slicing and np.newaxis.
We illustrate this technique with an example:
'''
x = np.array([2,5,18,14,4])
y = x[:, np.newaxis]
print(y)
[[ 2]
[ 5]
[18]
[14]
[ 4]]
'''Repeating Patterns, The "tile" Method
Sometimes, you want to or have to create a new matrix by repeating an existing matrix multiple times
to create a new matrix with a different shape or even dimension. You may have for example a one-
dimensional array array([ 3.4]) and you want to turn it into an array array([ 3.4, 3.4, 3.4, 3.4, 3.4])

In another usecase you may have a two-dimensional array like np.array([ [1, 2], [3, 4]]),
which you intend to use as a building block to construe the array with the shape (6, 8):
'''
array([[1, 2, 1, 2, 1, 2, 1, 2],
[3, 4, 3, 4, 3, 4, 3, 4],
[1, 2, 1, 2, 1, 2, 1, 2],
[3, 4, 3, 4, 3, 4, 3, 4],
[1, 2, 1, 2, 1, 2, 1, 2],
[3, 4, 3, 4, 3, 4, 3, 4]])
#
x = np.array([ [1, 2], [3, 4]])
np.tile(x, (3,4))

#
x = np.array([ 3.4])
y = np.tile(x, (5,))
print(y)

#
import numpy as np
x = np.array([[1, 2], [3, 4]])
print(np.tile(x, 2))
#
import numpy as np
x = np.array([[1, 2], [3, 4]])
print(np.tile(x, (2, 1)))
#
import numpy as np
x = np.array([[1, 2], [3, 4]])
print(np.tile(x, (2, 2)))

#
import random
random_number = random.random()
print(random_number)
#
from random import SystemRandom
crypto = SystemRandom()
print(crypto.random())
#Generate a list of Random Numbers
import random

def random_list(n, secure=True):


random_floats = []
if secure:
crypto = random.SystemRandom()
random_float = crypto.random
else:
random_float = random.random
for _ in range(n):
random_floats.append(random_float())
return random_floats

print(random_list(10, secure=False))

#
import random

outcome = random.randint(1,6)
print(outcome)
#
import random

[ random.randint(1, 6) for _ in range(10) ]


#
import numpy as np

outcome = np.random.randint(1, 7, size=10)


print(outcome)
#Random Choices with Python
from random import choice

possible_destinations = ["Berlin", "Hamburg", "Munich",


"Amsterdam", "London", "Paris",
"Zurich", "Heidelberg", "Strasbourg",
"Augsburg", "Milan", "Rome"]

print(choice(possible_destinations))
#Random Samples with Python
import numpy as np

x = np.random.random_sample((3, 4))
print(x)
#Random seed
import random

random.seed(42)

for _ in range(10):
print(random.randint(1, 10), end=", ")

print("\nLet's create the same random numbers again:")


random.seed(42)
for _ in range(10):
print(random.randint(1, 10), end=", ")
#Random Numbers in Python with Gaussian and Normalvariate Distribution
#We want to create now 1000 random numbers between 130 and 230 that have a gaussian
distribution
#with the mean value mu set to 550 and the standard deviation sigma is set to 30.

from random import gauss

n = 1000

values = []
frequencies = {}

while len(values) < n:


value = gauss(180, 30)
if 130 < value < 230:
frequencies[int(value)] = frequencies.get(int(value), 0) + 1
values.append(value)

print(values[:10])
#The following program plots the random values, which we have created before.
#We haven't covered matplotlib so far, so it's not necessary to understand the code:

%matplotlib inline

import matplotlib.pyplot as plt

freq = list(frequencies.items())
freq.sort()

plt.plot(*list(zip(*freq)))
import bk_random

firstnames = ["John", "Eve", "Jane", "Paul",


"Frank", "Laura", "Robert",
"Kathrin", "Roger", "Simone",
"Bernard", "Sarah", "Yvonne"]
surnames = ["Singer", "Miles", "Moore",
"Looper", "Rampman", "Chopman",
"Smiley", "Bychan", "Smith",
"Baker", "Miller", "Cook"]

number_of_specialists = 15

employees = set()
while len(employees) < number_of_specialists:
employee = bk_random.cartesian_choice(firstnames, surnames)
employees.add(" ".join(employee))

print(employees)

#Numpy: Boolean Indexing


import numpy as np

A = np.array([4, 7, 3, 4, 2, 8])

print(A == 4)
print(A < 5)

#
B = np.array([[42,56,89,65],
[99,88,42,12],
[55,42,17,18]])

print(B>=42)
'''
Extract from the array np.array([3,4,6,10,24,89,45,43,46,99,100]) with Boolean masking all the number

which are not divisible by 3

which are divisible by 5

which are divisible by 3 and 5

which are divisible by 3 and set them to 42

'''
import numpy as np
A = np.array([3,4,6,10,24,89,45,43,46,99,100])

div3 = A[A%3!=0]
print("Elements of A not divisible by 3:")
print(div3)
div5 = A[A%5==0]
print("Elements of A divisible by 5:")
print(div5)

print("Elements of A, which are divisible by 3 and 5:")


print(A[(A%3==0) & (A%5==0)])
print("------------------")

A[A%3==0] = 42
print("""New values of A after setting the elements of A,
which are divisible by 3, to 42:""")
print(A)

#
import matplotlib.pyplot as plt

plt.plot([-1, -4.5, 16, 23])


plt.show()
#
import matplotlib.pyplot as plt

plt.plot([-1, -4.5, 16, 23], "ob")


plt.show()
#
import matplotlib.pyplot as plt

# our X values:
days = list(range(0, 22, 3))
print(days)
# our Y values:
celsius_values = [25.6, 24.1, 26.7, 28.3, 27.5, 30.5, 32.8, 33.1]

plt.plot(days, celsius_values)
plt.show()
plt.plot(days, celsius_values, 'bo')
plt.show()
#
import matplotlib.pyplot as plt

fig, ax = plt.subplots()

print(type(fig))
print(type(ax))
#
import matplotlib.pyplot as plt

# Data for plotting


X = [2, 4, 6, 8, 10]
Y = [1, 4, 9, 19, 39]

fig, ax = plt.subplots()
ax.plot(X, Y)
#Labels on Axes
import matplotlib.pyplot as plt

days = list(range(1,9))
celsius_values = [25.6, 24.1, 26.7, 28.3, 27.5, 30.5, 32.8, 33.1]

fig, ax = plt.subplots()
ax.plot(days, celsius_values)
ax.set(xlabel='Day',
ylabel='Temperature in Celsius',
title='Temperature Graph')

plt.show()
#The plot Function
import matplotlib.pyplot as plt

days = list(range(1,9))
celsius_min = [19.6, 24.1, 26.7, 28.3, 27.5, 30.5, 32.8, 33.1]
celsius_max = [24.8, 28.9, 31.3, 33.0, 34.9, 35.6, 38.4, 39.2]

fig, ax = plt.subplots()

ax.set(xlabel='Day',
ylabel='Temperature in Celsius',
title='Temperature Graph')

ax.plot(days, celsius_min,
days, celsius_min, "oy",
days, celsius_max,
days, celsius_max, "or")

plt.show()
#
import matplotlib.pyplot as plt

days = list(range(1, 9))


celsius_min = [19.6, 24.1, 26.7, 28.3, 27.5, 30.5, 32.8, 33.1]
celsius_max = [24.8, 28.9, 31.3, 33.0, 34.9, 35.6, 38.4, 39.2]

fig, ax = plt.subplots()

ax.set(xlabel='Day',
ylabel='Temperature in Celsius',
title='Temperature Graph')

ax.plot(days, celsius_min)
ax.plot(days, celsius_min, "oy")
ax.plot(days, celsius_max)
ax.plot(days, celsius_max, "or")

plt.show()
#Checking and Defining the Range of Axes
import matplotlib.pyplot as plt

days = list(range(1, 9))


celsius_values = [25.6, 24.1, 26.7, 28.3, 27.5, 30.5, 32.8, 33.1]
fig, ax = plt.subplots()
ax.plot(days, celsius_values)
ax.set(xlabel='Day',
ylabel='Temperature in Celsius',
title='Temperature Graph')

print("The current limits for the axes are:")


print(ax.axis())
print("We set the axes to the following values:")
xmin, xmax, ymin, ymax = 0, 10, 14, 45
print(xmin, xmax, ymin, ymax)
ax.axis([xmin, xmax, ymin, ymax])
plt.show()
#"linspace" to Define X Values
import matplotlib.pyplot as plt

X = np.linspace(-2 * np.pi, 2 * np.pi, 50, endpoint=True)


F1 = 3 * np.sin(X)
F2 = np.sin(2*X)
F3 = 0.3 * np.sin(X)

fig, ax = plt.subplots()

startx, endx = -2 * np.pi - 0.1, 2*np.pi + 0.1


starty, endy = -3.1, 3.1
ax.axis([startx, endx, starty, endy])

ax.plot(X, F1, X, F2, X, F3)


plt.show()
#
import matplotlib.pyplot as plt

X = np.linspace(-2 * np.pi, 2 * np.pi, 50, endpoint=True)


F1 = 3 * np.sin(X)
F2 = np.sin(2*X)
F3 = 0.3 * np.sin(X)

fig, ax = plt.subplots()
startx, endx = -2 * np.pi - 0.1, 2*np.pi + 0.1
starty, endy = -3.1, 3.1

ax.axis([startx, endx, starty, endy])


ax.plot(X, F1, X, F2, X, F3)
ax.plot(X, F1, 'ro', X, F2, 'bx')
plt.show()
#
'''
Changing the Line Style
The linestyle of a plot can be influenced with the linestyle or ls parameter of the plot function. It can
be set to one of the following values:
'-', '--', '-.', ':', 'None', ' ', ''

We can use linewidth to set the width of a line as the name implies.
'''
import matplotlib.pyplot as plt
X = np.linspace(0, 2 * np.pi, 50, endpoint=True)
F1 = 3 * np.sin(X)
F2 = np.sin(2*X)
F3 = 0.3 * np.sin(X)
F4 = np.cos(X)

fig, ax = plt.subplots()
ax.plot(X, F1, color="blue", linewidth=2.5, linestyle="-")
ax.plot(X, F2, color="red", linewidth=1.5, linestyle="--")
ax.plot(X, F3, color="green", linewidth=2, linestyle=":")
ax.plot(X, F4, color="grey", linewidth=2, linestyle="-.")
plt.show()
'''
Draw LPoints in Matplotlib
We will learn now how to draw single points in Matplotlib.
'''
import matplotlib.pyplot as plt

fig, ax = plt.subplots()
ax.scatter(3, 7, s=42)
#
import matplotlib.pyplot as plt
import numpy as np

X = np.random.randint(0, 100, (20,))


Y = np.random.randint(0, 100, (20,))
fig, ax = plt.subplots()
ax.scatter(X, Y, s=42)
'''
Shading Regions with fill_between()
It is possible to shade or colorize regions between two curves.
We are filling the region between the X axis and the graph of sin(2*X) in the following example:
'''
import numpy as np
import matplotlib.pyplot as plt
n = 256
X = np.linspace(-np.pi,np.pi,n,endpoint=True)
Y = np.sin(2*X)

fig, ax = plt.subplots()
ax.plot (X, Y, color='blue', alpha=1.00)
ax.fill_between(X, 0, Y, color='blue', alpha=.1)
plt.show()
#
import numpy as np
import matplotlib.pyplot as plt

n = 256
X = np.linspace(-np.pi,np.pi,n,endpoint=True)
Y = np.sin(2*X)

fig, ax = plt.subplots()

ax.plot (X, Y, color='blue', alpha=1.00)


ax.fill_between(X, Y, 1, color='blue', alpha=.1)
plt.show()
#
import numpy as np
import matplotlib.pyplot as plt

X = np.linspace(-2 * np.pi, 2 * np.pi, 70, endpoint=True)


F1 = np.sin(2* X)
F2 = (2*X**5 + 4*X**4 - 4.8*X**3 + 1.2*X**2 + X + 1)*np.exp(-X**2)

fig, ax = plt.subplots()

# making the top and right spine invisible:


ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')

# moving bottom spine up to y=0 position:


ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data',0))

# moving left spine to the right to position x == 0:


ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data',0))

ax.plot(X, F1, X, F2)

plt.show()
'''
Customizing Ticks
Matplotlib has so far - in all our previous examples - automatically taken over the task of
spacing points on the axis. We can see for example that the X axis in our previous example was
numbered -6. -4, -2, 0, 2, 4, 6, whereas the Y axis was numbered -1.0, 0, 1.0, 2.0, 3.0

xticks is a method, which can be used to get or to set the current tick locations and the labels.
The same is true for yticks:
'''
import matplotlib.pyplot as plt
fig, ax = plt.subplots()

xticks = ax.get_xticks()
xticklabels = ax.get_xticklabels()
print(xticks, xticklabels)
for i in range(6):
print(xticklabels[i])

yticks = ax.get_yticks()
print(yticks)
#As we said before, we can also use xticks to set the location of xticks:

import matplotlib.pyplot as plt


fig, ax = plt.subplots()

ax.set_xticks([7, 13, 19, 33, 42])


#Now, we will set both the locations and the labels of the xticks:

import matplotlib.pyplot as plt


fig, ax = plt.subplots()
ax.set_xticks([7, 13, 19, 33, 42])
ax.set_xticklabels(['Berlin', 'London', 'Hamburg', 'Toronto'])
#Let's get back to our previous example with the trigonometric functions. Most people might consider
factors of Pi to be more appropriate for the X axis than the integer labels:

import numpy as np
import matplotlib.pyplot as plt

X = np.linspace(-2 * np.pi, 2 * np.pi, 70, endpoint=True)


X = np.linspace(-2 * np.pi, 2 * np.pi, 70, endpoint=True)
F1 = np.sin(X**2)
F2 = X * np.sin(X)

fig, ax = plt.subplots()

# making the top and right spine invisible:


ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
# moving bottom spine up to y=0 position:
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data',0))
# moving left spine to the right to position x == 0:
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data',0))

ax.set_xticks( [-6.28, -3.14, 3.14, 6.28])


ax.set_yticks([-3, -1, 0, +1, 3])
ax.plot(X, F1)
ax.plot(X, F2)

plt.show()
#There is an easier way to set the values of the xticks so that we do not have to caculate them
manually. We use plt.MultipleLocator with np.pi/2 as argument:

import numpy as np
import matplotlib.pyplot as plt

X = np.linspace(-2 * np.pi, 2 * np.pi, 100)


F1 = np.sin(X)
F2 = 3 * np.sin(X)
fig, ax = plt.subplots()

ax.xaxis.set_major_locator(plt.MultipleLocator(np.pi / 2))

ax.plot(X, F1, X, F2)

plt.show()
#Adding a Legend
from polynomials import Polynomial
import numpy as np
import matplotlib.pyplot as plt

p = Polynomial(-0.8, 2.3, 0.5, 1, 0.2)


p_der = p.derivative()
fig, ax = plt.subplots()
X = np.linspace(-2, 3, 50, endpoint=True)
F = p(X)
F_derivative = p_der(X)
ax.plot(X, F)
ax.plot(X, F_derivative)

ax.legend(['p', 'derivation of p'])


#
from polynomials import Polynomial
import numpy as np
import matplotlib.pyplot as plt

p = Polynomial(2, 3, -4, 6)
p_der = p.derivative()

fig, ax = plt.subplots()
X = np.linspace(-2, 3, 50, endpoint=True)
F = p(X)
F_derivative = p_der(X)
ax.plot(X, F, label="$2x^{3} + 3x^{2} - 4x + 6$")
ax.plot(X, F_derivative, label="$6x^{2} - 6x -4$")

ax.legend(loc='upper left')
'''
Annotations
The visualizations of function plots often makes annotations necessary.
This means we draw the readers attentions to important points and areas of the plot.
To this purpose we use texts, labels and arrows. We have already used axis labels and titles for
this purpose, but these are 'annotations' for the whole plot. We can easily annotate points inside
the axis or on the graph with the annotate method of an axes object. In an annotation,
there are two points to consider: the location being annotated represented by the argument
xy and the location of the text xytext. Both of these arguments are (x,y) tuples.

We demonstrate how easy it is in matplotlib to to annotate plots in matplotlib with the


annotate method. We will annotate the local maximum and the local minimum of a function.
In its simplest form annotate method needs two arguments annotate(s, xy), where s is the
text string for the annotation and xx is the position of the point to be annotated:
'''
from polynomials import Polynomial
import numpy as np
import matplotlib.pyplot as plt

p = Polynomial(1, 0, -12, 0)
p_der = p.derivative()

fig, ax = plt.subplots()
X = np.arange(-5, 5, 0.1)
F = p(X)

F_derivative = p_der(X)
ax.grid()

maximum = (-2, p(-2))


minimum = (2, p(2))
ax.annotate("local maximum", maximum)
ax.annotate("local minimum", minimum)

ax.plot(X, F, label="p")
ax.plot(X, F_derivative, label="derivation of p")

ax.legend(loc='best')
plt.show()
#If you are not satisfied with the automatic positioning of the text, you can assign a tuple with a
position for the text to the keyword parameter xytext:

from polynomials import Polynomial


import numpy as np
import matplotlib.pyplot as plt

p = Polynomial(1, 0, -12, 0)
p_der = p.derivative()

fig, ax = plt.subplots()
X = np.arange(-5, 5, 0.1)
F = p(X)

F_derivative = p_der(X)
ax.grid()

ax.annotate("local maximum",
xy=(-2, p(-2)),
xytext=(-1, p(-2)+35),
arrowprops=dict(facecolor='orange'))
ax.annotate("local minimum",
xy=(2, p(2)),
xytext=(-2, p(2)-40),
arrowprops=dict(facecolor='orange', shrink=0.05))
ax.annotate("inflection point",
xy=(0, p(0)),
xytext=(-3, -30),
arrowprops=dict(facecolor='orange', shrink=0.05))

ax.plot(X, F, label="p")
ax.plot(X, F_derivative, label="derivation of p")

ax.legend(loc='best')
plt.show()
#
import matplotlib.pyplot as plt

def demo_con_style(ax, connectionstyle):


x1, y1 = 0.3, 0.2
x2, y2 = 0.8, 0.6

ax.plot([x1, x2], [y1, y2], ".")


ax.annotate("",
xy=(x1, y1), xycoords='data',
xytext=(x2, y2), textcoords='data',
arrowprops=dict(arrowstyle="->", color="0.5",
shrinkA=5, shrinkB=5,
patchA=None, patchB=None,
connectionstyle=connectionstyle))

ax.text(.05, .95, connectionstyle.replace(",", ",\n"),


transform=ax.transAxes, ha="left", va="top")

fig, axs = plt.subplots(3, 5, figsize=(8, 4.8))


demo_con_style(axs[0, 0], "angle3,angleA=90,angleB=0")
demo_con_style(axs[1, 0], "angle3,angleA=0,angleB=90")
demo_con_style(axs[0, 1], "arc3,rad=0.")
demo_con_style(axs[1, 1], "arc3,rad=0.3")
demo_con_style(axs[2, 1], "arc3,rad=-0.3")
demo_con_style(axs[0, 2], "angle,angleA=-90,angleB=180,rad=0")
demo_con_style(axs[1, 2], "angle,angleA=-90,angleB=180,rad=5")
demo_con_style(axs[2, 2], "angle,angleA=-90,angleB=10,rad=5")
demo_con_style(axs[0, 3], "arc,angleA=-90,angleB=0,armA=30,armB=30,rad=0")
demo_con_style(axs[1, 3], "arc,angleA=-90,angleB=0,armA=30,armB=30,rad=5")
demo_con_style(axs[2, 3], "arc,angleA=-90,angleB=0,armA=0,armB=40,rad=0")
demo_con_style(axs[0, 4], "bar,fraction=0.3")
demo_con_style(axs[1, 4], "bar,fraction=-0.3")
demo_con_style(axs[2, 4], "bar,angle=180,fraction=-0.2")

for ax in axs.flat:
ax.set(xlim=(0, 1), ylim=(0, 1), xticks=[], yticks=[], aspect=1)
fig.tight_layout(pad=0.2)

plt.show()
#Multiple Plots and Double Axes
#Working with Multiple Figures and Axes
import matplotlib.pyplot as plt

python_course_green = "#476042"
plt.figure(figsize=(6, 4))
plt.subplot(221) # equivalent to: plt.subplot(2, 2, 1)

plt.text(0.5, # x coordinate, 0 leftmost positioned, 1 rightmost


0.5, # y coordinate, 0 topmost positioned, 1 bottommost
'subplot(2,2,1)', # the text which will be printed
horizontalalignment='center', # shortcut 'ha'
verticalalignment='center', # shortcut 'va'
fontsize=20, # can be named 'font' as well
alpha=.5 # float (0.0 transparent through 1.0 opaque)
)
plt.subplot(224, axisbg=python_course_green)
plt.text(0.5, 0.5,
'subplot(2,2,4)',
ha='center', va='center',
fontsize=20,
color="y")
#Histograms
import matplotlib.pyplot as plt
import numpy as np
gaussian_numbers = np.random.normal(size=10000)
plt.hist(gaussian_numbers)
plt.title("Gaussian Histogram")
plt.xlabel("Value")
plt.ylabel("Frequency")
plt.show()
#
n, bins, patches = plt.hist(gaussian_numbers)
print("n: ", n, sum(n))
print("bins: ", bins)
for i in range(len(bins)-1):
print(bins[i+1] -bins[i])
print("patches: ", patches)
print(patches[1])
#Bar Plots
bars = plt.bar([1,2,3,4], [1,4,9,16])
bars[0].set_color('green')
plt.show()
#Contour Plot
import numpy as np

xlist = np.linspace(-3.0, 3.0, 3)


ylist = np.linspace(-3.0, 3.0, 4)
X, Y = np.meshgrid(xlist, ylist)
print(xlist)
print(ylist)
print(X)
print(Y)
#
import matplotlib.pyplot as plt

plt.figure()
cp = plt.contour(X, Y,Z)
plt.clabel(cp, inline=True,
fontsize=10)
plt.title('Contour Plot')
plt.xlabel('x (cm)')
plt.ylabel('y (cm)')
plt.show()
#
import matplotlib.pyplot as plt

plt.figure()
cp = plt.contour(X, Y, Z, colors='black', linestyles='dashed')
plt.clabel(cp, inline=True,
fontsize=10)
plt.title('Contour Plot')
plt.xlabel('x (cm)')
plt.ylabel('y (cm)')
plt.show()
#Filled Contours
import numpy as np
import matplotlib.pyplot as plt

xlist = np.linspace(-3.0, 3.0, 100)


ylist = np.linspace(-3.0, 3.0, 100)
X, Y = np.meshgrid(xlist, ylist)
Z = np.sqrt(X**2 + Y**2)
plt.figure()

cp = plt.contourf(X, Y, Z)
plt.colorbar(cp)

plt.title('Filled Contours Plot')


plt.xlabel('x (cm)')
plt.ylabel('y (cm)')
plt.show()
#Individual Colours
import numpy as np
import matplotlib.pyplot as plt

xlist = np.linspace(-3.0, 3.0, 100)


ylist = np.linspace(-3.0, 3.0, 100)
X, Y = np.meshgrid(xlist, ylist)
Z = np.sqrt(X**2 + Y**2)

plt.figure()

contour = plt.contourf(X, Y, Z)
plt.clabel(contour, colors = 'k', fmt = '%2.1f', fontsize=12)
c = ('#ff0000', '#ffff00', '#0000FF', '0.6', 'c', 'm')
contour_filled = plt.contourf(X, Y, Z, colors=c)
plt.colorbar(contour)

plt.title('Filled Contours Plot')


plt.xlabel('x (cm)')
plt.ylabel('y (cm)')
plt.show()
'''
Levels
The levels were decided automatically by contour and contourf so far.
They can be defined manually, by providing a list of levels as a fourth parameter.
Contour lines will be drawn for each value in the list, if we use contour.
For contourf, there will be filled colored regions between the values in the list.
'''
import numpy as np
import matplotlib.pyplot as plt

xlist = np.linspace(-3.0, 3.0, 100)


ylist = np.linspace(-3.0, 3.0, 100)
X, Y = np.meshgrid(xlist, ylist)

Z = np.sqrt(X ** 2 + Y ** 2 )
plt.figure()

levels = [0.0, 0.2, 0.5, 0.9, 1.5, 2.5, 3.5]


contour = plt.contour(X, Y, Z, levels, colors='k')
plt.clabel(contour, colors = 'k', fmt = '%2.1f', fontsize=12)
contour_filled = plt.contourf(X, Y, Z, levels)
plt.colorbar(contour_filled)

plt.title('Plot from level list')


plt.xlabel('x (cm)')
plt.ylabel('y (cm)')
plt.show()
#Lovely
import matplotlib.pyplot as plt
import numpy as np

y, x = np.ogrid[-1:2:100j, -1:1:100j]
plt.contour(x.ravel(),
y.ravel(),
x**2 + (y-((x**2)**(1.0/3)))**2,
[1],
colors='red',)
plt.axis('equal')
plt.show()
#Introduction into Pandas
#Data Structures
import pandas as pd
S = pd.Series([11, 28, 72, 3, 5, 8])
S
print(S.index)
print(S.values)
#
fruits = ['apples', 'oranges', 'cherries', 'pears']
quantities = [20, 33, 52, 10]
S = pd.Series(quantities, index=fruits)
S
#If we add two series with the same indices, we get a new series with the same index and the
correponding values will be added:

fruits = ['apples', 'oranges', 'cherries', 'pears']

S = pd.Series([20, 33, 52, 10], index=fruits)


S2 = pd.Series([17, 13, 31, 32], index=fruits)
print(S + S2)
print("sum of S: ", sum(S))
#The indices do not have to be the same for the Series addition. The index will be the "union" of both
indices. If an index doesn't occur in both Series, the value for this Series will be NaN:

fruits = ['peaches', 'oranges', 'cherries', 'pears']


fruits2 = ['raspberries', 'oranges', 'cherries', 'pears']

S = pd.Series([20, 33, 52, 10], index=fruits)


S2 = pd.Series([17, 13, 31, 32], index=fruits2)
print(S + S2)
#Indexing
print(S[['apples', 'oranges', 'cherries']])
#
import pandas as pd
years = range(2014, 2018)
shop1 = pd.Series([2409.14, 2941.01, 3496.83, 3119.55], index=years)
shop2 = pd.Series([1203.45, 3441.62, 3007.83, 3619.53], index=years)
shop3 = pd.Series([3412.12, 3491.16, 3457.19, 1963.10], index=years)
pd.concat([shop1, shop2, shop3])
shops_df = pd.concat([shop1, shop2, shop3], axis=1)
shops_df
cities = ["Zürich", "Winterthur", "Freiburg"]
shops_df.columns = cities
print(shops_df)
# alternative way: give names to series:
shop1.name = "Zürich"
shop2.name = "Winterthur"
shop3.name = "Freiburg"
print("------")
shops_df2 = pd.concat([shop1, shop2, shop3], axis=1)
print(shops_df2)
#DataFrames from Dictionaries
#A DataFrame has a row and column index; it's like a dict of Series with a common index.

cities = {"name": ["London", "Berlin", "Madrid", "Rome",


"Paris", "Vienna", "Bucharest", "Hamburg",
"Budapest", "Warsaw", "Barcelona",
"Munich", "Milan"],
"population": [8615246, 3562166, 3165235, 2874038,
2273305, 1805681, 1803425, 1760433,
1754000, 1740119, 1602386, 1493900,
1350680],
"country": ["England", "Germany", "Spain", "Italy",
"France", "Austria", "Romania",
"Germany", "Hungary", "Poland", "Spain",
"Germany", "Italy"]}
city_frame = pd.DataFrame(cities)
city_frame
#
import pandas as pd
exchange_rates = pd.read_csv("dollar_euro.txt",
sep="\t")
print(exchange_rates)
#
import pandas as pd
exchange_rates = pd.read_csv("dollar_euro.txt",
sep="\t",
header=0,
names=["year", "min", "max", "days"])
print(exchange_rates)
Lab 6

x=(10<20)? 30:40
print(x)
x=30 if 100<20 else 40
print(x)

a="behala"
b="behala"
print(id(a))
print(id(b))
print(a is not b)

import math
print(math.sqrt(4))

from math import *


print(math.sqrt(4))

list1=[10,20,30]
list2=[10,20,30]
print(id(list1))
print(id(list2))
print(list1 is list2)
print(list1==list2)

#2input("Enter 2 nos").split()
a,b=[float(x)for x in input("Enter 2 float nos").split(',')]
print(a*b)

x=eval("10+34+78")
print(x)
print("10+20")

x=eval(input("Enter data"))
print(type(x))
print(x)
for x1 in x:
print(x1)

name="Debosi"
salary=75000
boyfrnd="??"
print("Hello {} your sal is {} and boyfrnd {} is waiting".format(name,salary,boyfrnd))

for i in range(4):
for j in range(4):
print("i={} and j={}".format(i,j))

n=int(input("Enter nos of rows"))


for i in range(n):
print('x'*n)

n=int(input("Enter nos of rows"))


for i in range(1,n+1):
print('i'*n)

num=int(input("Enter number"))
for i in range(1,num+1):
for j in range(1,i+1):
print(num-j,end=" ")
print()
for a in range(1,num+1):
for k in range(1,num+1-a):
print(num-k,end=" ")
print()
'''
#s=[0123456789]
s=input("Enter main string")
subs=input("Enter sub string")
flag=False
pos=-1
count=0
n=len(s)
while True:
pos=s.find(subs,pos+1,n)
if pos==-1:
break
print("Found at index",pos)
flag=True
count=count+1
if flag==False:
print("not found")
print("Number of occurance",count)

The aThe addThe addddThe ssThe


zz
Lab 7 Class Object

class Student:
def __init__(self,rollno,name):
self.roll=rollno
self.nm=name
def talk(self):
roll=99
print("My name is ",self.nm)
print("Roll no is ",self.roll)
print("Roll no is ",roll)
s=Student(100,'Sunny')
print(s.nm)
print(s.roll)
s.talk()
s1=Student(200,'Bunny')
s1.talk()

class Student:
cname='ABC'
def __init__(self,name,rollno):
self.name=name
self.rollno=rollno
s1=Student('Jhargram',101)
s2=Student('Gopiballavpur',102)
print(s1.name,s1.rollno,Student.cname)
print(s2.name,s2.rollno,Student.cname)

Instance Method************************************************
class Student:
def __init__(self,name,rollno):
self.name=name
self.rollno=rollno
print(self.name)
print(self.rollno)
def info(self):
self.marks=19
x=60
print(self.marks)
print(x)

s1=Student('Durga',101)
s1.info()
s1.age=12
print(s1.__dict__)

Static*****************************************************

class Test:
x=10
def __init__(self):
Test.y=20
def m1(self):
Test.c=30
@classmethod
def m2(cls):
cls.d=40
Test.e=50
@staticmethod
def m3():
Test.f=60
Test.g=70
t=Test()
t.m1()
Test.m2()
Test.m3()
print(Test.__dict__)

class Test:
x=10
def __init__(self):
Test.x=20
def m1(self):
print(Test.x)
print(self.x)
@classmethod
def m2(cls):
cls.x=30
Test.x=40
@staticmethod
def m3():
Test.x=50
t=Test()
t.m1()

Global Method*******************************************

x=999 #global
class Test:
def m1(self):
global x
x=888
print(x)
def m2(self):
print(x)
t=Test()
t.m1()
t.m2()
print(x)
Test.x=60
print(Test.x)
print(t.x)
Overloading**************************************
class Test:
def sum(self,a=None,b=None,c=None):
if a!=None and b!=None and c!=None:
print('The sum of 3 number is', a+b+c)
elif a!=None and b!=None:
print('The sum of 2 number is', a+b)
else:
print('Provide 2 or 3 arguments')
t=Test()
t.sum(10,20,30)
t.sum(10,20)
t.sum(10)

Operator Overloading******************************
class Book:
def __init__(self,pages):
self.pages=pages
def __add__(self,other):
return self.pages+other.pages
def __sub__(self,other):
return self.pages-other.pages
b1=Book(100)
b2=Book(200)
print(b1+b2)
print(b1-b2)
#"""

class Book:
def __init__(self,pages1):
self.pages1=pages1
def __str__(self):
return 'The number of pages'+str(self.pages1)
def __add__(self,other1):
total=self.pages1+other1.pages1
b=Book(total)
return b
b1=Book(100)
b2=Book(200)
b3=Book(300)
b4=Book(400)
print(b1+b2+b3+b4)
#print(b1+b2*b3+b4)
"""
"""
class Student:
def __init__(self,name,marks):
self.name=name
self.marks=marks
def __lt__(self,other):
return self.marks<other.marks
s1=Student('Durga',100)
s2=Student('Ravi',200)
print(s1<s2)
print(s2<s1)
class Employee:
def __init__(self,name,salary):
self.name=name
self.salary=salary
def __mul__(self,other):
return self.salary*other.days
class TimeSheet:
def __init__(self,name,days):
self.name=name
self.days=days
def __mul__(self,other):
return self.days*other.salary
e=Employee('Durga',500)
t=TimeSheet('Durga',25)
print('This month salary',e*t)
print('This month salary',t*e)
Lab 8 Inheritance

Inheritance**********************************************

class Person:

def __init__(self, first, last):


self.firstname = first
self.lastname = last

def __str__(self):
return self.firstname + " " + self.lastname

class Employee(Person):

def __init__(self, first, last, staffnum):


#super().__init__(first, last)
self.staffnumber = staffnum

x = Person("Marge", "Simpson")
y = Employee("Homer", "Simpson", "1007")

print(x)
print(y)

Super*************************************************
"""
Created on Tue Oct 22 07:48:04 2019

@author: USER
"""
"""
class Person:
def __init__(self,name,age):
self.name=name
self.age=age
def display(self):
print('Name', self.name)
print('Age',self.age)
class Student(Person):
def __init__(self, name, age, rollno,marks):
super().__init__(name,age)
self.rollno=rollno
self.marks=marks
def display(self):
super().display()
print('Rollno', self.rollno)
print('Marks',self.marks)
class Teacher(Person):
def __init__(self,name,age,salary,subject):
super().__init__(name,age)
self.salary=salary
self.subject=subject
def display(self):
super().display()
print('Salary', self.salary)
print('subject',self.subject)
s=Student('Ravi',23,101,90)
t=Teacher('Durga',62,1000,'Python')
s.display()
t.display()
"""
"""
class A:
def m1(self):
print('A class method')

class B(A):
def m1(self):
print('B class method')
class C(B):
def m1(self):
print('C class method')
class D(C):
def m1(self):
print('D class method')
class E(D):
def m1(self):
C.m1(self)
e=E()
e.m1()
"""
"""
class A:
def m1(self):
print('A class method')

class B(A):
def m1(self):
print('B class method')
class C(B):
def m1(self):
print('C class method')
class D(C):
def m1(self):
print('D class method')
class E(D):
def m1(self):
super(C,self).m1()
e=E()
e.m1()

"""
class P:
a=10
def __init__(self):
self.b=20
class C(P):
def m1(self):
print(super().a)
#print(super().b)
c=C()
c.m1()
"""
"""
class P:
def __init__(self):
print('Parent class constructor')
def m1(self):
print('Parent instance method')
@classmethod
def m2(cls):
print('Parent class method')
@staticmethod
def m3():
print('parent static method')
class C(P):
def __init__(self):
super().__init__()
super().m1()
super().m2()
super().m3()
c=C()
@classmethod
@staticmethod
def method1(self):
super.m1()
super.m2()
super.m3()
c=C()
c.method1()
"""
Lab 9 Threading

Threading*******************************************************

What Is a Thread?
A thread is a separate flow of execution. This means that your program will have two things
happening at once. But for most Python 3 implementations the different threads do not actually
execute at the same time: they merely appear to.
It’s tempting to think of threading as having two (or more) different processors running on your
program, each one doing an independent task at the same time. That’s almost right. The threads may
be running on different processors, but they will only be running one at a time.
Getting multiple tasks running simultaneously requires a non-standard implementation of Python,
writing some of your code in a different language, or using multiprocessing which comes with some
extra overhead.
Because of the way CPython implementation of Python works, threading may not speed up all tasks.
This is due to interactions with the GIL that essentially limit one Python thread to run at a time.
Tasks that spend much of their time waiting for external events are generally good candidates for
threading. Problems that require heavy CPU computation and spend little time waiting for external
events might not run faster at all.
This is true for code written in Python and running on the standard CPython implementation. If your
threads are written in C they have the ability to release the GIL and run concurrently. If you are running
on a different Python implementation, check with the documentation too see how it handles threads.
If you are running a standard Python implementation, writing in only Python, and have a CPU-bound
problem, you should check out the multiprocessing module instead.
Architecting your program to use threading can also provide gains in design clarity. Most of the
examples you’ll learn about in this tutorial are not necessarily going to run faster because they use
threads. Using threading in them helps to make the design cleaner and easier to reason about.
So, let’s stop talking about threading and start using it!
Starting a Thread
Now that you’ve got an idea of what a thread is, let’s learn how to make one. The Python standard
library provides threading, which contains most of the primitives you’ll see in this article. Thread, in
this module, nicely encapsulates threads, providing a clean interface to work with them.

Link: https://realpython.com/intro-to-python-threading/

Program 1
import time
#from threading import *
def doubles(numbers):
for n in numbers:
time.sleep(1)
print('Double value',2*n)
def squares(numbers):
for n in numbers:
time.sleep(1)
print('Square value',n*n)
numbers=[1,2,3,4,5,6]
begintime=time.time()
doubles(numbers)
squares(numbers)
endtime=time.time()
print('The total time taken: ',endtime-begintime)
"""
join() a Thread
Daemon threads are handy, but what about when you want to wait for a thread to stop? What about
when you want to do that and not exit your program?
To tell one thread to wait for another thread to finish, you call .join(). If you uncomment that line, the
main thread will pause and wait for the thread x to complete running.

Program 2
from threading import *
import time
def doubles(numbers):
for n in numbers:
time.sleep(1)
print('Double value',2*n)
def squares(numbers):
for n in numbers:
time.sleep(1)
print('Square value',n*n)
numbers=[1,2,3,4,5,6]
begintime=time.time()
t1=Thread(target=doubles,args=(numbers,))
t2=Thread(target=squares,args=(numbers,))
t1.start()
t2.start()
t1.join()
t2.join()
endtime=time.time()
print('The total time taken: ',endtime-begintime)
"""
Program 3
from threading import *
print(current_thread().getName())
current_thread().setName('Durga') #current_thread().name='Durga'
print(current_thread().getName())
"""
Program 4
from threading import *
def test():
print('Child thread ')
t=Thread(target=test)
t.start()
print('Main thread identification number ',current_thread().ident)
print('Child thread identification number ',t.ident)
"""
Program 5
from threading import *
import time
def display():
print(current_thread().name,'.....started')
time.sleep(2)
print('The number of active thread:',active_count())
t1=Thread(target=display,name='ChildThread-1')
t2=Thread(target=display,name='ChildThread-2')
t3=Thread(target=display,name='ChildThread-3')
t1.start()
t2.start()
t3.start()
print('The number of active thread: ',active_count())
time.sleep(10)
print('The number of active thread:',active_count())
"""
Program 6
from threading import *
import time
def display():
print(current_thread().name,'....started')
time.sleep(3)
print(current_thread().name,'....ended')
print('The number of active thread: ',active_count())
t1=Thread(target=display,name='ChildThread-1')
t2=Thread(target=display,name='ChildThread-2')
t3=Thread(target=display,name='ChildThread-3')
t1.start()
t2.start()
t3.start()
l=enumerate()
for t in l:
print('Thread name',t.name)
print('Thread identification number',t.ident)
"""
Program 7
from threading import *
import time
def display():
print(current_thread().name,'....started')
time.sleep(3)
print(current_thread().name,'....ended')
t1=Thread(target=display,name='ChildThread-1')
t2=Thread(target=display,name='ChildThread-2')
t1.start()
t2.start()
print(t1.name,'is alive:',t1.isAlive())
print(t2.name,'is alive:',t2.isAlive())
time.sleep(4)
print(t1.name,'is alive:',t1.isAlive())
print(t2.name,'is alive:',t2.isAlive())
"""

Program 8
from threading import *
import time
def display():
for i in range(10):
print('Child thread')
#time.sleep(2)
t=Thread(target=display)
t.start()
t.join()
for i in range(10):
print('Main thread')
"""
Daemon Threads
A daemon is a process that runs in the background.
Python threading has a more specific meaning for daemon. A daemon thread will shut down
immediately when the program exits. One way to think about these definitions is to consider
the daemon thread a thread that runs in the background without worrying about shutting it down.
If a program is running Threads that are not daemons, then the program will wait for those threads to
complete before it terminates. Threads that are daemons, however, are just killed wherever they are
when the program is exiting.

Program 9
from threading import *
mt=current_thread()
print(mt.isDeamon())
print(mt.daemon)

Program 10
from threading import *
mt=current_thread()
print(mt.isDeamon())
print(mt.daemon)
mt.setDaemon(True)
"""
Program 11
from threading import *
def job1():
print('Executed by child thread')
t=Thread(target=job1)
print(t.isDaemon())
t.setDaemon(True)
print(t.isDaemon())
"""
Lab 10

Exception Handling*************************************************************************

A Python program terminates as soon as it encounters an error. In Python, an error can be a syntax
error or an exception. In this article, you will see what an exception is and how it differs from a syntax
error.

Exceptions versus Syntax Errors


Syntax errors occur when the parser detects an incorrect statement. Observe the following example:

>>> print( 0 / 0 ))
File "<stdin>", line 1
print( 0 / 0 ))
^
SyntaxError: invalid syntax
The arrow indicates where the parser ran into the syntax error. In this example, there was one bracket
too many. Remove it and run your code again:

>>> print( 0 / 0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero
This time, you ran into an exception error. This type of error occurs whenever syntactically correct
Python code results in an error. The last line of the message indicated what type of exception error
you ran into.

Instead of showing the message exception error, Python details what type of exception error was
encountered. In this case, it was a ZeroDivisionError. Python comes with various built-in exceptions as
well as the possibility to create self-defined exceptions.

Raising an Exception
We can use raise to throw an exception if a condition occurs. The statement can be complemented
with a custom exception.

If you want to throw an error when a certain condition occurs using raise, you could go about it like
this:

x = 10
if x > 5:
raise Exception('x should not exceed 5. The value of x was: {}'.format(x))
When you run this code, the output will be the following:

Traceback (most recent call last):


File "<input>", line 4, in <module>
Exception: x should not exceed 5. The value of x was: 10
The program comes to a halt and displays our exception to screen, offering clues about what went
wrong.
print('Hi')

The try and except Block: Handling Exceptions


The try and except block in Python is used to catch and handle exceptions. Python executes code
following the try statement as a “normal” part of the program. The code that follows
the except statement is the program’s response to any exceptions in the preceding try clause.

Here are the key takeaways:

● A try clause is executed up until the point where the first exception is encountered.
● Inside the except clause, or the exception handler, you determine how the program responds
to the exception.
● You can anticipate multiple exceptions and differentiate how the program should respond to
them.
● Avoid using bare except clauses.
Program 1
try:
print(10/0)
except ZeroDivisionError:
print('Hello')

Program 2
try:
print(10/0)
except ZeroDivisionError:
print(10/2)
'''
Program 3
try:
print(10/0)
except ZeroDivisionError as msg:
print('Type of exception',type(msg))
print('Type of exception',msg.__class__)
print('Type of exception',msg.__class__.__name__)
print(msg)
'''
Program 4
try:
x=int(input('Enter first number'))
y=int(input('Enter second number'))
print('The result',x/y)
except ZeroDivisionError:
print('Cant divide by zero')
except ValueError:
print('Please provide int value only')
'''
Program 5
try:
print(10/0)
except ZeroDivisionError:
print('Zero div error')
except ArithmeticError:
print('Arithmetic Error')
'''
Program 6
try:
print(10/0)
except ArithmeticError:
print('Arithmetic Error')
except ZeroDivisionError:
print('Zero div error')
'''
Program 7
try:
x=int(input('Enter first number'))
y=int(input('Enter second number'))
print('The result',x/y)
except (ZeroDivisionError,ValueError) as msg:
print('raised exception',msg.__class__.__name__)
print('Description ofexception',msg)
print('Please provide valid input only')
'''
Program 8
try:
print(10/0)
except ZeroDivisionError:
print('Zero div error')
except:
print('default exception')
'''
Program 9
try:
print(10/0)
except:
print('default exception')
except ZeroDivisionError:
print('Zero div error')
#SyntaxError: default 'except:' must be last
'''
The else Clause
In Python, using the else statement, you can instruct a program to execute a certain block of code
only in the absence of exceptions.

Cleaning Up After Using finally


Imagine that you always had to implement some sort of action to clean up after executing your code.
Python enables you to do so using the finally clause.

Program 10
try:
print('try')
print(10/0)
except ZeroDivisionError:
print('Except')
finally:
print('finally')
'''
Program 11
try:
print('try')
print(10/0)
except ValueError:
print('Except')
finally:
print('finally')
ZeroDivisionError: division by zero

try
finally
'''
The OS module in python provides functions for interacting with the operating system. OS, comes
under Python’s standard utility modules. This module provides a portable way of using operating
system dependent functionality. The *os* and *os.path* modules include many functions to interact
with the file system.

https://www.geeksforgeeks.org/os-module-python-examples/

Following are some functions in OS module:

1. os.name: This function gives the name of the operating system dependent module
imported. The following names have currently been registered: ‘posix’, ‘nt’, ‘os2’, ‘ce’,
‘java’ and ‘riscos’
2. os.getcwd(): Function os.getcwd(), returns the Current Working Directory(CWD) of the
file used to execute the code, can vary from system to system.
3. os.error: All functions in this module raise OSError in the case of invalid or
inaccessible file names and paths, or other arguments that have the correct type, but are
not accepted by the operating system. os.error is an alias for built-in OSError exception.
4. os.popen(): This method opens a pipe to or from command. The return value can be
read or written depending on whether mode is ‘r’ or ‘w’.
5. os.close(): Close file descriptor fd. A file opened using open(), can be closed by
close()only. But file opened through os.popen(), can be closed with close() or os.close().
If we try closing a file opened with open(), using os.close(), Python would throw
TypeError.
6. os.rename(): A file old.txt can be renamed to new.txt, using the function os.rename().
The name of the file changes only if, the file exists and user has sufficient privilege
permission to change the file.

Program 12
import os
try:
print('try')
os._exit(0)
except ValueError:
print('except')
finally:
print('finally')
'''
Program 13
try:
print('Outer try block')
try:
print('Inner tryblock')
print(10/0)
except ZeroDivisionError:
print('Inner Except Block')
finally:
print('Inner Finally block')
except:
print('Outer except block')
finally:
print('Outer finally block')
'''
Program 14
try:
print('Outer try block')
try:
print('Inner tryblock')
print(10/0)
except ValueError:
print('Inner Except Block')
finally:
print('Inner Finally block')
except:
print('Outer except block')
finally:
print('Outer finally block')
'''

Program 15
try:
print('try')
except:
print('except')
else:
print('else')
finally:
print('finally')
'''
Program 16
try:
print('try')
print(10/0)
except:
print('except')
else:
print('else')
finally:
print('finally')
'''
Program 17
f=None
try:
f=open('abc.txt','r')
except:
print('Some problem while open')
else:
print('File opened successfully')
print('The content of the file')
print('*', *30)
print(f.read())
finally:
if f is not None:
f.close()
'''
User Defined Exception
Python throws errors and exceptions, when there is a code gone wrong, which may cause program to
stop abruptly. Python also provides exception handling method with the help of try-except. Some of
the standard exceptions which are most frequent include IndexError, ImportError, IOError,
ZeroDivisionError, TypeError and FileNotFoundError. A user can create his own error using exception
class.

https://www.geeksforgeeks.org/user-defined-exceptions-python-examples/

Program 18
class TooYoungException(Exception):
def __init__(self,msg):
self.msg=msg
class TooOldException(Exception):
def __init__(self,msg):
self.msg=msg
age=int(input('Enter Age'))
if age>60:
raise TooOldException('Too Old')
elif age<18:
raise TooYoungException('Too Young')
else:
print('You will be informed soon')

t.m1(10.5)
t.m1(10+20j)

The AssertionError Exception


Instead of waiting for a program to crash midway, you can also start by making an assertion in
Python. We assert that a certain condition is met. If this condition turns out to be True, then that is
excellent! The program can continue. If the condition turns out to be False, you can have the program
throw an AssertionError exception.

import sys
assert ('linux' in sys.platform), "This code runs on Linux only."

If you run this code on a Linux machine, the assertion passes. If you were to run this code on a
Windows machine, the outcome of the assertion would be False and the result would be the following:
Traceback (most recent call last):
File "<input>", line 2, in <module>
AssertionError: This code runs on Linux only.
In this example, throwing an AssertionError exception is the last thing that the program will do.

After seeing the difference between syntax errors and exceptions, you learned about various ways to
raise, catch, and handle exceptions in Python. In this article, you saw the following options:
● raise allows you to throw an exception at any time.
● assert enables you to verify if a certain condition is met and throw an exception if it isn’t.
● In the try clause, all statements are executed until an exception is encountered.
● except is used to catch and handle the exception(s) that are encountered in the try clause.
● else lets you code sections that should run only when no exceptions are encountered in the try
clause.
● finally enables you to execute sections of code that should always run, with or without any
previously encountered exceptions.

Lab 11

File Handling*************************************************************************

'''
Python too supports file handling and allows users to handle files i.e., to read and write files, along
with many other file handling options, to operate on files. The concept of file handling has stretched
over various other languages, but the implementation is either complicated or lengthy, but alike other
concepts of Python, this concept here is also easy and short. Python treats file differently as text or
binary and this is important. Each line of code includes a sequence of characters and they form text
file. Each line of a file is terminated with a special character, called the EOL or End of Line characters
like comma {,} or newline character. It ends the current line and tells the interpreter a new one has
begun. Let’s start with Reading and Writing files.
Working of open() function
We use open () function in Python to open a file in read or write mode. As explained above, open ( )
will return a file object. To return a file object we use open() function along with two arguments, that
accepts file name and the mode, whether to read or write. So, the syntax being: open(filename, mode).
There are three kinds of mode, that Python provides and how files can be opened:

● “ r “, for reading.
● “ w “, for writing.
● “ a “, for appending.
● “ r+ “, for both reading and writing

Python file method tell() returns the current position of the file read/write pointer within the file.

Python file method seek() sets the file's current position at the offset. The whence argument is
optional and defaults to 0, which means absolute file positioning, other values are 1 which means
seek relative to the current position and 2 means seek relative to the file's end.

There is no return value. Note that if the file is opened for appending using either 'a' or 'a+', any seek()
operations will be undone at the next write.

If the file is only opened for writing in append mode using 'a', this method is essentially a no-op, but it
remains useful for files opened in append mode with reading enabled (mode 'a+').

If the file is opened in text mode using 't', only offsets returned by tell() are legal. Use of other offsets
causes undefined behavior.

Note that not all file objects are seekable.

Program 1

f=open('abc.txt','r')
print(f.tell())
print(f.read(3))
print(f.tell())
'''
Program 2
data='All students are stupid'
f=open('abc.txt', 'w')
f.write(data)
with open('abc.txt','r+') as f:
text=f.read()
print(text)
print('The last position is',f.tell())
f.seek(17)
print('Current pos',f.tell())
f.write('horrible!!!')
f.seek(1000)
print('Current pos',f.tell())
f.write('dumb')
print(f.tell())
'''
Program 3
import os
fname=input('enter the file name')
if os.path.isfile(fname):
print('File exists',fname)
f=open(fname,'r')
print(f.read())
else:
print('dont exist')
'''
Program 4
import os
fname=input('enter the file name')
if os.path.isfile(fname):
print('File exists',fname)
f=open(fname,'r')
lcount=wcount=ccount=0
for line in f:
lcount=lcount+1
words=line.split()
wcount=wcount+len(words)
ccount=ccount+len(line)
print(lcount)
print(wcount)
'''
Program 5
import csv
f=open('student.csv','r')
r=csv.reader(f)
data=list(r)
#print(data)
for row in data:
for column in row:
print(column,'\t',end='')
print()
'''
import csv
with open('student.csv','w',newline='') as f:
w=csv.writer(f)
w.writerow(['Name','Roll','Marks','Addr'])
while True:
name=input('Nter student name')
rno=int(input('Nter roll no'))
marks=int(input('nter marks'))
addr=input('nter address')
w.writerow([name,rno,marks,addr])
option=input('Do u wantto continue[yes|no:]')
if option.lower()=='no':
break
print('successful')

Lab 12
Garbage Collection**********************************************************************

What is garbage collection and why do we need It?


Memory management
A programming language uses objects in its programs to perform operations. Objects include simple
variables, like strings, integers, or booleans. They also include more complex data structures like lists,
hashes, or classes.

The values of your program’s objects are stored in memory for quick access. In many programming
languages, a variable in your program code is simply a pointer to the address of the object in memory.
When a variable is used in a program, the process will read the value from memory and operate on it.

In early programming languages, developers were responsible for all memory management in their
programs. This meant before creating a list or an object, you first needed to allocate the memory for
your variable. After you were done with your variable, you then needed to deallocate it to “free” that
memory for other users.

This led to two problems:

Forgetting to free your memory. If you don’t free your memory when you’re done using it, it can result
in memory leaks. This can lead to your program using too much memory over time. For long-running
applications, this can cause serious problems.
Freeing your memory too soon. The second type of problem consists of freeing your memory while
it’s still in use. This can cause your program to crash if it tries to access a value in memory that
doesn’t exist, or it can corrupt your data. A variable that refers to memory that has been freed is called
a dangling pointer.

These problems were undesirable, and so newer languages added automatic memory management.

Automatic memory management and garbage collection


With automatic memory management, programmers no longer needed to manage memory
themselves. Rather, the runtime handled this for them.

There are a few different methods for automatic memory management, but one of the more popular
ones uses reference counting. With reference counting, the runtime keeps track of all of the references
to an object. When an object has zero references to it, it’s unusable by the program code and thus able
to be deleted.

For programmers, automatic memory management adds a number of benefits. It’s faster to develop
programs without thinking about low-level memory details. Further, it can help avoid costly memory
leaks or dangerous dangling pointers.

However, automatic memory management comes at a cost. Your program will need to use additional
memory and computation to track all of its references. What’s more, many programming languages
with automatic memory management use a “stop-the-world” process for garbage collection where all
execution stops while the garbage collector looks for and deletes objects to be collected.

With the advances in computer processing from Moore’s law and the larger amounts of RAM in newer
computers, the benefits of automatic memory management usually outweigh the downsides. Thus,
most modern programming languages like Java, Python, and Golang use automatic memory
management.

For long-running applications where performance is critical, some languages still have manual
memory management. The classic example of this is C++. We also see manual memory
management in Objective-C, the language used for macOS and iOS. For newer languages, Rust uses
manual memory management.

Now that we know about memory management and garbage collection in general, let’s get more
specific about how garbage collection works in Python.

Program 1
import gc
print(gc.isenabled())
gc.disable()
print(gc.isenabled())
gc.enable()
print(gc.isenabled())

Program 2
import time
class Test:
def __init__(self):
print('Object initialization')
def __del__(self):
print('Fulfilling last wish')
t=Test()
time.sleep(10)
print('End of application')
'''
Program 3
import time
class Test:
def __init__(self):
print('Object initialization')
def __del__(self):
print('Fulfilling last wish')
t=Test()
t=None
time.sleep(5)
print('End of application')
'''
Program 4
import time
class Test:
def __init__(self):
print('Object initialization')
def __del__(self):
print('Fulfilling last wish')
t=Test()
t=None
print(t)
'''
Program 5
import time
class Test:
def __init__(self):
print('Object initialization')
def __del__(self):
print('Fulfilling last wish')
t=Test()
del t
print(t)
Miscellaneous
Pattern Generation**********************************************************************

def pypart(n):

# outer loop to handle number of rows


# n in this case
for i in range(0, n):

# inner loop to handle number of columns


# values changing acc. to outer loop
for j in range(0, i+1):

# printing stars
print("* ",end="")

# ending line after each row


print("\r")

# Driver Code
n=5
pypart(n)
"""
def pypart2(n):

# number of spaces
k=n

# outer loop to handle number of rows


for i in range(0, n):

# inner loop to handle number spaces


# values changing acc. to requirement
for j in range(0, k):
print(end=" ")

# decrementing k after each loop


k=k-1

# inner loop to handle number of columns


# values changing acc. to outer loop
for j in range(0, i+1):

# printing stars
print("* ", end="")

# ending line after each row


print("\r")
# Driver Code
n=5
pypart2(n)

Inner
Class**********************************************************************************************
class Person:
def __init__(self):
self.name='Satrajit'
self.dob=self.DOB()#object creation
def display(self):
print('Name ',self.name)
self.dob.display()
class DOB:
def __init__(self):
self.dd=15
self.mm=8
self.yyyy=1947
def display(self):
print('DOB={}/{}/{}'.format(self.dd,self.mm,self.yyyy))
p=Person()
p.display()

You might also like