Determining Chemical Kinetics through Colour Space Analysis

Felicity Draper, PhD Student (Chemistry)
School of Life and Environment Sciences
Deakin University

Join the Conversation #AustralasiaWTC2024

Chemical Kinetics - Photoredox Catalysis

Using light to initiate chemical reactions

Nature = Photosynthesis
Chemists = Photoredox Catalysis

Photo = Light
Redox = Reduction/Oxidation Reaction (electron transfer)
Catalysis = To make something go faster!

Measurement of Kinetics

Spectroscopy - Use of light absorbed or emitted to study chemical systems

DensityPlot[x,{x,380,750},{y,0,50},ColorFunction->ColorData["VisibleSpectrum"],ColorFunctionScaling->False,AspectRatio->Automatic,FrameTicks->{{None,None},{Automatic,None}}]

Starting photocatalyst (PC) - weakly absorbing yellow

Reduced photocatalyst - after successful transfer of an electron - strongly coloured

Measurement of Kinetics

Using spectroscopy we can only measure one set of conditions at a time

What about if we want to measure 100 conditions at once?

The Party Box!

High Through-Put Analysis of Kinetics

Import Images

SetDirectory["/Users/felicitydraper/Dropbox/PhD/partyBox/PBOpt2024/Slink 600uL Tests/phen full test 26p5 test1"];
pics=Import["Images/*.PNG"];
pics[[1]]

picsCrop=Table[ImageTake[pics[[i]],{553,1518},{798,1785}],{i,1,Length[pics]}]; (*crops image to only required space*)
numPicsT=20;
Row[Table[picsCrop[[i]],{i,1,10}]]

High Through-Put Analysis of Kinetics

Separate each vial by row

r1x=Range[4,1100,96];(*row coordinates*)
rowsx=Table[ImageTake[picsCrop[[i]],{r1x[[j]],r1x[[j+1]]}],{i,1,numPicsT},{j,1,10}];
rowsBinx=Table[Binarize[rowsx[[2,i]],0.2],{i,1,10}];(*creates binarized image of each vial position*)
rowsx[[6,4]]
rowsBinx[[4]]

Separate   each   vial   by   column

blackImgs =ImageRotate[ Image[ConstantArray[0,ImageDimensions[rowsx[[1,1]]]],"Byte"]];
whiteSquare=Image[ConstantArray[1,{100,100}]]; (*creates mask to cover*)
coordsJx=Range[50,1000,100]; (*selects position of column*)
combinedImage=Table[ImageCompose[blackImgs,whiteSquare,{coordsJx[[i]],50}],{i,1,10}];(*creates mask for each column position*)
masksx=Table[ImageMultiply[rowsBinx[[i]],combinedImage[[j]]],{i,1,10},{j,1,10}];
masksx[[3,5]]

High Through-Put Analysis of Kinetics

Create masked Images

maskedImagesx=Monitor[Table[ImageMultiply[rowsx[[p,i]],masksx[[i,j]]],{p,1,numPicsT},{i,1,10},{j,1,10}],{i,j}] ;(*uses ImageMultiply to put each image in the mask*)
maskedImagesx[[2,3,5]]

Using Saturation to Approximate Absorbance

A strongly coloured (absorbing) solution will have greater saturation - obtained through HSB colour space

Convert  Images to Values/pixel in HSB

HSBimagesx=Table[ColorConvert[maskedImagesx[[p,i,j]],"HSB"],{p,1,numPicsT},{i,1,10},{j,1,10}]; (*convert pictures to HSB colour scheme*)
HSBimagesx[[2,3,5]]

pixelsHSBsx=Monitor[Table[ImageData[HSBimagesx[[p,i,j]],"Byte"],{p,1,numPicsT},{i,1,10},{j,1,10}],{p,i,j}];(*convert HSB to pixel value*)

satPixelsx=Table[pixelsHSBsx[[p,i,j,All,All,2]],{p,1,numPicsT},{i,1,10},{j,1,10}];

Clear[pixelsHSBsx]
Clear[HSBimagesx]

Selects desired pixels from each vial using mask

pixelsMasksx=Table[ImageData[masksx[[i,j]]],{i,1,10},{j,1,10}];
pixelsMaskFlatx=Table[Flatten[pixelsMasksx[[i,j]]],{i,1,10},{j,1,10}];(*flatten mask into each list*)
satPixelsFlatx=Table[Flatten[satPixelsx[[p,i,j]]],{p,1,numPicsT},{i,1,10},{j,1,10}];(*flatten each HSB set into a list*)
vialSatPixelsx=Table[Pick[satPixelsFlatx[[p,i,j]],pixelsMaskFlatx[[i,j]],1.],{p,1,numPicsT},{i,1,10},{j,1,10}];

Saturation - visualise

satPixArrays=Row[Table[ArrayPlot[SparseArray[satPixelsx[[i,8,10,All,900;;980]]],PlotLabel->"Saturation",LabelStyle->{FontSize->14,FontFamily->"Helvetica",Bold,Red},ImageSize->180],{i,1,4}]]

