micheledpierri.com: statistics, data analysis and coding

Nexus of Statistics, Data analysis, Coding, Art and Medicine

Menu
  • Home
  • Courses
    • Python Foundation
    • Statistics
    • Data Analysis
    • Machine Learning
  • Blog
    • All Pages
    • Health Informatics
    • Programming
    • Art
  • Illustrations
  • About
  • Contact
Menu
Home / Programming / Page 2

Category: Programming

Programming tutorials for medical researchers and healthcare professionals. Python programming, SQL databases, data structures, coding paradigms, and software development for medical applications.

Early 20th-century doctor in a white coat examines a seated woman wrapped in a blanket inside a modest rural clinic, with wooden furniture, medicine bottles, an oil lamp, and snow-covered windows.

Matplotlib (2)

Posted on October 12, 2024June 20, 2026 by Michele Danilo Pierri

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 plt
import numpy as np

# Create a random dataset with normal distribution
data = np.random.randn(1000)

# Create a histogram
plt.figure(figsize=(10, 6))
plt.hist(data, bins=30, color='skyblue', edgecolor='black', alpha=0.7)

# Add title and labels
plt.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:

Distribution plot

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:

More detailed distribution plot

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 reproducibility
data = [np.random.normal(0, std, 100) for std in range(1, 4)]

# Create the boxplot
plt.figure(figsize=(10, 6))
plt.boxplot(data, patch_artist=True, notch=True, vert=True)

# Add title and labels
plt.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:

Boxplot

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 labels
plt.title('Scatter Plot', fontsize=16, fontweight='bold')
plt.xlabel('X Variable')
plt.ylabel('Y Variable')
plt.grid(True, linestyle='--', alpha=0.6)

plt.show()
Scatterplot

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
  • color: fill color of the bars
  • edgecolor: color of the bar borders

Here’s an example of code generating a bar chart:

categories = ['A', 'B', 'C', 'D']
values = [15, 30, 45, 10]

plt.figure(figsize=(10, 6))
plt.bar(categories, values, color='cadetblue', edgecolor='black')

# Add title and labels
plt.title('Category Count', fontsize=16, fontweight='bold')
plt.xlabel('Categories')
plt.ylabel('Count')
plt.grid(axis='y', linestyle='--', alpha=0.6)

plt.show()

The resulting graph looks like this:

bar chart

Line Graph

Line graphs are ideal for showing time series.

By indicating time intervals on the x-axis, we can see how values change over time.

The command that allows us to create line graphs is:

plt.plot()

which accepts as parameters:

  • date, values: pair of date and values on that date
  • colors and other parameters to adjust the graphical appearance

Here’s an example of a line graph:

dates = np.arange('2024-01', '2024-06', dtype='datetime64[D]')
values = np.random.randn(len(dates)).cumsum()

plt.figure(figsize=(12, 6))
plt.plot(dates, values, color='dodgerblue', linewidth=2)

# Add title and labels
plt.title('Time Series', fontsize=16, fontweight='bold')
plt.xlabel('Date')
plt.ylabel('Cumulative Value')
plt.xticks(rotation=45)
plt.grid(True, linestyle='--', alpha=0.6)

plt.show()
line graph

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.

A formally dressed man in early 20th-century attire stands in a grand, softly lit gallery, studying large framed charts and illustrated panels, with vaulted ceilings, tall windows, and a warm sepia-toned historical atmosphere.

Matplotlib (1)

Posted on October 12, 2024June 20, 2026 by Michele Danilo Pierri

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:

pip install matplotlib

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.

Structure of figure in matplotlib

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 graph
plt.figure(1)
plt.plot([1, 2, 3, 4])
plt.title("Graph 1")

# Create a new figure with another graph
plt.figure(2)
plt.plot([4, 3, 2, 1])
plt.title("Graph 2")

# Return to the first figure and add something
plt.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 graph
fig, ax = plt.subplots(1, 1, figsize=(10, 6))

# Create 4 graphs in a 2x2 layout on a 10 x 6 inch figure
fig, 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 columns
fig, 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))

axes layout in matplotlib

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).
  • linewidth (lw): Line thickness (numerical value).
  • marker: Point style. Examples: “o” (circle), “s” (square), “x” (cross), “d” (diamond).
  • markersize (ms): Size of markers.
  • markerfacecolor (mfc): Internal color of markers.
  • markeredgecolor (mec): Color of marker borders.
  • label: Legend label.
  • alpha: Line transparency (0 for fully transparent, 1 for fully opaque).

