I have a graph that I made that has 2 sets of data, and plots these as 2 lines using LineLinePlot, does some simple calculations and writes these as an Epilog on the plot.

However, this was done by hand, there's just 2 sets of all the code. Which made me start thinking, how would I go about generalising this to n-many data sets, so I could just enter the stack of data, and the code would produce that line and it's calculations and epilog box (I appreciate I might run into problems with limited space on the graph to put the epilog boxes - I guess they could be put to the right hand side off the graph)

Would it use a loop in some way?

Current 'manual' version for 2 lines included below (minimised where i can):

dataSet = {{63, 1.26}, {92, 1.74}, {156, 1.88}, {250, 2.33}, {317,
2.69}, {351, 2.85}, {357, 3.42}, {391, 3.43}, {422, 3.44}};
dataSet2 = {{50, 0.55}, {167, 1.6}, {169, 2.47}, {182, 3.2}, {227,
3.32}, {232, 3.39}, {262, 3.91}, {281, 1.26}, {310, 1.74}, {374,
1.88}, {468, 2.33}, {535, 2.69}, {575, 3.42}, {609, 3.43}, {640,
3.44}};

set[1] = Cases[dataSet, {x_, y_} /; x < 423];
set[2] = Cases[dataSet2, {x_, y_} /; x < 263];
set[3] = Cases[dataSet2, {x_, y_} /; x > 264];

avgCurrent =
Integrate[
Interpolation[dataSet, InterpolationOrder -> 1][x], {x,
dataSet[[1, 1]], dataSet[[-1, 1]]}]/(Subtract @@
dataSet[[{-1, 1}, 1]]) // N // SetPrecision[#, 3] &
maxCurrent = MaximalBy[dataSet, Last][[1, 2]];
noPoints = Length[dataSet];

avgCurrent2 =
Integrate[
Interpolation[dataSet2, InterpolationOrder -> 1][x], {x,
dataSet2[[1, 1]], dataSet2[[-1, 1]]}]/(Subtract @@
dataSet2[[{-1, 1}, 1]]) // N // SetPrecision[#, 3] &
maxCurrent2 = MaximalBy[dataSet2, Last][[1, 2]];
noPoints2 = Length[dataSet2];

ListLinePlot[{set[1], set[2], set[3]},
PlotRange -> {{0, 700}, {0, 6}},
PlotStyle -> {Directive[RGBColor[0.4, 0.5, 0.6],
AbsoluteThickness[2.5]],
Directive[RGBColor[0.8, 0.5, 0.6], AbsoluteThickness[2.5]],
Directive[RGBColor[0.8, 0.5, 0.6], AbsoluteThickness[2.5]]},
PlotTheme -> "Detailed",
Epilog -> {{Blue, AbsolutePointSize[4], Point[dataSet]}, {Dashed,
Line[{{262, 3.91}, {281, 1.26}}]}, {Purple,
AbsolutePointSize[4], Point[dataSet2]},
Inset[Framed[
Grid[{{Style["Cathode 284 - Drilled",
Bold]}, {"Average Current: ", avgCurrent,
" \[Mu]A"}, {"Maximum Current: ", maxCurrent,
"minutes"}, {"Number of Data Points: ", noPoints}}],
Background -> White, RoundingRadius -> 5], Scaled[{.40, .85}]],
Inset[Framed[
Grid[{{Style["Cathode 285 - Undrilled", Bold,
TextAlignment -> Center]}, {"Average Current: ", avgCurrent2,
" \[Mu]A"}, {"Maximum Current: ", maxCurrent2,
"minutes"}, {"Number of Data Points: ", noPoints2}}],
Background -> White, RoundingRadius -> 5], Scaled[{.80, .85}]]},
PlotLabel ->
"Current Yield: Drilled Iron Cathode vs. Undrilled Iron Cathode",
PlotLegends ->
Placed[LineLegend[{"Iron (Cathode 284 - Drilled)",
"Iron (Cathode 285 - Undrilled)"},
LegendFunction -> "Panel"], {0.80, 0.28}],
LabelStyle -> {Black, Bold}, Frame -> {{True, False}, {True, False}},
FrameLabel -> {"Cathode Runtime (minutes)", "Current (\[Mu]A)"},
ImageSize -> {550, 550}, InterpolationOrder -> 1]