Plot Change in Average Saturation

Plot Change in Average Saturation

satMeanx=Map[Mean,vialSatPixelsx,{3}];(*take the average pixel value*)

colour=ColorData["Rainbow"]/@ Range[0,1,1/100];
time=Range[0,(Length[satDataFit[[2]]]/2)-0.5,0.5];

satDataFit=Flatten[Table[satMeanx[[1;;numPicsT,i,j]],{i,1,10},{j,1,10}],1];

kinAll=Show[Table[ListLinePlot[{time,satDataFit[[i]]}\[Transpose],
PlotStyle->Directive[colour[[i]]],
PlotRange->{{0,10},{0,255}},Frame->True,
FrameStyle->Directive[Black,12],
FrameLabel->{"Time (min)","Mean Saturation"}],{i,1,100}
]]

Comparison to Spectroscopy

When we compare this catalyst to changes observed with spectroscopy we find the rate of change appears similar

spec=;

pb=ListLinePlot[satMeanx[[1;;numPicsT,10,1]],PlotRange->{{0,20},{0,255}},PlotStyle->Green,Frame->True,FrameLabel->{"Time points","Mean Saturation"},PlotMarkers->Automatic,ImageSize->200];

{spec,pb}

Fit the Rate of Change

We can fit either the initial linear rate, or exponential rate over the whole reaction for each catalyst

timeFit=2;;4; (*choose time points to fit between*)
kvals=Table[With[{fit=LinearModelFit[{time[[timeFit]],satDataFit[[i,timeFit]]}\[Transpose],x,x]},fit["BestFitParameters"][[2]]],{i,1,100}];(*fit and extract fitted values for initia*)

kfitPlotsLin=Table[kfit[x_]:=kvals[[i]]*x+dvals[[i]];
Plot[kfit[x],{x,0,60},PlotStyle->{Red,Dashed},PlotLabel->"label"],{i,Length[kvals]}]; (*plot fit*)
kinPlots=Table[ListLinePlot[{time,satDataFit[[i]]}\[Transpose],PlotRange->{{0,10},{0,255}},PlotLabel->"Identifier"],{i,1,100}];(*plot graph*)

overlaidPlots=Table[Show[kfitPlotsLin[[i]],kinPlots[[i]],PlotRange->{{0,10},{0,255}},AxesOrigin->{0,0},Frame->True,LabelStyle->Directive[Black,8],ImageMargins->0 ],{i,1,100}];(*overlay plot of fit and graph over each other*)

satplotExp=Grid[Partition[overlaidPlots[[1;;5]],5],Frame->None,FrameStyle->Directive[GrayLevel[0.68],Thin],Spacings->{-0.08,-2.2}]

Exponential Fit

model=a*Exp[-k*x]+c;
nlmfits=Table[NonlinearModelFit[{time[[1;;-1]],satDataFit[[i,1;;-1]]}\[Transpose],model,{{a,-100},{k,0.5},{c,150}},x],{i,1,100}];
nlmplots=Table[Plot[nlmfits[[i]][x],{x,0,10},PlotRange->{{-0.1,25},{-0.1,255}},PlotStyle->Red],{i,1,100}];
dotPlots=Table[ListPlot[{time,satDataFit[[i]]}\[Transpose],PlotRange->{{-0.1,25},{-0.1,255}},PlotStyle->Black],{i,1,100}];

overlaidPlotsNLM=Table[Show[nlmplots[[i]],dotPlots[[i]],PlotRange->{{0,10},{0,255}},AxesOrigin->{0,0},Frame->True,LabelStyle->Directive[Black,8],ImageMargins->0 ],{i,1,100}];

nlmplotExp=Grid[Partition[overlaidPlotsNLM[[1;;5]],5],Frame->None,FrameStyle->Directive[GrayLevel[0.68],Thin],Spacings->{-0.08,-2.2}] (*Adjust spacing between plots*)

Visualise the Results - One Catalyst

Compare linear fits

barPlotLin=ListPlot[{Range[1,100],kvals}\[Transpose],PlotMarkers->{Black,Medium},PlotRange->{{0,100},{0,100}},Frame->True,FrameLabel->{"Vial number","Saturation/fit"},FrameStyle->Directive[Black,12]]

matrix=MatrixPlot[Partition[kvals,10],
FrameLabel->"Rate of Catalyst Reduction",
ColorFunction->ColorData["TemperatureMap"],
Mesh->True]

This slide has been left intentionally blank

A Problem - Colour Variations

Different colours lead to different saturation despite same spectroscopic peak intensities

Variance from spectroscopic results

Catalysts  that  become  different  colours  absorb  different  amounts  of  the  top  light

This  means  the  relative  rates  of  saturation  change  will  not  reflect  true  rates  of  reactivity

Solutions ???

How can we use this data to extract meaningful results ??

Different colour spaces?

Error corrections?

Selective experimental conditions?

Thank you :)

Questions?