Now, let’s combine these elements to create a figure with four graphs in a 2×2 layout:

import matplotlib.pyplot as plt
import numpy as np

# Create a figure and a 2x2 grid of subplots
fig, axes = plt.subplots(2, 2, figsize=(10, 8), dpi=100)

# Generate some data to plot
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
y3 = np.tan(x)
y4 = np.exp(-x)

# Plot on the first axes (axes[0, 0])
axes[0, 0].plot(x, y1, color='b', linestyle='--', linewidth=2, marker='o', markersize=5)
axes[0, 0].set_title('Sine Wave')
axes[0, 0].set_xlabel('Time (s)')
axes[0, 0].set_ylabel('Amplitude')
axes[0, 0].grid(True)
axes[0, 0].set_xlim([0, 10])
axes[0, 0].set_ylim([-1.5, 1.5])

# Plot on the second axes (axes[0, 1])
axes[0, 1].plot(x, y2, color='r', linestyle='-', linewidth=1.5, marker='s', markersize=4)
axes[0, 1].set_title('Cosine Wave')
axes[0, 1].set_xlabel('Time (s)')
axes[0, 1].set_ylabel('Amplitude')
axes[0, 1].grid(True, which='both', axis='both')
axes[0, 1].set_xlim([0, 10])
axes[0, 1].set_ylim([-1.5, 1.5])

# Plot on the third axes (axes[1, 0])
axes[1, 0].plot(x, y3, color='g', linestyle='-.', linewidth=1, marker='d', markersize=6)
axes[1, 0].set_title('Tangent (limited range)')
axes[1, 0].set_xlabel('Time (s)')
axes[1, 0].set_ylabel('Value')
axes[1, 0].set_xlim([0, 10])
axes[1, 0].set_ylim([-10, 10])
axes[1, 0].grid(True)

# Plot on the fourth axes (axes[1, 1])
axes[1, 1].plot(x, y4, color='purple', linestyle=':', linewidth=3, marker='x', markersize=8)
axes[1, 1].set_title('Exponential Decay')
axes[1, 1].set_xlabel('Time (s)')
axes[1, 1].set_ylabel('Amplitude')
axes[1, 1].set_xlim([0, 10])
axes[1, 1].set_ylim([0, 1])

# Adjust the layout to prevent overlap of labels and titles
fig.tight_layout()

# Save the figure as an image
fig.savefig('subplot_figure_subplots.png', dpi=300)

# Show the figure
plt.show()

The resulting figure will look like this:

Exemples of figure created with matplotlib
Two impoverished boys kneel in a war-damaged street, placing coins into a piggy bank amid rubble and crumbling buildings, in a warm sepia-toned historical painting style.

SQL databases

Posted on August 31, 2024July 29, 2026 by Michele Danilo Pierri

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 library
import 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.

pip install mysql-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 details
connection = mysql.connector.connect(
    host='localhost',        # Hostname of the MySQL server (e.g., 'localhost' or an IP address)
    user='your_username',    # Your MySQL username
    password='your_password',# Your MySQL password
    database='database_name' # The name of the database to connect to
)

# Create a cursor object to interact with the database
cursor = connection.cursor()

# Example: Execute an SQL query to create a new table
cursor.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' table
cursor.execute('INSERT INTO users (name, age) VALUES (%s, %s)', ('Alice', 30))

# Commit the transaction to save changes
connection.commit()

# Example: Execute a query to fetch data from the 'users' table
cursor.execute('SELECT * FROM users')

# Fetch all rows from the result set
rows = cursor.fetchall()

# Loop through the rows and print each one
for row in rows:
    print(row)

# Close the cursor and connection to free up resources
cursor.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:

pip install PyMySQL

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 details
connection = pymysql.connect(
    host='localhost',        # Hostname of the MySQL server (e.g., 'localhost' or an IP address)
    user='your_username',    # Your MySQL username
    password='your_password',# Your MySQL password
    database='database_name' # The name of the database to connect to
)

# Create a cursor object to interact with the database
cursor = connection.cursor()

# Example: Execute an SQL query to create a new table
cursor.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' table
cursor.execute('INSERT INTO users (name, age) VALUES (%s, %s)', ('Alice', 30))