• maxCurrent2 is nowhere defined. Commented Nov 28, 2022 at 11:35
• It's defined on this line, I think: maxCurrent2 = MaximalBy[dataSet2, Last][[1, 2]]; Commented Nov 28, 2022 at 12:03
• Okay, I've tried using something closer to my actual code, which definitely works Commented Nov 28, 2022 at 12:06

Clear["Global*"]

n = 2;


Use indexed variables, e.g., dataSet[2] rather than dataSet2. This will facilitate mapping of repetitive code.

dataSet[1] = {{63, 1.26}, {92, 1.74}, {156, 1.88}, {250, 2.33}, {317,
2.69}, {351, 2.85}, {357, 3.42}, {391, 3.43}, {422, 3.44}};
dataSet[2] = {{50, 0.55}, {167, 1.6}, {169, 2.47}, {182, 3.2}, {227,
3.32}, {232, 3.39}, {262, 3.91}, {281, 1.26}, {310, 1.74}, {374,
1.88}, {468, 2.33}, {535, 2.69}, {575, 3.42}, {609, 3.43}, {640, 3.44}};


Automatically detect the break in the data

data = Sequence @@@ (Split[#, #1[[2]] < #2[[2]] &] & /@ (dataSet /@
Range[n]));

Evaluate[set /@ Range[Length@data]] = data;

(avgCurrent[#] =
SetPrecision[
Integrate[
Interpolation[dataSet[#],
InterpolationOrder -> 1][x],
{x, dataSet[#][[1, 1]], dataSet[#][[-1, 1]]}]/
(Subtract @@ dataSet[#][[{-1, 1}, 1]]),
3]) & /@
Range[n];

(maxCurrent[#] =
MaximalBy[dataSet[#], Last][[1, 2]]) & /@ Range[n];
(noPoints[#] =
Length[dataSet[#]]) & /@ Range[n];
dataSet[#][[-1, 1]]) & /@ Range[n];


Plotting,

ListLinePlot[data,
PlotRange -> {{0, 700}, {0, 6}},
PlotStyle -> (
Directive[RGBColor[#, 0.5, 0.6],
AbsoluteThickness[2.5]] & /@
{0.4, 0.8, 0.8}),
PlotMarkers -> (Style["●", #, 8] & /@
{Blue, Purple, Purple}),
PlotTheme -> "Detailed",
Epilog -> {
{Dashed, Line[{Last@set[2], First@set[3]}]},
Inset[
Framed[
Grid[{
{Style[#[[2]], Bold, TextAlignment -> Center]},
{"Average Current: ", avgCurrent[#[[1]]], " μA"},
{"Maximum Current: ", maxCurrent[#[[1]]], " μA"},
{"Number of Data Points: ", noPoints[#[[1]]]}}],
Background -> White, RoundingRadius -> 5],
Scaled[{#[[3]], .85}]] & /@ {
{1, "Cathode 284 - Drilled", 0.4},
{2, "Cathode 285 - Undrilled", 0.8}}},
PlotLabel ->
"Current Yield: Drilled Iron Cathode vs. Undrilled Iron Cathode",
PlotLegends ->
Placed[
LineLegend[{
"Iron (Cathode 284 - Drilled)",
"Iron (Cathode 285 - Undrilled)"},
LegendFunction -> "Panel"],
{0.8, 0.25}],
LabelStyle -> {Black, Bold},
Frame -> {{True, False}, {True, False}},
FrameLabel -> {"Cathode Runtime (minutes)", "Current (μA)"},
ImageSize -> 550,
InterpolationOrder -> 1]
`

• Okay, so for the most part, it's replace variable# for variable[#]? Thanks for the help :) Commented Dec 1, 2022 at 9:45