Some of the key aspects of this book are: 1. It assumes knowledge of Python 3 and of concepts such as functions, classes, protocols, Abstract Base Classes, decorators, iterables, collection types (such as List and Tuple) etc. 2. However, the book assumes very little knowledge or experience of the topics presented. 3. The book is divided into eight topic areas; Computer graphics, Games, Testing, File InputOutput, Database Access, Logging, Concurrency and Parallelism and Network Programming. 4. Each topic in the book has an introductory chapter followed by chapters that delve into that topic. 5. The book includes exercises at the end of most chapters. 6. All code examples (and exercise solutions) are provided on line in a GitHub repository
Introduction
I have heard many people over the years say that Python is an easy language to lean and that Python is also a simple language.
While the Python language is known for its simplicity and ease of learning due to its consistent design, its extensive array of features and flexibility can be intimidating for new users Additionally, the vast Python ecosystem, with its numerous libraries and competing options, can make advancing to a more proficient level quite challenging.
After mastering the fundamental aspects of the language, including classes, inheritance, functions, protocols, and Abstract Base Classes, the next step is to explore advanced topics and practical applications to deepen your understanding and enhance your skills.
The aim of this book is to delve into those next steps The book is organised into eight different topics:
1 Computer Graphics The book covers Computer Graphics and Computer Generated Art in Python as well as Graphical User Interfaces and Graphing/ Charting via MatPlotLib.
2 Games Programming This topic is covered using thepygamelibrary.
3 Testing and Mocking Testing is an important aspect of any software devel- opment; this book introduces testing in general and the PyTest module in detail.
It also considers mocking within testing including what and when to mock.
The book explores file input and output, detailing how to read and write text files, as well as CSV and Excel formats Additionally, it introduces regular expressions, which are useful for processing textual data contained within these files.
5 Database Access The book introduces databases and relational database in particular It then presents the Python DB-API database access standard and © Springer Nature Switzerland AG 2019
J Hunt, Advanced Guide to Python 3 Programming ,
Undergraduate Topics in Computer Science, https://doi.org/10.1007/978-3-030-25943-3_1
1 one implementation of this standard, the PyMySQL module used to access a MySQL database.
Logging is a crucial yet frequently overlooked aspect of programming This article emphasizes the importance of logging, detailing what information should be recorded and what should be avoided Additionally, it introduces the Python logging module, providing essential insights for effective logging practices.
7 Concurrency and Parallelism The book provides extensive coverage of concurrency topics including Threads, Processes and inter thread or process synchronisation It also presents Futures and AsyncIO.
8 Reactive Programming This section of the book introduces Reactive Programming using the PyRx reactive programming library.
9 Network Programming The book concludes by introducing socket and web service communications in Python.
The article begins with a foundational chapter that outlines key concepts related to each topic, such as Computer Graphics It introduces the Turtle Graphics Python library, a tool for creating graphical displays The subsequent chapter explores Computer Generated Art, utilizing the Turtle Graphics library to demonstrate artistic concepts through various examples The discussion culminates with notable examples of fractals, including the Koch Snowflake and the Mandelbrot Fractal set, highlighting their significance in the realm of digital art.
This is followed by a chapter presenting the MatPlotLib library used for gen- erating 2D and 3D charts and graphs (such as a line chart, bar chart or scatter graph).
The final chapter focuses on Graphical User Interfaces (GUIs) utilizing the wxPython library, detailing the definition of a GUI and examining various alternatives in Python for GUI development.
Subsequent topics follow a similar pattern.
Each chapter focused on programming or libraries features multiple downloadable sample programs available on the GitHub repository for hands-on execution Additionally, these chapters offer one or more end-of-chapter exercises, complete with sample solutions also accessible in the GitHub repository.
The book's topics are designed for independent reading, enabling readers to explore specific subject areas as needed For instance, the File Input/Output and Database Access sections can be studied separately, though understanding both may be beneficial for choosing the best long-term data storage solution for a system.
Each section of the article contains essential dependencies; for instance, understanding the pygame library from the introductory chapter on 'Building Games with pygame' is crucial before diving into the case study of the StarshipMeteors game Likewise, familiarity with the Threading and Multiprocessing chapters is necessary prior to exploring the Inter Thread/Process Synchronisation chapter.
Computer Graphics
Introduction
Computer graphics are omnipresent in our daily lives, appearing on televisions, in cinema advertisements, and as essential elements of numerous films They are also found on tablets, mobile phones, PCs, and Macs, as well as in car dashboards, smartwatches, and children's electronic toys.
Computer Graphics refers to the visual representation of information generated by computers, encompassing the creation of Graphical User Interfaces (GUIs), various data visualizations like bar charts and line plots, graphics in video games such as Space Invaders and Flight Simulator, as well as the production of 2D and 3D images This field has significantly contributed to the widespread adoption of computer systems by non-experts over the past 40 years, making technology more accessible through graphical interfaces, which has led to the ubiquitous use of computers in everyday devices like PCs, tablets, mobile phones, and smart TVs.
A Graphical User Interface (GUI) effectively conveys concepts and situations, often eliminating the necessity for lengthy text or commands By utilizing the right visuals, a GUI captures the essence of an idea, demonstrating the adage that a picture can convey a thousand words.
In numerous scenarios where extensive information needs to be communicated, graphical representation is often more easily understood by users than text Additionally, manipulating system entities visually can convey meaning more effectively than relying solely on text commands.
A well-chosen graph can effectively clarify complex information that may be difficult to interpret from a data table Additionally, an adventure-style game can enhance user engagement and understanding of the data presented.
J Hunt, Advanced Guide to Python 3 Programming ,
Undergraduate Topics in Computer Science, https://doi.org/10.1007/978-3-030-25943-3_2
Computer graphics have transformed engagement and immersion in media, significantly enhancing the experience compared to the textual formats of the 1980s This shift underscores the benefits of visual presentations over traditional text-only approaches.
Background
Every interactive software system features a Human-Computer Interface (HCI), ranging from simple text-based systems to sophisticated graphical displays This interface serves as the primary means for developers to gather information from users, and it is essential for users to engage with some type of computer interface to execute their desired operations.
Historically, computer systems lacked a Graphical User Interface (GUI) and primarily focused on numerical and data processing tasks During the 1960s, 70s, and 80s, users interacted with these systems through text-oriented terminals that displayed information on green or grey screens, offering minimal to no graphical output.
During the 1960s, researchers at prestigious institutions like Stanford, MIT, Bell Telephone Labs, and Xerox explored the potential of graphic systems in computing Notably, Ivan Sutherland demonstrated the feasibility of interactive computer graphics in 1963 through his Ph.D thesis on the Sketchpad system.
The Graphical Computer Era
During the 1980s, graphical computer displays and interactive interfaces emerged as popular tools for human-computer interaction These user-friendly interfaces eliminate the necessity for users to memorize complicated commands, making technology more accessible to novices Additionally, they present information in a clear and digestible format, allowing users to quickly absorb large amounts of data.
The rise of high-quality graphical interfaces, exemplified by the Apple Macintosh and early Windows systems, set a standard that users now anticipate across all software These pioneering systems established the foundation for the graphical user interface (GUI) that is now ubiquitous on PCs, Macs, Linux devices, tablets, and smartphones Today's GUI predominantly follows the WIMP paradigm, which stands for Windows, Icons, Menus, and Pointers, making it the most common interface design in use.
The primary benefit of window-based systems, especially within a WIMP (Windows, Icons, Menus, Pointer) environment, is the minimal training required for users Unlike traditional systems that demand the memorization of complex commands, WIMP interfaces simplify operations through intuitive icons, user actions like swiping, and accessible menu options, making them user-friendly and easy to navigate.
WIMP-based systems, which stand for Windows, Icons, Menus, and Pointer, are designed to be user-friendly and intuitive They facilitate ease of learning and retention, making them straightforward for users to navigate and operate, whether within a computer graphics application or a larger software program.
The Apple Macintosh interface, influenced by the Xerox Star Machine at the Palo Alto Research Center, popularized WIMP (Windows, Icons, Menus, Pointer) systems, making them accessible to the mass market and establishing them as essential tools for business and home use This innovation transformed user interactions with computers, setting a de facto standard that compelled other manufacturers, like Microsoft, to adopt similar interfaces Additionally, direct manipulation graphics, such as icons, allow users to easily interact with applications by clicking to open or display associated windows.
Interactive and Non Interactive Graphics
Computer graphics can be broadly subdivided into two categories:
Non-Interactive Computer Graphics, also known as Passive Computer Graphics, generate images on a screen that users can view but not modify, such as art created with Python's Turtle Graphics library or basic bar charts made with Matplotlib In contrast, Interactive Computer Graphics allow users to engage with the displayed images, enabling them to alter data or change rendering methods This interactivity is commonly seen in Graphical User Interfaces (GUIs) featuring menus, buttons, and sliders, as well as in visual displays like Matplotlib charts, where a slider adjusts the data shown Additionally, computer games exemplify interactive graphics, as they constantly update visuals based on user inputs, such as a flight simulator where joystick movements directly influence the on-screen plane's actions.
Pixels
A pixel, a term derived from the combination of "picture" and "element," is a fundamental component of computer graphics systems, representing a single cell or dot on a screen The size and quantity of these pixels vary based on the screen's type, size, and resolution For instance, early Windows PCs typically featured a resolution of 640 by 480 pixels, indicating 640 pixels in width and 480 pixels in height In contrast, modern 4K TV displays boast a significantly higher resolution of 4096 by 2160 pixels, showcasing the evolution of display technology.
The quality of an image is significantly influenced by the size and number of pixels on the display Lower resolution screens, which feature fewer pixels, often result in images that look blocky or poorly defined In contrast, higher resolution displays provide a sharper and clearer image, enhancing the overall viewing experience.
Each pixel on a display grid is identified by its specific location, allowing for the creation of various images by filling these pixels with different colors For instance, in the accompanying image, a single pixel is filled at the coordinates 4 by 4.
A sequence of pixels can create various shapes, such as lines and circles However, because pixels are arranged in a grid of individual points, diagonal lines or curves may appear jagged when zoomed in, as they require multiple pixels to represent smooth edges.
Each pixel on a display can have a specific color and transparency, with the available color range depending on the display type Monochrome displays show only black and white, while grayscale displays feature various shades of gray Modern systems typically utilize RGB color codes, where R stands for Red, G for Green, and B for Blue, allowing for a broad spectrum of colors For instance, solid Red is represented as [255, 0, 0], solid Green as [0, 255, 0], and solid Blue as [0, 0, 255] By combining these codes, various shades can be created, such as Orange, which can be represented as [255, 150, 50].
Transparency can be applied to a pixel to control the solidity of the fill color, as demonstrated in the grid showing 75%, 50%, and 25% transparency levels using the Python wxPython GUI library In this library, transparency is known as the alpha opaque value, which ranges from 0 to 255, where 0 represents complete transparency and 255 indicates full opacity.
Bit Map Versus Vector Graphics
There are two primary methods for generating images on a screen: bit mapped (or raster) graphics and vector graphics Raster graphics create images by mapping each pixel to specific display values, making them simpler to use In contrast, vector graphics represent images using geometric shapes like lines and points, allowing for greater flexibility and scalability.
Buffering
To enhance user experience in interactive graphical displays, it is crucial to ensure smooth and seamless transitions between images Jerky or abrupt changes can lead to discomfort for users, making the use of an in-memory structure, commonly known as a buffer, essential By pre-rendering the next display in this buffer, the entire image can be finalized before it appears on the screen For instance, Turtle Graphics allows users to specify the number of changes to be made before rendering, which can significantly improve the performance of graphic applications.
In some cases systems will use two buffers; often referred to as double buffering.
This technique involves rendering one buffer to the screen while simultaneously updating another, significantly enhancing system performance Modern computers can calculate and generate data at speeds that far exceed their ability to display it, making this method highly effective for optimizing graphics rendering.
Python and Computer Graphics
In this section, we will explore the Python Turtle Graphics library for generating computer graphics and creating Computer Generated Art Next, we will delve into the MatPlotLib library, which is essential for producing various charts and data visualizations, including bar charts, scatter graphs, line plots, and heat maps Finally, we will examine how to utilize Python libraries for developing graphical user interfaces (GUIs) that incorporate menus, fields, and tables.
References
The following are referenced in this chapter:
• I.E Sutherland, Sketchpad: a man-machine graphical communication system (courtesy Computer Laboratory, University of Cambridge UCAM-CL-TR-574, September 2003), January 1963.
• D.C Smith, C Irby, R Kimball, B Verplank, E Harslem, Designing the Star user interface BYTE7(4), 242–282 (1982).
Online Resources
The following provide further reading material:
• https://en.wikipedia.org/wiki/SketchpadIvan Sutherlands Sketchpad from 1963.
• http://images.designworldonline.com.s3.amazonaws.com/CADhistory/
Sketchpad_A_Man-Machine_Graphical_Communication_System_Jan63.pdf Ivan Sutherlands Ph.D 1963.
• https://en.wikipedia.org/wiki/Xerox_StarThe Xerox Star computer and GUI.
Introduction
Python offers robust support for graphics libraries, with the Turtle Graphics library being one of the most popular options Its appeal lies in its ease of use and the fact that it comes pre-installed with the Python environment, eliminating the need for additional installations.
The chapter concludes by briefly considering a number of other graphic libraries including PyOpen GL The PyOpenGL library can be used to create sophisticated3D scenes.
The Turtle Graphics Library
This article introduces a comprehensive library of features for creating vector graphics, which are defined by lines or vectors displayed on a screen The drawing area, commonly known as the drawing plane or drawing board, utilizes x and y coordinates to facilitate precise graphic design.
The Turtle Graphics library serves as a fundamental drawing tool, distinct from other libraries like MatPlotLib that specialize in specific types of two and three-dimensional graphs Its name and concept originate from the Logo programming language, developed in the 1960s and 70s to teach programming to children through the use of an on-screen turtle, which could be directed with simple commands such as "forward" to move ahead, "right" to turn at a specified angle, and "left" for left turns.
J Hunt, Advanced Guide to Python 3 Programming ,
Undergraduate Topics in Computer Science, https://doi.org/10.1007/978-3-030-25943-3_3
The Python Turtle Graphics library allows users to create intricate shapes by combining simple commands, such as `turtle.forward(10)`, which moves the turtle or cursor forward by 10 pixels This functionality has evolved from earlier concepts, enabling the creation of complex designs through straightforward programming commands.
Although theturtle module is built into Python 3 it is necessary toimportthe module before you use it:
The Turtle Graphics library offers two methods for creating drawings: utilizing the available classes or opting for a simpler set of functions that abstract these classes and objects This chapter will concentrate on the function-based approach for working with the Turtle module.
To begin, we will configure the window designated for our drawings, utilizing the TurtleScreen class, which serves as the foundational element for all screen implementations across various operating systems.
When utilizing the functions of the turtle module, the screen object is automatically set up according to your operating system This allows you to concentrate on configuring the layout and display options, including setting a title, adjusting the size, and defining the starting location of the screen.
• setup(width, height, startx, starty)Sets the size and position of the main window/screen The parameters are:
– width—if an integer, a size in pixels, if afloat, a fraction of the screen; default is 50% of screen.
– height—if an integer, the height in pixels, if a float, a fraction of the screen; default is 75% of screen.
The parameters startx and starty determine the initial positioning of a window on the screen The startx value, if positive, specifies the distance in pixels from the left edge; if negative, it measures from the right edge, and if set to None, it centers the window horizontally Similarly, the starty value, when positive, indicates the position in pixels from the top edge, while a negative value measures from the bottom edge, and if None, the window is centered vertically.
• title(titlestring)sets the title of the screen/window.
• exitonclick()shuts down the turtle graphics screen/window when the use clicks on the screen.
• bye()shuts down the turtle graphics screen/window.
• done() starts the main event loop; this must be the last statement in a turtle graphics program. importturtle
• speed(speed) the drawing speed to use, the default is 3 The higher the value the faster the drawing takes place, values in the range 0–10 are accepted.
The `turtle.tracer(n = None)` function allows for batch updates to the turtle graphics screen, enhancing performance for large and complex drawings By setting the parameter `n` to a high value, such as 600, the function enables the drawing of 600 elements in memory before updating the screen all at once, significantly accelerating processes like generating fractal images When invoked without arguments, it returns the current value of `n`.
The turtle.update() function is essential for refreshing the turtle screen, particularly after using tracer() It should be called at the end of your program to guarantee that all graphical elements are rendered, even if the specified tracer threshold has not been met.
The `pencolor(color)` function is used to set the color for drawing lines on the screen Colors can be specified in various ways, including named colors like 'red', 'blue', and 'green', as well as RGB color codes or hexadecimal numbers For detailed information on available named colors and RGB codes, please visit [this link](https://www.tcl.tk/man/tcl/TkCmd/colors.htm) It's important to note that all color methods use American spellings; for instance, it is `pencolor` and not `pencolour`.
• fillcolor(color)used to set the colour to use tofill in closed areas within drawn lines Again note the spelling of colour!
The following code snippet illustrates some of these functions:
We can now look at how to actually draw a shape onto the screen.
The cursor on the screen possesses various properties, including the current drawing color of the pen it controls, its position defined by x and y coordinates, and the direction it is facing To utilize these features, we begin by importing the turtle module.
# set a title for your canvas window turtle.title('My Turtle Animation')
# set up the screen size (in pixels)
# set the starting point of the turtle (0, 0) turtle.setup(width 0, height 0, startx=0, starty=0)
# sets the pen color to red turtle.pencolor('red')
# Add this so that the window will close when clicked on turtle.exitonclick()
3.2 The Turtle Graphics Library 15 already seen that you can control one of these properties using thepencolor() method, other methods are used to control the cursor (or turtle) and are presented below.
The direction in which the cursor is pointing can be altered using several functions including:
• right(angle)Turn cursor right by angle units.
• left(angle)Turn the cursor left by angle units.
• setheading(to_angle)Set the orientation of the cursor to to_angle. Where 0 is east, 90 is north, 180 is west and 270 is south.
You can move the cursor (and if the pen is down this will draw a line) using:
• forward(distance)move the cursor forward by the specified distance in the direction that the cursor is currently pointing If the pen is down then draw a line.
• backward(distance) move the cursor backward by distance in the opposite direction that in which the cursor is pointing.
And you can also explicitly position the cursor:
The goto(x, y) command allows you to move the cursor to a specified location on the screen, defined by the x and y coordinates If the pen is down during this movement, a line will be drawn Additionally, you can achieve similar results using the steps and set position commands.
• setx(x)sets the cursor’s x coordinate, leaves the y coordinate unchanged.
• sety(y)sets the cursor’s y coordinate, leaves the x coordinate unchanged.
It is also possible to move the cursor without drawing by modifying whether the pen is up or down:
• penup()move the pen up—moving the cursor will no longer draw a line.
• pendown()move the pen down—moving the cursor will now draw a line in the current pen colour.
The size of the pen can also be controlled:
• pensize(width) set the line thickness to width The methodwidth()is an alias for this method.
It is also possible to draw a circle or a dot:
The function circle(radius, extent, steps) is used to draw a circle based on the specified radius The extent parameter controls the portion of the circle that is rendered; if omitted, the entire circle will be drawn Additionally, the steps parameter defines the number of steps taken to create the circle, allowing for the drawing of regular polygons as well.
• dot(size, color)draws afilled circle with the diameter of size using the specified color.
You can now use some of the above methods to draw a shape on the screen For thisfirst example, we will keep it very simple, we will draw a simple square:
The above moves the cursor forward 50 pixels then turns 90° before repeating these steps three times The end result is that a square of 5050 pixels is drawn on the screen:
Note that the cursor is displayed during drawing (this can be turned off with turtle.hideturtle()as the cursor was originally referred to as the turtle).
Of course you do not need to just usefixed values for the shapes you draw, you can use variables or calculate positions based on expressions etc.
For example, the following program creates a sequences of squares rotated around a central location to create an engaging image:
# Draw a square turtle.forward(50) turtle.right(90) turtle.forward(50) turtle.right(90) turtle.forward(50) turtle.right(90) turtle.forward(50) turtle.right(90)
This program defines two functions: one for setting up the screen with a title, size, and disabling the cursor, and another for drawing a square based on a given size parameter The main section initializes the window and employs a for loop to draw 12 squares, each measuring 50 pixels, while rotating 120° between each square The loop variable is represented as an anonymous variable using the '_' format, as it is not needed for further reference.
The image generated by this program is shown below: import turtle def setup():
""" Provide the config for the screen """ turtle.title('Multiple Squares Animation') turtle.setup(100, 100, 0, 0) turtle.hideturtle() def draw_square(size):
Other Graphics Libraries
Turtle Graphics is a unique and accessible option for creating graphics in Python, as it comes pre-installed with the language, unlike other graphics libraries that require separate downloads via tools like Anaconda, PIP, or PyCharm For example, the code snippet `turtle.title('Filled Square Example')` sets the title of the window, while `turtle.setup(100, 100, 0, 0)` initializes the drawing area By using commands such as `turtle.hideturtle()`, `turtle.pencolor('red')`, and `turtle.fillcolor('yellow')`, users can customize their graphics, culminating in a filled square drawn with `turtle.begin_fill()`, `draw_square(60)`, and `turtle.end_fill()`, before completing the drawing with `turtle.done()`.
• PyQtGraph The PyQtGraph library is pure Python library oriented towards mathematics, scientific and engineering graphic applications as well as GUI applications For more information seehttp://www.pyqtgraph.org.
Pillow is a powerful Python imaging library that enhances image processing capabilities in Python applications It is built on the foundations of the original Python Imaging Library (PIL) and offers a wide range of features for image manipulation For detailed documentation and usage examples, visit the official Pillow website.
• Pyglet pyglet is another windowing and multimedia library for Python See https://bitbucket.org/pyglet/pyglet/wiki/Home.
While Turtle Graphics allows developers to create 3D images, it is not its main focus The library lacks direct support for 3D image creation, relying instead on basic cursor movement capabilities and the programmer's expertise.
Python offers several 3D graphics libraries, including Panda3D, VPython, and pi3d Among these, PyOpenGL is noteworthy as it is based on the widely used OpenGL library, providing robust capabilities for 3D graphics development.
PyOpenGL is an open-source project that offers a set of bindings for the OpenGL library, a cross-platform API used for rendering 2D and 3D vector graphics OpenGL is widely utilized in various applications, including gaming, virtual reality, data visualization, and Computer Aided Design (CAD) systems With PyOpenGL, developers can easily create 3D vector-based images in Python by leveraging the capabilities of the industry-standard OpenGL library An example of an image generated using PyOpenGL illustrates its simplicity and effectiveness.
Online Resources
The following provide further reading material:
• https://docs.python.org/3/library/turtle.htmlTurtle graphics documentation.
• http://pythonturtle.org/ The Python Turtle programming environment—this intended for teaching the basic concepts behind programming using the Turtle graphics library.
• http://pyopengl.sourceforge.netThe PyOpenGL home page.
• https://www.opengl.orgThe OpenGL home page.
Exercises
The aim of this exercise is to create a graphic display using Python Turtle Graphics. You should create a simple program to draw an octagon on the Turtle Graphics screen.
Enhance your program by adding a hexagon drawing function that accepts three parameters: the x and y coordinates for the starting point and the length of each side of the hexagon.
Modify your program to draw the hexagon in multiple locations to create the following picture:
Creating Computer Art
Computer Art refers to any artistic creation that utilizes a computer, particularly focusing on art generated by computer programs For instance, a simple example using just a few lines of Python code with the Turtle graphics library can demonstrate the potential to create images that qualify as computer art.
The image depicted is created using a recursive function that draws circles at specified x, y coordinates with a defined size This function continually calls itself, adjusting the parameters to produce progressively smaller circles at varying locations until the circle size falls below 20 pixels.
J Hunt, Advanced Guide to Python 3 Programming ,
Undergraduate Topics in Computer Science, https://doi.org/10.1007/978-3-030-25943-3_4
The program used to generate this picture is given below for reference: import turtle
# Set up the window turtle.title('Circles in My Mind') turtle.setup(WIDTH, HEIGHT, 0, 0) turtle.colormode(255) # Indicates RGB numbers will be in the range 0 to 255 turtle.hideturtle()
# Batch drawing to the screen for faster rendering turtle.tracer(2000)
# Speed up drawing process turtle.speed(10) turtle.penup() def draw_circle(x, y, radius, redP, green%5, blue, width=7):
""" Draw a circle at a specific x, y location.
Then draw four smaller circles recursively""" colour = (red, green, blue)
# Recursively drawn smaller circles if radius > 50:
# Calculate colours and line width for smaller circles if red < 216: red = red + 33 green = green - 42 blue = blue + 10 width -= 1
# Run the program print('Starting') setup_window() draw_circle(25, -100, 200)
# Ensure that all the drawing is rendered turtle.update() print('Done') turtle.done()
This program utilizes recursion to create circles, progressively drawing smaller circles until their radius reaches a predefined threshold, marking the termination point of the process.
It also uses theturtle.tracer()function to speed up drawing the picture as 2000 changes will be buffered before the screen is updated.
The colors of the circles are modified at each level of recession, employing a straightforward method that alters the Red, Green, and Blue codes to create distinct color variations Additionally, a reduced line width is applied to the circle outlines, enhancing the visual appeal of the image.
A Computer Art Generator
Turtle graphics can be utilized to create captivating computer art by randomly generating RGB colors for the drawn lines, enhancing the visual appeal of the images Additionally, users have the option to customize the color input, for instance, by setting red to 0 and green to 255.
# Calculate the radius for the smaller circles new_radius = int(radius / 1.3)
To draw four circles, use the function draw_circle with the specified parameters: draw_circle(int(x + new_radius), y, new_radius, red, green, blue, width) for the right circle, draw_circle(x - new_radius, y, new_radius, red, green, blue, width) for the left circle, draw_circle(x, int(y + new_radius), new_radius, red, green, blue, width) for the bottom circle, and draw_circle(x, int(y - new_radius), new_radius, red, green, blue, width) for the top circle.
To create a circle using the turtle graphics library, use the command `turtle.goto(x, y)` to position the turtle, followed by `turtle.color(colour)` to set the desired color and `turtle.width(width)` to adjust the line thickness Begin drawing with `turtle.pendown()` and use `turtle.circle(radius)` to draw the circle, then lift the pen with `turtle.penup()` By altering the angle during the drawing loop, you can produce a variety of unique and interesting shapes.
# Lets play with some colours import turtle from random import randint def get_input_angle():
To obtain user input and convert it into an integer, prompt the user with the message 'Please provide an angle:' and store the input as a string Implement a loop that checks if the input is numeric; if not, inform the user that 'The input must be an integer!' and request the input again Once a valid integer is provided, return the integer value Additionally, create a function to generate a random color.
"""Generates an R,G,B values randomly in range
The provided code snippet demonstrates how to create a colorful pattern using the Turtle graphics library in Python It begins by generating random RGB color values ranging from 0 to 255 for red, green, and blue components The Turtle screen is set up with a black background and a title, while the drawing speed is adjusted for efficiency The user is prompted to input an angle, and a loop is initiated to draw a series of lines, changing the color with each iteration Finally, the drawing is completed with a call to `turtle.done()`.
Below are sample images produced by the program, showcasing different angles: the leftmost image is generated with a 38-degree angle, the middle image uses a 68-degree angle, and the bottom image features a 98-degree angle.
The following pictures below use angles of 118, 138 and 168 degrees respectively.
The intriguing aspect of these images lies in their distinctiveness, despite being created using the same program This demonstrates that algorithmic or computer-generated art can possess the same nuance and versatility as traditional art forms Ultimately, it underscores the human role in selecting the most aesthetically appealing image from the generated options.
Fractals in Python
Fractals are a prominent art form within Computer Art, characterized by recurring patterns generated through iterative or recursive methods A fascinating aspect of fractals is their ability to display similar patterns at various levels of magnification, a phenomenon known as expanding symmetry or unfolding symmetry When these patterns replicate identically at every scale, they are referred to as affine self-similar.
Fractals, originating in 17th-century mathematics, were defined in the 20th century by mathematician Benoit Mandelbrot, who introduced the term in 1975 Mandelbrot described geometric fractals as rough or fragmented shapes that can be divided into smaller sections, each resembling a reduced-size version of the entire structure.
For more information see Mandelbrot, Benoợt B (1983) The fractal geometry of nature Macmillan ISBN (978-0-7167-1186-5).
Since the later part of the 20th century fractals have been a commonly used way of creating computer art.
The Koch snowflake and the Mandelbrot set are two prominent examples of fractals frequently utilized in computer art This chapter demonstrates how to create fractal-based artwork using Python and the Turtle graphics library, showcasing the fascinating intersection of mathematics and creativity.
The Koch snowflake is a unique fractal that starts with an equilateral triangle It involves replacing the middle third of each line segment with two additional segments that create an equilateral bump This process can be repeated to various depths, resulting in increasingly smaller triangles and ultimately creating a shape that resembles a snowflake.
This program utilizes the turtle graphics library to create a Koch snowflake, allowing users to specify varying levels of recursion Increasing the recursion levels results in a more intricate design, as each line segment is subdivided multiple times, enhancing the complexity of the snowflake pattern.
SIZE_OF_SNOWFLAKE = 300 def get_input_depth():
To obtain user input for depth, prompt with the message 'Please provide the depth (0 or a positive integer):' and ensure the input is a numeric value If the input is not valid, display an error message and request input again until a valid integer is provided Once validated, convert the input to an integer Additionally, to set up the screen, use the function setup_screen, which takes parameters for the title, background color, and screen dimensions, and initializes the turtle graphics environment by setting the title, screen size, and positioning the turtle off-screen.
# Batch drawing to the screen for faster rendering turtle.tracer(tracer_size) turtle.bgcolor(background) # Set the background colour of the screen
Several different runs of the program are shown below with the depth set at 0, 1,
The Koch snowflake can be drawn using a recursive function that takes size and depth as parameters When the depth is greater than zero, the function divides the size by three and decreases the depth by one, while turning the turtle by specified angles If the depth is zero, the turtle simply moves forward by the given size To visualize the snowflake, set up a screen with a black background and the desired dimensions, incorporating the input depth into the title.
# Set foreground colours turtle.color('sky blue')
# Ensure snowflake is centred turtle.penup() turtle.setposition(-180,0) turtle.left(30) turtle.pendown()
# Draw three sides of snowflake for _ in range(3): draw_koch(SIZE_OF_SNOWFLAKE, depth) turtle.right(120)
# Ensure that all the drawing is rendered turtle.update() print('Done') turtle.done()
The simpledraw_koch() function allows for the visualization of how each side of a triangle can be divided into smaller triangle-like shapes at varying depths By repeating this process multiple times, a more intricate structure emerges, showcasing the recursive nature of the shape as it is replicated continuously.
One of the most renowned fractal images is derived from the Mandelbrot set, which consists of complex numbers \( c \) for which the function \( z^2 + c \) remains bounded when iterated from \( z = 0 \) This means that the sequence of functions, such as \( func(0) \) and \( func(func(0)) \), does not diverge The term "Mandelbrot set" was coined by French mathematician Adrien Douady in honor of mathematician Benoit Mandelbrot.
Mandelbrot set images are generated by sampling complex numbers and evaluating each sample point \( c \) to determine whether the sequence \( func(0), func(func(0)), \) and so on, diverges to infinity This involves checking if the sequence leaves a defined bounded neighborhood of 0 within a specified number of iterations By interpreting the real and imaginary components of \( c \) as coordinates on the complex plane, pixels can be colored based on how quickly the sequence surpasses a chosen threshold Typically, a distinct color, often black, is assigned to values of \( c \) where the sequence does not exceed the threshold after the set number of iterations, ensuring a clear distinction between the Mandelbrot set and its complement.
The following image was generated for the Mandelbrot set using Python and Turtle graphics.
The image generation program iterates through a specified range for both the y and x coordinates, calculating complex numbers based on defined minimum and maximum values For each iteration, it checks if the magnitude of the complex number exceeds 2.0, breaking the loop if so The program then colors the points based on the iteration count and positions them on the screen, creating a visual representation of the data Each point is rendered as a dot, contributing to the final image.
Online Resources
The following provide further reading material:
• https://en.wikipedia.org/wiki/FractalFor the Wikipedia page on Fractals.
• https://en.wikipedia.org/wiki/Koch_snow akeThe Wikipedia page on the Koch snowflake.
• https://en.wikipedia.org/wiki/Mandelbrot_set Wikipedia page on the Mandel- brot set.
Exercises
The aim of this exercise is to create a Fractal Tree.
A Fractal Tree is a tree in which the overall structure is replicated atfiner and
finer levels through the tree until a set of leaf elements are reached.
To draw the fractal tree you will need to:
To create a visually appealing tree structure, divide the trunk into two branches at the end, angling the left and right trunks 30° to the left and right, respectively Each split can result in a thinner trunk for enhanced aesthetics, and the trunk can be illustrated in a brown hue.
Continue the splitting process until you reach either the maximum number of splits allowed or the trunk size decreases to a specified minimum At this point, you will have reached the leaves, which you can illustrate in a distinct color, such as green.
An example of a Fractal Tree is given below:
Introduction
Matplotlib is a versatile Python library used for creating a wide range of graphs and charts in various formats It enables users to produce line charts, scatter plots, heat maps, bar charts, pie charts, and 3D visualizations Additionally, Matplotlib supports animations and interactive displays, enhancing data presentation and analysis.
An example of a graph generated using Matplotlib is given below This shows a line chart used to plot a simple sign wave:
Matplotlib is a versatile and robust graphing library for Python, compatible with various graphics platforms and operating systems It allows users to create high-quality output graphics in multiple formats, such as PNG, JPEG, SVG, and PDF.
J Hunt, Advanced Guide to Python 3 Programming ,
Undergraduate Topics in Computer Science, https://doi.org/10.1007/978-3-030-25943-3_5
Matplotlib is a versatile library that can be used independently or alongside other libraries, such as NumPy, which is essential in Data Science for its functions and n-dimensional arrays that aid in data processing for visualizations It's important to note that Matplotlib is not included by default in the Python environment; it must be installed separately to be utilized in your projects.
This chapter introduces the Matplotlib library, highlighting its architecture and the essential components that make up a chart It also focuses on the pyplot API, which is the most straightforward and widely used method for programmers to interact with Matplotlib.
In this article, we will delve into various types of charts that can be created with Matplotlib, including simple line charts, scatter charts, bar charts, and pie charts, concluding with an overview of a basic 3D chart.
Matplotlib
Matplotlib is a user-friendly graph plotting library for Python, ideal for creating simple graphs For instance, to generate a basic line graph from a set of x and y coordinates, you can utilize the matplotlib.pyplot.plot function.
This very simple program generates the following graph: pyplot.plot([1, 0.25, 0.5, 2, 3, 3.75, 3.5])
# Display the chart in a window pyplot.show() import matplotlib.pyplot as pyplot
The plot() function utilizes a sequence of values for the y-axis, while the x-axis values are determined by the order of these y values in the list Consequently, with six elements in the list, the x-axis will span a range corresponding to these values.
0–6 In turn as the maximum value contained in the list is 3.75, then the y axis ranges from 0 to 4.
Plot Components
Matplotlib graphs may appear straightforward, but they consist of various components that can be independently adjusted Understanding the terminology related to these elements, including ticks, legends, and labels, is essential for effective manipulation and customization of your plots.
The elements that make up a plot are illustrated below:
The diagram illustrates the following elements:
The Axes in Matplotlib, defined by the `matplotlib.axes.Axes` class, serve as the fundamental component of a figure, encompassing essential elements such as the X and Y axes, ticks, line plots, text, and polygon shapes.
• TitleThis is the title of the wholefigure.
• Ticks (Major and Minor) The Ticks are represented by the class mat- plotlib.axis.Tick A Tick is the mark on the Axis indicating a new
5.2 Matplotlib 37 value There can be Major ticks which are larger and may be labeled There are also minor ticks which can be smaller (and may also be labelled).
• Tick Labels(Major and Minor) This is a label on a Tick.
The Axis class in Matplotlib defines an axis object, such as the X or Y axis, within a parent Axes instance It allows for the customization of label formatting for both major and minor ticks, and provides options to set the locations of these ticks.
• Axis Labels(X, Y and in some cases Z) These are labels used to describe the Axis.
• Plottypes such as line and scatter plots Various types of plots and graphs are supported by Matplotlib including line plots, scatter graphs, bar charts and pie charts.
GridThis is an optional feature that enhances the visual appeal of plots, graphs, or charts by displaying a grid in the background This grid can be customized with various line styles, including solid and dashed options, as well as different colors and line widths to suit the user's preferences.
Matplotlib Architecture
The Matplotlib library features a layered architecture designed to simplify interactions with various windowing systems and graphic outputs It consists of three primary layers: the Scripting Layer, the Artist Layer, and the Backend Layer The Backend Layer manages the reading and interaction with the generated plots, while the Artist Layer is tasked with creating the graphical objects for rendering Lastly, the Scripting Layer serves as the interface for developers to generate the graphs effectively.
This architecture is illustrated below:
The Matplotlib backend layerhandles the generation of output to different target formats Matplotlib itself can be used in many different ways to generate many different outputs.
Matplotlib is a versatile library that allows for interactive plotting, can be embedded within applications or graphical user interfaces, and is suitable for batch applications where plots can be saved in various formats such as PNG, SVG, and PDF.
Matplotlib supports various use cases by utilizing different outputs known as backends, while the "frontend" refers to the developer-facing code The Backend Layer manages these backends, allowing programmers to choose the default or select an alternative as needed The desired backend can be set using the matplotlib.use() function; for instance, to render Postscript, one would use: matplotlib.use('PS').
When using the `matplotlib.use()` function, it is crucial to call it before importing `matplotlib.pyplot`, as invoking it afterward will not have any effect Additionally, be aware that the argument for `matplotlib.use()` is case sensitive By default, the renderer is set to 'Agg', which utilizes the Anti-Grain Geometry C++ library to generate high-quality raster graphics images of data plots.
The 'Agg' backend is the default choice for Matplotlib due to its compatibility with a wide range of Linux systems, requiring minimal dependencies In contrast, other backends may function only on specific systems, potentially failing if the necessary dependencies are not installed To utilize Matplotlib, ensure the backend is set correctly by importing it and using the command `matplotlib.use('PS')` if the 'matplotlib.backends' module is not already loaded.
The Backend Layer can be divided into two categories:
• User interface backends (interactive) that support various Python windowing systems such as wxWidgets(discussed in the next chapter), Qt, TK etc.
• Hardcopy Backends (non interactive) that support raster and vector graphic outputs.
The User Interface and Hardcopy backends are built upon common abstractions referred to as the Backend base classes.
The Artist layer is essential for Matplotlib, as it handles the creation of plots and graphs that are displayed to users or exported in various formats.
The artist layer is concerned with things such as the lines, shapes, axis, and axes, text etc that comprise a plot.
The classes used by the Artist Layer can be classified into one of the following three groups; primitives, containers and collections:
• Primitives are classes used to represent graphical objects that will be drawn on to afigures canvas.
• Containers are objects that hold primitives For example, typically a figure would be instantiated and used to create one or more Axes etc.
• Collections are used to efficiently handle large numbers of similar types of objects.
While understanding these classes can be beneficial, direct interaction with them is often unnecessary since the pyplot API simplifies much of the complexity Nevertheless, if needed, you can still engage with figures, axes, ticks, and other elements directly.
The scripting layer is the developer facing interface that simplifies the task of working with the other layers.
From a programmer's perspective, the Scripting Layer is embodied by the pyplot module, which utilizes module-level objects to manage data states and facilitate graph rendering.
When importedpyplotselects either thedefaultbackend for the system or the one that has been configured; for example via thematplotlib.use()function.
It then calls asetup()function that:
• creates afigure manager factory function, which when called will create a new
figure manager appropriate for the selected backend,
• prepares the drawing function that should be used with the selected backend,
• identifies the callable function that integrates with the backend mainloop function,
• provides themodulefor the selected backend.
The pyplot interface simplifies interactions with the internal wrappers by providing methods such as plot(), pie(), bar(), title(), savefig(), draw()and figure() etc.
Most of the examples presented in the next chapter will use the functions pro- vided by thepyplotmodule to create the required charts; thereby hiding the lower level details.
Online Resources
See the online documentation for:
• https://matplotlib.org The Matplotlib library This incorporates numerous examples with complete listings, documentation, galleries and a detailed user guide and FAQ.
• https://pythonprogramming.net/matplotlib-python-3-basics-tutorialPython Mat- plotlib crash course.
Introduction
In this chapter we will explore the Matplotlib pyplot API This is the most common way in which developers generate different types of graphs or plots usingMatplotlib.
The pyplot API
The pyplot module in Matplotlib simplifies the creation and manipulation of plots and charts, aiming to make simple tasks easy and complex tasks possible It offers high-level functions like bar(), plot(), scatter(), and pie() for easily generating various types of visualizations While these functions come with numerous parameters, most have reasonable default values that can be used without modification For more customized visual representations, users are encouraged to consult the extensive Matplotlib documentation, which includes a wealth of examples and information.
To utilize the plotting capabilities of the Matplotlib library, it is essential to import the pyplot module, typically referenced as 'plt' for convenience This module, known as matplotlib.pyplot, simplifies the process of creating visualizations in Python.
A typical import for thepyplot module is given below: importmatplotlib.pyplotaspyplot © Springer Nature Switzerland AG 2019
J Hunt, Advanced Guide to Python 3 Programming ,
Undergraduate Topics in Computer Science, https://doi.org/10.1007/978-3-030-25943-3_6
The plyplot API can be used to
• manage color and line styles,
• handles events/allows plots to be interactive,
We will see examples of using the pyplot API in the following sections.
Line Graphs
A Line Graph, also known as a Line Plot, visually represents data points connected by lines to illustrate changes in value over a specific range of values, typically displayed along the x-axis These graphs are particularly useful for depicting time series data, where values are plotted in chronological order, resulting in what are referred to as run charts.
The following chart is an example of a run chart; it charts time across the bottom(x axis) against speed (represented by the y axis).
The program used to generate this chart is given below: import matplotlib.pyplot as pyplot
# Set the axes headings pyplot.ylabel('Speed', fontsize) pyplot.xlabel('Time', fontsize)
# Set the title pyplot.title("Speed v Time")
# Plot and display the graph
# Using blue circles for markers ('bo')
# and a solid line ('-') pyplot.plot(x, y, 'bo-') pyplot.show()
This program begins by importing the matplotlib.pyplot module, which is aliased as 'pyplot' for improved code readability.
Two lists of values are then created for thexandycoordinates of each marker or plot point.
The graph is configured by labeling the x and y axes using the pyplot functions xlabel() and ylabel() Additionally, the title of the graph is set using a corresponding pyplot function.
The x and y values are plotted as a line chart using the pyplot.plot() function, which requires data to define the plot points as its only mandatory parameter In the example, a third parameter, the string 'bo-', is included, which is a coded format string where each element conveys specific meaning to the pyplot.plot() function.
• b—this indicates the colour to use when drawing the line; in this case the letter
‘b’ indicates the colour blue (in the same way‘r’ would indicate red and ‘g’ would indicate green).
• o—this indicates that each marker (each point being plotted) should be repre- sented by a cirlce The lines between the markers then create the line plot.
• ‘–’—This indicates the line style to use A single dash (‘-’) indicates a solid line, where as a double dash (‘–’) indicates a dashed line.
Finally the program then uses theshow()function to render thefigure on the screen; alternativelysavefig()could have been used to save thefigure to afile.
There are numerous options that can be provided via the format string, the fol- lowing tables summarises some of these:
The following colour abbreviations are supported by the format string:
Different ways of representing the markers (points on the graph) connected by the lines are also supported including:
Finally, the format string supports different line styles:
Some examples of formatting strings:
• ‘r’red line with default markers and line style.
• ‘–’dashed line with the default colour and default markers.
• ‘yo:’yellow dotted line with circle markers.
Scatter Graph
A scatter graph, also known as a scatter plot, is a graphical representation that uses Cartesian coordinates to display individual values Each data point is represented by a mark, such as a circle or triangle, allowing for the visualization of two different variables—one plotted on the x-axis and the other on the y-axis Scatter plots are effective tools for analyzing relationships between these variables.
An example of a scatter chart with three sets of scatter values is given below
In this graph each dot represents the amount of time people of different ages spend on three different activities.
The program that was used to generate the above graph is shown below:
The `plot.scatter()` function is utilized to create a scatter graph based on the data from the riding, swimming, and sailing tuples The marker colors are defined using the named parameter `c`, which can accept either a color name string or a two-dimensional array containing RGB color codes Additionally, the marker style can be specified, with options such as 'o' representing a circular marker.
‘^’for a triangle and‘*’for a star shape Thelabelis used in the chart legend for the marker.
Other options available on thepyplot.scatter()function include:
• alpha : indicates the alpha blending value, between 0 (transparent) and 1 (opaque). import matplotlib.pyplot as pyplot
# Plot the data pyplot.scatter(x=riding[0], y=riding[1], c='red', marker='o', label='riding') pyplot.scatter(x=swimming[0], y=swimming[1], c='green', marker='^', label='swimming') pyplot.scatter(x=sailing[0], y=sailing[1], c='blue', marker='*', label='sailing')
# Configure graph pyplot.xlabel('Age') pyplot.ylabel('Hours') pyplot.title('Activities Scatter Graph') pyplot.legend() pyplot.show()
• linewidths: which is used to indicate the line width of the marker edges.
• edgecolors: indicates the color to use for the marker edges if different from thefill colour used for the marker (indicates by the parameter ‘c’).
6.4.1 When to Use Scatter Graphs
Scatter plots are essential for illustrating the relationship between two variables, often referred to as correlation plots due to their ability to display the correlation between these variables.
A scatter chart often reveals discernible trends among the plotted points, despite the presence of outliers To enhance visualization of these trends, adding a trend line to the scatter graph can be beneficial, as it clarifies the relationship between the scatter plots and the overall trend.
The chart displays a scatter graph of values with an accompanying trend line, illustrating that certain data points are positioned closer to the trend line than others.
The trend line has been created in this case using thenumpyfunctionpolyfit().
The `polyfit()` function in NumPy performs a least squares polynomial fit on the provided data, creating a `poly1d` class from the resulting array This one-dimensional polynomial class simplifies common operations on polynomials The resulting `poly1d` object is then utilized to generate a corresponding set of values for a given set of x values, which can be visualized using the `pyplot.plot()` function For example, using the data points x = (5, 5.5, 6, 6.5, 7, 8, 9, 10) and y = (120, 115, 100, 112, 80, 85, 69, 65) allows for effective plotting of the polynomial fit.
# Generate the scatter plot pyplot.scatter(x, y)
# Generate the trend line z = np.polyfit(x, y, 1) p = np.poly1d(z) pyplot.plot(x, p(x), 'r')
# Display the figure pyplot.show()
Pie Charts
A Pie Chart is a circular graph divided into sectors, each representing a specific proportion of the total These wedges illustrate the contribution of different categories to the overall data, resembling slices of a pie.
In a pie chart, sectors are usually displayed in distinct colors and arranged in a clockwise manner according to their size When a slice represents a combination of data, such as "other types" or "other answers," it is typically positioned last, regardless of its size, to ensure that the primary categories remain the focus of attention.
The following chart illustrates a pie chart used to represent programming lan- guage usage within a particular organisation.
To create a pie chart in Python, use the `pyplot.pie()` function from the Matplotlib library First, import Matplotlib with `import matplotlib.pyplot as pyplot` Define your labels, such as ('Python', 'Java', 'Scala', 'C#'), and specify the sizes of each segment, for example, `[45, 30, 15, 10]` Then, call `pyplot.pie()` with the sizes and labels, and customize the chart with parameters like `autopct='%1.f%%'` for percentage display, `counterclock=False` to set the direction, and `startangle` to determine the starting angle Finally, use `pyplot.show()` to display the pie chart.
The pyplot.pie() function requires only one mandatory parameter, which specifies the values for the sizes of the pie chart segments Additionally, it offers several optional parameters to enhance the chart's appearance and functionality.
• The labels parameter is an optional parameter that can take a sequence of strings that are used to provide labels for each wedge.
• Theautopct parameter takes a string (or function) to be used to format the numeric values used with each wedge.
• Thecounterclockwise parameter By default wedges are plotted counter clockwise in pyplot and so to ensure that the layout is more like the traditional clockwise approach thecounterclockparameter is set toFalse.
• The startangle parameter The starting angle has also been moved 90° using thestartangleparameter so that thefirst segment starts at the top of the chart.
To highlight a specific segment of a pie chart, you can use the explode feature, which separates that segment from the rest This is achieved by utilizing the explode parameter in the pie() function, where you provide a sequence of values to determine the degree of separation for each segment.
Enhancing the visual appeal of a pie chart can be achieved by incorporating shadows into its segments through the namedshadowboolean parameter, as demonstrated in the examples below.
The program that generated this modified chart is given below for reference: import matplotlib.pyplot as pyplot labels = ('Python', 'Java', 'Scala', 'C#') sizes = [45, 30, 15, 10]
# only "explode" the 1st slice (i.e 'Python') explode = (0.1, 0, 0, 0) pyplot.pie(sizes, explode=explode, labels=labels, autopct='%1.f%%', shadow=True, counterclock=False, startangle) pyplot.show()
6.5.2 When to Use Pie Charts
Pie charts are effective for visualizing data that falls into nominal or ordinal categories Nominal data includes qualitative information such as programming languages, car types, or countries of birth, while ordinal data involves ranked categories, like survey responses ranging from very poor to very good.
Pie charts can also be used to show percentage or proportional data and usually the percentage represented by each category is provided next to the corresponding slice of pie.
Pie charts are most effective when displaying data with six or fewer categories, as exceeding this limit can make it challenging for viewers to accurately perceive the relative sizes of the sectors, leading to difficulties in interpretation.
Bar Charts
A Bar Chart is a graphical representation used to display distinct categories of data, typically oriented vertically, although horizontal versions can also be utilized Each category is depicted by a bar, with its height or length corresponding to the value of the data for that specific category.
Bar charts are widely used due to their simplicity in interpreting data and illustrating relationships between categories Common variations include grouped and stacked bar charts For instance, a typical bar chart may display five programming languages along the x-axis, with the y-axis representing their percentage usage, where each bar visually conveys the usage percentage for each language.
The program used to generate the abovefigure is given below:
# Set up the data labels = ('Python', 'Scala', 'C#', 'Java', 'PHP') index = (1, 2, 3, 4, 5) # provides locations on x axis sizes = [45, 10, 15, 30, 22]
# Set up the bar chart pyplot.bar(index, sizes, tick_label=labels)
# Configure the layout pyplot.ylabel('Usage') pyplot.xlabel('Programming Languages')
# Display the chart pyplot.show() import matplotlib.pyplot as pyplot
The chart visually represents various categories with bars proportional to their sizes, highlighting discrete categories by incorporating gaps between the bars on the x-axis While the x-axis lacks a scale, the y-axis includes a measurement scale to indicate the units used.
Bar charts are typically represented with vertical bars, where greater height indicates larger categories Alternatively, horizontal bar charts can be used, where longer bars signify larger categories This format is especially useful for displaying numerous categories when space is limited for a vertical layout.
In Matplotlib the pyplot.barh()function can be used to generate a hori- zontal bar chart:
In this case the only line of code to change from the previous example is: pyplot.barh(x_values, sizes, tick_label = labels)
Using various colors or shades for different bars in a chart enhances visual distinction, making it easier to differentiate between them.
To customize the color of each category in a bar chart, you can use the color parameter in the bar() and barh() functions, which allows you to specify a sequence of colors for the bars.
Stacked bar charts effectively display total values and their contributions across multiple categories, allowing for a clear comparison of how various elements contribute to overall totals in different categories.
Different colors represent various sub-groups within a bar chart, and a legend is typically included to clarify which color corresponds to each sub-group This legend can be positioned within the plot area or placed beneath the chart for easy reference.
For example, in the following chart the total usage of a particular programming language is composed of its use in games and web development as well as data science analytics.
The chart illustrates the contribution of each programming language use to its overall usage Below is the code that generated this visual representation: pyplot.bar(x_values, sizes, tick_label=labels, color=('red'.
When creating stacked bar charts with the pyplot.bar() function, it's essential to define the bottom parameter for subsequent sets of bars to ensure they are positioned correctly For the second bar chart, this can be done using the values from the web_usage dataset However, for the third bar chart, you need to combine the values from both web_usage and data_science_usage, which can be efficiently achieved using list comprehension.
Grouped Bar Charts effectively display data related to various sub-groups within main categories To clarify the representation of each sub-group, a legend or key is typically included, indicating the meaning of different shadings or colors This legend can be positioned either within the plot area or beneath the chart for easy reference.
Separate bar charts are created for each subgroup within a specific category For instance, the chart below illustrates the results for two sets of teams, utilizing the matplotlib.pyplot library for visualization.
# Set up the data labels = ('Python', 'Scala', 'C#', 'Java', 'PHP') index = (1, 2, 3, 4, 5) web_usage = [20, 2, 5, 10, 14] data_science_usage = [15, 8, 5, 15, 2] games_usage = [10, 1, 5, 5, 4]
To create a stacked bar chart using Matplotlib's pyplot, first use `pyplot.bar()` to plot web usage data with specified labels Next, add data science usage on top of the web usage by setting the `bottom` parameter to the web usage values Finally, combine web and data science usage into a new list and plot the games usage on top of this combined data, ensuring all categories are clearly labeled for better visualization.
# Configure the layout pyplot.ylabel('Usage') pyplot.xlabel('Programming Languages') pyplot.legend()
To enhance data visualization, the chart is displayed using pyplot.show(), showcasing a series of lab exercises Each team is represented by a bar for labs 1, 2, and 3, with intentional spacing between categories to facilitate easy comparison of subcategories.
The following program generates the grouped bar chart for the lab exercises example:
In the program, calculating the index for the second team is essential to ensure that the bars are displayed next to each other The index for each team accounts for the width of the bars at each index point, positioning the first bar at index 1.35 and the second at 2.35 Consequently, the tick positions must be placed between the two bars, which requires careful calculation of the bar widths.
# set up grouped bar charts teama_results = (60, 75, 56, 62, 58) teamb_results = (55, 68, 80, 73, 55)
# Set up the index for each bar index_teama = (1, 2, 3, 4, 5) index_teamb = [i + BAR_WIDTH for i in index_teama]
# Determine the mid point for the ticks ticks = [i + BAR_WIDTH / 2 for i in index_teama] tick_labels = ('Lab 1', 'Lab 2', 'Lab 3', 'Lab 4', 'Lab 5')
# Plot the bar charts pyplot.bar(index_teama, teama_results, BAR_WIDTH, color='b', label='Team A') pyplot.bar(index_teamb, teamb_results, BAR_WIDTH, color='g', label='Team B')
# Set up the graph pyplot.xlabel('Labs') pyplot.ylabel('Scores') pyplot.title('Scores by Lab') pyplot.xticks(ticks, tick_labels) pyplot.legend()
# Display the graph pyplot.show()
This program generates the following grouped bar chart:
Figures and Subplots
A Matplotlib figure serves as the primary object that encompasses all graphical elements in a plot, including axes, legends, titles, and the actual line plots or bar charts It represents the overall window or page, functioning as the top-level graphical component in data visualization.
In many cases thefigure is implicit as the developer interacts with thepyplot API; however thefigure can be accessed directly if required.
The `matplotlib.pyplot.figure()` function creates a figure object, which is a `matplotlib.figure.Figure` instance This allows for direct interaction with the figure, enabling users to add axes and create subplots within a graph.
To effectively incorporate multiple subplots into a single figure, direct interaction with the figure is essential This approach allows for a side-by-side comparison of different perspectives on the same dataset Each subplot maintains its own axes, enabling them to coexist seamlessly within the overall figure.
To add one or more subplots to a figure, use the figure.add_subplot() method, which incorporates an Axes into the figure as part of a set of subplots Subplots can be specified using a 3-digit integer or three individual integers that indicate the number of rows, columns, and the index of the subplot within the matrix.
The notation 2, 2, 1 (or 221) signifies that the subplot occupies the first index in a two-by-two grid of plots Conversely, 2, 2, 3 (223) indicates that the subplot is positioned at index 3, which corresponds to row 2 and column 1 within the same grid layout.
2, 2, 4 (or 224) indicates that the plot should be added as at index 4 or the fourth subplot within the grid (so position 2 by 2) etc.
For example, the following figure illustrates four subplots presented within a singlefigure Each subplot is added via thefigure.add_subplot()method.
Thisfigure is generated by the following program: import matplotlib.pyplot as pyplot t = range(0, 20) s = range(30, 10, -1)
# Set up the grid of subplots to be 2 by 2 grid_size='22'
# Initialize a Figure figure = pyplot.figure()
# Add first subplot position = grid_size + '1' print('Adding first subplot to position', position) axis1 = figure.add_subplot(position) axis1.set(title='subplot(2,2,1)') axis1.plot(t, s)
# Add second subplot position = grid_size + '2' print('Adding second subplot to position', position) axis2 = figure.add_subplot(position) axis2.set(title='subplot(2,2,2)') axis2.plot(t, s, 'r-')
# Add third subplot position = grid_size + '3' print('Adding third subplot to position', position) axis3 = figure.add_subplot(position) axis3.set(title='subplot(2,2,3)') axis3.plot(t, s, 'g-')
# Add fourth subplot position = grid_size + '4' print('Adding fourth subplot to position', position) axis4 = figure.add_subplot(position) axis4.set(title='subplot(2,2,4)') axis4.plot(t, s, 'y-')
# Display the chart pyplot.show()
The console output from this program is given below:
Adding first subplot to position 221
Adding second subplot to position 222
Adding third subplot to position 223
Adding fourth subplot to position 224
A three-dimensional graph visualizes the relationships among three sets of values, incorporating an additional z-axis alongside the traditional x and y axes The program demonstrated utilizes the numpy range function to generate two sets of values, which are then transformed into coordinate matrices using the numpy meshgrid() function The z-axis values are calculated with the numpy sin() function, and the 3D graph surface is created using the plot_surface() function from the futures axes object, which requires the x, y, and z coordinates, as well as a color map for surface rendering, specifically the Matplotlib cool to warm color map in this instance.
# Make the data to be displayed x_values = np.arange(-6, 6, 0.3) y_values = np.arange(-6, 6, 0.3)
# Generate coordinate matrices from coordinate vectors x_values, y_values = np.meshgrid(x_values, y_values)
# Generate Z values as sin of x plus y values z_values = np.sin(x_values + y_values) import matplotlib.pyplot as pyplot
# Import matplotlib colour map from matplotlib import cm as colourmap
# Required for £D Projections from mpl_toolkits.mplot3d import Axes3D
# Provide access to numpy functions import numpy as np
This program generates the following 3D graph:
# Obtain the figure object figure = pyplot.figure()
# Get the axes object for the 3D graph axes = figure.gca(projection='3d')
# Plot the surface. surf = axes.plot_surface(x_values, y_values, z_values, cmap=colourmap.coolwarm)
# Add a color bar which maps values to colors. figure.colorbar(surf)
# Add labels to the graph pyplot.title("3D Graph") axes.set_ylabel('y values', fontsize=8) axes.set_xlabel('x values', fontsize=8) axes.set_zlabel('z values', fontsize=8)
# Display the graph pyplot.show()
Three-dimensional graphs are often criticized for not effectively presenting data, as they can complicate interpretation and detract from clarity A key principle of data visualization is to maintain simplicity, and many argue that 3D charts fail to achieve this by obscuring the true values represented, making it challenging to discern the peaks in relation to the X, Y, and Z axes Consequently, these charts are sometimes viewed as mere eye candy—visually appealing but lacking in informative value Therefore, the use of 3D charts should be limited and reserved for instances where they are genuinely necessary.
Exercises
The table presents population data for various cities in the UK, excluding London to maintain clarity, as its significantly larger population would skew the overall representation.
1 A scatter plot for the city to population data.
2 A bar chart for the city to population data.
Introduction
A Graphical User Interface (GUI) effectively conveys ideas and situations without lengthy text, simplifying user interaction by eliminating the need for complex commands GUIs are user-friendly, reducing intimidation for computer users, and they present information rapidly in an easily digestible format.
The increasing prevalence of high-quality graphical interfaces has raised user expectations for software applications across the board Consequently, most programming languages now either include a Graphical User Interface (GUI) library or provide access to third-party libraries that facilitate GUI development.
Python is a versatile cross-platform programming language, which introduces complexities due to varying windowing facilities provided by different operating systems such as Unix, Linux, Mac OS, and Windows.
In this chapter, we will define Graphical User Interfaces (GUIs) with a focus on WIMP-based UIs We will explore various Python libraries available for GUI development and select one for our purposes Additionally, we will demonstrate how to create rich client graphical displays, specifically desktop applications, using the chosen library The chapter will cover the creation, addition, positioning, and organization of essential GUI components such as windows, buttons, text fields, and labels.
J Hunt, Advanced Guide to Python 3 Programming ,
Undergraduate Topics in Computer Science, https://doi.org/10.1007/978-3-030-25943-3_7
GUIs and WIMPS
Graphical User Interfaces (GUIs) and WIMP (Windows, Icons, Mice, and Pop-up Menus) have been pivotal advancements in computer systems over the years They were designed to overcome the limitations of traditional text-based interfaces, enhancing user interaction and accessibility.
The textual interface of an operating system is characterized by a commanding prompt, often represented by a single character like %, >, or $ in Unix/Linux systems This can be daunting, even for seasoned computer users who may not be well-versed in the Unix/Linux environment.
For example, a user wishing to copy afile from one directory to another might have to type something like:
> cp file.pdf ~otheruser/projdir/srcdir/newfile.pdf
To ensure acceptance, it is crucial to enter this lengthy sequence accurately, as any mistakes will trigger an error message from the system, which may not provide clear guidance.
“user friendly’’ through features like command histories, much typing of arrow keys andfilenames is typically needed.
Bandwidth is a critical factor for both input and output in information processing Graphical output is more effective than tables for conveying complex relationships among large data sets Similarly, input methods utilizing mouse actions can replace lengthy text descriptions, enhancing user experience WIMP, which stands for Windows, Icons, Mice, and Pop-up menus, offers a more intuitive interface compared to traditional text-based systems This approach allows users to visualize the operating system through relatable images, utilize menus instead of text commands, and access information in a graphical format, addressing some limitations of text-driven interfaces.
The WIMP interface concepts, initially developed at XEROX's Palo Alto Research Center for the Xerox Star machine, gained broader recognition through their implementation on the Apple Macintosh and IBM PC, leading to widespread adoption.
Most WIMP style environments use a desktop analogy (although this is less true of mobile devices such as phones and tablets):
• the whole screen represents a working surface (a desktop),
• graphic windows that can overlap represent sheets of paper on that desktop,
• graphic objects are used for specific concepts, for example filing cabinets for disks or a waste bin for file disposal (these could be regarded as desk accessories),
• various application programs are displayed on the screen, these stand for tools that you might use on your desktop.
To interact with the display, WIMP users utilize a mouse, light pen, or touch-sensitive screen, enabling them to select icons, navigate menus, and manipulate windows efficiently.
The window manager is the essential software component of any WIMP (Windows, Icons, Menus, Pointer) environment, responsible for managing multiple overlapping windows and icons on the screen It facilitates the communication of events occurring within these windows to the relevant applications and generates various menus and prompts for user interaction.
A window is a designated area on a graphic screen that displays information, which can include text, graphics, or both Windows can overlap and may belong to the same process or different processes Users have the ability to create, open, close, move, and resize these windows as needed.
An icon is a small graphic representation that symbolizes a specific operation or a larger entity, such as an application or file When an icon is opened, it either launches the corresponding application or displays the related window.
The event loop is essential for user interaction in WIMP-based programs, as it continuously monitors for events like button clicks, menu selections, or text entry When an event is detected, it activates the corresponding action, such as executing a function tied to a button.
Windowing Frameworks for Python
Python is a versatile cross-platform programming language that allows developers to write programs on one operating system, such as Linux, and run them on others like Windows or Mac OS However, this flexibility can lead to challenges, particularly with libraries that must function across different platforms GUI libraries, for instance, may encounter compatibility issues, as features designed for Microsoft Windows may not be accessible or may appear differently on Mac OS or Linux systems.
Python operates on various operating systems, each potentially featuring unique windowing systems that may not be compatible with others This diversity complicates the development of a universal GUI library for Python.
Developers of Python GUIs have taken one of two approaches to handle this:
One effective approach to achieving cross-platform compatibility is to create a wrapper that abstracts the underlying GUI facilities, allowing developers to work at a higher level of abstraction, independent of a specific windowing system's facilities This wrapper then maps the abstracted facilities to the underlying system being used, enabling seamless integration and minimizing platform-specific dependencies.
• The other approach is to provide a closer wrapping to a particular set of facilities on the underlying GUI system and to only target systems that support those facilities.
Some of the libraries available for Python are listed below and have been cat- egorised into platform-independent libraries and platform-specific libraries:
Tkinter is the standard built-in GUI library for Python, leveraging the long-established Tcl/Tk widget set, which supports various operating systems Tcl, or Tool Command Language, serves as the foundation, while Tk provides the graphical user interface toolkit for Tcl.
wxPython is a free and highly portable GUI library, built on the wxWidgets framework, which is written in C++ It offers a native look and feel across multiple operating systems, including Windows, Mac OS, and Linux In this chapter, we will focus on utilizing wxPython, the set of Python bindings for wxWidgets.
• PyQT or PySideboth of these libraries wrap the Qt toolkit facilities Qt is a cross platform software development system for the implementation of GUIs and applications.
• PyObjcis a Mac OS specific library that provides an Objective-C bridge to the Apple Mac Cocoa GUI libraries.
• PythonWin provides a set of wrappings around the Microsoft Windows Foundation classes and can be used to create Windows based GUIs.
Online Resources
There are numerous online references that support the development of GUIs and of Python GUIs in particular, including:
• https://www.wxpython.orgwxPython home page.
• https://www.tcl.tkfor Information on Tcl/Tk.
• https://www.qt.io For information on the Qt cross-platform software and UI development library.
• https://wiki.python.org/moin/PyQtFor information about PyQt.
• https://pypi.org/project/PySide/which provides project information for PySide.
• https://en.wikipedia.org/wiki/Cocoa_(API) for the Wikipedia page on the MacOS Cocoa library.
• https://pythonhosted.org/pyobjc/for information on the Python to Objective-C bridge.
• https://docs.microsoft.com/en-us/cpp/mfc/mfc-desktop-applications?view=vs-
2019Provides an introduction to the Microsoft Foundation classes.
• https://www.cgl.ucsf.edu/Outreach/pc204/pythonwin.html for information onPythonWin.
The wxPython Library
The wxPython library is a versatile, cross-platform GUI toolkit for Python, enabling developers to create visually appealing graphical user interfaces It utilizes familiar elements like menu bars, buttons, fields, panels, and frames, making it easier for programmers to design interactive applications.
In wxPython, graphical user interface (GUI) elements are organized within top-level windows like wx.Frame and wx.Dialog These windows house various graphical components referred to as widgets or controls, which can be grouped into Panels that may or may not be visibly represented Consequently, wxPython allows for the effective construction of a GUI using these foundational elements.
• Frameswhich provide the basic structure for a window: borders, a label and some basic functionality (e.g resizing).
• Dialogswhich are like Frames but provide fewer border controls.
• Widgets/Controlsthat are graphical objects displayed in a frame Some other languages refer to them as UI components Examples of widgets are buttons, checkboxes, selection lists, labels and textfields.
• Containersare component that are made up of one or more other components (or containers) All the components within a container (such as a panel) can be treated as a single entity.
A graphical user interface (GUI) is organized hierarchically using various elements such as widgets, containers, and frames, or dialogs for pop-up windows This structure enables the creation of windows that can contain multiple panels and interactive widgets, enhancing user experience and functionality.
J Hunt, Advanced Guide to Python 3 Programming ,
Undergraduate Topics in Computer Science, https://doi.org/10.1007/978-3-030-25943-3_8
Windows, including Frames and Dialogs, utilize a component hierarchy that governs the drawing and redrawing of window elements This hierarchy is anchored by the frame, which serves as the foundation for adding various components and containers.
The diagram depicts a component hierarchy for a frame, featuring two container panels that house various basic widgets and UI components It is important to note that each panel can also contain sub-panels, which may include different widgets.
The wxPython library is comprised of many different modules These modules provide different features from the corewxmodule to the html orientedwx.html andwx.html2modules These modules include:
• wxwhich holds the core widgets and classes in thewxlibrary.
• wx.adv that provides less commonly used or more advanced widgets and classes.
• wx.grid contains widgets and classes supporting the display and editing of tabular data.
• wx.richtext consists of widgets and classes used for displaying multiple text styles and images.
• wx.htmlcomprises widgets and supporting classes for a generic html renderer.
• wx.html2 provides further widget and supporting classes for a native html renderer, with CSS and javascript support.
In wxPython, creating a window involves instantiating classes like Frame, Dialog, Panel, Button, or StaticText, which are responsible for displaying content on the screen To effectively show information to the user, you need to specify what the window should display and instruct it to render its contents.
You should bear the following points in mind during your reading of this chapter; they will help you understand what you are required to do:
• You create a window by instantiating a Frame or Dialog object.
• You define what the window displays by creating a widget that has an appro- priate parent component This adds the widget to a container, such as a type of panel or a frame.
• You can send messages to the window to change its state, perform an operation, and display a graphic object.
• The window, or components within the window, can send messages to other objects in response to user (or program) actions.
• Everything displayed by a window is an instance of a class and is potentially subject to all of the above.
• wx.Apphandles the main event loop of the GUI application.
An example of creating a very simple window using wxPython is given below The result of running this short program is shown here for both a Mac and a Windows PC:
This program creates a top level window (thewx.Frame) and gives it a title It also creates a label (awx.StaticTextobject) to be displayed within the frame.
To use the wxPython library it is necessary to import thewxmodule.
The program also creates a new instance of the Application Object calledwx. App().
Every wxPython GUI application requires a single Application Object, which functions similarly to the main() function found in non-GUI programs, managing the execution of the GUI This object offers built-in capabilities for defining startup and shutdown operations and can be subclassed to implement custom behaviors.
The wx.StaticText class is utilized to create a label that can display one or multiple lines of text, such as the string 'Hello Python.' The StaticText object is linked to its parent container, which determines where the text will appear; in this instance, it is displayed directly within the Frame, making the Frame its parent object Unlike the Frame, which serves as a top-level window, it does not have a parent container Additionally, it is essential for the Frame to be displayed for users to view the content, as applications may require various windows to be shown or hidden depending on the situation.
Finally the program starts the applications’main eventloop; within this loop the program listens for any user input (such as requesting that the window is closed).
The wx.App Class
Thewx.Appclass represents the application and is used to:
• start up the wxPython system and initialise the underlying GUI toolkit,
• set and get application-wide properties,
• implement the native windowing system main message or event loop, and to dispatch events to window instances. import wx
# Create the Application Object app = wx.App()
# Now create a Frame (representing the window) frame = wx.Frame(parent=None, title=' Simple Hello World')
# And add a text label to it text = wx.StaticText(parent=frame, label='Hello Python')
# Display the window (frame) frame.Show()
# Start the event loop app.MainLoop()
Every wxPython application requires a single instance of wx.App To ensure that the GUI platform and wxWidgets are fully initialized, the creation of all UI objects should be postponed until after the wx.App instance has been established.
Subclassing the wx.App class and overriding methods like OnPreInit and OnExit allows developers to implement custom behaviors that execute at the right moments Key methods available for overriding include OnInit, OnPreInit, and OnExit, ensuring that the application runs smoothly and efficiently.
• OnPreInit, This method can be overridden to define behaviour that should be run once the application object is created, but before the OnInit method has been called.
• OnInitThis is expected to create the applications main window, display that window etc.
• OnRun, This is the method used to start the execution of the main program.
• OnExit, This can be overridden to provide any behaviour that should be called just before the application exits.
To properly initialize and display a GUI application after instantiating the wx.App class, it is recommended to override the OnInit() method in a custom subclass This method must return either True or False, with True signaling that the application should continue processing, while False indicates an immediate termination due to an unexpected issue.
An examplewx.Appsubclass is shown below:
This class can now be instantiated and theMainLoopstarted, for example:
It is also possible to override theOnExit()to clean up anything initialised in theOnInit()method. class MainApp(wx.App): def OnInit(self):
""" Initialise the main GUI Application""" frame = WelcomeFrame() frame.Show()
# Indicate whether processing should continue or not return True
# Run the GUI application app = MainApp() app.MainLoop()
Window Classes
The window or widget container classes that are commonly used within a wxPython application are:
A wx.Dialog is a top-level window designed for popups that restrict user interaction, typically allowing only for data input or the acceptance or rejection of options.
• wx.FrameA Frame is a top level window whose size and position can be set and can (usually) be controlled by the user.
wx.Panel serves as a container for controls and widgets, functioning as a non-top-level window It is commonly utilized alongside a Dialog or Frame to effectively manage the layout and positioning of widgets within a graphical user interface (GUI).
The inheritance hierarchy for these classes is given below for reference:
This application demonstrates the use of a Frame and two Panels, where both Panels are displayed within a top-level Frame The Frame features a default grey background, while the first Panel is styled with a blue background and the second Panel with a red background.
The program that generated this GUI is given below: import wx class SampleFrame(wx.Frame): def init (self): super(). init (parent=None, title='Sample App', size=(300, 300))
# Set up the first Panel to be at position 1, 1
# (The default) and of size 300 by 100
# with a blue background self.panel1 = wx.Panel(self) self.panel1.SetSize(300, 100) self.panel1.SetBackgroundColour(wx.Colour(0, 0, 255))
# Set up the second Panel to be at position 1, 110
# and of size 300 by 100 with a red background self.panel2 = wx.Panel(self) self.panel2.SetSize(1, 110, 300, 100) self.panel2.SetBackgroundColour(wx.Colour(255, 0, 0)) class MainApp(wx.App): def OnInit(self):
""" Initialise the main GUI Application""" frame = SampleFrame() frame.Show() return True
# Run the GUI application app = MainApp() app.MainLoop()
The SampleFrame is a subclass of the wx.Frame class, inheriting all functionalities of a top-level window In its init () method, the SampleFrame calls the superclass's init () method to set the frame's size and title Additionally, it specifies that the frame does not have a parent window.
When the Panel is created it is necessary to specify the window (or in this case Frame) within which it will be displayed This is a common pattern within wxPython.
Also note that theSetSizemethod of thePanelclass also allows the position to be specified and that theColourclass is the wxPythonColourclass.
Widget/Control Classes
Although there are very many widgets/controls available to the developer, the most commonly used include:
• wx.Button/wx.ToggleButton/wx.RadioButton These are widgets that provide button like behaviour within a GUI.
• wx.TextCtrlThis widget allows text to be displayed and edited I can be a single line or multiple line widget depending upon configuration.
• wx.StaticTextUsed to display one or more lines of read-only text In many libraries this widgets is known as a label.
• wx.StaticLineA line used in dialogs to separate groups of widgets The line may be vertical or horizontal.
• wx.ListBoxThis widget is used to allow a user to select one option from a list of options.
• wx.MenuBar/wx.Menu/wx.MenuItem The components that can be used to construct a set of menus for a User Interface.
• wx.ToolBar This widget is used to display a bar of buttons and/or other widgets usually placed below the menubar in awx.Frame.
The inheritance hierarchy of these widgets is outlined below, emphasizing that they all derive from the class Control, which is why they are commonly known as Controls, Widgets, or GUI components.
Whenever a widget is created it is necessary to provide the container window class that will hold it, such as aFrameor aPanel, for example:
In this code snippet awx.Buttonis being created that will have a label‘Enter’ and will be displayed within the given Panel.
Dialogs
The genericwx.Dialogclass can be used to build any custom dialog you require.
It can be used to createmodaland modelessdialogs:
• A modal dialog blocks programflow and user input on other windows until it is dismissed.
• A modeless dialog behaves more like a frame in that programflow continues, and input in other windows is still possible.
The wx.Dialog class features two versions of the show method, enabling the creation of both modal and modeless dialogs The ShowModal() method is specifically designed to present a modal dialog, whereas the Show() method is utilized to display a modeless dialog.
As well as the generic wx.Dialog class, the wxPython library provides numerous prebuilt dialogs for common situations These pre built dialogs include:
• wx.ColourDialogThis class is used to generate a colour chooser dialog.
• wx.DirDialogThis class provides a directory chooser dialog.
• wx.FileDialogThis class provides afile chooser dialog.
• wx.FontDialogThis class provides a font chooser dialog.
The wx.MessageDialog class is designed to create both single and multi-line message dialogs, offering options such as Yes, No, and Cancel This versatile tool can be utilized for displaying general information or error messages effectively.
• wx.MultiChoiceDialogThis dialog can be used to display a lit of strings and allows the user to select one or more values for the list.
• wx.PasswordEntryDialog This class represents a dialog that allows a user to enter a one-line password string from the user.
• wx.ProgressDialogIf supported by the GUI platform, then this class will provide the platforms native progress dialog, otherwise it will use the pure
Python wx.GenericProgressDialog The wx.
GenericProgressDialogshows a short message and a progress bar.
• wx.TextEntryDialogThis class provides a dialog that requests a one-line text string from the user. enter_button = wx.Button(panel, label='Enter')
Most of the dialogs that return a value follow the same pattern This pattern returns a value from theShowModel()method that indicates if the user selected
To retrieve the selected value from a dialog in wxPython, use the return values wx.ID_OK or wx.ID_CANCEL You can obtain the chosen data through appropriate methods, such as GetColourData() for the ColourDialog and GetPath() for the DirDialog.
Arranging Widgets Within a Container
When positioning widgets within a window, specific coordinates (e.g., 10 pixels down and 5 pixels across) can be used, but this approach poses challenges for cross-platform applications The rendering of buttons varies significantly across different operating systems, such as Mac, Windows, and Linux/Unix, leading to inconsistencies in appearance and functionality.
Different platforms require varying amounts of spacing, as well as distinct font choices for text boxes and labels, leading to necessary adjustments in widget layouts.
To effectively manage widget layout in wxPython, Sizers are utilized within containers like Frames or Panels By adding widgets to a sizer and then assigning that sizer to a container, developers can achieve organized and flexible arrangements of their user interface elements.
A Sizer is a tool that collaborates with a container and the host windowing platform to optimize the display of objects within a window This allows developers to focus on functionality without concern for how their application will respond to window resizing or variations across different windowing platforms.
Sizers play a crucial role in creating portable and visually appealing user interfaces, allowing for the nesting of one Sizer within another to form intricate component layouts A variety of Sizers are available for different design needs.
The wx.BoxSizer is a layout manager that organizes multiple widgets in either a row or column format, based on the specified orientation When creating a BoxSizer, you can choose between wx.VERTICAL for vertical arrangement or wx.HORIZONTAL for horizontal alignment.
The wx.GridSizer is a layout manager that organizes widgets in a uniform two-dimensional grid, where each cell maintains equal dimensions When creating a GridSizer object, you can define the number of rows and columns, as well as set the horizontal and vertical spacing between the cells.
The wx.FlexGridSizer is a versatile layout manager that enhances the traditional GridSizer by allowing for varying sizes in rows and columns While it maintains uniform width for all cells within the same column and consistent height for cells in the same row, it offers greater flexibility in arranging components.
• wx.GridBagSizer is the most flexible sizer It allows widgets to be posi- tioned relative to the grid and also allows widgets to span multiple rows and/or columns.
To use a Sizer it mustfirst be instantiated When widgets are created they should be added to the sizer and then the sizer should be set on the container.
For example, the following code uses a GridSizer used with a Panel to layout out four widgets comprised of two buttons, a StaticText label and a TextCtrlinputfield:
The resulting display is shown below:
# Create the panel panel = wx.Panel(self)
# Create the sizer to use with 4 rows and 1 column
# And 5 spacing around each cell grid = wx.GridSizer(4, 1, 5, 5)
# Create the widgets text = wx.TextCtrl(panel, size=(150, -1)) enter_button = wx.Button(panel, label='Enter') label = wx.StaticText(panel,label='Welcome') message_button = wx.Button(panel, label='Show Message')
# Add the widgets to the grid sizer grid.AddMany([text, enter_button, label, message_button])
# Set the sizer on the panel panel.SetSizer(grid)
Drawing Graphics
In earlier chapters we looked at the Turtle graphics API for generating vector and raster graphics in Python.
The wxPython library provides its own facilities for generating cross platform graphic displays using lines, squares, circles, text etc This is provided via the Device Context.
A Device Context (often shortened to just DC) is an object on which graphics and text can be drawn.
The goal is to enable various output devices to utilize a shared graphics API, known as the Graphics Device Interface (GDI) Depending on the intended output medium, such as a computer screen or a printer, specific device contexts can be instantiated for the program's use.
There are several Device Context types available such aswx.WindowDC,wx. PaintDCand wx.ClientDC:
• Thewx.WindowDCis used if we want to paint on the whole window (Windows only) This includes window decorations.
• Thewx.ClientDCis used to draw on the client area of a window The client area is the area of a window without its decorations (title and border).
• Thewx.PaintDCis used to draw on the client area as well but is intended to support the window refresh paint event handling mechanism.
Note that thewx.PaintDCshould be used only from a wx.PaintEvent handler while thewx.ClientDCshould never be used from awx.PaintEvent handler.
Whichever Device Context is used, they all support a similar set of methods that are used to generate graphics, such as:
• DrawCircle (x, y, radius) Draws a circle with the given centre and radius.
• DrawEllipse (x, y, width, height)Draws an ellipse contained in the rectangle specified either with the given top left corner and the given size or directly.
• DrawPoint (x, y)Draws a point using the color of the current pen.
• DrawRectangle (x, y, width, height) Draws a rectangle with the given corner coordinate and size.
• DrawText (text, x, y)Draws a text string at the specified point, using the current text font, and the current text foreground and background colours.
• DrawLine (pt1, pt2)/DrawLine (x1, y1, x2, y2) This method draws a line from thefirst point to the second.
Understanding when the device context is refreshed or redrawn is crucial; for instance, actions like resizing, maximizing, minimizing, moving a window, or altering its contents trigger a redraw, generating a paint event (aPaintEvent) You can associate a method with the aPaintEvent using wx.EVT_PAINT, allowing it to be executed every time the window is refreshed.
To ensure your window displays the correct content, it's essential to redraw the device context when necessary; otherwise, previously drawn elements will reappear upon refresh The example program below demonstrates the application of various Draw methods and shows how to link a method to the paint event, ensuring the display is updated correctly when using a device context.
When executed, this program creates a graphical window using wxPython It defines a class called `DrawingFrame`, which inherits from `wx.Frame` The constructor initializes the frame with a specified title and size of 300 by 200 pixels Additionally, it binds the paint event to the `on_paint` method, which is triggered during the window's rendering process.
To set up the device context (DC) for painting in wxPython, use `dc = wx.PaintDC(self)` This allows you to draw various shapes and text, such as lines, rectangles, and circles For example, you can draw a line from (10, 10) to (60, 20), a rectangle at (20, 40) with a width of 40 and height of 20, and display the text "Hello World" at coordinates (30, 70) Additionally, you can create a circle with a specified radius centered at (130, 40) The `GraphicApp` class extends `wx.App` and includes the `OnInit` method to initialize the application.
""" Initialise the GUI display""" frame = DrawingFrame(title='PyDraw') frame.Show() return True
# Run the GUI application app = GraphicApp() app.MainLoop()
Online Resources
There are numerous online references that support the development of GUIs and of Python GUIs in particular, including:
• https://docs.wxpython.orgfor documentation on wxPython.
• https://www.wxpython.orgwxPython home page.
• https://www.wxwidgets.org For information on the underlying wxWidgetsCross platform GUI library.
Exercises
In this exercise you will implement your own simple GUI application.
The application should generate the display for a simple UI An example of the user interface is given below:
Notice that we have added a label to the inputfields for name and age; you can manage their display using a nested panel.
In the next chapter we will add event handling to this application so that the application can respond to button clicks etc.
Events in wxPython User Interfaces
Event Handling
Events are an integral part of any GUI; they represent user interactions with the interface such as clicking on a button, entering text into afield, selecting a menu option etc.
The main event loop in wxPython listens for events and processes them, typically by invoking a function or method This loop is started by calling the MainLoop() method on the wx.App object, allowing the application to wait for and respond to subsequent events.
An event is defined as a piece of information that represents an interaction, often occurring within a graphical user interface (GUI), although it can be generated by other sources as well Events are processed by an Event Handler, which is a method or function triggered when the event takes place, with the event being passed to the handler as a parameter To link an event to its corresponding event handler, an Event Binder is utilized.
Event De fi nitions
It is useful to summarise the definitions around events as the terminology used can be confusing and is very similar:
An event in a GUI framework conveys information about an occurrence and its related data, which varies based on the specific action For instance, moving a window generates data about its new position, while a CommandEvent triggered by a ListBox selection provides the index of the selected item.
J Hunt, Advanced Guide to Python 3 Programming,
Undergraduate Topics in Computer Science, https://doi.org/10.1007/978-3-030-25943-3_9
• Event Loop the main processing loop of the GUI that waits for an event to occur When an event occurs the associated event handler is called.
• Event Handlersthese are methods (or functions) that are called when an event occurs.
Event binders link specific events to their corresponding event handlers, with distinct binders designated for various event types For instance, the binder for the wx.MoveEvent is referred to as wx.EVT_MOVE.
The relationship between the Event, the Event Handler via the Event Binder is illustrated below:
The top three boxes illustrate the concepts while the lower 3 boxes provide a concrete example of binding aMove_Eventto anon_move()method via theEVT_MOVEbinder.
Types of Events
There are numerous different types of event including:
• wx.CloseEventused to indicate that a Frame or Dialog has been closed The event binder for this event is namedwx.EVT_CLOSE.
wx.CommandEvent is utilized with various widgets, including buttons, list boxes, menu items, radio buttons, scrollbars, and sliders Each widget type generates specific information upon an event; for instance, a CommandEvent for a button signifies a click, while for a ListBox, it indicates an option selection Different event binders are required for handling these events: wx.EVT_BUTTON is used to bind a command event to a button's event handler, whereas wx.EVT_LISTBOX is appropriate for a ListBox.
The wx.FocusEvent occurs when a window's focus changes, either gaining or losing it To handle a window gaining focus, you can use the wx.EVT_SET_FOCUS event binder Conversely, the wx.EVT_KILL_FOCUS allows you to bind an event handler that triggers when a window loses focus.
• wx.KeyEvent This event contains information relating to a key press or release.
• wx.MaximizeEvent This event is generated when a top level window is maximised.
The wx.MenuEvent is triggered by menu-related actions, including when a menu is opened or closed It is important to note that this event does not occur when a menu item is selected, as that action generates CommandEvents instead.
The wx.MouseEvent class provides essential details about mouse-related events, including which mouse button was pressed or released, as well as whether a double-click occurred.
• wx.WindowCreateEventThis event is sent just after the actual window is created.
• wx.WindowDestoryedEventThis event is sent as early as possible during the window destruction process.
Binding an Event to an Event Handler
An event is bound to an Event Handler using theBind() method of an event generating object (such as a button, field, menu item etc.) via a named Event Binder.
For example: button.Bind(wx.EVT_BUTTON, self.event_handler_method)
Implementing Event Handling
There are four steps involved in implementing event handling for a widget or window, these are:
1 Identify the event of interest Many widgets will generate different events in different situations; it may therefore be necessary to determine which event you are interested in.
2 Find the correct Event Binder name, e.g wx.EVT_CLOSE, wx.EVT_MOVE or wx.EVT_BUTTON etc Again you may find that the widget you are inter- ested in supports numerous different event binders which may be used in dif- ferent situations (even for the same event).
3 Implement an event handler(i.e a suitable method or function) that will be called when the event occurs The event handler will be supplied with the event object.
4 Bind the Event to the Event Handlervia the Binder Name using theBind() method of the widget or window.
To illustrate this we will use a simple example.
We will write a very simple event handling application This application will have aFramecontaining aPanel The Panel will contain a label using thewx. StaticTextclass.
In this article, we will create an event handler named on_mouse_click() that allows us to relocate the StaticText label to the current position of the mouse cursor whenever the left mouse button is clicked, enabling dynamic movement of the label across the screen.
To generate the event, we first need to identify the widget, which in this case is the panel containing the text label Upon examining the Panel class, we find that it only directly supports NavigationKeyEvents However, since the Panel class extends the Window class, we can explore additional event options available through the Window class.
The Window class offers various event bindings, including focus events (wx.EVT_SET_FOCUS and wx.EVT_KILL_FOCUS), key presses (wx.EVT_KEY_DOWN and wx.EVT_KEY_UP), and multiple mouse events Among these, the wx.EVT_LEFT_DOWN binding is particularly significant, as it detects MouseEvents triggered by pressing the left mouse button, while the wx.EVT_LEFT_UP binding captures events when the left mouse button is released.
To handle mouse click events in wxPython, it's essential to bind the `on_mouse_click()` event handler to the `MouseEvent` using the `wx.EVT_LEFT_DOWN` event binder For instance, you can achieve this by using the code: `self.panel.Bind(wx.EVT_LEFT_DOWN, self.on_mouse_click)`.
All event handler methods takes two parameters, self and the mouse event. Thus the signature of theon_mouse_click()method is: def on_mouse_click(self, mouse_event):
The mouse event object includes several methods to gather mouse-related information, such as the number of clicks (GetClickCount()), the pressed button (GetButton()), and the current mouse position within a widget or window (GetPosition()) By utilizing the GetPosition() method, we can determine the mouse's current location and subsequently use the SetPosition(x, y) method on the StaticText object to adjust its position accordingly.
The end result is the program shown below: import wx class WelcomeFrame(wx.Frame):
""" The Main Window / Frame of the application """ def init (self): super(). init (parent=None, title='Sample App', size=(300, 200))
# Set up panel within the frame and text label self.panel = wx.Panel(self) self.text = wx.StaticText(self.panel, label='Hello')
# Bind the on_mouse_click method to the
# left mouse click binder self.panel.Bind(wx.EVT_LEFT_DOWN, self.on_mouse_click) def on_mouse_click(self, mouse_event):
""" When the left mouse button is clicked
This method retrieves the current mouse coordinates and updates the position of the text label accordingly By using `x, y = mouse_event.GetPosition()`, the x and y coordinates are obtained, and `self.text.SetPosition(wx.Point(x, y))` repositions the text label to the new location The `MainApp` class initializes the application.
""" Initialise the main GUI Application""" frame = WelcomeFrame() frame.Show()
# Indicate that processing should continue return True
# Run the GUI application app = MainApp() app.MainLoop()
When the program is executed, a window appears featuring a 'Hello' StaticText label positioned in the top left corner of the Frame Although the label is added to a Panel, the Panel occupies the entire Frame in this instance If the user clicks the left mouse button anywhere within the Frame, the 'Hello' label moves to the clicked location.
This is shown below for the initial setup and then for two locations within the window.
An Interactive wxPython GUI
An example of a slightly larger GUI application, that brings together many of the ideas presented in this chapter, is given below.
This application features a text input field (awx.TextCtrl) for users to enter their name Upon clicking the Enter button (wx.Button), the welcome label (wx.StaticText) is updated to display the user's name Additionally, the 'Show Message' button triggers a wx.MessageDialog that includes the user's name.
The initial display for both Mac and Windows PC reveals a notable difference in the default background color of a Frame, highlighting that while the GUI operates on both platforms, their appearance varies significantly.
The provided code snippet demonstrates the implementation of a GUI application using wxPython It defines a class named `HelloFrame`, which inherits from `wx.Frame` The class constructor initializes the frame with a specified title and a default size of 300 by 200 pixels, while also setting a placeholder for the name as ''.
# Create the BoxSizer to use for the Frame vertical_box_sizer = wx.BoxSizer(wx.VERTICAL) self.SetSizer(vertical_box_sizer)
# Create the panel to contain the widgets panel = wx.Panel(self)
# Add the Panel to the Frames Sizer vertical_box_sizer.Add(panel, wx.ID_ANY, wx.EXPAND | wx.ALL, 20)
# Create the GridSizer to use with the Panel grid = wx.GridSizer(4, 1, 5, 5)
# Set up the input field self.text = wx.TextCtrl(panel, size=(150, -1))
# Set the sizer on the panel panel.SetSizer(grid)
# Centre the Frame on the Computer Screen self.Centre() def show_message(self, event):
To create a message dialog that displays a welcome message using the current value of the name attribute, use the wx.MessageDialog function in your event handler This function constructs a dialog with a message that combines 'Welcome To Python ' with the user's name, and includes a caption 'Hello' along with an OK button The dialog is then presented to the user by calling the ShowModal() method To set the name attribute, implement the set_name method to handle the relevant event.
""" Event Handler for the Enter button.
The code retrieves the text from the input field and assigns it to the attribute self.name This value is then utilized to update the label text, displaying a welcome message that includes the user's name.
# Now configure the enter button enter_button = wx.Button(panel, label='Enter') enter_button.Bind(wx.EVT_BUTTON, self.set_name)
# Next set up the text label self.label = wx.StaticText(panel, label='Welcome', style=wx.ALIGN_LEFT)
# Now configure the Show Message button message_button = wx.Button(panel, label='Show Message') message_button.Bind(wx.EVT_BUTTON, self.show_message)
# Add the widgets to the grid sizer to handle layout grid.AddMany([self.text, enter_button, self.label, message_button]) class MainApp(wx.App): def OnInit(self):
""" Initialise the GUI display""" frame = HelloFrame(title='Sample App') frame.Show()
# Indicate whether processing should continue or not return True def OnExit(self):
""" Executes when the GUI application shuts down""" print('Goodbye')
# Need to indicate success or failure return True
# Run the GUI application app = MainApp() app.MainLoop()
If the user enters their name in the top TextCtrlfield, for example‘Phoebe’, then when they click on the ‘Enter’ button the welcome label changes to ‘Welcome Phoebe’:
If they now click on the ‘Show Message’ button then the wx. MessageDialog (a specific type of wx.Dialog) will display a welcome message to Phoebe:
Online Resources
There are numerous online references that support the development of GUIs and of Python GUIs in particular, including:
• https://docs.wxpython.orgfor documentation on wxPython.
• https://www.wxpython.orgwxPython home page.
• https://www.wxwidgets.org For information on the underlying wxWidgetsCross platform GUI library.
Exercises
This exercise builds on the GUI you created in the last chapter.
The application must enable users to input their name and age It is essential to validate that the age entered is a numeric value, which can be achieved by utilizing functions like isnumeric() If the input for age is not a number, an error message should be presented to the user.
A button should be provided labelled ‘Birthday’; when clicked it should increment the age by one and display a Happy Birthday message The age should be updated within the GUI.
An example of the user interface you created in the last chapter is given below:
As an example, the user might enter their name and age as shown below:
When the user clicks on the‘birthday’button then the Happy Birthday message dialog is displayed:
9.8.2 GUI Interface to a Tic Tac Toe Game
This exercise focuses on creating a straightforward Tic Tac Toe game that enables two players to engage interactively using a single mouse The first player will assume the role of 'X', while the second player will take on the role of 'O'.
When each user selects a button you can set the label for the button to their symbol.
You will need two check after each move to see if someone has won (or if the game is a draw).
You will still need an internal representation of the grid so that you can deter- mine who, if anyone, has won.
An example of how the GUI for the TicTacToe game might look is given below:
You can also add dialogs to obtain the players names and to notify them who won or whether there was a draw.
Introduction
This chapter expands on the GUI library discussed in the previous two chapters, demonstrating the development of a more extensive application It features a case study of a drawing tool similar to Visio, showcasing practical implementation and functionality.
The PyDraw Application
The PyDraw application enables users to create diagrams with shapes such as squares, circles, lines, and text Currently, it lacks features for selecting, resizing, repositioning, or deleting elements, though these options could be incorporated in the future PyDraw is built using the wxPython framework, specifically version 4.0.6.
When a user starts the PyDraw application, they see the interface shown above (for both the Microsoft Windows and Apple Mac operating systems) Depending on © Springer Nature Switzerland AG 2019
J Hunt, Advanced Guide to Python 3 Programming ,
Undergraduate Topics in Computer Science, https://doi.org/10.1007/978-3-030-25943-3_10
The operating system features a menu bar at the top of the display, a toolbar positioned beneath it, and a scrollable drawing area located below the toolbar On a Mac, the menu bar is prominently displayed at the top of the screen.
The first button on the toolbar clears the drawing area, while the second and third buttons are designed to display messages in the Python console, with the intention of enabling users to load and save their drawings.
The tool bar buttons are duplicated on the menus defined for the application,along with a drawing tool selection menu, as shown below:
The Structure of the Application
The user interface of the PyDraw application consists of several key components, including the PyDrawMenuBar, a PyDrawToolbar featuring a series of buttons at the top of the window, a drawing panel for creating artwork, and the window frame, which is implemented by the PyDrawFrame class.
The diagram illustrates a containment hierarchy, demonstrating how lower-level objects are encompassed within higher-level objects This visual representation conveys the relationship between different elements, highlighting their organizational structure.
It is important to visualize this as the majority of wxPython interfaces are built up in this way, using containers and sizers.
The inheritance structure in the PyDraw application showcases a typical class hierarchy that integrates user interface components with graphical elements.
10.3.1 Model, View and Controller Architecture
The application utilizes the widely recognized Model-View-Controller (MVC) design pattern, which effectively separates the responsibilities among the view component, such as the Frame or Panel, the control component that manages user input, and the model component that stores the data to be displayed.
The separation of concerns is a fundamental concept that facilitates the development of GUI applications based on the Model-View-Controller (MVC) architecture This design pattern aims to distinctly separate the user interface display, the management of user inputs, and the underlying data model.
10.3 The Structure of the Application 101
There are a number of reasons why this separation is useful:
• reusability of application and/or user interface components,
• ability to develop the application and user interface separately,
• ability to inherit from different parts of the class hierarchy.
• ability to define control style classes which provide common features separately from how these features may be displayed.
Different interfaces can be utilized with the same application independently, allowing for modifications in one part of the system without impacting others For instance, the graphical interface's appearance can be altered without changing the application's core functionality or input handling This design ensures that the application remains unaware of the specific interface in use, promoting flexibility and adaptability in system interactions.
The PyDraw application employs an MVC structure featuring a primary controller class, PyDrawController, and a main view class, PyDrawFrame, while notably lacking a model, as the top-level MVC triad does not maintain any explicit data.
At a deeper level, the application employs an MVC architecture specifically for its drawing component, which includes a DrawingController, a DrawingModel, and a DrawingPanel serving as the view.
The DrawingModel, DrawingPanel, and DrawingController classes exemplify the traditional MVC architecture, where the view and controller (DrawingPanel and DrawingController) are aware of each other and the drawing model In contrast, the DrawingModel remains oblivious to both the view and the controller Changes in the drawing are communicated to the view through the paint event.
The Figure class serves as the foundation for four types of drawing objects: Circle, Line, Square, and Text figures Each type varies in what is rendered on the graphic device context within the on_paint() method Despite these differences, all drawing objects share common attributes defined by the Figure class, such as point coordinates for x and y locations and size specifications.
The PyDrawFrame class incorporates both the PyDrawMenuBar and PyDrawToolBar classes The PyDrawMenuBar enhances the wx.MenuBar by adding menu items specifically designed for the PyDraw application, while the PyDrawToolBar extends the wx.ToolBar to offer icons that enhance the functionality of PyDraw.
10.3 The Structure of the Application 103
Thefinal class is thePyDrawAppclass that extends thewx.Appclass.
However, the inheritance hierarchy is only part of the story for any object oriented application The followingfigure illustrates how the objects relate to one another within the working application.
The PyDrawFrame is responsible for setting up the controller and the DrawingPanel.
ThePyDrawControlleris responsible for handling menu and tool bar user interactions.
This separates graphical elements from the behaviour triggered by the user.
The DrawingPanel displays figures stored in the DrawingModel, while the DrawingController manages user interactions, such as adding and clearing figures The DrawingModel maintains a list of figures for display.
The Interactions Between Objects
We have now examined the physical structure of the application but not how the objects within that application interact.
In various scenarios, information can be obtained from the application's source code, albeit with differing levels of complexity For applications like PyDraw, which consists of multiple interacting components, it is beneficial to explicitly outline the system interactions.
The diagrams illustrating the interactions between the objects use the following conventions:
• a solid arrow indicates a message send,
• a name in brackets indicates the type of instance,
• numbers indicate the sequence of message sends.
These diagrams are based on the collaboration diagrams found in the UML (Unified Modelling Language) notation.
When thePyDrawAppis instantiated thePyDrawFramein created and displayed using theOnInit()method TheMainLoop()method is then invoked This is shown below: def OnInit(self):
""" Initialise the GUI display""" frame = PyDrawFrame(title='PyDraw') frame.Show() return True
# Run the GUI application app = PyDrawApp() app.MainLoop() class PyDrawApp(wx.App):
10.3 The Structure of the Application 105
The PyDrawFrame constructor method sets up the main display of the UI application and also initialises the controllers and drawing elements This is shown below using a collaboration diagram:
The PyDrawFrame constructor establishes the application's environment by creating the top-level PyDrawController, initializing the DrawingPanel and display layout, setting up the menu bar and tool bar, binding the controller's menu handler to the menus, and centering itself within the interface.
When a user selects an option from the Drawing menu, the mode changes to various shapes such as square, circle, line, or text For instance, choosing the 'Circle' option from the Drawing menu alters the interaction, as illustrated in the collaboration diagram below.
When a user selects a menu item, the `command_menu_handler()` method in the PyDrawController is triggered This method identifies the selected menu item and subsequently invokes the relevant setter method, such as `set_circle_mode()` or `set_line_mode()` These setter methods update the mode attribute of the controller to reflect the chosen option.
A user adds a graphic object to the drawing displayed by theDrawingPanelby pressing the mouse button.
When the user clicks on the drawing panel, the DrawingController responds as shown below:
The above illustrates what happens when the user presses and releases a mouse button over the drawing panel, to create a newfigure.
When a user clicks the mouse button, a message indicating the click is sent to the DrawingController, which determines the appropriate action to take In PyDraw, the controller retrieves the cursor position where the event occurred by invoking the GetPosition() method on the mouse_event.
The controller invokes its own add() method, supplying the current mode and mouse position It retrieves the current mode from the PyDrawController through a callback method used during the instantiation of the DrawingController, allowing it to add the corresponding type of figure to the DrawingModel.
Theadd()method then adds a newfigure to the drawing model based on the specified mode.
The Classes
This section outlines the classes within the PyDraw application, building on previously discussed concepts Each class will be presented in full, with comments that emphasize key aspects of their implementation It's important to note that the code includes the wx module from the wxPython library, as shown in the import statement: `import wx`.
The PyDrawConstants class serves as a repository for essential constants utilized throughout the application It defines constants for menu item and toolbar tool IDs, as well as for indicating the current mode, whether it be for adding a line, square, circle, or text to the display.
The PyDrawFrame class serves as the primary window for the application, adhering to the MVC architecture principles This design ensures that the view class focuses solely on the layout of the components, maintaining a clear separation of concerns.
""" Main Frame responsible for the layout of the UI.""" def init (self, title): super(). init (None, title=title, size=(300, 200))
# Set up the controller self.controller = PyDrawController(self)
# Set up the layout fo the UI self.vertical_box_sizer = wx.BoxSizer(wx.VERTICAL) self.SetSizer(self.vertical_box_sizer)
# Set up the menu bar self.SetMenuBar(PyDrawMenuBar())
# Set up the toolbar self.vertical_box_sizer.Add(PyDrawToolBar(self), wx.ID_ANY, wx.EXPAND | wx.ALL, )
# Setup drawing panel self.drawing_panel = DrawingPanel(self, self.controller.get_mode) self.drawing_controller = self.drawing_panel.controller
# Add the Panel to the Frames Sizer self.vertical_box_sizer.Add(self.drawing_panel, wx.ID_ANY, wx.EXPAND | wx.ALL)
# Set up the command event handling for the menu bar and tool bar self.Bind(wx.EVT_MENU, self.controller.command_menu_handler) self.Centre()
The PyDrawMenuBar class extends the wx.MenuBar class to define the menu bar for the PyDraw application by creating two wx.Menu objects Each wx.Menu serves as a dropdown menu, allowing for the addition of individual menu items using the wx.MenuItem class These items are appended to the menus, which in turn are added to the menu bar Each menu item is assigned a unique ID for event handling, enabling a single event handler to manage events from multiple menu items efficiently The implementation includes file operations such as "New," "Open," "Save," and an exit option, each accompanied by a corresponding bitmap icon for enhanced user experience.
'&Quit\tCtrl+Q') fileMenu.Append(quit) self.Append(fileMenu, '&File') drawingMenu = wx.Menu() lineMenuItem = wx.MenuItem(drawingMenu,
PyDraw_Constants.LINE_ID, text="Line", kind=wx.ITEM_NORMAL) drawingMenu.Append(lineMenuItem) squareMenuItem = wx.MenuItem(drawingMenu,
PyDraw_Constants.SQUARE_ID, text="Square", kind=wx.ITEM_NORMAL) drawingMenu.Append(squareMenuItem) circleMenuItem = wx.MenuItem(drawingMenu,
PyDraw_Constants.CIRCLE_ID, text="Circle", kind=wx.ITEM_NORMAL) drawingMenu.Append(circleMenuItem) textMenuItem = wx.MenuItem(drawingMenu,
PyDraw_Constants.TEXT_ID, text="Text", kind=wx.ITEM_NORMAL) drawingMenu.Append(textMenuItem) self.Append(drawingMenu, '&Drawing')
The `PyDrawToolBar` class is a subclass of `wx.ToolBar` designed to create a user-friendly toolbar with three essential tools: New, Open, and Save In its constructor, the toolbar initializes these tools with unique IDs and corresponding bitmaps for visual representation The `Realize()` method is called to ensure proper rendering of the tools By using consistent IDs for related menu items and command tools, the class allows for a single event handler to effectively manage commands from both sources, enhancing event handling efficiency.
This class serves as the control element for the top-level view, managing the current mode and implementing an event handler for menu items and toolbar tools Each menu or tool is identified by a unique ID, enabling a single handler to be registered with the frame for efficient event management.
10.5 The Classes 111 def init (self, view): self.view = view
The PyDraw application allows users to switch between different drawing modes, including line, square, circle, and text, by utilizing specific methods such as `set_line_mode()`, `set_square_mode()`, `set_circle_mode()`, and `set_text_mode()` The current mode can be retrieved with the `get_mode()` function, and users can clear the drawing area using the `clear_drawing()` method The application also features a command menu handler that responds to various events, such as clearing the drawing area, opening or saving files, and exiting the application Each command is identified by unique IDs, enabling seamless mode transitions and user interactions within the drawing interface.
TheDrawingModelclass has acontentsattribute that is used to hold all the
The DrawingModel class manages a collection of figures, offering convenient methods for manipulating its contents It features an initializer that creates an empty list to store figures, a method to clear all figures, and another method to add a new figure to the collection.
The Drawing Model is a straightforward framework that stores a collection of graphical figures in a list These figures can be any object type, and their display is flexible, provided they implement the on_paint() method The appearance of each object when rendered is dictated by the objects themselves.
The DrawingPanel class, a subclass of wx.Panel, serves as the visual representation of the drawing data model within the classical MVC architecture It consists of three main components: the model (DrawingModel), the view (DrawingPanel), and the controller (DrawingController).
The DrawingPanel instantiates its own DrawingController to handle mouse events.
The DrawingPanel class in wxPython initializes a drawing interface by setting a white background color and creating instances of DrawingModel and DrawingController It registers for paint events to refresh the display and binds mouse click events to the controller for interactive functionality.
10.5 The Classes 113 def on_paint(self, event):
"""set up the device context (DC) for painting""" dc = wx.PaintDC(self) for figure in self.model.contents: figure.on_paint(dc)
The DrawingController class serves as the central control component in the top-level MVC architecture, working in conjunction with the DrawingModel (model) and DrawingPanel (view) classes It specifically manages mouse events within the DrawingPanel through the on_mouse_click() method.
It also defines an add method that is used to add afigure to the DrawingModel (the actual figure depends on the current mode of the PyDrawController).
The `clear()` method effectively removes all figures from the drawing model and refreshes the display Within the `DrawingController` class, the ` init ` method initializes the view, model, and mode retrieval function The `on_mouse_click` method captures the mouse event's position and adds a new figure based on the selected mode The `add` method creates different shapes—Square, Circle, Text, or Line—depending on the specified mode and point, and then adds the figure to the model.
The Figure class serves as an abstract superclass within the Figure class hierarchy, encapsulating the shared attributes of graphic objects in a drawing It defines the figure's position through the point attribute and its size with the size attribute Additionally, the Figure class is a subclass of wx.Panel, allowing for the construction of displays using inner panels where different figure shapes are rendered.
The Figure class in wxPython requires all concrete subclasses to implement the abstract method on_paint(dc), which is responsible for defining the drawing behavior of shapes on the drawing panel The class constructor initializes the Figure object with parameters such as parent, id, position, size, and style, while also storing the position and size attributes for further use.
@abstractmethod def on_paint(self, dc):
References
The following provides some background on the Model-View-Controller archi- tecture in user interfaces.
• G.E Krasner, S.T Pope, A cookbook for using the model-view controller user interface paradigm in smalltalk-80 JOOP1(3), 26–49 (1988).
Exercises
You could develop the PyDraw application further by adding the following features:
To enhance functionality, a Delete button can be incorporated into the interface, which will set the mode to "delete." Modifications to the drawingPanel are necessary, ensuring that the mouseReleased method transmits a delete message to the drawing Consequently, the drawing will identify and remove the corresponding graphic object, subsequently sending a change notification to itself.
The resize option allows users to select a shape and either enter a new size through a dialog box or adjust the size using mouse controls.
Games programming is performed by developers/coders who implement the logic that drives a game.
Historically, game developers managed all aspects of game creation, including coding, sprite and icon design, gameplay mechanics, sound and music integration, and animation generation However, as the gaming industry has evolved, companies have established specialized roles such as computer graphics (CG) animators, artists, game developers, and physics engine developers to enhance the development process.
Game development involves various specialized roles, including code developers who create physics engines, game engines, and the games themselves Game engine developers concentrate on building the framework that supports the game, while physics engine developers implement the mathematical principles governing the simulated world's physics, such as gravity's effect on characters and objects Additionally, AI engine developers enhance the game by enabling characters to behave intelligently, contributing to a more immersive gaming experience.
Game developers utilize engines and frameworks to craft the final gameplay experience, bringing the game to life and ensuring it is both enjoyable and playable for users.
There are many frameworks and libraries available that allow you to create anything from simple games to large complex role playing games with infinite worlds. © Springer Nature Switzerland AG 2019
J Hunt, Advanced Guide to Python 3 Programming ,
Undergraduate Topics in Computer Science, https://doi.org/10.1007/978-3-030-25943-3_11
One example is the Unity framework that can be used with the C# programming language Another such framework is the Unreal engine used with the C++ pro- gramming language.
Python is a versatile programming language utilized in game development, with notable titles relying on it for various functionalities For instance, the military simulator first-person shooter game Battlefield 2, developed by Digital Illusions CE, incorporates Python to manage aspects of game logic, including game modes and scoring in Battlefield Heroes.
Other games that use Python include Civilisation IV (for many of the tasks), Pirates of the Caribbean Online and Overwatch (which makes its choices with Python).
Python is also embedded as a scripting engine within tools such as Autodesk’s Maya which is a computer animation toolkit that is often used with games.
For those wanting to learn more about game development; Python has much to offer There are many examples available online as well as several game oriented frameworks.
The frameworks/libraries available for games development in Python including:
• Arcade This is a Python library for creating 2D style video games.
• pygletis a windowing and multimedia library for Python that can also be used for games development.
• Cocos2dis a framework for building 2D games that is built on top of pyglet.
Pygame is the most popular library for game development in Python, offering numerous extensions that facilitate the creation of various game types.
We will focus on pygame in the next two chapters in this book.
Other libraries of interest to Python games developers include:
• PyODE This is an open-source Python binding for the Open Dynamics Engine which is an open-source physics engine.
Pymunk is a user-friendly 2D physics library designed for implementing rigid body physics in Python applications Ideal for games and demos, it offers robust 2D physics capabilities and is built on the foundation of the Chipmunk physics library.
pyBox2D is a versatile 2D physics library designed for game development and simple simulations, built upon the robust Box2D library originally written in C++ It offers support for various shape types, including circles, polygons, and thin line segments, along with multiple joint types such as revolute, prismatic, and wheel joints.
Blender is a powerful open-source 3D computer graphics software used for creating animated films, visual effects, art, 3D printed models, interactive applications, and video games Its extensive features encompass 3D modeling, texturing, raster graphics editing, rigging, and skinning Additionally, Blender supports Python scripting for tasks such as creation, prototyping, and game logic, making it a versatile tool for artists and developers alike.
• Quake Army Knife which is an environment for developing 3D maps for games based on the Quake engine It is written in Delphi and Python.
In the upcoming chapters, we will delve into the corepygame library and its applications in creating interactive computer games The next chapter will focus on pygame and the features it offers, while the subsequent chapter will guide developers in creating a simple interactive game where the player navigates a starship to avoid vertically descending meteors.
For further information games programming and the libraries mentioned in this chapter see:
• https://unity.com/the C# framework for games development.
• https://www.unrealengine.comfor C++ games development.
• http://arcade.academy/provides details on the Arcade games framework.
• http://www.pyglet.org/for information on the piglet library.
• http://cocos2d.org/is the home page for the Cocos2d framework.
• https://www.pygame.orgfor information on pygame.
• http://pyode.sourceforge.net/ for details of the PyODE bindings to the Open Dynamics Engine.
• http://www.pymunk.org/provides information on pymunk.
• https://github.com/pybox2d/pybox2d which is a Git hub repository for pyBox2d.
• https://git.blender.org/gitweb/gitweb.cgi/blender.git Git Hub repository for Blender.
• https://sourceforge.net/p/quark/code SourceForge repository for Quake Army Knife.
• https://www.autodesk.co.uk/products/maya/overview for information on Autodesks Maya computer animation software.
12.1 Introduction pygame is a cross-platform, free and Open Source Python library designed to make building multimedia applications such as games easy Development of pygame started back in October 2000 with pygame version 1.0 being released six months later The version of pygame discussed in this chapter is version 1.9.6 If you have a later version check to see what changes have been made to see if they have any impact on the examples presented here. pygame is built on top of the SDL library SDL (or Simple Directmedia Layer) is a cross platform development library designed to provide access to audio, key- boards, mouse, joystick and graphics hardware via OpenGL and Direct3D To promote portability, pygame also supports a variety of additional backends including WinDIB, X11, Linux Frame Buffer etc.
SDL officially supports multiple platforms, including Windows, Mac OS X, Linux, iOS, and Android, with unofficial support for others Written in C, SDL serves as a foundation for pygame, which enhances game development by providing additional functionalities not available in SDL These enhancements include vector mathematics, collision detection, 2D sprite scene graph management, MIDI support, camera control, pixel array manipulation, and transformations, making the creation of graphical and video games more accessible.
filtering, advanced freetype font support and drawing.
This chapter provides an introduction to Pygame, covering essential concepts, key modules, classes, and functions, along with a basic first application The following chapter will guide you through the development of a simple arcade-style video game, demonstrating the process of creating a game using Pygame.
J Hunt, Advanced Guide to Python 3 Programming ,
Undergraduate Topics in Computer Science, https://doi.org/10.1007/978-3-030-25943-3_12
The Display Surface (aka the display) is the most important part of a pygame game.
It is the main window display of your game and can be of any size, however you can only have one Display Surface.
The Display Surface functions like a blank canvas, allowing for creative expression through its pixel-based layout Each pixel is indexed, starting from the top left corner at coordinates 0,0, with locations organized along the x and y axes.