# Commit the transaction to save changes
connection.commit()

# Example: Execute a query to fetch data from the 'users' table
cursor.execute('SELECT * FROM users')

# Fetch all rows from the result set
rows = cursor.fetchall()

# Loop through the rows and print each one
for row in rows:
    print(row)

# Close the cursor and connection to free up resources
cursor.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.

pip install psycopg2-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 details
connection = 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 username
    password='your_password',# Your PostgreSQL password
    dbname='database_name'   # The name of the database to connect to
)

# Create a cursor object to interact with the database
cursor = connection.cursor()

# Example: Execute an SQL query to create a new table
cursor.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' table
cursor.execute('INSERT INTO users (name, age) VALUES (%s, %s)', ('Alice', 30))

# Commit the transaction to save changes
connection.commit()

# Example: Execute a query to fetch data from the 'users' table
cursor.execute('SELECT * FROM users')

# Fetch all rows from the result set
rows = cursor.fetchall()

# Loop through the rows and print each one
for row in rows:
    print(row)

# Close the cursor and connection to free up resources
cursor.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:

pip install SQLAlchemy

Example of code using SQLAlchemy:

from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.ext.declarative import declarative_base
from 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 MySQL
engine = create_engine('sqlite:///example.db', echo=True)

# Create a base class for our class definitions
Base = declarative_base()

# Define a User class that maps to the 'users' table in the database
class User(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 type

    def __repr__(self):
        return f"<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 database
Session = sessionmaker(bind=engine)
session = Session()

# Add a new user to the session
new_user = User(name='Alice', age=30)
session.add(new_user)

# Commit the session to save the new user to the database
session.commit()

# Query the database to retrieve all users
users = session.query(User).all()

# Print the retrieved users
for user in users:
    print(user)

# Close the session
session.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.

Among these are: Oracle Database – Oracle Database, Microsoft SQL Server – Microsoft SQL Server, IBM Db2 – IBM Db2, SAP HANA – SAP HANA, Teradata – Teradata, Amazon Aurora (Part of Amazon RDS) – Amazon Aurora, Snowflake – Snowflake, Oracle TimesTen – Oracle TimesTen, Couchbase – Couchbase, Vertica – Vertica

Ancient stone labyrinth with ornate carved pathways and a central spiral motif, illuminated by warm golden light.

Python Environments

Posted on July 30, 2024June 19, 2026 by Michele Danilo Pierri

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:

pip install name_library

or, in conda environment:

conda install name_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 is

python -m venv environment_name

# the conda command is

conda create -—name environment_name python= 3.X

Once the environment is created, it can be activated for use:

# in windows

environment_name\scripts\activate

# con conda

conda activate environment_name

# in linux or MacOS

source environment_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 conda

conda deactivate

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:

folder structure of python environment in Window

On linux or Mac OS:

folder structure of python environment in Mac and Linux

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:

pip freeze > requirement.txt

The structure of the requirements.txt file consists of a simple list of libraries and versions:

Example of requirements.txt

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 environment

python -m venv new_env

# activate the new environment

new_env/Scripts/activate # in windows

source new_env/bin/activate # in linux MacOS

# intall all librarias listed in requirements.txt file

pip install -r requirements.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 dependencies

conda old_env export > requirements.yml

# Creation of a new environment using the exported dependencies

conda new_env create -f environment.yml

# Activation of the new environment

conda activate new_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.

Early 20th-century physician using an optical device to examine an illuminated human skeleton in a vintage medical laboratory.

Exploring DICOM

Posted on July 17, 2024July 28, 2026 by Michele Danilo Pierri

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:

pip install pydicom

The following program reads the attributes of the DICOM (.dcm) file specified in the “dicom_file_path” variable.

import pydicom

def print_dicom_attributes(dicom_file):
    # Load the DICOM file
    ds = pydicom.dcmread(dicom_file)

    # Iterate over all data elements in the DICOM dataset
    for element in ds:
        # Extract the tag, name, and value of the DICOM attribute
        tag = element.tag
        name = element.name
                
        # Print the attribute information
        print(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 pydicom

def print_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 values
    for tag, description in important_tags.items():
        if tag in ds:
            value = ds.data_element(tag).value
            print(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.

  • Previous
  • 1
  • 2
© 2024–2026 micheledpierri.com · Privacy Policy · Impressum