Python and SQL for Manufacturing: Hands-On Training¶
Demo Notebook 3: Visualizing Data with Python¶
Author: Prakash Ukhalkar
Role: Assistant Professor (MCA) | Researcher in Data Science and Machine Learning
Notebook Scope: Query data from the EMP/DEPT database and turn it into charts — bar, pie, line, scatter, histogram, and horizontal bar — using Matplotlib.
We'll continue using company.db created in Demo Notebook 1.
By the end of this notebook you will be able to:
- Pull data from SQLite directly into Python lists
- Draw a bar chart
- Draw a pie chart
- Draw a line chart
- Draw a scatter plot
- Draw a histogram
- Draw a horizontal bar chart
Prerequisite: Complete
day1_emp_dept.ipynbfirst socompany.dbexists.
Step 1 - Import libraries and connect¶
import sqlite3
import matplotlib.pyplot as plt
conn = sqlite3.connect('company.db')
cursor = conn.cursor()
print('Connected to company.db')
Connected to company.db
Step 2 - Pull data from SQL into Python lists¶
Charts need plain Python lists. We query the data and unpack each column into its own list using a simple for loop (or a list comprehension — see the alternate approach below).
We want: average salary per department, joined with the department name.
rows = cursor.execute('''
SELECT d.dname, AVG(e.sal)
FROM emp AS e
JOIN dept AS d ON e.deptno = d.deptno
GROUP BY d.dname
ORDER BY d.dname
''').fetchall()
dept_names = []
avg_salaries = []
for row in rows:
dept_names.append(row[0])
avg_salaries.append(row[1])
print('Departments:', dept_names)
print('Avg Salaries:', avg_salaries)
Departments: ['ACCOUNTING', 'RESEARCH', 'SALES'] Avg Salaries: [2916.6666666666665, 2195.0, 1566.6666666666667]
Alternate approach - Unpack into two separate lists¶
dept_names = [row[0] for row in rows]
avg_salaries = [row[1] for row in rows]
Step 3 - Bar chart: Average salary per department¶
A bar chart is the simplest way to compare one number across several categories.
plt.figure(figsize=(7, 4))
plt.bar(dept_names, avg_salaries, color='steelblue')
plt.title('Average Salary by Department')
plt.xlabel('Department')
plt.ylabel('Average Salary')
plt.tight_layout()
plt.show()
Step 4 - Pie chart: Headcount by job¶
A pie chart shows proportions - what fraction of the workforce each job represents.
rows = cursor.execute(
'SELECT job, COUNT(*) FROM emp GROUP BY job ORDER BY job'
).fetchall()
jobs = []
counts = []
for row in rows:
jobs.append(row[0])
counts.append(row[1])
print(jobs)
print(counts)
['ANALYST', 'CLERK', 'MANAGER', 'PRESIDENT', 'SALESMAN'] [2, 4, 3, 1, 4]
plt.figure(figsize=(6, 6))
# autopct='%1.0f%%' adds percentage labels to the pie slices
# startangle=90 rotates the pie chart so the first slice starts at the top
plt.pie(counts, labels=jobs, autopct='%1.0f%%', startangle=90)
plt.title('Employee Headcount by Job')
plt.tight_layout()
plt.show()
Step 5 - Line chart: Salary sorted lowest to highest¶
A line chart shows a trend across an ordered sequence. Here we rank employees by salary to see the distribution shape.
rows = cursor.execute(
'SELECT ename, sal FROM emp ORDER BY sal ASC'
).fetchall()
names = []
salaries = []
for row in rows:
names.append(row[0])
salaries.append(row[1])
# Alternate approach
# names = [row[0] for row in rows]
# salaries = [row[1] for row in rows]
print(names)
print(salaries)
['SMITH', 'JAMES', 'ADAMS', 'WARD', 'MARTIN', 'MILLER', 'TURNER', 'ALLEN', 'CLARK', 'BLAKE', 'JONES', 'SCOTT', 'FORD', 'KING'] [900.0, 950.0, 1100.0, 1250.0, 1250.0, 1300.0, 1500.0, 1600.0, 2450.0, 2850.0, 2975.0, 3000.0, 3000.0, 5000.0]
plt.figure(figsize=(10, 4))
plt.plot(names, salaries, marker='o', color='darkorange')
plt.title('Employee Salaries (Sorted Lowest to Highest)')
plt.xlabel('Employee')
plt.ylabel('Salary')
plt.xticks(rotation=45, ha='right')
plt.tight_layout()
plt.show()
Step 6 - Scatter plot: Employee number vs Salary¶
A scatter plot shows the relationship between two numeric columns. Here we check whether earlier hires (lower empno) tend to earn more.
rows = cursor.execute(
'SELECT empno, sal FROM emp ORDER BY empno'
).fetchall()
empnos = []
salaries = []
for row in rows:
empnos.append(row[0])
salaries.append(row[1])
print(empnos)
print(salaries)
[7369, 7499, 7521, 7566, 7654, 7698, 7782, 7788, 7839, 7844, 7876, 7900, 7902, 7934] [900.0, 1600.0, 1250.0, 2975.0, 1250.0, 2850.0, 2450.0, 3000.0, 5000.0, 1500.0, 1100.0, 950.0, 3000.0, 1300.0]
plt.figure(figsize=(7, 4))
plt.scatter(empnos, salaries, color='seagreen', s=80)
plt.title('Employee Number vs Salary')
plt.xlabel('Employee Number (empno)')
plt.ylabel('Salary')
plt.tight_layout()
plt.show()
Step 7 - Histogram: Salary distribution¶
A histogram groups numeric values into bins and shows how many items fall in each bin. Here it reveals whether salaries cluster around a midpoint or spread widely.
rows = cursor.execute(
'SELECT sal FROM emp ORDER BY sal'
).fetchall()
all_salaries = []
for row in rows:
all_salaries.append(row[0])
print('Salaries:', all_salaries)
Salaries: [900.0, 950.0, 1100.0, 1250.0, 1250.0, 1300.0, 1500.0, 1600.0, 2450.0, 2850.0, 2975.0, 3000.0, 3000.0, 5000.0]
plt.figure(figsize=(7, 4))
# bins=6 splits the salary range into 6 equal-width buckets
plt.hist(all_salaries, bins=6, color='mediumpurple', edgecolor='white')
plt.title('Salary Distribution (Histogram)')
plt.xlabel('Salary')
plt.ylabel('Number of Employees')
plt.tight_layout()
plt.show()
Step 8 - Horizontal bar chart: Total salary bill per department¶
A horizontal bar chart works well when category labels are long. Here we compare total salary expenditure across departments - each bar grows to the right, making the labels easy to read.
rows = cursor.execute('''
SELECT d.dname, SUM(e.sal)
FROM emp AS e
JOIN dept AS d ON e.deptno = d.deptno
GROUP BY d.dname
ORDER BY SUM(e.sal) DESC
''').fetchall()
dept_names = []
total_sal = []
for row in rows:
dept_names.append(row[0])
total_sal.append(row[1])
print('Departments:', dept_names)
print('Total Salaries:', total_sal)
Departments: ['RESEARCH', 'SALES', 'ACCOUNTING'] Total Salaries: [10975.0, 9400.0, 8750.0]
plt.figure(figsize=(7, 4))
# barh draws bars horizontally; y-axis holds categories, x-axis holds values
plt.barh(dept_names, total_sal, color='tomato')
plt.title('Total Salary Bill by Department')
plt.xlabel('Total Salary')
plt.ylabel('Department')
plt.tight_layout()
plt.show()
Step 9 - Close the connection¶
conn.close()
print('Done!')
Done!
Summary¶
| Chart type | When to use it |
|---|---|
| Bar chart | Compare one value across categories |
| Pie chart | Show proportions of a whole |
| Line chart | Show trend across an ordered sequence |
| Scatter plot | Show relationship between two numeric columns |
| Histogram | Show the frequency distribution of a numeric column |
| Horizontal bar chart | Compare values when category labels are long |
Next: day4_capstone.ipynb — put SQL + Python + charts together into one mini-report.
About This Material¶
| Author | Prakash Ukhalkar |
| Role | Assistant Professor (MCA) · Researcher in Data Science and Machine Learning |
| GitHub | @prakash-ukhalkar |
| Repository | mfg-python-sql-training |
| License | MIT |
Provided for educational use in manufacturing analytics training programmes.
For questions, corrections, or contributions, open an issue or pull request on GitHub.