Unit V · Basics of Python Programming for Pharmaceutical Sciences (BP101T) · As per PCI B.Pharmacy Syllabus, NEP 2020
With Matplotlib set up, the next step is learning the specific chart types a pharmacy graduate will reach for again and again: line plots for tracking a value over time, histograms for understanding how a set of measurements is distributed, scatter plots for spotting relationships between two variables, and box plots for comparing spread and outliers across groups. This article works through all four, building from a basic call to a fully customised, publication-ready figure at each stage.

A Quick Note on the Code Examples
Because the examples in this article are written to run inside the free W3Schools online Python compiler, each one switches Matplotlib to the non-interactive “Agg” backend and, immediately after the usual plt.show() call, adds two extra lines — plt.savefig(sys.stdout.buffer) and sys.stdout.flush() — purely so that the compiler’s environment can capture the figure and render it in its output window. These two lines are not required when running the same code in a normal desktop Python environment (Anaconda, Spyder, a local Jupyter Notebook) that has its own graphical display.
1. Line Plots
A line plot displays the relationship between two variables — conventionally labelled x and y — across a continuous scale, making it the natural choice for showing how one quantity changes as another increases. It is drawn using the general-purpose plt.plot() function.
import sys
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np
x = np.array([64, 74, 84, 94, 104, 114, 124, 134, 144, 154])
y = np.array([141, 151, 161, 171, 181, 191, 201, 211, 221, 231])
plt.plot(x, y)
plt.show()
plt.savefig(sys.stdout.buffer)
sys.stdout.flush()
This produces a simple straight line connecting each pair of x-y points in order. In a pharmaceutical context, x might represent time in hours and y a plasma drug concentration, immediately giving a visual read on how the concentration trends over the sampling period.
Customising Line Appearance
The look of a line plot is controlled through keyword arguments to plt.plot(). The color argument accepts named colours (such as “red” or “hotpink”) or hexadecimal codes; linestyle controls whether the line is solid, dashed ('--'), or dotted (':'); and linewidth controls how thick the line is drawn.
plt.plot(x, y, color='green', linestyle='--', label='Sine Wave')
plt.show()
Two further customisations are especially useful for scientific figures. The marker parameter places a symbol — such as 'o' for circles or 's' for squares — at every individual data point along the line, which highlights the actual observations rather than only the interpolated trend between them. The fill_between() function shades the region between two lines on the same axes, useful for representing a range of uncertainty, such as an upper and lower confidence bound around a mean concentration curve.
x = [10, 20, 30, 40]
y = [20, 25, 35, 55]
plt.plot(x, y, linestyle='--', color='green', linewidth=3,
marker='o', markersize=15)
plt.title("Customizing Line Chart")
plt.ylabel('Y-Axis')
plt.xlabel('X-Axis')
plt.show()
This example combines a dashed green line, thick linewidth, and large circular markers with a chart title and axis labels added via plt.title(), plt.xlabel(), and plt.ylabel() — the same three functions you will use to label every chart type covered in this unit.
2. Histograms
A histogram shows how the values in a dataset are distributed across a set of intervals called bins. Each bar’s width corresponds to one bin, and its height shows how many data points fall inside that interval. The plt.hist() function automatically works out how many values belong in each bin and draws the bars accordingly — you do not need to calculate bin boundaries yourself.
x = np.random.normal(190, 20, 280)
plt.hist(x)
plt.show()
Here, np.random.normal(190, 20, 280) generates 280 random values drawn from a normal distribution with a mean of 190 and a standard deviation of 20 — a useful way to simulate, for example, a body-weight distribution or a set of dissolution percentages for practice plotting. A histogram of this data would show the classic bell-shaped clustering around the mean value of 190.
A related but distinct chart is the bar chart, produced with plt.bar(). Where a histogram bins continuous values, a bar chart draws exactly one bar per discrete category:
x = np.array(['Thur', 'Fri', 'Sat', 'Sun'])
y = np.array([170, 120, 250, 190])
plt.bar(x, y, color='blue', edgecolor='black', linewidth=2)
plt.title("Customizing Bar Chart")
plt.xlabel("Day")
plt.ylabel("Total Bill")
plt.show()
The color argument sets the bar fill, while edgecolor and linewidth control the outline — useful for making individual bars stand out clearly in a printed report or poster.
plt.hist()) groups continuous numerical data into bins and is used to study distribution/spread, whereas a bar chart (plt.bar()) compares discrete categories and is used to compare magnitudes across those categories. Confusing the two, or their function names, is a common mistake examiners specifically look for.3. Scatter Plots
Scatter plots examine the relationship or correlation between individual paired observations, rather than showing an overall connected trend line. The plt.scatter() function draws one dot for every x-y pair, requiring two arrays of equal length representing the coordinates of each point. This makes scatter plots especially useful for spotting whether one variable appears to influence another.
x = np.array([4, 6, 7, 6, 1, 16, 1, 8, 3, 10, 11, 8, 5])
y = np.array([98, 87, 86, 87, 110, 85, 104, 86, 95, 79, 76, 84, 85])
plt.scatter(x, y)
plt.show()
In a pharmacy context, x and y here could represent, for instance, a patient’s age against their observed adverse-event severity score, or dose against response — a scatter plot is often the very first chart used to visually screen for such a relationship before running a formal correlation or regression analysis.
Plotting Multiple Datasets on One Scatter Chart
A single scatter chart can display more than one dataset at once, simply by calling plt.scatter() a second time with a new pair of x and y arrays before plt.show() is called. Matplotlib automatically assigns each call a different default colour, making the two groups of points easy to tell apart visually.
# Session one
x = np.array([6, 8, 9, 8, 3, 18, 3, 10, 5, 12, 13, 10, 7])
y = np.array([98, 87, 86, 87, 89, 87, 72, 86, 93, 77, 76, 84, 87])
plt.scatter(x, y)
# Session two
x = np.array([3, 3, 9, 2, 12, 9, 13, 10, 8, 4, 12, 5, 8, 15, 13])
y = np.array([99, 90, 84, 93, 94, 92, 90, 96, 93, 88, 77, 82, 90, 79, 86])
plt.scatter(x, y)
plt.show()
This pattern is directly applicable to comparing two formulations, two dose groups, or two treatment arms on the same axes — plotting them together makes any difference between the groups immediately visible.
4. Box Plots
A box plot summarises how a dataset is spread out. In one compact drawing, it shows the minimum, the maximum, the median, and the quartiles of the data, making it a convenient way to spot outliers within one or more groups at a glance — considerably more information-dense than a simple bar of averages.
np.random.seed(10)
d_1 = np.random.normal(110, 20, 210)
d_2 = np.random.normal(100, 30, 210)
d_3 = np.random.normal(90, 40, 210)
d_4 = np.random.normal(80, 50, 210)
d = [d_1, d_2, d_3, d_4]
fig = plt.figure(figsize=(10, 7))
ax = fig.add_axes([0, 0, 1, 1])
bp = ax.boxplot(d)
plt.show()
plt.savefig(sys.stdout.buffer)
sys.stdout.flush()
Here, four simulated datasets — which could represent, for example, dissolution percentages from four different tablet batches, or plasma concentrations from four dose groups — are passed to ax.boxplot() as a list. Each resulting box shows its own median line, the interquartile range as the box itself, “whiskers” extending to the typical range of the data, and individual circles marking any statistical outliers beyond that range. np.random.seed(10) fixes the random number generator so the same “random” values are produced every time the code runs — useful for reproducible teaching examples and for comparing your output against a reference answer.
| Chart Type | Function | Best Used For |
|---|---|---|
| Line plot | plt.plot() |
Trends over a continuous scale, e.g. concentration vs time |
| Histogram | plt.hist() |
Distribution/frequency of continuous numerical data |
| Bar chart | plt.bar() |
Comparing magnitudes across discrete categories |
| Scatter plot | plt.scatter() |
Relationship/correlation between two paired variables |
| Box plot | ax.boxplot() |
Spread, median, and outliers across one or more groups |
Frequently Asked Questions
What is the difference between a histogram and a bar chart, since both use vertical bars?
A histogram bins continuous numerical data into ranges and shows frequency within each range using plt.hist(), with bars typically touching because the underlying scale is continuous. A bar chart uses plt.bar() to compare discrete, separate categories (like days of the week), and its bars are conventionally drawn with gaps between them since the categories are not on a continuous numeric scale.
Why do I see two extra lines after plt.show() in these examples, and do I need them?
Those two lines (plt.savefig(sys.stdout.buffer) and sys.stdout.flush()) exist only to make the plot visible inside the W3Schools browser-based compiler, which has no graphical display of its own. If you are running the same code in a normal desktop Python environment (Anaconda, Spyder, Jupyter), you can safely omit both lines — plt.show() alone is sufficient.
What do the “whiskers” and circles on a box plot actually represent?
The box itself spans the interquartile range (from the 25th to the 75th percentile), with a line inside marking the median. The whiskers extend from the box to the smallest and largest values that are not considered outliers, and individual circles beyond the whiskers mark data points identified as statistical outliers — a quick way to flag, for example, an anomalous dissolution result in a batch.
Summary
Matplotlib provides four essential chart types that cover most pharmaceutical data visualization needs: line plots (plt.plot()) for trends over a continuous variable like time, histograms (plt.hist()) for understanding how numeric data is distributed, scatter plots (plt.scatter()) for examining relationships between two variables, and box plots (ax.boxplot()) for comparing spread and identifying outliers across one or more groups. Each supports rich customisation through keyword arguments like color, linestyle, marker, and edgecolor, and every chart should be labelled clearly with plt.title(), plt.xlabel(), and plt.ylabel() for scientific clarity — a topic covered in full in the next article of this unit.
References
- Pharmacy Council of India (PCI) — B.Pharm Regulations, NEP 2020, BP101T Syllabus
- Python Software Foundation — Official Python Documentation, docs.python.org
- Matplotlib Development Team — Matplotlib Official Documentation, matplotlib.org, particularly the pyplot API reference
- NumPy Developers — NumPy Official Documentation, numpy.org
