Programming tutorials for medical researchers and healthcare professionals. Python programming, SQL databases, data structures, coding paradigms, and software development for medical applications.
Following our general introduction to the matplotlib environment, let’s explore the types of graphs this Python library can produce.
Among the most commonly used graphs for data presentation are:
Histograms
Box plots
Scatter plots
Bar charts
Line graphs
Histograms
Histograms primarily illustrate the distribution of a continuous variable. The data is divided into uniform intervals (bins), and the frequency of each bin is represented.
You can create histograms using the following function:
plt.hist()
This function accepts several arguments:
bins: number of intervals for dividing the data
color and edgecolor: fill color of the bars and color of their edges
alpha: controls the transparency of the bars
The following program generates a series of data with normal distribution and displays them using histograms:
import matplotlib.pyplot as pltimport numpy as np# Create a random dataset with normal distributiondata = np.random.randn(1000)# Create a histogramplt.figure(figsize=(10, 6))plt.hist(data, bins=30, color='skyblue', edgecolor='black', alpha=0.7)# Add title and labelsplt.title('Data Distribution', fontsize=16, fontweight='bold')plt.xlabel('Values')plt.ylabel('Frequency')plt.grid(axis='y', linestyle='--', alpha=0.6)plt.show()
The resulting graph looks as follows:
To increase the detail of the distribution, we can increase the number of bins. In the following example, we’ve increased the number of bins from 30 to 300:
Box Plots
Box plots (also known as box-and-whisker plots) are ideal for highlighting the distribution of continuous variables in quartiles. The box shows the data ranging from the first to the third quartile, with the median highlighted. Outliers are also displayed.
Box plots are created with the function:
plt.boxplot()
The key parameters are:
data: the variable containing the values
patch_artist: boolean, indicates whether the box plot should be filled with colors
notch: boolean, indicates the confidence interval of the median
vert: boolean, specifies whether the graph should be oriented vertically
Let’s create a box plot using normally distributed data. We’ll generate a list (data) containing three groups of 100 random numbers. Each group will have a mean of 0 and standard deviations of 1, 2, and 3 respectively.
np.random.seed(10) # Set a seed for reproducibilitydata = [np.random.normal(0, std, 100) for std inrange(1, 4)]# Create the boxplotplt.figure(figsize=(10, 6))plt.boxplot(data, patch_artist=True, notch=True, vert=True)# Add title and labelsplt.title('Data Distribution with Boxplot', fontsize=16, fontweight='bold')plt.xlabel('Dataset')plt.ylabel('Values')plt.xticks([1, 2, 3], ['Dataset 1', 'Dataset 2', 'Dataset 3'])plt.grid(axis='y', linestyle='--', alpha=0.6)plt.show()
The resulting graph will look like this:
Scatter Plots
Scatter plots are used to highlight relationships between two variables, revealing trends and correlations. They’re particularly useful for visualizing how one variable changes to another.
To generate a scatter plot, use the following function:
plt.scatter()
The key parameters for this function are:
x and y: the variables containing the values to be compared
color and edgecolor: colors of the points and their borders
alpha: transparency level, which can help highlight overlapping points
Here’s an example of how to create a scatter plot comparing two variables:
np.random.seed(0)x = np.random.rand(100)y =2* x + np.random.normal(0, 0.1, 100)plt.figure(figsize=(10, 6))plt.scatter(x, y, color='teal', alpha=0.7, edgecolor='k')# Add title and labelsplt.title('Scatter Plot', fontsize=16, fontweight='bold')plt.xlabel('X Variable')plt.ylabel('Y Variable')plt.grid(True, linestyle='--', alpha=0.6)plt.show()
Bar Charts
Bar charts effectively display the count or frequency of categorical data. They provide a clear visual representation of data categories and their corresponding values.
To generate a bar chart, use the following function:
plt.bar()
This function accepts several key parameters:
categories, values: pairs of categories and their corresponding counts or frequencies
The already impressive capabilities of matplotlib can be significantly enhanced by incorporating the Seaborn library. Built upon matplotlib’s foundation, Seaborn offers a user-friendly approach to creating intricate and visually appealing graphs. This powerful combination allows data scientists and analysts to effortlessly generate complex visualizations, expanding the range of possibilities for data representation and analysis.
Python offers several libraries for creating professional graphs, but Matplotlib stands out as the foundation upon which many others are built. Often referred to by its alias “plt,” Matplotlib enables users to generate complex, element-rich graphs as well as multiple visualizations. Another popular library, Seaborn (alias “sns”), functions as an extension of Matplotlib and requires its installation to operate. Seaborn enhances both procedural management and graphical handling compared to Matplotlib. In this article, we’ll explore Matplotlib, beginning with its fundamental concepts and progressing to the development of more sophisticated statistical graphs.
Installation and Importing Matplotlib
To install Matplotlib, enter the following command in your terminal:
pipinstallmatplotlib
It’s best to perform this installation within a virtual environment.
After installation, import the library into your Python program with:
import matplotlib.pyplot as plt
Conventionally, Matplotlib is aliased as “plt”. Note that we typically import the pyplot module directly. This module offers functionality similar to MATLAB—a widely used program in scientific and technical fields—and provides access to advanced graphing functions.
Figure, Axes, and Plot
To fully comprehend Matplotlib, it’s crucial to understand the relationship between figure, axes, and plot.
The figure is the entire window or area of the graph we’re creating—the foundation for any Matplotlib visualization. Without it, we’d have nowhere to place our graphs. Think of it as an artist’s blank canvas: it’s the space where all our graphical elements come to life. A single figure can house one or more graphs, enabling complex, multi-dimensional visualizations. Far from being a passive container, the figure actively shapes how we organize and present our data.
Axes represent individual drawing areas within a figure, each containing a specific graph. This structure offers great flexibility. In its simplest form, we might have a single axes within a figure. But the real power emerges when creating complex visualizations—a single figure can host multiple axes, allowing us to present two, three, or more graphs simultaneously. This feature is particularly useful for comparing different datasets or showing various perspectives of the same information, providing a comprehensive view of our data.
Plot is the key function that brings our data to life on an axes. It’s the heart of Matplotlib’s graphic creation, transforming abstract numbers into visual representations. With plot, we define not only the basic shape of our graph—whether lines, points, or bars—but also customize every aspect of the visualization. This includes colors, line styles, point sizes, and even element transparency.
Figure
Moving on to practical aspects, the creation of a figure is done by specifying its dimensions as a parameter:
fig = plt.figure(figsize=(10,6))
fig is the figure we have created using the plt.figure module; figsize is the parameter that allows us to specify its dimensions. In this specific case, we have created a figure, called fig, with dimensions of 10 x 6 inches.
Other parameters that can be applied to figure are:
dpi: resolution of the figure in dots per inch
facecolor: background color
edgecolor: border color
tight_layout: optimizes the layout of contents
savefig: saves the entire figure in various formats (e.g., savefig(“figure.png”, dpi=300, transparent=True saves the figure with the specified name and format, with a resolution of 300 dpi and with a transparent background)
Axes
To add an axes to our figure, we use the add_subplot method:
ax = fig.add_subplot(1,1,1)
ax is the axes we have created on the figure fig. The axis is positioned on the first row, first column, and is the first graph of the figure (1,1,1) which, in the case of single graphs, is also the only axes present.
If we want to use only one axes, we don’t even need to create it. It is generated automatically. We just need to create a figure and start plotting.
Every time we create a figure, it becomes the active figure and all subsequent graphical commands will refer to it. If we want to create multiple figures and switch between them when adding graphical elements, we can identify the figure with a number (figure(1), for example) and recall it whenever we want to work on it:
# Create a figure with a graphplt.figure(1)plt.plot([1, 2, 3, 4])plt.title("Graph 1")# Create a new figure with another graphplt.figure(2)plt.plot([4, 3, 2, 1])plt.title("Graph 2")# Return to the first figure and add somethingplt.figure(1)plt.xlabel("X-axis")
The subplots function allows us to create figures and axes with a single command. This versatile method works for both single and multiple graph layouts:
fig, ax = plt.subplots()
The subplots function takes three key parameters:
nrows: number of rows (default is 1)
ncols: number of columns (default is 1)
figsize: dimensions of the figure in inches
# Create a single 10 x 6 inch graphfig, ax = plt.subplots(1, 1, figsize=(10, 6))# Create 4 graphs in a 2x2 layout on a 10 x 6 inch figurefig, ax = plt.subplots(2, 2, figsize=(10, 6))
Compared to the older subplot method, which only allows creating one axes at a time, subplots offers greater flexibility. It’s now the preferred choice in modern Matplotlib programming.
After creating a figure and one or more axes, we can begin drawing our graphs within these axes. Each axes is identified as a two-dimensional array, indicating its row and column position:
# Create a figure with 4 axes arranged in two rows and two columnsfig, ax = plt.subplots(2, 2, figsize=(10, 6))# Draw on the first axes (top-left)ax[0, 0].plot(...)# Draw on the second axes (top-right)ax[0, 1].plot(...)# Draw on the third axes (bottom-left)ax[1, 0].plot(...)# Draw on the fourth axes (bottom-right)ax[1, 1].plot(...)
Below are the layouts of the axes created with the following commands:
fig, axes = plt.subplots(1, 1, figsize=(x, x))
fig, axes = plt.subplots(2, 2, figsize=(x, x))
fig, axes = plt.subplots(2, 1, figsize=(x, x))
Several parameters can be applied to axes to customize their appearance. The most important ones are:
set_xlim and set_ylim: Define the axis range. For example, set_xlim([0, 10]) sets the x-axis from 0 to 10.
set_xlabel and set_ylabel: Set the axis labels.
set_title: Set the graph title.
set_xticks and set_yticks: Place reference marks on the axes. For example, set_xticks([1, 2, 3, 4, 5]) adds ticks at those values.
grid: A boolean to show (True) or hide (False) the grid.
set_facecolor: Set the background color.
spines: Control the visibility and color of borders. For example, spine[“top”].set_visible(False) removes the top border, while spine[“right”].set_color(“blue”) colors the right border blue.
tight_layout: Optimize the layout of multiple graphs.
autoscale: Adjust the axes to fit the data.
axis: Control axis visibility. axis(“off”) hides all axes, while axis(“equal”) makes axis limits equal on all axes.
Once we’ve set up the number, arrangement, and appearance of the axes (and thus the graphs) on the figure, we can proceed to draw the graphs using the plot method.
Plot
The plot function offers numerous parameters for extensive graph customization:
x, y: Coordinates of points to plot. These are typically arrays or lists of coordinate values, not just single points.
color: Line color. Specify using color names (“red”, “blue”), abbreviations (“r” for red, “b” for blue), or hexadecimal codes (“#FF5733”).
linestyle (ls): Line style. Options include “-” (solid), “–” (dashed), “-.” (dash-dot), and “:” (dotted).
In Python data management, SQL databases become essential when dealing with large data volumes. These databases efficiently handle extensive structured data, offering robust features for complex querying, maintaining data integrity, and managing storage effectively. As datasets grow in size and complexity, SQL databases provide the necessary scalability, performance optimization, and data consistency mechanisms crucial for effective large-scale data analysis and manipulation.
SQL is a powerful language for data manipulation, enabling complex queries, joins, and aggregations of structured data. Python offers various libraries that facilitate interaction with SQL databases, efficiently executing CRUD operations (Create, Read, Update, Delete). These libraries include sqlite3 for SQLite, pymysql for MySQL, psycopg2 for PostgreSQL, and SQLAlchemy as an ORM (Object-Relational Mapping) library. Below, I’ll demonstrate how to use some of these libraries with code examples.
SQLite
SQLite is a lightweight, serverless database that can be directly integrated into Python applications. It is widely appreciated for its simplicity, portability, and ease of use. These qualities make it ideal for desktop applications, mobile apps, small websites, development tools, and other scenarios where a complex, server-based database management system is unnecessary.
In SQLite, all data—including table definitions, indexes, and the data itself—is stored in a single file. This design makes the database portable and easy to manage. Despite its simplicity, SQLite supports most SQL standards.
Python’s built-in sqlite3 module is used for working with SQLite databases. As part of Python’s standard library, the SQLite module requires no additional installation.
# Import the sqlite3 module, which is part of Python's standard libraryimport sqlite3 # Create a connection to an SQLite database.# If the database file 'example.db' does not exist, it will be created in the current directory.conn = sqlite3.connect('example.db')# Create a cursor object.# A cursor is used to execute SQL commands and interact with the database.cursor = conn.cursor()# Execute an SQL command to create a new table named 'users' if it doesn't already exist.# The table has three columns: 'id', 'name', and 'age'.# - 'id' is an INTEGER and serves as the PRIMARY KEY, which is unique for each row and auto-incremented.# - 'name' is a TEXT field and cannot be NULL.# - 'age' is an INTEGER field.cursor.execute('''CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, age INTEGER)''')# Insert a new row into the 'users' table.# The '?' placeholders are used to securely insert the values ('Alice' and 30) to prevent SQL injection.cursor.execute('INSERT INTO users (name, age) VALUES (?, ?)', ('Alice', 30))# Commit the current transaction. This saves all the changes made to the database since the last commit.# Without this, the changes (inserting data in this case) would not be saved to the 'example.db' file.conn.commit()# Execute a SQL query to retrieve all rows from the 'users' table.cursor.execute('SELECT * FROM users')# Fetch all the results of the last executed SQL command (SELECT).# This returns a list of tuples, where each tuple represents a row from the result set.rows = cursor.fetchall()# Iterate over the rows and print each one.# Each 'row' is a tuple containing the values of each column for that specific row.for row in rows:print(row)# Close the connection to the database.# This is important to ensure all changes are saved and to free up resources.conn.close()
MySQL
MySQL is a robust and feature-rich relational database management system (RDBMS) that requires installation and setup outside of Python.
Unlike SQLite, which is serverless and embedded, MySQL operates as a separate database server running independently of Python applications.
To use MySQL, you must install the MySQL server software on your machine or use a managed MySQL service (e.g., AWS RDS, Azure Database for MySQL). The MySQL server needs to be configured and started separately from your Python environment. Once installed, the server runs as a service or process that manages database operations and responds to client requests.
Your Python application acts as a client, connecting to the MySQL server using a network protocol (typically TCP/IP). Multiple clients can connect to the server simultaneously, enabling high concurrency and centralized database management.
To connect to a MySQL database from Python, you need to use an external library or driver, such as mysql-connector-python, PyMySQL, or MySQLdb. These libraries must be installed separately using the package manager pip.
To connect to a MySQL database from Python, you first need to install the MySQL Connector library.
pipinstallmysql-connector-python
After installing the library, you can import and use it in Python as follows:
import mysql.connector # Import the mysql-connector library# Establish a connection to the MySQL server# Replace 'localhost', 'user', 'password', and 'database_name' with your MySQL server detailsconnection = mysql.connector.connect(host='localhost', # Hostname of the MySQL server (e.g., 'localhost' or an IP address)user='your_username', # Your MySQL usernamepassword='your_password',# Your MySQL passworddatabase='database_name'# The name of the database to connect to)# Create a cursor object to interact with the databasecursor = connection.cursor()# Example: Execute an SQL query to create a new tablecursor.execute('''CREATE TABLE IF NOT EXISTS users ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) NOT NULL, age INT)''')# Example: Insert a new row into the 'users' tablecursor.execute('INSERT INTO users (name, age) VALUES (%s, %s)', ('Alice', 30))# Commit the transaction to save changesconnection.commit()# Example: Execute a query to fetch data from the 'users' tablecursor.execute('SELECT * FROM users')# Fetch all rows from the result setrows = cursor.fetchall()# Loop through the rows and print each onefor row in rows:print(row)# Close the cursor and connection to free up resourcescursor.close()connection.close()
Another popular library used in Python to interact with MySQL databases is PyMySQL.
Before using PyMySQL, you need to install it via pip:
pipinstallPyMySQL
The use of PyMySQL in Python doesn’t differ significantly from the previously illustrated mysql-connector-python library. Both provide similar functionality for interacting with MySQL databases.
import pymysql # Import the PyMySQL library# Establish a connection to the MySQL server# Replace 'localhost', 'user', 'password', and 'database_name' with your MySQL server detailsconnection = pymysql.connect(host='localhost', # Hostname of the MySQL server (e.g., 'localhost' or an IP address)user='your_username', # Your MySQL usernamepassword='your_password',# Your MySQL passworddatabase='database_name'# The name of the database to connect to)# Create a cursor object to interact with the databasecursor = connection.cursor()# Example: Execute an SQL query to create a new tablecursor.execute('''CREATE TABLE IF NOT EXISTS users ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(100) NOT NULL, age INT)''')# Example: Insert a new row into the 'users' tablecursor.execute('INSERT INTO users (name, age) VALUES (%s, %s)', ('Alice', 30))# Commit the transaction to save changesconnection.commit()# Example: Execute a query to fetch data from the 'users' tablecursor.execute('SELECT * FROM users')# Fetch all rows from the result setrows = cursor.fetchall()# Loop through the rows and print each onefor row in rows:print(row)# Close the cursor and connection to free up resourcescursor.close()connection.close()
PostgreSQL
PostgreSQL is a versatile database management system, akin to a Swiss Army knife. It’s highly sophisticated and capable of handling diverse tasks, ranging from traditional data storage to cutting-edge applications requiring complex data processing. Its popularity stems from several key attributes:
PostgreSQL exhibits exceptional robustness and resilience, demonstrating high fault tolerance and stability under various operational conditions. It implements advanced data integrity mechanisms and ensures ACID (Atomicity, Consistency, Isolation, Durability) compliance, safeguarding data accuracy and reliability. The system adheres rigorously to SQL standards, facilitating seamless integration and interoperability. PostgreSQL’s extensible architecture allows for the incorporation of custom functions, data types, and procedural languages, enhancing its adaptability to diverse use cases. Furthermore, it demonstrates remarkable scalability, efficiently managing increasing data volumes and concurrent user loads without compromising performance.
These technical attributes render PostgreSQL an optimal choice for both individual developers and large-scale enterprises seeking a database management system that combines reliability with high-performance capabilities.
PostgreSQL, like most traditional relational database management systems (RDBMS), requires installation on a local or remote server and employs a client-server architecture. This setup means your Python application (or any other client application) must establish a connection to the PostgreSQL server via TCP/IP or through a local Unix socket.
Psycopg2 is the most popular Python library for interacting with PostgreSQL. It must be installed using pip, Python’s package installer.
pipinstallpsycopg2-binary
The use in Python is in sameway similar to the others libraries:
import psycopg2 # Import the psycopg2 library# Establish a connection to the PostgreSQL server# Replace 'localhost', 'user', 'password', and 'database_name' with your PostgreSQL server detailsconnection = psycopg2.connect(host='localhost', # Hostname of the PostgreSQL server (e.g., 'localhost' or an IP address)port='5432', # Port number (default is 5432 for PostgreSQL)user='your_username', # Your PostgreSQL usernamepassword='your_password',# Your PostgreSQL passworddbname='database_name'# The name of the database to connect to)# Create a cursor object to interact with the databasecursor = connection.cursor()# Example: Execute an SQL query to create a new tablecursor.execute('''CREATE TABLE IF NOT EXISTS users ( id SERIAL PRIMARY KEY, name VARCHAR(100) NOT NULL, age INT)''')# Example: Insert a new row into the 'users' tablecursor.execute('INSERT INTO users (name, age) VALUES (%s, %s)', ('Alice', 30))# Commit the transaction to save changesconnection.commit()# Example: Execute a query to fetch data from the 'users' tablecursor.execute('SELECT * FROM users')# Fetch all rows from the result setrows = cursor.fetchall()# Loop through the rows and print each onefor row in rows:print(row)# Close the cursor and connection to free up resourcescursor.close()connection.close()
SQLAlchemy
SQLAlchemy isn’t a database engine like MySQL, PostgreSQL, or SQLite. It doesn’t directly manage or store data. Rather, it offers a high-level interface for connecting to and interacting with various relational databases using Python code.
SQLAlchemy is an Object-Relational Mapping (ORM) library that offers a comprehensive toolkit for database interaction. It bridges the gap between object-oriented programming and relational databases, allowing developers to work with Python objects instead of writing raw SQL queries.
SQLAlchemy is database-agnostic. This means it can work with various database backends such as MySQL, PostgreSQL, SQLite, Oracle, and Microsoft SQL Server. It enables developers to write code that doesn’t depend on a specific database engine, making it easier to switch databases if necessary.
To use SQLAlchemy, install it via pip:
pipinstallSQLAlchemy
Example of code using SQLAlchemy:
from sqlalchemy import create_engine, Column, Integer, Stringfrom sqlalchemy.ext.declarative import declarative_basefrom sqlalchemy.orm import sessionmaker# Create an engine that connects to an SQLite database file named 'example.db'# You can replace 'sqlite:///example.db' with the connection string for other databases like PostgreSQL or MySQLengine = create_engine('sqlite:///example.db', echo=True)# Create a base class for our class definitionsBase = declarative_base()# Define a User class that maps to the 'users' table in the databaseclassUser(Base): __tablename__ ='users'id= Column(Integer, primary_key=True) # 'id' column with an integer type, set as the primary key name = Column(String, nullable=False) # 'name' column with a string type, cannot be NULL age = Column(Integer) # 'age' column with an integer typedef__repr__(self):returnf"<User(name='{self.name}', age={self.age})>"# Create the 'users' table in the database (if it doesn't exist already)Base.metadata.create_all(engine)# Create a configured "Session" class and a session object to interact with the databaseSession = sessionmaker(bind=engine)session = Session()# Add a new user to the sessionnew_user = User(name='Alice', age=30)session.add(new_user)# Commit the session to save the new user to the databasesession.commit()# Query the database to retrieve all usersusers = session.query(User).all()# Print the retrieved usersfor user in users:print(user)# Close the sessionsession.close()
Additionally, numerous commercial Database Management Systems (DBMS) exist, each offering unique features tailored for specific use cases such as data warehousing, real-time analytics, high transaction volumes, or industry-specific needs. These commercial systems often provide enterprise-grade features, professional support, advanced security, and compliance tools—making them a preferred choice for large organizations where these factors are critical. However, they typically require licenses and come at a higher cost compared to open-source alternatives.
Python has a rich standard library that covers basic functionalities and common tasks in programming. This includes modules for file handling, system operations, networking, and simple web development, allowing you to accomplish many tasks without additional tools. However, for more complex or specialized programs, you often need external libraries. These libraries significantly extend the program’s capabilities, enabling advanced data analysis, machine learning, scientific computing, and other specialized functions beyond what the standard library provides.
Most external Python libraries are found in a repository called PyPI (Python Package Index). It hosts thousands of libraries that can be installed in Python using the package manager “pip.”
On the PyPI site, you can search for libraries using filters or by taking advantage of the organization into categories. The filters allow you to narrow down your search based on parameters such as programming language, license type, and compatibility with different operating systems. Additionally, the categories help you find libraries specific to certain fields like web development, data science, or machine learning, making it easier to locate the tools you need for your project.
Besides PyPI, many libraries, especially those related to data science and scientific processing, are found on Conda systems (AnaConda and MiniConda), which use “conda” as a package manager.
Besides PyPI, many libraries, especially those related to data science and scientific processing, are found on Conda systems (AnaConda and MiniConda), which use “conda” as a package manager.
The Conda libraries are available on both Anaconda Cloud and Conda-Forge, containing useful packages for data science, machine learning, and bioinformatics.
Once the necessary library is identified, it can be installed and used in your Python application using a terminal command:
pipinstallname_library
or, in conda environment:
condainstallname_library
Compared to PyPI, Conda offers more robust dependency and environment management, especially for libraries that need to be compiled or have system dependencies.
To build a Python project, especially if it is complex or highly specialized, we need to find and install the specific libraries. In a Python project, there can be dozens or even hundreds of external libraries.
Some libraries need other libraries to function, and so on, creating dependencies and dependencies of dependencies (or transitive dependencies), which can make the system even more complex.
It may happen that two libraries installed on our system have common dependencies for the same library, but in different versions. This situation can cause a conflict known as “dependency hell,” where the system struggles to satisfy the version requirements for both libraries. As a result, it can lead to issues in the functionality or stability of the software, making it difficult to manage and resolve these dependency conflicts.
Other times, there are libraries that work only with specific versions of Python.
These situations can become unmanageable if we use the same Python installation for all the applications we develop.
For these reasons, it is strongly recommended to create a “virtual environment” for each project or group of similar projects to “isolate” the libraries and avoid conflicts. A virtual environment is an “isolated” system consisting of a version of Python and all the libraries needed for a project (or a similar group of projects). We can create a dedicated virtual environment for each project.
The virtual environment is easily replicable. It can be reconstructed and regenerated on another system, facilitating collaboration and application deployment. Additionally, the environments can use different versions of Python for different projects.
The first step is to create a virtual environment to ensure dependencies and packages do not interfere with the system-wide Python environment. Once the virtual environment is set up, activate it to work within this isolated setup. Activation ensures that any installations or changes are contained within the virtual environment.
There are various ways to create virtual environments: one option is to use venv, which has been integrated into Python since version 3.3; the other option is using conda.
# The venv command ispython-mvenvenvironment_name# the conda command iscondacreate-—nameenvironment_namepython=3.X
Once the environment is created, it can be activated for use:
# in windowsenvironment_name\scripts\activate# con condacondaactivateenvironment_name# in linux or MacOSsourceenvironment_name/bin/activate
With the activation of the environment changes occur. One primary change is that the prompt itself is modified. Specifically, the name of the activated environment appears at the beginning of the command line. This visual cue reminds the user that they are working within a particular environment, ensuring that commands and operations are executed in the correct context.
The environment can be deactivated with the command:
deactivate# or, with condacondadeactivate
Each time a virtual environment is created, a dedicated folder for the environment is made in the directory from which the environment was created. Typically, this is the directory where we will develop our program. This folder contains several subfolders that house various components of the virtual environment. These subfolders include executables, libraries, and scripts necessary for the isolated environment to function properly. By organizing these components within a specific directory, it ensures that the dependencies and packages used in one project do not interfere with those used in another. This approach not only prevents conflicts but also makes it easier to manage and replicate the environment on different systems.
The structure of these folders varies depending on whether you use a Windows or Linux/Mac OS environment.
On Windows:
On linux or Mac OS:
The bin/ directory (in Linux/macOS) or Scripts/ (in Windows) contains the executables and scripts of the virtual environment, including the Python interpreter.
The lib/ folder (in Unix-MacOS) or Lib/ (in Windows) contains the libraries specific to the environment. In the site-packages/ subfolder, you will find all the installed Python packages.
The folders include/Include contain the header files for compiling Python packages that use the C or C++ languages.
pyvenv.cfg is a configuration file that stores information about the virtual environment.
Using Visual Studio Code as an IDE (Integrated Development Environment), you can issue commands directly from the integrated terminal window. Additionally, you can select the Python environment from the Command Palette. Access it through the menu by navigating to View and selecting Command Palette, or use the shortcut Ctrl+Shift+P. This flexibility allows for easy switching between different Python interpreters and environments, managing various projects and dependencies.
The creation of Python environments makes replication easy. To recreate a Python environment with all the installed libraries on another system, you first need a list of the libraries (including their versions) in the environment.
To do this, export the list of libraries and their versions to a requirements.txt file with the command:
pipfreeze>requirement.txt
The structure of the requirements.txt file consists of a simple list of libraries and versions:
To replicate an environment on another system or after a reinstallation, create a new virtual environment, activate it, and install the libraries listed in the requirements.txt file.
# create e new virtuale environmentpython-mvenvnew_env# activate the new environmentnew_env/Scripts/activate# in windowssourcenew_env/bin/activate# in linux MacOS# intall all librarias listed in requirements.txt filepipinstall-rrequirements.txt
With Conda, the procedure differs slightly because a Conda environment can contain not only Python packages but also other configurations, such as dependencies required by different programming languages and various system libraries.
# Exporting environment dependenciescondaold_envexport>requirements.yml# Creation of a new environment using the exported dependenciescondanew_envcreate-fenvironment.yml# Activation of the new environmentcondaactivatenew_env
Essentially, the difference between replicating an environment with pip and conda is that conda uses the requirements.yml file, which includes system dependencies and other specifications. However, the purpose remains the same: exporting the configuration data of an environment and using it to recreate a similar environment.
DICOM stands for Digital and Communications in Medicine and is used for managing medical data. One of the most common uses of this format is the storage, transfer, and display of diagnostic images like X-rays, CT scans, and MRIs.
While there are variations depending on the type of image and the manufacturer of the equipment that generated it, a DICOM file contains some common elements:
HEADER: The initial part of the file contains metadata describing its content (patient identification, image acquisition modality, parameters for acquiring the images, equipment manufacturer, etc.).
ATTRIBUTE GROUPS: The metadata in the header is organized into attribute groups containing a series of DICOM tags that provide specific information. For example, tag 0010,0010 specifies the patient’s name.
TRANSFER SYNTAX: Specifies how the data is encoded and stored.
IMAGE: Contains the pixels or voxels that make up the image, which may be compressed or uncompressed.
TRAILER: Indicates the end of the DICOM file and may be absent.
The main attributes of a DICOM file include:
PatientName: Patient’s name.
PatientAge: Patient’s age.
StudyDate: Date of the study.
StudyDescription: Study description.
Modality: Imaging modality used (e.g., CT, MR, X-ray, etc.).
Manufacturer: Imaging equipment manufacturer.
Rows: Number of rows in the image.
Columns: Number of columns in the image.
PixelData: Image pixel data.
ImageOrientationPatient: Image orientation relative to the patient.
ImagePositionPatient: Spatial position of the image relative to the patient.
SliceThickness: Slice thickness in an imaging volume.
PixelSpacing: Pixel spacing in the image.
When examining a DICOM file related to angiographic images, the modality will be XA. The study type attribute will specify whether it is coronary, cerebral, or another type of angiography. The sequence type attribute indicates the direction of the subsequent images (anteroposterior, lateral, oblique). The number of images in the sequence is usually indicated by the “NumberOfFrames” tag.
A very useful library for working with DICOM files in Python is pydicom. It is the one we will use for all work on DICOM files.
Before accessing it, you need to install it by running the following command in the terminal:
pipinstallpydicom
The following program reads the attributes of the DICOM (.dcm) file specified in the “dicom_file_path” variable.
import pydicomdefprint_dicom_attributes(dicom_file):# Load the DICOM file ds = pydicom.dcmread(dicom_file)# Iterate over all data elements in the DICOM datasetfor element in ds:# Extract the tag, name, and value of the DICOM attribute tag = element.tag name = element.name# Print the attribute informationprint(f"Tag: {tag}, Name: {name}")if__name__=="__main__":# Specify the path to the DICOM file dicom_file_path ="path/to/your/dicom/file.dcm"# Call the function to print DICOM attributes print_dicom_attributes(dicom_file_path)
The list of attributes obtained is often very long and not very useful.
We can limit the number of attributes to those we are interested in and read their contents. In the following program, we created a dictionary containing some specific attributes and read them:
import pydicomdefprint_important_dicom_attributes(dicom_file):# Load the DICOM file ds = pydicom.dcmread(dicom_file)# Define a list of important tags to print important_tags = {"PatientName": "Patient's Name","PatientID": "Patient's ID","PatientBirthDate": "Patient's Birth Date","PatientSex": "Patient's Sex","StudyID": "Study ID","StudyDate": "Study Date","StudyTime": "Study Time","SeriesNumber": "Series Number","Modality": "Modality","Rows": "Number of Rows in Image","Columns": "Number of Columns in Image","NumberOfFrame": "Number of Frames in Sequence }# Iterate over the important tags and print their valuesfor tag, description in important_tags.items():if tag in ds: value = ds.data_element(tag).valueprint(f"{description} ({tag}): {value}")else:print(f"{description} ({tag}): Not Available")if__name__=="__main__":# Specify the path to the DICOM file dicom_file_path ="path/to/your/dicom/file.dcm"# Call the function to print important DICOM attributes print_important_dicom_attributes(dicom_file_path)
The output is as follows:
Patient’s Name (PatientName): XXXXXX^XXXXXX
Patient’s ID (PatientID): 000000000000000000
Patient’s Birth Date (PatientBirthDate): 19000402
Patient’s Sex (PatientSex): M
Study ID (StudyID): 2020000
Study Date (StudyDate): 20200000
Study Time (StudyTime): 084611.000
Series Number (SeriesNumber): 1
Modality (Modality): XA
Number of Rows in Image (Rows): 512
Number of Columns in Image (Columns): 512
Number of Frames in Sequence (NumberOfFrames): 86
In an upcoming article, we will delve into the part of the file containing the image pixels to view and manage them.