## ----setup, include = FALSE---------------------------------------------------
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
eval = FALSE
)
## ----va-engine, echo = FALSE, results = "asis", eval = TRUE-------------------
cat('
')
## -----------------------------------------------------------------------------
# library(taxify)
## -----------------------------------------------------------------------------
# field_names <- c(
# "Quercus robur L.", # authorship to strip
# "Quercus robus", # typo
# "cf. Betula pendula", # field qualifier
# "FAGUS SYLVATICA", # caps
# "Quercus pedunculata", # historical synonym of Q. robur
# "Q. petraea", # abbreviated genus
# "Pinus abies", # synonym of Picea abies (a different genus)
# "Festuca rubrra", # typo
# "Fallopia japonica", # synonym of Reynoutria japonica (invasive)
# "Taraxacum officinale"
# )
#
# res <- taxify(field_names)
# res[, c("input_name", "accepted_name", "family",
# "is_synonym", "match_type", "fuzzy_dist")]
## ----pipe-anim, echo = FALSE, results = "asis", eval = TRUE-------------------
body <- "
var s=VA.setup('pp-cv'); if(!s)return; var x=s.ctx,W=s.w,H=s.h,C=VA.C;
var N=NM.length;
var labs=['input','clean','match','resolve','accepted'];
var SX=[64,232,420,602,786];
var yTrack=176;
var PER_NAME=4.2,PERIOD=N*PER_NAME;
function chip(cx,cy,txt,col,w){x.font=VA.F(12);var tw=x.measureText(txt).width;var hw=(w||Math.max(70,tw+16))/2;hw=Math.min(hw,(W-12)/2);cx=VA.clamp(cx,hw+6,W-hw-6);x.save();VA.glow(x,col,9);x.fillStyle=C.bg;x.strokeStyle=col;x.lineWidth=2;x.beginPath();x.rect(cx-hw,cy-15,hw*2,30);x.fill();x.stroke();VA.noglow(x);x.fillStyle=C.ink;x.textAlign='center';x.textBaseline='middle';x.fillText(txt,cx,cy);x.restore();x.textBaseline='alphabetic';}
function station(i,active,col,sub){var cx=SX[i];x.strokeStyle=active?col:C.off;x.lineWidth=active?2:1;if(active)VA.glow(x,col,8);x.beginPath();x.arc(cx,yTrack,11,0,6.2832);x.stroke();VA.noglow(x);if(active){x.fillStyle=col;x.beginPath();x.arc(cx,yTrack,4,0,6.2832);x.fill();}x.fillStyle=active?C.ink:C.mut;x.font=VA.F(12,active);x.textAlign='center';x.fillText(labs[i],cx,yTrack+34);if(sub){x.fillStyle=col;x.font=VA.F(11);x.fillText(sub,cx,yTrack+50);}}
function draw(tc){VA.bg(x,W,H);
VA.glow(x,C.cyan,7);x.fillStyle=C.cyan;x.textAlign='left';x.font=VA.F(15,true);x.fillText('ONE NAME THROUGH THE PIPELINE',16,28);VA.noglow(x);
var gi=Math.min(N-1,Math.floor(tc/PER_NAME));var lt=(tc-gi*PER_NAME)/PER_NAME;
var isSyn=SYN[gi]===1;var isNone=MT[gi]==='none';
x.strokeStyle=C.grid;x.lineWidth=2;x.beginPath();x.moveTo(SX[0],yTrack);x.lineTo(SX[4],yTrack);x.stroke();
var seg=VA.clamp(lt/0.5,0,1)*4;var here=Math.floor(seg+0.0001);
for(var i=0;i<5;i++){
var reached=i<=here;
var col=C.cyan;var sub=null;
if(i===1){col=C.amber;sub=reached?CLN[gi]:null;}
if(i===2){col=isNone?C.red:C.green;sub=reached?MAT[gi]:null;}
if(i===3){col=C.purple;sub=reached?(isSyn?'synonym':'already accepted'):null;if(!isSyn)col=C.off;}
if(i===4){col=isNone?C.red:C.green;}
station(i,reached,col,sub);
}
var a=Math.min(3,Math.floor(seg)),f=VA.clamp(seg-a,0,1);
var px=VA.lerp(SX[a],SX[a+1],VA.easeOut(f));
if(lt<0.5) chip(px,yTrack-46,NM[gi],isNone?C.red:C.cyan);
x.fillStyle=C.mut;x.font=VA.F(12);x.textAlign='center';x.fillText('input',SX[0],yTrack-86);
x.fillStyle=isNone?C.red:C.green;x.font=VA.F(12,true);x.fillText(isNone?'unmatched':'accepted name',SX[4],yTrack-86);
if(lt>=0.5){var aa=VA.clamp((lt-0.5)/0.2,0,1);x.globalAlpha=aa;chip(SX[4],yTrack-46,ACC[gi],isNone?C.red:C.green);x.globalAlpha=1;}
var dotw=12;for(var k=0;k\n",
"\n"))
## ----block-anim, echo = FALSE, results = "asis", eval = TRUE------------------
body <- "
var s=VA.setup('bl-cv'); if(!s)return; var x=s.ctx,W=s.w,H=s.h,C=VA.C;
var GX=16,GY=64,COLS=44,ROWS=22,TW=13,TH=15,GW=COLS*TW,GH=ROWS*TH;
var bc0=8,bc1=15,br0=7,br1=13;
var winC=12,winR=10;
var GGX=GX+GW+44,GGW=64,GGY=64,GGH=GH;
var T1=4.8,H1=2.0,T2=5.9,H2=3.4,CYCLE=T1+H1+T2+H2;
function inBlock(c,r){return c>=bc0&&c<=bc1&&r>=br0&&r<=br1;}
function tile(c,r,col,a){x.globalAlpha=a;x.fillStyle=col;x.fillRect(GX+c*TW,GY+r*TH,TW-1.4,TH-1.4);x.globalAlpha=1;}
function frame(){VA.glow(x,C.cyan,6);x.strokeStyle=C.cyan;x.strokeRect(GX,GY,GW,GH);VA.noglow(x);}
function blockOutline(){VA.glow(x,C.green,10);x.strokeStyle=C.green;x.lineWidth=2;x.strokeRect(GX+bc0*TW-1,GY+br0*TH-1,(bc1-bc0+1)*TW,(br1-br0+1)*TH);x.lineWidth=1;VA.noglow(x);}
function gauge(frac,col,ghost,pct){x.strokeStyle=C.mut;x.strokeRect(GGX,GGY,GGW,GGH);var h=Math.max(frac>0?2:0,frac*GGH);VA.glow(x,col,8);x.fillStyle=col;x.fillRect(GGX+1,GGY+GGH-h,GGW-2,h);VA.noglow(x);if(ghost){x.strokeStyle=C.red;x.setLineDash([5,4]);x.lineWidth=1.5;x.beginPath();x.moveTo(GGX-4,GGY+2);x.lineTo(GGX+GGW+4,GGY+2);x.stroke();x.setLineDash([]);x.lineWidth=1;x.fillStyle=C.red;x.font=VA.F(11);x.textAlign='left';x.fillText('whole backbone',GGX-6,GGY-10);}x.fillStyle=C.ink;x.font=VA.F(14,true);x.textAlign='center';x.fillText(pct,GGX+GGW/2,GGY+GGH+20);x.fillStyle=C.mut;x.font=VA.F(11);x.fillText('names scored',GGX+GGW/2,GGY+GGH+36);}
function header(t,col){x.textAlign='left';VA.glow(x,C.cyan,7);x.fillStyle=C.cyan;x.font=VA.F(15,true);x.fillText('FUZZY MATCH :: Quercus robus',16,26);VA.noglow(x);x.fillStyle=col;x.font=VA.F(13);x.fillText(t,16,46);}
function draw(tc){VA.bg(x,W,H);
var c,r;
if(tc0.7){VA.glow(x,'#fff',10);x.fillStyle='#fff';x.fillRect(GX+winC*TW,GY+winR*TH,TW-1.4,TH-1.4);VA.noglow(x);}
gauge(0.06,C.green,true,'one genus');
header('genus-blocked: scored only against other Quercus',C.green);
} else {
for(r=0;r '+QACC+' (1 edit, dist '+QD+')',GX,GY+GH+24);
gauge(0.06,C.green,true,'one genus');
header('match found inside the block',C.green);
}
VA.scan(x,W,H);
}
VA.run(draw,CYCLE,null,'bl','bl-cv');
"
cat(paste0(
"\n",
"\n"))
## -----------------------------------------------------------------------------
# summary(res)
## ----benchmark-anim, echo = FALSE, results = "asis", eval = TRUE--------------
body <- "
var s=VA.setup('sp-cv'); if(!s)return; var x=s.ctx,W=s.w,H=s.h,C=VA.C;
var BX=150,BW=W-150-150,b1=96,b2=190,bh=46;
var PERIOD=17,HOLD=4;
function fmt(sec){if(sec<60)return sec.toFixed(1)+' s';var m=sec/60;return sec.toFixed(0)+' s ('+m.toFixed(0)+' min)';}
function bar(y,frac,col,name,done,lab){
x.fillStyle=C.off;x.fillRect(BX,y,BW,bh);
var w=Math.max(frac>0?3:0,frac*BW);
if(done)VA.glow(x,col,10);x.fillStyle=col;x.fillRect(BX,y,w,bh);VA.noglow(x);
x.strokeStyle=C.grid;x.strokeRect(BX,y,BW,bh);
x.fillStyle=C.ink;x.font=VA.F(14,true);x.textAlign='right';x.fillText(name,BX-12,y+bh/2+5);
x.fillStyle=done?col:C.mut;x.font=VA.F(13,true);x.textAlign='left';x.fillText(lab,BX+w+12,y+bh/2+5);
}
function draw(tc){VA.bg(x,W,H);
VA.glow(x,C.cyan,7);x.fillStyle=C.cyan;x.textAlign='left';x.font=VA.F(15,true);x.fillText('FUZZY MATCH :: 1,000 NAMES',16,28);VA.noglow(x);
var run=Math.min(tc,PERIOD-HOLD);var prog=run/(PERIOD-HOLD);
var simSec=prog*WFO;
var taxDone=simSec>=TAX;
var taxFrac=taxDone?1:simSec/TAX;
var wfoFrac=Math.min(1,simSec/WFO);
bar(b1,taxFrac,C.green,'taxify',taxDone,taxDone?fmt(TAX):'');
bar(b2,wfoFrac,C.red,'WorldFlora',wfoFrac>=1,wfoFrac>=1?fmt(WFO):fmt(simSec));
x.fillStyle=C.mut;x.font=VA.F(12);x.textAlign='left';x.fillText('elapsed (simulated): '+fmt(simSec),BX,b2+bh+22);
if(taxDone&&tc>PERIOD-HOLD-0.01){var aa=VA.clamp((tc-(PERIOD-HOLD))/1.0,0,1);x.globalAlpha=aa;VA.glow(x,C.green,8);x.fillStyle=C.green;x.font=VA.F(20,true);x.textAlign='center';x.fillText(Math.round(WFO/TAX)+'x faster',W/2,H-40);VA.noglow(x);x.globalAlpha=1;}
VA.scan(x,W,H);
}
VA.run(draw,PERIOD,null,'sp','sp-cv');
"
cat(paste0(
"\n",
"\n"))
## -----------------------------------------------------------------------------
# my_traits <- data.frame(
# species = c("Quercus pedunculata", # synonym of Q. robur
# "Pinus sylvestris",
# "Betula pendula"),
# seed_mass_mg = c(3200, 7.5, 0.2)
# )
#
# taxify(c("Quercus robur", "Pinus sylvestris", "Betula pendula")) |>
# add_data(my_traits, species_col = "species")
## ----enrich-anim, echo = FALSE, results = "asis", eval = TRUE-----------------
con_data <- "var G=[
{n:'Plants',s:'Plants',c:'#6bcb77',L:[['add_zanne()','woody / herbaceous'],['add_eive()','EIVE indicator values'],['add_diaz_traits()','seed mass & height'],['add_leda()','LEDA life-history'],['add_wcvp()','native range'],['add_glonaf()','naturalized alien flora'],['add_baseflor()','ecological traits'],['add_ecoflora()','British flora'],['add_floraweb()','German flora'],['add_pignatti()','Italian indicator values'],['add_fungalroot()','mycorrhizal type']]},
{n:'Birds & mammals',s:'Birds/mammals',c:'#3ad7ff',L:[['add_avonet()','bird morphology'],['add_elton_traits()','diet & body mass'],['add_pantheria()','mammal life-history']]},
{n:'Amphibians & reptiles',s:'Amph & reptiles',c:'#b388ff',L:[['add_amphibio()','amphibian traits'],['add_repttraits()','reptile traits & range']]},
{n:'Fish',s:'Fish',c:'#4d96ff',L:[['add_fishmorph()','morphology'],['add_fishbase()','ecology']]},
{n:'Arthropods',s:'Arthropods',c:'#ff8fd0',L:[['add_arthropod_traits()','arthropod traits'],['add_leptraits()','butterfly traits']]},
{n:'Fungi',s:'Fungi',c:'#ffd93d',L:[['add_fungal_traits()','fungal traits'],['add_funguild()','trophic guild']]},
{n:'Algae',s:'Algae',c:'#33ffd0',L:[['add_algae_traits()','algal traits']]},
{n:'Cross-taxon animals',s:'Cross-taxon',c:'#ffc24b',L:[['add_animaltraits()','body mass & metabolism'],['add_anage()','longevity & ageing']]},
{n:'Status, alien & names',s:'Status & alien',c:'#ff3b6b',L:[['add_iucn()','IUCN Red List'],['add_griis()','GRIIS invasive'],['add_alien_first_records()','first-record years'],['add_common_names()','vernacular names']]}
];
"
body <- "
var s=VA.setup('en-cv'); if(!s)return; var x=s.ctx,W=s.w,H=s.h,C=VA.C;
var NG=G.length;
var cx=280,cy=298,R=192;
var px0=556,pw=W-556-12;
var nLayers=0;for(var gi=0;gi=cy;var ly=n.y+(below?rad+15:-rad-8);x.fillText(G[i].s,n.x,ly);x.fillStyle=foc?G[i].c:C.mut;x.font=VA.F(10);x.fillText('('+G[i].L.length+')',n.x,ly+(below?13:-13));}
function travel(i,t){var n=node(i);var u=t-Math.floor(t);var tx=VA.lerp(n.x,cx,VA.easeOut(u)),ty=VA.lerp(n.y,cy,VA.easeOut(u));VA.glow(x,G[i].c,8);x.fillStyle=G[i].c;x.beginPath();x.arc(tx,ty,3.6,0,6.2832);x.fill();VA.noglow(x);}
function panel(i,lt){var g=G[i];x.textAlign='left';VA.glow(x,g.c,8);x.fillStyle=g.c;x.font=VA.F(15,true);x.fillText(g.n,px0,92);VA.noglow(x);x.strokeStyle=g.c;x.lineWidth=2;x.beginPath();x.moveTo(px0,102);x.lineTo(px0+pw,102);x.stroke();x.lineWidth=1;for(var k=0;k\n",
"\n"))
## -----------------------------------------------------------------------------
# field <- c(
# "Quercus petraea", "Pinus sylvestris", "Picea abies", "Betula pendula",
# "Acer pseudoplatanus", "Acer platanoides", "Acer campestre", "Corylus avellana",
# "Fraxinus excelsior", "Carpinus betulus", "Sorbus aucuparia", "Tilia cordata",
# "Ulmus glabra", "Alnus glutinosa", "Salix caprea", "Populus tremula",
# "Prunus avium", "Prunus spinosa", "Crataegus monogyna", "Sambucus nigra",
# "Cornus sanguinea", "Viburnum opulus", "Euonymus europaeus", "Ligustrum vulgare",
# "Frangula alnus", "Juniperus communis", "Taxus baccata", "Larix decidua",
# "Abies alba", "Rosa canina", "Rubus idaeus", "Hedera helix",
# "Clematis vitalba", "Berberis vulgaris", "Betula pubescens", "Prunus padus",
# "Rhamnus cathartica", "Lonicera xylosteum", "Trifolium repens", "Trifolium pratense",
# "Festuca ovina", "Dactylis glomerata", "Plantago lanceolata", "Plantago major",
# "Plantago media", "Achillea millefolium", "Ranunculus acris", "Ranunculus repens",
# "Urtica dioica", "Poa pratensis", "Poa annua", "Galium mollugo",
# "Galium aparine", "Bellis perennis", "Cardamine pratensis", "Cirsium arvense",
# "Cirsium vulgare", "Daucus carota", "Heracleum sphondylium", "Anthriscus sylvestris",
# "Lotus corniculatus", "Medicago lupulina", "Vicia cracca", "Lathyrus pratensis",
# "Stellaria media", "Silene dioica", "Silene vulgaris", "Geranium pratense",
# "Geranium robertianum", "Glechoma hederacea", "Lamium album", "Prunella vulgaris",
# "Ajuga reptans", "Veronica chamaedrys", "Rumex acetosa", "Rumex obtusifolius",
# "Chenopodium album", "Capsella bursa-pastoris", "Senecio vulgaris", "Leucanthemum vulgare",
# "Centaurea jacea", "Knautia arvensis", "Campanula rotundifolia", "Primula veris",
# "Anemone nemorosa", "Filipendula ulmaria", "Lythrum salicaria", "Robinia pseudoacacia",
# "Solidago canadensis", "Solidago gigantea", "Impatiens glandulifera",
# "Heracleum mantegazzianum", "Prunus serotina", "Quercus rubra",
# "Quercus robur L.", "FAGUS SYLVATICA", "Quercus robus",
# "cf. Taraxacum officinale", "Quercus pedunculata", "Festuca rubrra"
# )
#
# dat <- taxify(field) |>
# add_zanne() |>
# add_eive() |>
# add_diaz_traits()
#
# head(dat[, c("accepted_name", "woodiness", "eive_light",
# "eive_reaction", "eive_nutrients", "plant_height_m")], 6)
## -----------------------------------------------------------------------------
# cor.test(dat$eive_reaction, dat$eive_nutrients)