TransWikia.com

Adding some measurements into the plot

Mathematica Asked by Emre on April 24, 2021

From Godbeer et al, Modelling proton tunnelling in the adenine–thymine base pair:

Godbeer, A. D., Al-Khalili, J. S., & Stevenson, P. D. (2015). Modelling proton tunnelling in the adenine–thymine base pair. Physical Chemistry Chemical Physics, 17(19), 13034–13044. doi:10.1039/c5cp00472a

Hello,

Well, I have very similar graph like in the image. I am trying to add that additional measurments like deltaE and EB arrows. I couldnt find a way to express the question better.

Thanks in advance.

2 Answers

You must add these graphical elements in an Epilog by hand. Here is an example how to do it:

d = {1, 0, 1, .5, 1};
pol = InterpolatingPolynomial[d, x];
Plot[pol, {x, 1, 5}, Epilog -> {
   Arrowheads[{-0.04, 0.04}],
   Arrow[{{3.7, -0.237}, {3.7, 0.236}}], 
   Arrow[{{2.5, -0.237}, {2.5, 1.02}}],
   Dashed,
   Line[{{0.5, -0.237}, {5, -0.237}}], Line[{{2, 1.02}, {3.5, 1.02}}],
    Line[{{3.5, 0.236}, {5, 0.236}}],
   Text[Style["E", 20], {2.7, 0.3}], Text[Style["Del", 20], {4, 0.1}]
   }]

enter image description here

Answered by Daniel Huber on April 24, 2021

First a data set that looks like the one behind the picture in OP:

SeedRandom[1]
dt = Table[ {x, Cos[5 Pi x/3]/(5 Pi x/3) + 1/2}, {x, Sort @ RandomReal[{0, 2}, 50]}];

ClearAll[iF]
iF = Interpolation[dt, 
  "ExtrapolationHandler" -> {Automatic, "WarningMessage" -> False}];

listplot = ListPlot[dt, PlotMarkers -> {"[Cross]", 20}, PlotStyle -> Black];

Show[Plot[iF[x], {x, 0, 2}, PlotStyle -> Directive[Red, Thick, Dotted]], listplot]

