Topic - study of effect of the temperature on the solubility of solids in liquids around 30 pages with includes of graph and charts for records For cbse based class 12 Prepare this project in a pdf downloadable format in one go
mkdir -p /home/daytona/workspace/solubility-project && ls /home/daytona/workspace/solubility-project/
~/solubility-project/generate_project.py
#!/usr/bin/env python3
"""
CBSE Class 12 Chemistry Project:
Effect of Temperature on Solubility of Solids in Liquids
Generates a ~30-page professional PDF with charts and tables.
"""
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from matplotlib.patches import FancyBboxPatch
import numpy as np
import os
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import cm, mm
from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_JUSTIFY, TA_RIGHT
from reportlab.platypus import (
SimpleDocTemplate, Paragraph, Spacer, Image, Table, TableStyle,
PageBreak, HRFlowable, KeepTogether
)
from reportlab.platypus.flowables import Flowable
from reportlab.pdfgen import canvas
from reportlab.lib.colors import HexColor
# ─────────────────────────────────────────────
# COLOUR PALETTE
# ─────────────────────────────────────────────
DARK_BLUE = HexColor('#0D2B6B')
MID_BLUE = HexColor('#1565C0')
LIGHT_BLUE = HexColor('#E3F2FD')
ACCENT = HexColor('#FF6F00')
GREEN = HexColor('#2E7D32')
RED_COL = HexColor('#C62828')
TABLE_HEAD = HexColor('#1565C0')
TABLE_ALT = HexColor('#F3F8FF')
WHITE = colors.white
BLACK = colors.black
LIGHT_GREY = HexColor('#F5F5F5')
BORDER_GREY = HexColor('#BDBDBD')
OUTPUT_DIR = '/home/daytona/workspace/solubility-project'
IMG_DIR = os.path.join(OUTPUT_DIR, 'imgs')
os.makedirs(IMG_DIR, exist_ok=True)
# ─────────────────────────────────────────────
# CHART GENERATION
# ─────────────────────────────────────────────
def chart_style():
plt.rcParams.update({
'font.family': 'DejaVu Sans',
'axes.titlesize': 13,
'axes.labelsize': 11,
'xtick.labelsize': 9,
'ytick.labelsize': 9,
'axes.grid': True,
'grid.alpha': 0.35,
'axes.spines.top': False,
'axes.spines.right': False,
})
def save(name):
path = os.path.join(IMG_DIR, name)
plt.savefig(path, dpi=150, bbox_inches='tight', facecolor='white')
plt.close()
return path
def make_solubility_vs_temp_main():
chart_style()
temps = np.array([0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100])
kno3 = np.array([13.3, 20.9, 31.6, 45.8, 63.9, 85.5, 110.0, 138.0, 169.0, 202.0, 246.0])
nacl = np.array([35.7, 35.8, 36.0, 36.3, 36.6, 37.0, 37.3, 37.8, 38.4, 39.0, 39.8])
kbr = np.array([53.5, 59.5, 65.3, 70.9, 76.6, 82.4, 88.4, 94.2, 100.2, 106.2, 112.5])
khco3 = np.array([22.4, 27.5, 33.7, 41.2, 50.0, 60.1, 72.0, 85.0, 100.0, 116.0, 134.0])
caso4 = np.array([1.76, 2.00, 2.09, 2.07, 1.98, 1.86, 1.70, 1.55, 1.41, 1.26, 1.14])
fig, ax = plt.subplots(figsize=(8, 5.2))
ax.plot(temps, kno3, 'o-', color='#1565C0', lw=2, ms=5, label='KNO₃')
ax.plot(temps, kbr, 's-', color='#2E7D32', lw=2, ms=5, label='KBr')
ax.plot(temps, khco3, '^-', color='#FF6F00', lw=2, ms=5, label='KHCO₃')
ax.plot(temps, nacl, 'D-', color='#6A1B9A', lw=2, ms=5, label='NaCl')
ax2 = ax.twinx()
ax2.plot(temps, caso4, 'v--', color='#C62828', lw=2, ms=5, label='CaSO₄ (right axis)')
ax2.set_ylabel('Solubility of CaSO₄ (g/100 g water)', color='#C62828', fontsize=9)
ax2.tick_params(axis='y', labelcolor='#C62828', labelsize=8)
ax2.set_ylim(0, 4)
ax.set_xlabel('Temperature (°C)')
ax.set_ylabel('Solubility (g/100 g water)')
ax.set_title('Solubility vs Temperature for Common Salts')
lines1, labels1 = ax.get_legend_handles_labels()
lines2, labels2 = ax2.get_legend_handles_labels()
ax.legend(lines1 + lines2, labels1 + labels2, loc='upper left', fontsize=8)
fig.tight_layout()
return save('solubility_vs_temp_main.png')
def make_kno3_curve():
chart_style()
temps = np.array([0,10,20,30,40,50,60,70,80,90,100])
kno3 = np.array([13.3,20.9,31.6,45.8,63.9,85.5,110.0,138.0,169.0,202.0,246.0])
fig, ax = plt.subplots(figsize=(7, 4.5))
ax.fill_between(temps, kno3, alpha=0.15, color='#1565C0')
ax.plot(temps, kno3, 'o-', color='#1565C0', lw=2.5, ms=6)
for x, y in zip(temps, kno3):
ax.annotate(f'{y}', (x, y), textcoords='offset points', xytext=(0, 7), fontsize=7, ha='center', color='#0D2B6B')
ax.set_xlabel('Temperature (°C)')
ax.set_ylabel('Solubility (g KNO₃ / 100 g water)')
ax.set_title('Solubility Curve of Potassium Nitrate (KNO₃)')
fig.tight_layout()
return save('kno3_curve.png')
def make_nacl_curve():
chart_style()
temps = np.array([0,10,20,30,40,50,60,70,80,90,100])
nacl = np.array([35.7,35.8,36.0,36.3,36.6,37.0,37.3,37.8,38.4,39.0,39.8])
fig, ax = plt.subplots(figsize=(7, 4.5))
ax.fill_between(temps, nacl, alpha=0.15, color='#6A1B9A')
ax.plot(temps, nacl, 'D-', color='#6A1B9A', lw=2.5, ms=6)
for x, y in zip(temps, nacl):
ax.annotate(f'{y}', (x, y), textcoords='offset points', xytext=(0, 7), fontsize=7, ha='center', color='#4A148C')
ax.set_xlabel('Temperature (°C)')
ax.set_ylabel('Solubility (g NaCl / 100 g water)')
ax.set_title('Solubility Curve of Sodium Chloride (NaCl)')
ax.set_ylim(34, 42)
fig.tight_layout()
return save('nacl_curve.png')
def make_caso4_curve():
chart_style()
temps = np.array([0,10,20,30,40,50,60,70,80,90,100])
caso4 = np.array([1.76,2.00,2.09,2.07,1.98,1.86,1.70,1.55,1.41,1.26,1.14])
fig, ax = plt.subplots(figsize=(7, 4.5))
ax.fill_between(temps, caso4, alpha=0.15, color='#C62828')
ax.plot(temps, caso4, 'v-', color='#C62828', lw=2.5, ms=6)
for x, y in zip(temps, caso4):
ax.annotate(f'{y}', (x, y), textcoords='offset points', xytext=(0, 7), fontsize=7, ha='center', color='#B71C1C')
ax.set_xlabel('Temperature (°C)')
ax.set_ylabel('Solubility (g CaSO₄ / 100 g water)')
ax.set_title('Solubility Curve of Calcium Sulphate (CaSO₄) — Inverse Relationship')
fig.tight_layout()
return save('caso4_curve.png')
def make_bar_chart():
chart_style()
salts = ['KNO₃', 'KBr', 'KHCO₃', 'NaCl', 'CaSO₄']
at_0 = [13.3, 53.5, 22.4, 35.7, 1.76]
at_50 = [85.5, 82.4, 60.1, 37.0, 1.86]
at_100 = [246.0, 112.5, 134.0, 39.8, 1.14]
x = np.arange(len(salts))
w = 0.25
fig, ax = plt.subplots(figsize=(8, 5))
b1 = ax.bar(x - w, at_0, w, label='0 °C', color='#90CAF9')
b2 = ax.bar(x, at_50, w, label='50 °C', color='#1565C0')
b3 = ax.bar(x + w, at_100, w, label='100 °C', color='#0D2B6B')
ax.set_xticks(x)
ax.set_xticklabels(salts)
ax.set_ylabel('Solubility (g / 100 g water)')
ax.set_title('Comparison of Solubility at Different Temperatures')
ax.legend()
for bars in [b1, b2, b3]:
for bar in bars:
h = bar.get_height()
ax.annotate(f'{h}', xy=(bar.get_x()+bar.get_width()/2, h),
xytext=(0,3), textcoords='offset points', ha='center', fontsize=7)
fig.tight_layout()
return save('bar_chart.png')
def make_enthalpy_diagram():
chart_style()
fig, axes = plt.subplots(1, 2, figsize=(9, 4.5))
# Endothermic
ax = axes[0]
stages = ['Reactants\n(Solid + Solvent)', 'Transition\nState', 'Products\n(Solution)']
energies = [0, 15, 10]
ax.plot([0,1,2], energies, 'o-', color='#1565C0', lw=2.5, ms=8)
ax.fill_between([0,1,2], energies, alpha=0.1, color='#1565C0')
ax.set_xticks([0,1,2]); ax.set_xticklabels(stages, fontsize=8)
ax.set_ylabel('Energy (arbitrary units)')
ax.set_title('Endothermic Dissolution\n(e.g., KNO₃)', fontsize=11)
ax.annotate('ΔH > 0', xy=(1.5, 10.5), fontsize=10, color='#C62828', fontweight='bold')
# Exothermic
ax2 = axes[1]
energies2 = [0, 5, -8]
ax2.plot([0,1,2], energies2, 'o-', color='#C62828', lw=2.5, ms=8)
ax2.fill_between([0,1,2], energies2, alpha=0.1, color='#C62828')
ax2.set_xticks([0,1,2]); ax2.set_xticklabels(stages, fontsize=8)
ax2.set_ylabel('Energy (arbitrary units)')
ax2.set_title('Exothermic Dissolution\n(e.g., NaOH)', fontsize=11)
ax2.annotate('ΔH < 0', xy=(1.5, -5), fontsize=10, color='#1565C0', fontweight='bold')
plt.suptitle("Enthalpy Diagrams for Dissolution", fontsize=12, fontweight='bold', y=1.01)
fig.tight_layout()
return save('enthalpy_diagram.png')
def make_pie_chart():
chart_style()
fig, axes = plt.subplots(1, 2, figsize=(9, 4.5))
labels = ['KNO₃', 'KBr', 'KHCO₃', 'NaCl', 'CaSO₄']
sizes_0 = [13.3, 53.5, 22.4, 35.7, 1.76]
sizes_100 = [246.0, 112.5, 134.0, 39.8, 1.14]
pie_colors = ['#1565C0','#2E7D32','#FF6F00','#6A1B9A','#C62828']
axes[0].pie(sizes_0, labels=labels, colors=pie_colors, autopct='%1.1f%%', startangle=90)
axes[0].set_title('Relative Solubility at 0 °C')
axes[1].pie(sizes_100, labels=labels, colors=pie_colors, autopct='%1.1f%%', startangle=90)
axes[1].set_title('Relative Solubility at 100 °C')
fig.tight_layout()
return save('pie_chart.png')
def make_rate_change_chart():
chart_style()
temps = np.array([0,10,20,30,40,50,60,70,80,90,100])
kno3 = np.array([13.3,20.9,31.6,45.8,63.9,85.5,110.0,138.0,169.0,202.0,246.0])
nacl = np.array([35.7,35.8,36.0,36.3,36.6,37.0,37.3,37.8,38.4,39.0,39.8])
# Rate of change (derivative approx)
dkno3 = np.gradient(kno3, temps)
dnacl = np.gradient(nacl, temps)
fig, ax = plt.subplots(figsize=(7, 4.5))
ax.plot(temps, dkno3, 'o-', color='#1565C0', lw=2, ms=5, label='KNO₃ rate of change')
ax.plot(temps, dnacl, 'D-', color='#6A1B9A', lw=2, ms=5, label='NaCl rate of change')
ax.axhline(0, color='grey', lw=1, ls='--')
ax.set_xlabel('Temperature (°C)')
ax.set_ylabel('dS/dT (g / 100 g water / °C)')
ax.set_title('Rate of Change of Solubility with Temperature')
ax.legend()
fig.tight_layout()
return save('rate_change.png')
# Generate all charts
print("Generating charts...")
img_main = make_solubility_vs_temp_main()
img_kno3 = make_kno3_curve()
img_nacl = make_nacl_curve()
img_caso4 = make_caso4_curve()
img_bar = make_bar_chart()
img_enthalpy= make_enthalpy_diagram()
img_pie = make_pie_chart()
img_rate = make_rate_change_chart()
print("All charts generated.")
# ─────────────────────────────────────────────
# PAGE TEMPLATES
# ─────────────────────────────────────────────
PAGE_W, PAGE_H = A4 # 595.27 x 841.89 pts
def header_footer(canv, doc):
canv.saveState()
# Header bar
canv.setFillColor(DARK_BLUE)
canv.rect(0, PAGE_H - 1.1*cm, PAGE_W, 1.1*cm, fill=1, stroke=0)
canv.setFillColor(WHITE)
canv.setFont('Helvetica-Bold', 9)
canv.drawString(1.5*cm, PAGE_H - 0.75*cm,
'Effect of Temperature on Solubility of Solids in Liquids')
canv.setFont('Helvetica', 8)
canv.drawRightString(PAGE_W - 1.5*cm, PAGE_H - 0.75*cm, 'CBSE Class XII Chemistry')
# Footer
canv.setFillColor(DARK_BLUE)
canv.rect(0, 0, PAGE_W, 0.8*cm, fill=1, stroke=0)
canv.setFillColor(WHITE)
canv.setFont('Helvetica', 8)
canv.drawCentredString(PAGE_W/2, 0.22*cm, f'Page {doc.page}')
canv.restoreState()
def cover_page(canv, doc):
canv.saveState()
# Dark blue top band
canv.setFillColor(DARK_BLUE)
canv.rect(0, PAGE_H*0.72, PAGE_W, PAGE_H*0.28, fill=1, stroke=0)
# Accent stripe
canv.setFillColor(ACCENT)
canv.rect(0, PAGE_H*0.70, PAGE_W, PAGE_H*0.02, fill=1, stroke=0)
# Bottom band
canv.setFillColor(DARK_BLUE)
canv.rect(0, 0, PAGE_W, PAGE_H*0.07, fill=1, stroke=0)
# Footer text
canv.setFillColor(WHITE)
canv.setFont('Helvetica', 8)
canv.drawCentredString(PAGE_W/2, 0.35*cm, 'Central Board of Secondary Education | Class XII | Chemistry | 2025-26')
canv.restoreState()
# ─────────────────────────────────────────────
# STYLES
# ─────────────────────────────────────────────
styles = getSampleStyleSheet()
def S(name, **kw):
return ParagraphStyle(name, **kw)
cover_title = S('CoverTitle',
fontName='Helvetica-Bold', fontSize=22, textColor=WHITE,
alignment=TA_CENTER, leading=30, spaceAfter=6)
cover_sub = S('CoverSub',
fontName='Helvetica', fontSize=13, textColor=HexColor('#BBDEFB'),
alignment=TA_CENTER, leading=20)
cover_detail = S('CoverDetail',
fontName='Helvetica', fontSize=11, textColor=DARK_BLUE,
alignment=TA_CENTER, leading=18)
ch_title = S('ChTitle',
fontName='Helvetica-Bold', fontSize=17, textColor=DARK_BLUE,
alignment=TA_LEFT, spaceBefore=6, spaceAfter=10,
borderPad=4)
sec_title = S('SecTitle',
fontName='Helvetica-Bold', fontSize=13, textColor=MID_BLUE,
alignment=TA_LEFT, spaceBefore=8, spaceAfter=4)
body = S('Body',
fontName='Helvetica', fontSize=10, textColor=colors.black,
alignment=TA_JUSTIFY, leading=16, spaceAfter=6)
body_bold = S('BodyBold',
fontName='Helvetica-Bold', fontSize=10, textColor=DARK_BLUE,
alignment=TA_LEFT, leading=16, spaceAfter=4)
bullet = S('Bullet',
fontName='Helvetica', fontSize=10, textColor=colors.black,
alignment=TA_LEFT, leading=15, leftIndent=18, spaceAfter=4,
bulletIndent=6, bulletFontName='Helvetica', bulletFontSize=10)
caption = S('Caption',
fontName='Helvetica-Oblique', fontSize=9, textColor=HexColor('#555555'),
alignment=TA_CENTER, leading=13, spaceAfter=8)
small = S('Small',
fontName='Helvetica', fontSize=9, textColor=colors.black,
alignment=TA_LEFT, leading=13, spaceAfter=4)
table_hdr_style = S('TblHdr',
fontName='Helvetica-Bold', fontSize=9, textColor=WHITE,
alignment=TA_CENTER, leading=12)
table_cell_style = S('TblCell',
fontName='Helvetica', fontSize=9, textColor=BLACK,
alignment=TA_CENTER, leading=12)
def tbl_style(col_widths=None):
return TableStyle([
('BACKGROUND', (0,0), (-1,0), TABLE_HEAD),
('TEXTCOLOR', (0,0), (-1,0), WHITE),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,0), 9),
('ALIGN', (0,0), (-1,-1), 'CENTER'),
('VALIGN', (0,0), (-1,-1), 'MIDDLE'),
('ROWBACKGROUNDS', (0,1), (-1,-1), [WHITE, TABLE_ALT]),
('FONTNAME', (0,1), (-1,-1), 'Helvetica'),
('FONTSIZE', (0,1), (-1,-1), 9),
('GRID', (0,0), (-1,-1), 0.5, BORDER_GREY),
('TOPPADDING', (0,0), (-1,-1), 5),
('BOTTOMPADDING',(0,0), (-1,-1), 5),
('LEFTPADDING', (0,0), (-1,-1), 6),
('RIGHTPADDING',(0,0), (-1,-1), 6),
])
def chapter_rule():
return HRFlowable(width='100%', thickness=2, color=ACCENT, spaceAfter=8)
def section_rule():
return HRFlowable(width='40%', thickness=1, color=MID_BLUE, spaceAfter=6)
def img(path, w=14*cm, caption_text=''):
items = [
Image(path, width=w, height=None),
]
if caption_text:
items.append(Paragraph(caption_text, caption))
return items
# ─────────────────────────────────────────────
# DOCUMENT CONTENT
# ─────────────────────────────────────────────
story = []
cm2 = 2*cm
# ── COVER ──────────────────────────────────────────────────────────────────────
story.append(Spacer(1, PAGE_H * 0.25)) # push into the white area below blue band
# (Title sits in the dark blue region via cover_page callback, so we put
# a spacer then the white-area text)
story.append(Paragraph(
"EFFECT OF TEMPERATURE ON<br/>SOLUBILITY OF SOLIDS IN LIQUIDS",
cover_title))
story.append(Spacer(1, 0.3*cm))
story.append(Paragraph("Chemistry Investigatory Project", cover_sub))
story.append(Spacer(1, 2.5*cm))
cover_table_data = [
['School Name:', '__________________________'],
['Student Name:', '__________________________'],
['Class & Section:', 'XII — ___'],
['Roll Number:', '__________________________'],
['Subject Teacher:', '__________________________'],
['Academic Year:', '2025 – 26'],
]
cover_tbl = Table(cover_table_data, colWidths=[5.5*cm, 8*cm])
cover_tbl.setStyle(TableStyle([
('FONTNAME', (0,0), (0,-1), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,-1), 11),
('TEXTCOLOR', (0,0), (0,-1), DARK_BLUE),
('ALIGN', (0,0), (0,-1), 'RIGHT'),
('ALIGN', (1,0), (1,-1), 'LEFT'),
('TOPPADDING',(0,0), (-1,-1), 5),
('BOTTOMPADDING',(0,0), (-1,-1), 5),
('LINEBELOW', (1,0), (1,-1), 0.5, BORDER_GREY),
]))
story.append(cover_tbl)
story.append(PageBreak())
# ── CERTIFICATE ────────────────────────────────────────────────────────────────
story.append(Spacer(1, cm))
story.append(Paragraph("CERTIFICATE", ch_title))
story.append(chapter_rule())
story.append(Spacer(1, 0.5*cm))
cert_text = """
This is to certify that <b>________________________________</b>, a student of Class <b>XII</b>,
Roll No. <b>_______</b>, has successfully completed the Chemistry Investigatory Project
entitled <b><i>"Effect of Temperature on Solubility of Solids in Liquids"</i></b> as per
the guidelines prescribed by the Central Board of Secondary Education (CBSE) for the
academic year <b>2025–26</b>.
<br/><br/>
This project has been completed under my guidance and supervision and is forwarded
for evaluation.
"""
story.append(Paragraph(cert_text, body))
story.append(Spacer(1, 2*cm))
sig_data = [
['Date: ______________', '', 'Date: ______________'],
['', '', ''],
['________________________', '', '________________________'],
['Subject Teacher', '', 'External Examiner'],
['(Chemistry)', '', ''],
]
sig_tbl = Table(sig_data, colWidths=[5.5*cm, 3*cm, 5.5*cm])
sig_tbl.setStyle(TableStyle([
('FONTNAME', (0,0), (-1,-1), 'Helvetica'),
('FONTSIZE', (0,0), (-1,-1), 10),
('ALIGN', (0,0), (0,-1), 'CENTER'),
('ALIGN', (2,0), (2,-1), 'CENTER'),
('TOPPADDING',(0,0), (-1,-1), 5),
]))
story.append(sig_tbl)
story.append(Spacer(1, 1.5*cm))
story.append(Paragraph("<b>School Seal:</b>", body))
story.append(PageBreak())
# ── ACKNOWLEDGEMENT ─────────────────────────────────────────────────────────────
story.append(Spacer(1, cm))
story.append(Paragraph("ACKNOWLEDGEMENT", ch_title))
story.append(chapter_rule())
story.append(Spacer(1, 0.3*cm))
ack = """
I would like to express my sincere gratitude to my Chemistry teacher for providing
constant guidance, encouragement, and invaluable suggestions during the preparation
of this project. Without their expert guidance, this project would not have been
completed successfully.
<br/><br/>
I am also grateful to the Principal of our school for providing the necessary
laboratory facilities and resources. My heartfelt thanks go to the laboratory
assistant for the help rendered during the experimental phase.
<br/><br/>
I extend my thanks to my parents for their moral support and motivation throughout
this project. I also thank my classmates and friends for their encouragement.
<br/><br/>
Finally, I am thankful to the Central Board of Secondary Education (CBSE) for
including such practical and application-oriented projects in the curriculum, which
help develop a scientific temperament and research attitude among students.
"""
story.append(Paragraph(ack, body))
story.append(Spacer(1, 1.5*cm))
story.append(Paragraph("____________________________", body))
story.append(Paragraph("<i>(Student's Signature)</i>", caption))
story.append(PageBreak())
# ── TABLE OF CONTENTS ──────────────────────────────────────────────────────────
story.append(Spacer(1, cm))
story.append(Paragraph("TABLE OF CONTENTS", ch_title))
story.append(chapter_rule())
toc_data = [
['S. No.', 'Title', 'Page No.'],
['1', 'Introduction', '5'],
['2', 'Aim of the Experiment', '6'],
['3', 'Theoretical Background', '6'],
['4', 'Types of Solutions and Solubility', '8'],
['5', 'Effect of Temperature: Le Chatelier\'s Principle', '9'],
['6', 'Materials Required', '10'],
['7', 'Procedure', '11'],
['8', 'Precautions', '12'],
['9', 'Observations and Recorded Data', '13'],
['10', 'Graphical Analysis & Charts', '17'],
['11', 'Analysis of Results', '22'],
['12', 'Discussion', '24'],
['13', 'Sources of Error & Limitations', '26'],
['14', 'Conclusion', '27'],
['15', 'Applications in Daily Life & Industry', '28'],
['16', 'References & Bibliography', '29'],
]
toc_tbl = Table(toc_data, colWidths=[2*cm, 11.5*cm, 3*cm])
toc_tbl.setStyle(tbl_style())
story.append(toc_tbl)
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# CHAPTER 1 — INTRODUCTION
# ══════════════════════════════════════════════════════════════════════════════
story.append(Spacer(1, 0.4*cm))
story.append(Paragraph("1. INTRODUCTION", ch_title))
story.append(chapter_rule())
intro = """
Solubility is one of the most fundamental concepts in chemistry and plays a central
role in a wide range of natural phenomena and industrial processes. It is defined as
the maximum amount of a solute that can dissolve in a given quantity of solvent at a
specified temperature to form a homogeneous (uniform) solution. The resulting solution
is called a <b>saturated solution</b>.
<br/><br/>
The dissolving process is governed by the molecular interactions between solute and
solvent particles. The well-known principle <i>"Like dissolves like"</i> summarises
the rule that polar solvents dissolve polar solutes and non-polar solvents dissolve
non-polar solutes. Water, being a highly polar molecule with strong hydrogen-bonding
capacity, is an excellent solvent for most ionic compounds and many polar covalent
compounds, earning it the title of <b>"universal solvent."</b>
<br/><br/>
Among the many factors that influence solubility — nature of the solute and solvent,
pressure (mainly for gases), and the presence of other solutes — <b>temperature</b>
stands out as particularly significant for solid solutes. In most cases, increasing
the temperature increases the solubility of solids in water; however, notable
exceptions exist. Understanding this relationship is not only of academic interest
but has profound implications in pharmaceutical manufacturing, food science,
environmental chemistry, mining, and materials engineering.
<br/><br/>
This project systematically investigates the effect of temperature on the solubility
of three common solid solutes — <b>Potassium Nitrate (KNO₃)</b>, <b>Sodium Chloride (NaCl)</b>,
and <b>Calcium Sulphate (CaSO₄)</b> — in water, at temperatures ranging from 0 °C to
100 °C. Experimental data are recorded, graphically represented, and analysed in
the context of thermodynamic principles.
"""
story.append(Paragraph(intro, body))
# ══════════════════════════════════════════════════════════════════════════════
# CHAPTER 2 — AIM
# ══════════════════════════════════════════════════════════════════════════════
story.append(Spacer(1, 0.4*cm))
story.append(Paragraph("2. AIM OF THE EXPERIMENT", ch_title))
story.append(chapter_rule())
aim_items = [
"To study the effect of temperature on the solubility of a solid (Potassium Nitrate, KNO₃) in water.",
"To draw the solubility curve (solubility vs temperature graph) for KNO₃.",
"To compare the solubility behaviour of KNO₃, NaCl, and CaSO₄ at various temperatures.",
"To understand the thermodynamic basis (Le Chatelier's Principle) governing solubility-temperature relationships.",
"To record systematic observations, tabulate data, and draw scientifically valid conclusions.",
]
for item in aim_items:
story.append(Paragraph(f"• {item}", bullet))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# CHAPTER 3 — THEORETICAL BACKGROUND
# ══════════════════════════════════════════════════════════════════════════════
story.append(Spacer(1, 0.4*cm))
story.append(Paragraph("3. THEORETICAL BACKGROUND", ch_title))
story.append(chapter_rule())
story.append(Paragraph("3.1 What is Solubility?", sec_title))
story.append(section_rule())
theory1 = """
Solubility is quantitatively expressed as the <b>mass of solute (in grams) dissolved
per 100 g of solvent</b> at a given temperature, when the solution is saturated. It can
also be expressed in molarity (mol/L), molality (mol/kg), mole fraction, or parts per
million (ppm), depending on context.
<br/><br/>
A solution is classified as:
"""
story.append(Paragraph(theory1, body))
sol_type_data = [
['Type', 'Definition', 'Example'],
['Unsaturated', 'Solute < maximum possible; more solute can dissolve','Dilute NaCl solution'],
['Saturated', 'Solute = maximum possible at given T; equilibrium', 'NaCl dissolved to saturation'],
['Supersaturated', 'Solute > normal maximum; unstable, crystallises on disturbance', 'Hot saturated NaCl rapidly cooled'],
]
sol_type_tbl = Table(sol_type_data, colWidths=[3.5*cm, 7.5*cm, 5.5*cm])
sol_type_tbl.setStyle(tbl_style())
story.append(sol_type_tbl)
story.append(Spacer(1, 0.4*cm))
story.append(Paragraph("3.2 The Dissolution Process", sec_title))
story.append(section_rule())
theory2 = """
When a solid ionic compound (e.g., NaCl) is added to water, several energy changes occur:
<br/><br/>
<b>(a) Lattice Energy:</b> Energy required to break the crystal lattice (endothermic). For NaCl,
lattice energy ≈ 786 kJ/mol.
<br/><br/>
<b>(b) Hydration Energy:</b> Energy released when ions become surrounded by water molecules
(exothermic). For NaCl, hydration energy ≈ 784 kJ/mol.
<br/><br/>
The net <b>enthalpy of solution (ΔH<sub>sol</sub>) = Lattice Energy – Hydration Energy</b>.
<br/><br/>
• If ΔH<sub>sol</sub> > 0 (endothermic): Solubility increases with temperature (e.g., KNO₃, NH₄Cl).
<br/>
• If ΔH<sub>sol</sub> < 0 (exothermic): Solubility decreases with temperature (e.g., CaSO₄, Li₂SO₄).
<br/>
• If ΔH<sub>sol</sub> ≈ 0 (nearly athermal): Solubility changes very little with temperature (e.g., NaCl).
"""
story.append(Paragraph(theory2, body))
story.append(Paragraph("3.3 Van't Hoff Equation for Solubility", sec_title))
story.append(section_rule())
theory3 = """
The quantitative relationship between solubility and temperature is given by the
<b>Van't Hoff equation</b>:
<br/><br/>
<b>d(ln K<sub>sp</sub>) / dT = ΔH<sub>sol</sub> / RT²</b>
<br/><br/>
Integrating between two temperatures T₁ and T₂:
<br/><br/>
<b>ln(K₂/K₁) = – ΔH<sub>sol</sub>/R × (1/T₂ – 1/T₁)</b>
<br/><br/>
where K is the solubility product, R is the universal gas constant (8.314 J mol⁻¹ K⁻¹),
and T is in Kelvin.
<br/><br/>
This equation predicts:
<br/>
• For endothermic dissolution: K₂ > K₁ when T₂ > T₁ → solubility increases with temperature.
<br/>
• For exothermic dissolution: K₂ < K₁ when T₂ > T₁ → solubility decreases with temperature.
"""
story.append(Paragraph(theory3, body))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# CHAPTER 4 — TYPES OF SOLUTIONS
# ══════════════════════════════════════════════════════════════════════════════
story.append(Spacer(1, 0.4*cm))
story.append(Paragraph("4. TYPES OF SOLUTIONS AND SOLUBILITY", ch_title))
story.append(chapter_rule())
types_text = """
A <b>solution</b> is a homogeneous mixture of two or more substances. The component present
in a larger amount is the <b>solvent</b> and the one in smaller amount is the <b>solute</b>.
Solutions can be classified based on the physical states of solute and solvent:
"""
story.append(Paragraph(types_text, body))
types_data = [
['Type of Solution', 'Solute State', 'Solvent State', 'Example'],
['Solid in Liquid', 'Solid', 'Liquid', 'Salt in water, Sugar in water'],
['Gas in Liquid', 'Gas', 'Liquid', 'CO₂ in water (aerated drinks)'],
['Liquid in Liquid', 'Liquid', 'Liquid', 'Ethanol in water'],
['Solid in Solid', 'Solid', 'Solid', 'Alloys: brass (Cu+Zn)'],
['Gas in Solid', 'Gas', 'Solid', 'H₂ in palladium'],
['Liquid in Solid', 'Liquid', 'Solid', 'Mercury in amalgams'],
['Gas in Gas', 'Gas', 'Gas', 'Air (N₂, O₂, Ar, ...)'],
]
types_tbl = Table(types_data, colWidths=[4*cm, 3*cm, 3*cm, 6.5*cm])
types_tbl.setStyle(tbl_style())
story.append(types_tbl)
story.append(Spacer(1, 0.5*cm))
factors_text = """
<b>Factors Affecting Solubility of Solids in Liquids:</b>
<br/><br/>
<b>1. Nature of Solute and Solvent</b><br/>
Ionic and polar covalent solids dissolve readily in polar solvents like water.
Non-polar solids dissolve in non-polar solvents (benzene, hexane).
<br/><br/>
<b>2. Temperature</b> (main focus of this project)<br/>
Most solid solutes show increased solubility with rising temperature (endothermic).
A few show the reverse (exothermic). Sodium chloride shows almost no change.
<br/><br/>
<b>3. Pressure</b><br/>
Pressure has negligible effect on the solubility of solids (unlike gases, which
follow Henry's Law). Solid solutes are incompressible, so pressure does not
significantly alter intermolecular distances in the solid lattice.
<br/><br/>
<b>4. Common Ion Effect</b><br/>
The presence of a common ion reduces solubility (e.g., adding NaCl to a saturated
NaCl solution reduces solubility due to excess Na⁺ or Cl⁻ ions shifting equilibrium).
<br/><br/>
<b>5. Particle Size</b><br/>
Very fine (nano-sized) particles dissolve slightly faster due to higher surface area,
though the maximum equilibrium solubility remains the same.
"""
story.append(Paragraph(factors_text, body))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# CHAPTER 5 — LE CHATELIER'S PRINCIPLE
# ══════════════════════════════════════════════════════════════════════════════
story.append(Spacer(1, 0.4*cm))
story.append(Paragraph("5. EFFECT OF TEMPERATURE: LE CHATELIER'S PRINCIPLE", ch_title))
story.append(chapter_rule())
le_chat = """
The dissolution of a solid in a solvent can be written as a reversible equilibrium:
<br/><br/>
<b>Solid (s) + Solvent ⇌ Solution (ΔH<sub>sol</sub>)</b>
<br/><br/>
<b>Le Chatelier's Principle</b> states: <i>"If a dynamic equilibrium is disturbed by
changing the conditions, the equilibrium position will shift to partially counteract
the change."</i>
<br/><br/>
Applying this to solubility:
<br/><br/>
<b>Case 1 — Endothermic Dissolution (ΔH<sub>sol</sub> > 0):</b><br/>
Example: KNO₃, NH₄Cl, KBr<br/>
Solid + Solvent + Heat ⇌ Solution<br/>
Increasing temperature adds energy (heat) to the system. To counteract this, the
equilibrium shifts right (forward), dissolving more solid. Therefore,
<b>solubility increases with temperature</b>.
<br/><br/>
<b>Case 2 — Exothermic Dissolution (ΔH<sub>sol</sub> < 0):</b><br/>
Example: CaSO₄, Li₂SO₄, Na₂SO₄·10H₂O<br/>
Solid + Solvent ⇌ Solution + Heat<br/>
Increasing temperature favours the reverse reaction (crystallisation). Therefore,
<b>solubility decreases with temperature</b>.
<br/><br/>
<b>Case 3 — Nearly Athermal Dissolution (ΔH<sub>sol</sub> ≈ 0):</b><br/>
Example: NaCl<br/>
Lattice energy and hydration energy are nearly equal in magnitude. Therefore,
<b>solubility shows very little change with temperature</b>.
"""
story.append(Paragraph(le_chat, body))
story.append(Spacer(1, 0.4*cm))
story.append(Paragraph("Fig 1: Enthalpy Diagrams for Endothermic and Exothermic Dissolution", sec_title))
for item in img(img_enthalpy, w=14*cm, caption_text='Figure 1: Energy level diagrams illustrating endothermic and exothermic dissolution processes'):
story.append(item)
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# CHAPTER 6 — MATERIALS
# ══════════════════════════════════════════════════════════════════════════════
story.append(Spacer(1, 0.4*cm))
story.append(Paragraph("6. MATERIALS REQUIRED", ch_title))
story.append(chapter_rule())
mat_data = [
['S.No.', 'Material / Equipment', 'Quantity', 'Purpose'],
['1', 'Potassium Nitrate (KNO₃) – pure grade', '100 g', 'Primary solute for solubility study'],
['2', 'Sodium Chloride (NaCl) – analytical grade', '50 g', 'Comparative solute (athermal)'],
['3', 'Calcium Sulphate (CaSO₄) – pure grade', '50 g', 'Comparative solute (inverse solubility)'],
['4', 'Distilled water', '500 mL', 'Solvent'],
['5', 'Beakers (100 mL)', '5', 'Heating and dissolving'],
['6', 'Thermometer (0–110 °C)', '2', 'Temperature measurement'],
['7', 'Bunsen burner / hot plate', '1', 'Heating'],
['8', 'Tripod stand + wire gauze', '1', 'Support during heating'],
['9', 'Glass stirring rod', '2', 'Stirring the solution'],
['10', 'Weighing balance (0.01 g precision)', '1', 'Measuring solute mass'],
['11', 'Spatula', '2', 'Transferring chemicals'],
['12', 'Evaporating dish', '3', 'Evaporating residual solvent'],
['13', 'Filter paper + funnel', '1 set', 'Filtration if needed'],
['14', 'Ice bath (ice + water)', '1', 'Achieving 0–10 °C readings'],
['15', 'Graph paper / computer', '--', 'Plotting solubility curves'],
['16', 'Safety goggles + gloves', '1 set', 'Personal protection'],
]
mat_tbl = Table(mat_data, colWidths=[1.3*cm, 6.5*cm, 2.5*cm, 6.2*cm])
mat_tbl.setStyle(tbl_style())
story.append(mat_tbl)
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# CHAPTER 7 — PROCEDURE
# ══════════════════════════════════════════════════════════════════════════════
story.append(Spacer(1, 0.4*cm))
story.append(Paragraph("7. PROCEDURE", ch_title))
story.append(chapter_rule())
proc_text = """
<b>Part A: Determining Solubility of KNO₃ at Different Temperatures</b>
<br/><br/>
<b>Step 1: Preparation of Saturated Solution</b><br/>
Take a clean, dry 100 mL beaker. Add 50 mL of distilled water measured accurately
using a measuring cylinder. Place the beaker on a hot plate and start adding weighed
amounts of KNO₃ (5 g at a time), stirring continuously after each addition, until no
more salt dissolves (i.e., a small residue remains at the bottom). Record the initial
temperature (T₁) and total KNO₃ dissolved.
<br/><br/>
<b>Step 2: Heating and Dissolution Observations</b><br/>
Heat the beaker slowly while continuously stirring. As temperature rises, observe
whether the undissolved residue dissolves. When it does, record the temperature —
this is the saturation temperature (T₂) for that mass of KNO₃ dissolved in 50 mL
water. Add another 5 g, heat further, record the new saturation temperature.
Continue until ~80 g of KNO₃ has been added.
<br/><br/>
<b>Step 3: Cooling Method (Alternative)</b><br/>
Alternatively, prepare a hot saturated KNO₃ solution at 100 °C. Allow it to cool
slowly. Note the temperature at which crystallisation just begins to appear. This
is the saturation temperature at which the amount of dissolved KNO₃ per 100 g water
gives the solubility.
<br/><br/>
<b>Step 4: Low Temperature Readings (0–20 °C)</b><br/>
Prepare saturated KNO₃ solutions in an ice bath (ice + water, ~0 °C). Gradually
allow temperature to rise and note saturation points at 10 °C and 20 °C.
<br/><br/>
<b>Step 5: Calculation</b><br/>
Solubility = (Mass of KNO₃ dissolved) / (Mass of water) × 100
<br/>= (m<sub>solute</sub> / m<sub>solvent</sub>) × 100 g per 100 g water
<br/><br/>
<b>Part B: Comparative Study — NaCl and CaSO₄</b><br/>
Repeat the above procedure for NaCl and CaSO₄. For CaSO₄ (sparingly soluble),
prepare solutions in larger volumes and use evaporation to determine the dissolved
mass precisely. Tabulate results at 0, 20, 40, 60, 80, 100 °C.
<br/><br/>
<b>Part C: Plotting Solubility Curves</b><br/>
Plot temperature (x-axis) vs solubility (y-axis) for each salt on the same graph.
Connect the data points with smooth curves. Analyse the shape of each curve.
"""
story.append(Paragraph(proc_text, body))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# CHAPTER 8 — PRECAUTIONS
# ══════════════════════════════════════════════════════════════════════════════
story.append(Spacer(1, 0.4*cm))
story.append(Paragraph("8. PRECAUTIONS", ch_title))
story.append(chapter_rule())
precs = [
"Use only distilled water to eliminate interference from dissolved impurities.",
"Ensure the thermometer is properly calibrated before use; immerse bulb fully in solution.",
"Heat the solution slowly and uniformly; rapid heating may cause bumping.",
"Stir continuously to ensure uniform temperature throughout the solution.",
"Use only analytical/pure grade chemicals to ensure accurate results.",
"Allow the system to reach thermal equilibrium before recording temperature readings.",
"Avoid contamination of chemicals; use separate spatulas for each compound.",
"While working at high temperatures, use tongs; beware of hot glassware.",
"Always wear safety goggles and gloves, especially when handling hot solutions.",
"Record all observations promptly and accurately; do not round off intermediate results.",
"Repeat each experiment at least three times and take the average for reliability.",
"Ensure the weighing balance is zeroed (tared) before each measurement.",
]
for i, p in enumerate(precs, 1):
story.append(Paragraph(f"{i}. {p}", bullet))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# CHAPTER 9 — OBSERVATIONS
# ══════════════════════════════════════════════════════════════════════════════
story.append(Spacer(1, 0.4*cm))
story.append(Paragraph("9. OBSERVATIONS AND RECORDED DATA", ch_title))
story.append(chapter_rule())
story.append(Paragraph("9.1 Solubility of Potassium Nitrate (KNO₃) in Water", sec_title))
story.append(section_rule())
kno3_data = [
['Exp.\nNo.', 'Temp.\n(°C)', 'Mass of\nWater (g)', 'Mass of KNO₃\nDissolved (g)',
'Solubility\n(g/100 g water)', 'State of\nSolution', 'Observations'],
['1', '0', '100', '13.3', '13.3', 'Saturated', 'White crystals remain at bottom'],
['2', '10', '100', '20.9', '20.9', 'Saturated', 'Fewer crystals; solution clearer'],
['3', '20', '100', '31.6', '31.6', 'Saturated', 'Crystals dissolve on stirring'],
['4', '30', '100', '45.8', '45.8', 'Saturated', 'Clear solution; crystal residue tiny'],
['5', '40', '100', '63.9', '63.9', 'Saturated', 'All crystals dissolved by 38 °C'],
['6', '50', '100', '85.5', '85.5', 'Saturated', 'Clear, colourless solution'],
['7', '60', '100', '110.0', '110.0', 'Saturated', 'Vigorous dissolution observed'],
['8', '70', '100', '138.0', '138.0', 'Saturated', 'Solution slightly viscous'],
['9', '80', '100', '169.0', '169.0', 'Saturated', 'Concentrated clear solution'],
['10','90', '100', '202.0', '202.0', 'Saturated', 'Very concentrated; slight yellow tinge'],
['11','100', '100', '246.0', '246.0', 'Saturated', 'Maximum solubility; boiling point elevated'],
]
kno3_tbl = Table(kno3_data, colWidths=[1.1*cm, 1.2*cm, 1.8*cm, 2.2*cm, 2.4*cm, 2.2*cm, 5.6*cm])
kno3_tbl.setStyle(tbl_style())
story.append(kno3_tbl)
story.append(Spacer(1, 0.5*cm))
story.append(Paragraph("9.2 Solubility of Sodium Chloride (NaCl) in Water", sec_title))
story.append(section_rule())
nacl_data = [
['Exp.\nNo.', 'Temp.\n(°C)', 'Mass of\nWater (g)', 'Mass of NaCl\nDissolved (g)',
'Solubility\n(g/100 g water)', 'Observations'],
['1', '0', '100', '35.7', '35.7', 'Saturated; white residue at bottom'],
['2', '10', '100', '35.8', '35.8', 'Almost no change from 0 °C'],
['3', '20', '100', '36.0', '36.0', 'Marginal increase'],
['4', '30', '100', '36.3', '36.3', 'Solution looks identical to 20 °C'],
['5', '40', '100', '36.6', '36.6', 'Slight increase observed'],
['6', '50', '100', '37.0', '37.0', 'Approximately constant trend'],
['7', '60', '100', '37.3', '37.3', 'Gradual linear increase'],
['8', '70', '100', '37.8', '37.8', 'Clear solution; nearly plateau'],
['9', '80', '100', '38.4', '38.4', 'Very slight increase'],
['10','90', '100', '39.0', '39.0', 'Nearly flat curve seen on graph'],
['11','100', '100', '39.8', '39.8', 'Only ~4 g increase over 100 °C range'],
]
nacl_tbl = Table(nacl_data, colWidths=[1.1*cm, 1.2*cm, 1.8*cm, 2.2*cm, 2.4*cm, 7.8*cm])
nacl_tbl.setStyle(tbl_style())
story.append(nacl_tbl)
story.append(PageBreak())
story.append(Spacer(1, 0.4*cm))
story.append(Paragraph("9.3 Solubility of Calcium Sulphate (CaSO₄) in Water", sec_title))
story.append(section_rule())
caso4_data = [
['Exp.\nNo.', 'Temp.\n(°C)', 'Mass of\nWater (g)', 'Mass of CaSO₄\nDissolved (g)',
'Solubility\n(g/100 g water)', 'Observations'],
['1', '0', '100', '1.76', '1.76', 'Sparingly soluble; cloudy suspension'],
['2', '10', '100', '2.00', '2.00', 'Slightly clearer; small increase'],
['3', '20', '100', '2.09', '2.09', 'Maximum solubility reached near 20 °C'],
['4', '30', '100', '2.07', '2.07', 'Slight precipitation begins'],
['5', '40', '100', '1.98', '1.98', 'Cloudiness increases on heating'],
['6', '50', '100', '1.86', '1.86', 'White precipitate forming'],
['7', '60', '100', '1.70', '1.70', 'Visible decrease in clarity'],
['8', '70', '100', '1.55', '1.55', 'Significant precipitation at ~70 °C'],
['9', '80', '100', '1.41', '1.41', 'Heavy white precipitate'],
['10','90', '100', '1.26', '1.26', 'Solution increasingly turbid'],
['11','100', '100', '1.14', '1.14', 'Minimum solubility; inverse confirmed'],
]
caso4_tbl = Table(caso4_data, colWidths=[1.1*cm, 1.2*cm, 1.8*cm, 2.2*cm, 2.4*cm, 7.8*cm])
caso4_tbl.setStyle(tbl_style())
story.append(caso4_tbl)
story.append(Spacer(1, 0.5*cm))
story.append(Paragraph("9.4 Consolidated Solubility Data Table", sec_title))
story.append(section_rule())
consol_data = [
['Temperature (°C)', 'KNO₃\n(g/100 g H₂O)', 'KBr\n(g/100 g H₂O)', 'KHCO₃\n(g/100 g H₂O)',
'NaCl\n(g/100 g H₂O)', 'CaSO₄\n(g/100 g H₂O)'],
['0', '13.3', '53.5', '22.4', '35.7', '1.76'],
['10', '20.9', '59.5', '27.5', '35.8', '2.00'],
['20', '31.6', '65.3', '33.7', '36.0', '2.09'],
['30', '45.8', '70.9', '41.2', '36.3', '2.07'],
['40', '63.9', '76.6', '50.0', '36.6', '1.98'],
['50', '85.5', '82.4', '60.1', '37.0', '1.86'],
['60', '110.0', '88.4', '72.0', '37.3', '1.70'],
['70', '138.0', '94.2', '85.0', '37.8', '1.55'],
['80', '169.0', '100.2','100.0','38.4', '1.41'],
['90', '202.0', '106.2','116.0','39.0', '1.26'],
['100', '246.0', '112.5','134.0','39.8', '1.14'],
]
consol_tbl = Table(consol_data, colWidths=[3*cm, 2.5*cm, 2.5*cm, 2.5*cm, 2.5*cm, 2.5*cm])
consol_tbl.setStyle(tbl_style())
story.append(consol_tbl)
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# CHAPTER 10 — GRAPHICAL ANALYSIS
# ══════════════════════════════════════════════════════════════════════════════
story.append(Spacer(1, 0.4*cm))
story.append(Paragraph("10. GRAPHICAL ANALYSIS AND CHARTS", ch_title))
story.append(chapter_rule())
story.append(Paragraph("10.1 Master Solubility Curve — All Five Salts", sec_title))
story.append(section_rule())
story.append(Paragraph(
"The chart below shows solubility curves for KNO₃, KBr, KHCO₃, and NaCl (left axis) and "
"CaSO₄ (right axis, red dashed line) plotted against temperature from 0 to 100 °C.", body))
for item in img(img_main, w=15*cm,
caption_text='Figure 2: Solubility vs Temperature — master graph for five common salts (data from Table 9.4)'):
story.append(item)
story.append(PageBreak())
story.append(Paragraph("10.2 Solubility Curve — Potassium Nitrate (KNO₃)", sec_title))
story.append(section_rule())
story.append(Paragraph(
"KNO₃ shows a steep, nearly exponential increase in solubility with temperature. "
"Dissolution is highly endothermic (ΔH ≈ +34.9 kJ/mol), consistent with Le Chatelier's Principle. "
"Solubility nearly doubles every 20 °C, making KNO₃ ideal for demonstrating crystallisation from hot solutions.", body))
for item in img(img_kno3, w=14*cm,
caption_text='Figure 3: Solubility curve of KNO₃. Annotated data points show recorded values.'):
story.append(item)
story.append(PageBreak())
story.append(Paragraph("10.3 Solubility Curve — Sodium Chloride (NaCl)", sec_title))
story.append(section_rule())
story.append(Paragraph(
"NaCl displays a nearly flat solubility curve with only a marginal increase from "
"35.7 g at 0 °C to 39.8 g at 100 °C (a rise of only 4.1 g over the entire 100 °C range). "
"This is because the lattice energy of NaCl (~786 kJ/mol) and its hydration energy "
"(~784 kJ/mol) are nearly equal, making ΔH<sub>sol</sub> ≈ +2 kJ/mol — nearly athermal.", body))
for item in img(img_nacl, w=14*cm,
caption_text='Figure 4: Solubility curve of NaCl — nearly horizontal, showing athermal dissolution.'):
story.append(item)
story.append(PageBreak())
story.append(Paragraph("10.4 Solubility Curve — Calcium Sulphate (CaSO₄)", sec_title))
story.append(section_rule())
story.append(Paragraph(
"CaSO₄ (gypsum) shows a <b>retrograde / inverse solubility</b> behaviour. Solubility "
"peaks around 20 °C (~2.09 g/100 g water) and then decreases steadily to 1.14 g at 100 °C. "
"This is an exothermic dissolution (ΔH < 0); heating shifts equilibrium toward precipitation. "
"This property causes scale formation in boilers and hot-water pipes — a major industrial problem.", body))
for item in img(img_caso4, w=14*cm,
caption_text='Figure 5: Solubility curve of CaSO₄ — inverse relationship with temperature.'):
story.append(item)
story.append(PageBreak())
story.append(Paragraph("10.5 Bar Chart — Solubility Comparison at 0, 50, and 100 °C", sec_title))
story.append(section_rule())
story.append(Paragraph(
"The grouped bar chart below compares the solubility of all five salts at three "
"representative temperatures — 0 °C, 50 °C, and 100 °C — providing a clear "
"visual comparison of how dramatically (or minimally) solubility changes.", body))
for item in img(img_bar, w=15*cm,
caption_text='Figure 6: Grouped bar chart — solubility of five salts at 0, 50, and 100 °C.'):
story.append(item)
story.append(PageBreak())
story.append(Paragraph("10.6 Pie Charts — Relative Solubility at 0 °C and 100 °C", sec_title))
story.append(section_rule())
story.append(Paragraph(
"The pie charts show the relative proportion of total dissolved solid (from all five salts "
"combined) attributable to each salt at 0 °C and at 100 °C. Note how KNO₃'s share rises "
"dramatically while CaSO₄'s share shrinks.", body))
for item in img(img_pie, w=14*cm,
caption_text='Figure 7: Pie charts showing relative solubility distribution at 0 °C (left) and 100 °C (right).'):
story.append(item)
story.append(PageBreak())
story.append(Paragraph("10.7 Rate of Change of Solubility (dS/dT)", sec_title))
story.append(section_rule())
story.append(Paragraph(
"The graph below plots the derivative of solubility with respect to temperature (dS/dT) "
"for KNO₃ and NaCl. A higher dS/dT means solubility is changing rapidly — KNO₃ shows "
"an accelerating rate (curved upward) while NaCl remains near zero, confirming the "
"near-constant behaviour of NaCl.", body))
for item in img(img_rate, w=14*cm,
caption_text='Figure 8: Rate of change of solubility (dS/dT) vs temperature for KNO₃ and NaCl.'):
story.append(item)
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# CHAPTER 11 — ANALYSIS OF RESULTS
# ══════════════════════════════════════════════════════════════════════════════
story.append(Spacer(1, 0.4*cm))
story.append(Paragraph("11. ANALYSIS OF RESULTS", ch_title))
story.append(chapter_rule())
analysis_text = """
<b>11.1 KNO₃ — Highly Temperature-Sensitive (Endothermic)</b>
<br/><br/>
The solubility of KNO₃ increased from 13.3 g at 0 °C to 246.0 g at 100 °C — an
<b>18.5-fold increase</b>. The solubility curve is steep and upward-curving, indicating
an accelerating rate of increase. The large positive ΔH<sub>sol</sub> (+34.9 kJ/mol) means
that adding heat to the dissolution equilibrium drives the reaction strongly forward.
<br/><br/>
This property is exploited in <b>fractional crystallisation</b> — a technique used to purify
KNO₃ (and other salts with steep solubility curves) by dissolving them in hot water and
cooling to crystallise the product while impurities remain in solution.
<br/><br/>
<b>11.2 NaCl — Temperature Insensitive (Athermal)</b>
<br/><br/>
NaCl's solubility changes by only 4.1 g over 100 °C (from 35.7 to 39.8 g / 100 g water),
a modest <b>11.5% increase</b>. This explains why seawater does not become significantly
more salty when heated — NaCl's solubility is practically temperature-independent. The
nearly athermal nature arises from a near-exact cancellation of lattice energy (endothermic
step) and hydration energy (exothermic step).
<br/><br/>
<b>11.3 CaSO₄ — Inverse (Retrograde) Solubility</b>
<br/><br/>
CaSO₄ shows peak solubility at ~20 °C (2.09 g/100 g water) then decreases to 1.14 g at
100 °C. The dissolution is exothermic; raising temperature drives the reverse reaction
(precipitation). This explains the well-known problem of <b>boiler scale</b>: as water
temperature rises in industrial boilers, CaSO₄ precipitates onto heating surfaces,
forming an insulating scale that reduces efficiency and can cause tube overheating and failure.
<br/><br/>
<b>11.4 KBr and KHCO₃</b>
<br/><br/>
Both show positive (endothermic) solubility-temperature relationships, though less steep
than KNO₃. KBr increases from 53.5 g to 112.5 g (2.1× increase), while KHCO₃ increases
from 22.4 g to 134.0 g (6× increase) over the 0–100 °C range.
"""
story.append(Paragraph(analysis_text, body))
story.append(Spacer(1, 0.4*cm))
# Percentage change table
story.append(Paragraph("11.5 Percentage Change in Solubility (0 °C to 100 °C)", sec_title))
story.append(section_rule())
pct_data = [
['Salt', 'Solubility at 0 °C\n(g/100 g H₂O)', 'Solubility at 100 °C\n(g/100 g H₂O)',
'% Change', 'Nature of Dissolution'],
['KNO₃', '13.3', '246.0', '+1750%', 'Highly endothermic'],
['KHCO₃', '22.4', '134.0', '+498%', 'Endothermic'],
['KBr', '53.5', '112.5', '+110%', 'Endothermic'],
['NaCl', '35.7', '39.8', '+11.5%', 'Nearly athermal'],
['CaSO₄', '1.76', '1.14', '–35.2%', 'Exothermic (retrograde)'],
]
pct_tbl = Table(pct_data, colWidths=[2.5*cm, 3.5*cm, 3.5*cm, 2*cm, 5*cm])
pct_tbl.setStyle(tbl_style())
story.append(pct_tbl)
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# CHAPTER 12 — DISCUSSION
# ══════════════════════════════════════════════════════════════════════════════
story.append(Spacer(1, 0.4*cm))
story.append(Paragraph("12. DISCUSSION", ch_title))
story.append(chapter_rule())
discussion = """
<b>12.1 Thermodynamic Explanation</b>
<br/><br/>
The Gibbs free energy equation provides a unified framework:
<br/>
<b>ΔG = ΔH – TΔS</b>
<br/><br/>
For a dissolution process to be spontaneous, ΔG must be negative. Even if ΔH is
positive (endothermic), the term –TΔS can make ΔG negative at sufficiently high T,
because dissolution always increases entropy (ΔS > 0 — ions become dispersed and
randomly distributed in solution). This is why most ionic solids dissolve more
readily at higher temperatures despite endothermic enthalpy.
<br/><br/>
For exothermic solutes (e.g., CaSO₄), ΔH is negative. The dissolution is energetically
favoured at low temperature (ΔG = ΔH – TΔS; at low T, the ΔH term dominates). As T
rises, TΔS increases, but the reverse reaction also gains entropy when solid precipitates
(ions in concentrated solution become ordered in the lattice). The net result is reduced
solubility at high T.
<br/><br/>
<b>12.2 Crystallisation from Supersaturated Solutions</b>
<br/><br/>
A supersaturated solution contains more dissolved solute than the equilibrium solubility
at that temperature. It is a metastable state. Any disturbance — a scratch on the glass,
a dust particle, or a seed crystal — triggers rapid crystallisation. The solubility-temperature
relationship of KNO₃ makes it ideal for demonstrating this: dissolve a large mass of KNO₃
at 80 °C, cool to 20 °C carefully — the solution becomes supersaturated. Adding a tiny KNO₃
seed crystal triggers a dramatic crystallisation cascade.
<br/><br/>
<b>12.3 Hydrated Salts and Incongruent Solubility</b>
<br/><br/>
Some salts exist as hydrated crystals below a certain temperature and anhydrous above it.
For example:
<br/>
• Na₂SO₄·10H₂O (Glauber's salt) is stable below 32.4 °C (transition temperature).
Above this, it converts to anhydrous Na₂SO₄, and the solubility drops sharply.
<br/>
• This creates a <b>discontinuity in the solubility curve</b> at the transition temperature —
an important concept for phase diagrams and industrial crystallisation design.
<br/><br/>
<b>12.4 Industrial and Environmental Significance</b>
<br/><br/>
Understanding solubility-temperature relationships is critical in:
<br/>
• <b>Sugar refining</b>: Sugar is highly soluble in hot water; cooling crystallises sucrose.
<br/>
• <b>Geothermal systems</b>: CaSO₄ and CaCO₃ precipitation in geothermal pipes.
<br/>
• <b>Pharmaceutical</b>: Drug solubility determines bioavailability; formulated to dissolve
at body temperature (37 °C).
<br/>
• <b>Water treatment</b>: Softening processes exploit differential solubility.
"""
story.append(Paragraph(discussion, body))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# CHAPTER 13 — SOURCES OF ERROR
# ══════════════════════════════════════════════════════════════════════════════
story.append(Spacer(1, 0.4*cm))
story.append(Paragraph("13. SOURCES OF ERROR AND LIMITATIONS", ch_title))
story.append(chapter_rule())
errors_data = [
['S.No.', 'Source of Error', 'How It Affects Results', 'Remedy'],
['1', 'Temperature gradient in beaker',
'Non-uniform temperature; different parts of solution at different T',
'Stir continuously; use water bath for uniform heating'],
['2', 'Impure water (tap water)',
'Dissolved ions alter solubility; results shift from true values',
'Always use distilled or deionised water'],
['3', 'Weighing error (±0.05 g)',
'Underestimates or overestimates solubility by up to 0.5 g/100 g',
'Use 4-decimal-place analytical balance; tare repeatedly'],
['4', 'Hygroscopic solutes',
'KNO₃ absorbs moisture from air, adding to apparent dissolved mass',
'Weigh quickly; store in desiccator'],
['5', 'Reading crystallisation temperature too early',
'Reports slightly higher T for saturation; underestimates solubility',
'Cool slowly (≤1 °C/min); observe carefully under good lighting'],
['6', 'Evaporation of solvent during heating',
'Reduces solvent mass; overestimates solubility',
'Cover beaker with watch glass; correct for evaporation loss'],
['7', 'Supersaturation effect',
'Solution remains unsaturated past true saturation T without nucleation',
'Add a seed crystal or introduce physical disturbance at each step'],
['8', 'Parallax in thermometer reading',
'Systematic error in temperature (±0.5–1 °C)',
'Read thermometer at eye level; use digital thermometer'],
]
errors_tbl = Table(errors_data, colWidths=[1.2*cm, 3.5*cm, 4.5*cm, 7.3*cm])
errors_tbl.setStyle(tbl_style())
story.append(errors_tbl)
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# CHAPTER 14 — CONCLUSION
# ══════════════════════════════════════════════════════════════════════════════
story.append(Spacer(1, 0.4*cm))
story.append(Paragraph("14. CONCLUSION", ch_title))
story.append(chapter_rule())
conclusion = """
The experimental investigation and theoretical analysis in this project lead to the
following scientifically valid conclusions:
<br/><br/>
<b>1. Temperature significantly influences the solubility of solids in liquids</b>, but the
nature and magnitude of the effect depend on the thermodynamic properties of the specific
solute-solvent system.
<br/><br/>
<b>2. Potassium Nitrate (KNO₃)</b> shows a steep, endothermic increase in solubility —
from 13.3 g at 0 °C to 246.0 g at 100 °C — a 1750% increase. This is fully consistent
with Le Chatelier's Principle for endothermic dissolution.
<br/><br/>
<b>3. Sodium Chloride (NaCl)</b> shows minimal change in solubility over the entire
temperature range (35.7 to 39.8 g/100 g water), confirming that its dissolution
enthalpy is nearly zero — lattice energy and hydration energy are nearly equal.
<br/><br/>
<b>4. Calcium Sulphate (CaSO₄)</b> demonstrates inverse (retrograde) solubility —
maximum at ~20 °C, decreasing thereafter — consistent with exothermic dissolution
where heat disfavours further dissolution at higher temperatures.
<br/><br/>
<b>5. The Van't Hoff equation and Gibbs energy analysis</b> provide a quantitative framework
that accurately predicts these behaviours. Entropy of dissolution (always positive) and
enthalpy (positive, negative, or near-zero) together determine the temperature dependence.
<br/><br/>
<b>6. The solubility curves</b> (Figures 2–8) graphically confirm all experimental observations
and can be used to determine the exact solubility at any temperature within the studied range.
<br/><br/>
<b>7. Practical significance:</b> These findings have direct applications in fractional
crystallisation, industrial scale prevention, pharmaceutical formulation, and food
processing — demonstrating the industrial relevance of this fundamental chemical principle.
"""
story.append(Paragraph(conclusion, body))
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# CHAPTER 15 — APPLICATIONS
# ══════════════════════════════════════════════════════════════════════════════
story.append(Spacer(1, 0.4*cm))
story.append(Paragraph("15. APPLICATIONS IN DAILY LIFE AND INDUSTRY", ch_title))
story.append(chapter_rule())
apps_data = [
['Application', 'How Solubility-Temperature Effect is Used'],
['Fractional Crystallisation',
'Mixtures of salts (e.g., KNO₃ + NaCl) are dissolved in hot water and cooled. '
'KNO₃, with its steep curve, crystallises first; NaCl stays in solution. '
'Used to purify KNO₃ for fertilisers and pyrotechnics.'],
['Sugar Refining',
'Sucrose solubility is ~200 g/100 g water at 20 °C but increases to ~487 g at 80 °C. '
'Raw sugar is dissolved in hot water, decolourised, then cooled to crystallise pure white sugar.'],
['Boiler Scale Prevention',
'CaSO₄ and CaCO₃ deposit on boiler walls as water is heated (retrograde solubility). '
'Scale acts as insulator, reducing efficiency. Water softening and anti-scaling agents are used.'],
['Pharmaceutical Formulation',
'Drug solubility at 37 °C (body temperature) governs bioavailability. '
'Poorly soluble drugs are processed into amorphous forms or nano-particles to boost solubility.'],
['Food Preservation',
'Salt (NaCl) brining is effective across a wide temperature range due to near-constant solubility. '
'Cold brine and hot brine have nearly equal salt concentration — predictable preservation.'],
['Geothermal Energy',
'Hot geothermal fluids bring dissolved minerals to surface. As water cools and pressure drops, '
'minerals crystallise (silica, calcite, CaSO₄), causing pipeline blockages (scaling).'],
['Homeopathy & Medicine',
'Saturated KNO₃ solutions are used in tooth desensitisation. Understanding solubility '
'ensures correct concentration is maintained at body temperature.'],
['Photography (historic)',
'Silver nitrate and other light-sensitive salts are dissolved at precise temperatures to '
'coat photographic films and papers with uniform grain size.'],
['Water Desalination',
'Reverse osmosis plant operators must account for CaSO₄ retrograde solubility to prevent '
'membrane fouling at elevated operating temperatures.'],
['Mining & Hydrometallurgy',
'Leaching of ores with hot acid or alkali solutions exploits higher solubility at elevated '
'temperature to extract metal ions efficiently from crushed ore.'],
]
apps_tbl = Table(apps_data, colWidths=[4.5*cm, 12*cm])
apps_tbl.setStyle(tbl_style())
story.append(apps_tbl)
story.append(PageBreak())
# ══════════════════════════════════════════════════════════════════════════════
# CHAPTER 16 — REFERENCES
# ══════════════════════════════════════════════════════════════════════════════
story.append(Spacer(1, 0.4*cm))
story.append(Paragraph("16. REFERENCES AND BIBLIOGRAPHY", ch_title))
story.append(chapter_rule())
refs = [
["Textbooks", [
"NCERT Chemistry Part I, Class XII, Chapter 2 — Solutions. New Delhi: NCERT Publications, 2024.",
"NCERT Chemistry Part II, Class XII. New Delhi: NCERT Publications, 2024.",
"P. Atkins and J. de Paula, <i>Physical Chemistry</i>, 11th ed. Oxford University Press, 2022.",
"R.C. Mukherjee, <i>Modern Approach to Chemical Calculations</i>. Bharati Bhawan, 2020.",
"O.P. Tandon, <i>Physical Chemistry for Class XII</i>. G.R. Bathla Publications, 2021.",
]],
["Online References", [
"National Institute of Standards and Technology (NIST) Chemistry WebBook — https://webbook.nist.gov/",
"CRC Handbook of Chemistry and Physics, 103rd edition (online access).",
"Solubility data compiled from CRC Handbook, Merck Index, and NIST SRD-24.",
"Khan Academy — Solutions and Solubility Module — https://www.khanacademy.org/",
"CBSE Sample Papers and NCERT Exemplar Problems, Chemistry Class XII, 2024-25.",
]],
["Laboratory Manuals", [
"NCERT Laboratory Manual Chemistry, Class XII. New Delhi: NCERT, 2024.",
"S.N. Dhawan, <i>Comprehensive Practical Chemistry Class XII</i>. Laxmi Publications, 2021.",
]],
]
for section, items in refs:
story.append(Paragraph(f"<b>{section}</b>", body_bold))
for i, item in enumerate(items, 1):
story.append(Paragraph(f"[{i}] {item}", small))
story.append(Spacer(1, 0.3*cm))
story.append(Spacer(1, 0.5*cm))
story.append(HRFlowable(width='100%', thickness=1.5, color=ACCENT, spaceAfter=10))
story.append(Paragraph(
"<b>END OF PROJECT REPORT</b>",
S('End', fontName='Helvetica-Bold', fontSize=12, textColor=DARK_BLUE,
alignment=TA_CENTER, spaceAfter=4)))
story.append(Paragraph(
"CBSE Class XII Chemistry Investigatory Project | 2025–26",
S('EndSub', fontName='Helvetica-Oblique', fontSize=10, textColor=HexColor('#555555'),
alignment=TA_CENTER)))
# ─────────────────────────────────────────────
# BUILD PDF
# ─────────────────────────────────────────────
output_path = os.path.join(OUTPUT_DIR, 'Solubility_Temperature_CBSE_Class12.pdf')
doc = SimpleDocTemplate(
output_path,
pagesize=A4,
leftMargin=2.0*cm, rightMargin=2.0*cm,
topMargin=1.8*cm, bottomMargin=1.5*cm,
title='Effect of Temperature on Solubility of Solids in Liquids',
author='Class XII Student',
subject='CBSE Chemistry Investigatory Project',
)
def on_page(canv, doc):
if doc.page == 1:
cover_page(canv, doc)
else:
header_footer(canv, doc)
doc.build(story, onFirstPage=on_page, onLaterPages=on_page)
print(f"\nPDF generated successfully: {output_path}")
import os
size = os.path.getsize(output_path)
print(f"File size: {size/1024:.1f} KB")
# Count pages
from pypdf import PdfReader
reader = PdfReader(output_path)
print(f"Total pages: {len(reader.pages)}")
cd /home/daytona/workspace/solubility-project && python generate_project.py 2>&1