plot = Plot[iF[x], {x, 0, 2}, MeshFunctions -> {iF'[#] &}, 
   Mesh -> {{0}}, MeshStyle -> Directive[Red, AbsolutePointSize[15]], 
   PlotStyle -> Directive[Red, Thick, Dotted]];

Show[plot, listplot]

enter image description here

A convenient graphical trick to identify the extreme points is to use {iF'[#]&} as the option value for MeshFunctions and set Mesh -> {{0}}:

plot = Plot[iF[x], {x, 0, 2}, MeshFunctions -> {iF'[#] &}, 
   Mesh -> {{0}}, MeshStyle -> Directive[Red, AbsolutePointSize[15]], 
   PlotStyle -> Directive[Red, Thick, Dotted]];

Show[plot, listplot]

enter image description here

Now we can extract the coordinates of Points from plot output and use them to add tangent lines passing through those points, annotated arrows marking the vertical displacements from a reference point etc.

First, a helper function to create custom arrowheads with labels:

ClearAll[arrowHeadsLabeled]
arrowHeadsLabeled[lbl_, side_: {1, 0}, dir_: {0, -1}, pos_: .5] := 
 Arrowheads[{{-.03, 0}, {.03, 1}, 
   {.03, pos, {Graphics[Text[lbl, {0, 0}, side, dir]], 1}}}]

Example:

Graphics[{arrowHeadsLabeled["LABEL 1"], Red, Arrow[{{1, 0}, {1, 4}}], 
  arrowHeadsLabeled["LABEL 2", {0, -1}, {1, 0}], Blue, 
  Arrow[{{3, -1}, {3, 3}}], 
  arrowHeadsLabeled[Style["LABEL 3", 16], {0, 1.5}, {1, 0}, .25], Green, 
  Arrow[{{4, 0}, {5, 3}}]}, PlotRange -> {{0, 6}, {-2, 5}}, 
 ImageSize -> Medium]

enter image description here

Next, a function that annotates the output from Plot with Mesh* options as in the example above:

ClearAll[annotatedPlot]
annotatedPlot[plt_, labels_, disp_: 1.5] := 
 Module[{sortedextrema = SortBy[First]@Cases[Normal[plt], Point[x_] :> x, All], start, 
   xma, arrows, tangentlines},
  start = First@MinimalBy[Last]@sortedextrema; 
  xma = MovingAverage[Join[{PlotRange[plt][[1, 1]]}, 
      sortedextrema[[All, 1]], {PlotRange[plt][[1, 2]]}], {2, 1}];
  arrows = Arrow[Offset[{If[#[[1]] < start[[1]], -5, 10], 0}, #] & /@ 
     Partition[#, 2]] & /@ Thread[{Rest @ Most @ xma, start[[2]], 
         Rest @ Most @ xma, DeleteCases[sortedextrema, start][[All, 2]]}];
  tangentlines = Line /@ DeleteCases[
     Thread /@ Transpose[{Partition[xma, 2, 1] , sortedextrema[[All, 2]]}], start];
  Show[plt /. Point[_] -> {}, 
   Graphics[{Dashed, tangentlines, 
     Line[{{sortedextrema[[1, 1]], start[[2]]}, {sortedextrema[[-1, 1]], start[[2]]}}], 
     Black, Dashing[{}], 
     MapThread[{arrowHeadsLabeled[#, {disp, 0}], #2} &, {labels, arrows}]}], 
   ImageSize -> Large, Frame -> True, Axes -> False]]

Examples:

Using plot and listplot from the first example above:

labels = {Style[Subscript[InputForm@E, B], 16], Style[∇InputForm@E, 16]};

Show[annotatedPlot[plot, labels], listplot, PlotRange -> {{0, 2}, {0, 1}}]

enter image description here

SeedRandom[1]
dt2 = Table[ {x, Cos[5 Pi x/3]/(5 Pi x/3) + 1/2}, {x, Sort@RandomReal[{0, 4}, 50]}];

ClearAll[iF2]
iF2 = Interpolation[dt2, 
    "ExtrapolationHandler" -> {Automatic, "WarningMessage" -> False}];

listplot2 = ListPlot[dt2, PlotMarkers -> {"[Cross]", 20}, PlotStyle -> Black];
plot2 = Plot[iF2[x], {x, 0, 4}, MeshFunctions -> {iF2'[#] &}, 
   Mesh -> {{0}}, MeshStyle -> Directive[Red, AbsolutePointSize[15]], 
   PlotStyle -> Directive[Red, Thick, Dotted]];

labels2 = labellist = Style[Subscript[∇InputForm@E, #], 16] & /@ Range[6];

Show[annotatedPlot[plot2, labels2, -1.5], listplot2]

enter image description here

A variation that takes a data set and labels as input:

ClearAll[annotatedListPlot]
annotatedListPlot[lbls_: Automatic, disp_: 1.5][data_, 
  opts : OptionsPattern[{Plot, ListPlot}]] := 
 Module[{lp = ListPlot[data, opts], 
   if = Interpolation[data, "ExtrapolationHandler" -> {Automatic, 
       "WarningMessage" -> False}], plt, lblst}, 
  plt = Plot[if[x], {x, Min[data[[All, 1]]], Max[data[[All, 1]]]}, 
    MeshFunctions -> {if'[#] &}, Mesh -> {{0}}, opts]; 
  lblst = lbls /. Automatic -> (ToString /@ 
       Range[Count[Normal@plt, _Point, All] - 1]); 
  Show[annotatedPlot[plt, lblst, disp], lp, opts]]

Example:

annotatedListPlot[labellist, -1.5][dt2, 
 PlotTheme -> {"Minimal", "OpenMarkersThick"}, 
 PlotStyle -> Directive[Red, Thick]]

enter image description here

Answered by kglr on April 24, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP