{"id":137,"date":"2018-04-08T17:56:00","date_gmt":"2018-04-08T16:56:00","guid":{"rendered":"https:\/\/blogs.ncl.ac.uk\/mep\/?p=137"},"modified":"2018-04-09T13:22:57","modified_gmt":"2018-04-09T12:22:57","slug":"reproducible-publication-quality-multivariate-plots-in-r","status":"publish","type":"post","link":"https:\/\/blogs.ncl.ac.uk\/mep\/2018\/04\/08\/reproducible-publication-quality-multivariate-plots-in-r\/","title":{"rendered":"Reproducible, publication quality multivariate plots in R"},"content":{"rendered":"<div id=\"introduction\" class=\"section level3\">\n<h1>Introduction<\/h1>\n<p>Good communication of the results from any models or analyses to the potential end-user is essential for environmental data scientists. R has a number of excellent packages for multivariate analyses, one of the most popular being Jari Oksanen\u2019s \u201cvegan\u201d package which implements many methods including principal components analysis, reducancy analysis, correspondence analysis and canonical correspondence analysis. The package is particularly popular with ecologists: it was originally developed for vegetation analysis (hence its name), but can be applied to any problem needing multivariate analysis. (As an aside, if searching Google for advice on the vegan package, remember to add the word \u201cmultivariate\u201d as a search term, otherwise you\u2019ll return rather a lot of recipes!).<\/p>\n<p>One weakness of vegan is that whilst its default graphics are fine when analysing the data, they are not good enough to publish, or include in presentations at conferences. In the past I\u2019ve exported vegan output into Excel, but then you get into chaos of menus, click boxes and general lack of reproducibility. There is a development package by Gavin Simpson, called ggvegan, which looks promising but is not yet available on CRAN and does not yet provide the amount of flexibility I need for plotting reliably. In this post I\u2019ll show you how we can make use of vegan + ggplot2 to produce good quality plots.<\/p>\n<\/div>\n<div id=\"unconstrained-ordination\" class=\"section level3\">\n<h1>Unconstrained ordination<\/h1>\n<p>In unconstrained ordination we\u2019re typically dealing with a samples x species matrix, without including any explanatory variables in the ordination. However, it can be expanded to any set of \u201cattributes\u201d data, so instead of species, you might have soil data, land cover types, operational taxonomic units (OTUs) etc. The most widely used techniques are Principal Components Analysis (PCA), Correspondence Analysis (CA) and Non-metric multidimenional scaling (NMDS) all of which are available in vegan. If your data matrix contains nominal or qualitative data you might want to consider Multiple Correspondence Analysis (MCA) available in the FactoMineR package.<\/p>\n<p>First, using one of vegan\u2019s in-built datasets, Dutch dune vegetation, let\u2019s undertake a PCA and look at the default species plot:<\/p>\n<pre class=\"r\"><code class=\"hljs\"><span class=\"hljs-keyword\">library<\/span>(vegan)<\/code><\/pre>\n<pre><code class=\"hljs\">## Loading required package: permute<\/code><\/pre>\n<pre><code class=\"hljs\">## Loading required package: lattice<\/code><\/pre>\n<pre><code class=\"hljs\">## This is vegan 2.4-6<\/code><\/pre>\n<pre class=\"r\"><code class=\"hljs\">data(dune)\r\n\r\ndune_pca &lt;- rda(dune)\r\nplot(dune_pca, display = <span class=\"hljs-string\">\"species\"<\/span>)<\/code><\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-138 size-medium\" src=\"https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/default_pca-300x263.jpeg\" alt=\"\" width=\"300\" height=\"263\" srcset=\"https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/default_pca-300x263.jpeg 300w, https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/default_pca-342x300.jpeg 342w, https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/default_pca.jpeg 484w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<p>Hmm\u2026 not ideal, because many of the labels overlap and are unreadable. As is conventional, species names are reduced to 8 characters (4 for genus plus 4 for species) to save space, but a lot of labels still overlap. A better approach is to extract the PCA species scores, pipe them into ggplot, and use ggrepel to display the species names:<\/p>\n<pre class=\"r\"><code class=\"hljs\"><span class=\"hljs-keyword\">library<\/span>(tidyverse)\r\n<span class=\"hljs-keyword\">library<\/span>(ggrepel)\r\n\r\n<span class=\"hljs-comment\"># Extract the species scores; it returns a matrix so convert to a tibble<\/span>\r\ndune_sco &lt;- scores(dune_pca, display=<span class=\"hljs-string\">\"species\"<\/span>)\r\ndune_tbl &lt;- as_tibble(dune_sco)\r\n<span class=\"hljs-comment\"># Note that tibbles do not contain rownames so we need to add them<\/span>\r\ndune_tbl &lt;- mutate(dune_tbl, vgntxt = rownames(dune_sco))\r\nplt &lt;- ggplot(dune_tbl, aes(x = PC1, y = PC2, label = vgntxt)) +\r\n        geom_point() +\r\n        geom_text_repel(seed = <span class=\"hljs-number\">123<\/span>)\r\nplt<\/code><\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-139 size-medium\" src=\"https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/PCA_with_ggplot.jpg-300x263.jpeg\" alt=\"\" width=\"300\" height=\"263\" srcset=\"https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/PCA_with_ggplot.jpg-300x263.jpeg 300w, https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/PCA_with_ggplot.jpg-342x300.jpeg 342w, https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/PCA_with_ggplot.jpg.jpeg 484w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<p>If like me you don\u2019t particularly like the grey background then add a theme. One oddity of ggrepel is that it uses a random number generator to try and position the labels, so if you run the identical command twice you\u2019ll end up with different plots (not very reproducible!). Luckily it is easy to fix with a fixed seed for the random number generator used by ggrepel, which is why I\u2019ve added the \u201cseed = 123\u201d option. We can also add dotted vertical lines to indicate the zero on the x and y-axes:<\/p>\n<pre class=\"r\"><code class=\"hljs\">plt &lt;- plt + \r\n        geom_vline(aes(xintercept = <span class=\"hljs-number\">0<\/span>), linetype = <span class=\"hljs-string\">\"dashed\"<\/span>) +\r\n        geom_hline(aes(yintercept = <span class=\"hljs-number\">0<\/span>), linetype = <span class=\"hljs-string\">\"dashed\"<\/span>) +\r\n        theme_classic()\r\nplt<\/code><\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-141 size-full\" src=\"https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/clean_PCA.jpg.jpeg\" alt=\"\" width=\"484\" height=\"424\" srcset=\"https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/clean_PCA.jpg.jpeg 484w, https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/clean_PCA.jpg-300x263.jpeg 300w, https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/clean_PCA.jpg-342x300.jpeg 342w\" sizes=\"auto, (max-width: 484px) 100vw, 484px\" \/><\/p>\n<div id=\"unconstrained-ordination\" class=\"section level3\">\n<p>There are other options in ggrepel allowing you to increase the distance from the points to labels, change the point types etc.<\/p>\n<\/div>\n<h1 id=\"constrained-ordination\" class=\"section level3\">\u00a0Constrained ordination<\/h1>\n<p>In constrained ordination you have two sets of data, one the response matrix (conventionally the samples x sites matrix) and the other a set of explanatory variables (e.g.\u00a0environmental variables). The importance of these environmental variables can be tested via permutation-ANOVA, but the most useful outputs (in my experience) are the graphs, where the environmental variables can be superimposed onto the species or samples to create \u2018biplots\u2019. Let\u2019s look at one of the default vegan datasets, Scandinavian lichen pastures plus their environmental data, and carry out a constrained analysis via canonical correspondence analysis, and display the default vegan plots:<\/p>\n<pre class=\"r\"><code class=\"hljs\">data(<span class=\"hljs-string\">\"varespec\"<\/span>)\r\ndata(<span class=\"hljs-string\">\"varechem\"<\/span>)\r\n<span class=\"hljs-comment\"># For simplicity, just use three of the fourteen soil variables<\/span>\r\nvare_cca &lt;- cca(varespec ~ Al + P + K, data = varechem)\r\nplot(vare_cca, display=c(<span class=\"hljs-string\">\"sites\"<\/span>, <span class=\"hljs-string\">\"bp\"<\/span>))<\/code><\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-143 size-medium\" src=\"https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/default_CCA_sites.jpg-300x263.jpeg\" alt=\"\" width=\"300\" height=\"263\" srcset=\"https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/default_CCA_sites.jpg-300x263.jpeg 300w, https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/default_CCA_sites.jpg-342x300.jpeg 342w, https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/default_CCA_sites.jpg.jpeg 484w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<pre class=\"r\"><code class=\"hljs\">plot(vare_cca, display=c(<span class=\"hljs-string\">\"species\"<\/span>, <span class=\"hljs-string\">\"bp\"<\/span>))<\/code><\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-144 size-medium\" src=\"https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/default_CCA_spp.jpg-300x263.jpeg\" alt=\"\" width=\"300\" height=\"263\" srcset=\"https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/default_CCA_spp.jpg-300x263.jpeg 300w, https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/default_CCA_spp.jpg-342x300.jpeg 342w, https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/default_CCA_spp.jpg.jpeg 484w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<p>A few comments about these default plots, apart from the obvious one that the species plot is very cluttered. The importantance of an environmental variable is indicated by the length of the arrow, so Al and P are more important than K. The direction of an arrow indicates the main change for that variable, so samples 9, 24 and 28 will be relatively high in P, whilst sample 13 relatively low.\u00a0<em>Calluna vulgaris<\/em>\u00a0appears to prefer low P conditions etc. Notice that Al and P are at almost 90-degrees to each other, which indicates that the two variables are uncorrelated. Finally, be alert to the fact that the scaling of the arrows on the plots is <strong>relative<\/strong>: in the species plot the Al arrowhead is at about 1.2 on CCA1 x-axis, whereas on the samples plot it is at about 1.8. It is their\u00a0<em>relative<\/em>\u00a0positions that matter when interpreting the plots.<\/p>\n<p>These plots are still rather messy, so how can we smarten them up within a ggplot framework. We need to create a tibble containing the species, samples and environmental (biplot) scores, plus a label to indicate the score type. We also need a simple method of rescaling the environmental scores so that they fit neatly within the plot window for either species or samples plots.<\/p>\n<pre class=\"r\"><code class=\"hljs\">vare_spp_sco &lt;- scores(vare_cca, display = <span class=\"hljs-string\">\"species\"<\/span>)\r\nvare_sam_sco &lt;- scores(vare_cca, display = <span class=\"hljs-string\">\"sites\"<\/span>)\r\nvare_env_sco &lt;- scores(vare_cca, display = <span class=\"hljs-string\">\"bp\"<\/span>)\r\nvare_spp_tbl &lt;- as_tibble(vare_spp_sco)\r\nvare_sam_tbl &lt;- as_tibble(vare_sam_sco)\r\nvare_env_tbl &lt;- as_tibble(vare_env_sco)\r\nvare_spp_tbl &lt;- mutate(vare_spp_tbl, vgntxt=rownames(vare_spp_sco),\r\n                       ccatype = <span class=\"hljs-string\">\"species\"<\/span>)\r\nvare_sam_tbl &lt;- mutate(vare_sam_tbl, vgntxt=rownames(vare_sam_sco),\r\n                       ccatype = <span class=\"hljs-string\">\"sites\"<\/span>)\r\nvare_env_tbl &lt;- mutate(vare_env_tbl, vgntxt=rownames(vare_env_sco),\r\n                       ccatype = <span class=\"hljs-string\">\"bp\"<\/span>)<\/code><\/pre>\n<p>It may seem a bit cumbersome having to extract each set of scores separately, labelling, given that vegan will allow you to return all three in one command. However, vegan returns the three sets of scores as a list, and I find it easier to handle them separately. The output tibbles has the CCA1 and CCA2 axis scores, plus character variables varetxt (species names, sample names and env names) and ccatype (to indicate the type of score).<\/p>\n<p>You\u2019ll recall that the environmental variables are plotted with scales relative to the samples or species plots. Therefore, it\u2019s usually easiest to plot the species on their own, next check values of the environmental variables, then decide on an appropriate scaling factor.<\/p>\n<pre class=\"r\"><code class=\"hljs\">plt &lt;- ggplot(vare_spp_tbl, aes(x = CCA1, y = CCA2, label = vgntxt)) +\r\n       geom_point() +\r\n       geom_text_repel(seed = <span class=\"hljs-number\">123<\/span>)\r\nplt<\/code><\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-146 size-medium\" src=\"https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/CCA_spp.jpg-300x263.jpeg\" alt=\"\" width=\"300\" height=\"263\" srcset=\"https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/CCA_spp.jpg-300x263.jpeg 300w, https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/CCA_spp.jpg-342x300.jpeg 342w, https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/CCA_spp.jpg.jpeg 484w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<p>In this plot the species names are still a little cluttered in the centre of the graph, around zero on both axes. These will tend to be the most ubiquitous species, and so are of least interest. Later on we\u2019ll remove the labels from some of these species to tidy up the plot. As noted earlier, we\u2019ll want the arrowhead of the Al to be at about 1.2 on the x-axis for a reasonably proportioned plot. Let\u2019s check what the actual biplot scores are:<\/p>\n<pre class=\"r\"><code class=\"hljs\">vare_env_tbl<\/code><\/pre>\n<pre><code class=\"hljs\">## # A tibble: 3 x 4\r\n##     CCA1   CCA2 vgntxt ccatype\r\n##    &lt;dbl&gt;  &lt;dbl&gt; &lt;chr&gt;  &lt;chr&gt;  \r\n## 1  0.860 -0.160 Al     bp     \r\n## 2 -0.420 -0.751 P      bp     \r\n## 3 -0.440 -0.165 K      bp<\/code><\/pre>\n<p>We can see that Al is 0.86 so we need to apply a multiplier of about 1.5 to all the environmental variables. Then we need to select the environmental variable labels, and create a single tibble containing both the (rescaled) environment and species scores and labels:<\/p>\n<pre class=\"r\"><code class=\"hljs\">rescaled &lt;- vare_env_tbl %&gt;% \r\n            select(CCA1, CCA2) %&gt;%\r\n            as.matrix() * <span class=\"hljs-number\">1.5<\/span>\r\nvare_tbl &lt;- select(vare_env_tbl, vgntxt, ccatype) %&gt;%\r\n            bind_cols(as_tibble(rescaled)) %&gt;%\r\n            bind_rows(vare_spp_tbl)<\/code><\/pre>\n<p>Now we are in a position to create a biplot, with arrows for the environmental variables:<\/p>\n<pre class=\"r\"><code class=\"hljs\">ggplot() +\r\n  geom_point(aes(x=CCA1, y=CCA2), data=filter(vare_tbl, ccatype==<span class=\"hljs-string\">\"species\"<\/span>))  +\r\n  geom_text_repel(aes(x=CCA1, y=CCA2, label=vgntxt, size=<span class=\"hljs-number\">3.5<\/span>),\r\n                  data=vare_tbl, seed=<span class=\"hljs-number\">123<\/span>) + \r\n  geom_segment(aes(x=<span class=\"hljs-number\">0<\/span>, y=<span class=\"hljs-number\">0<\/span>, xend=CCA1, yend=CCA2), arrow=arrow(length = unit(<span class=\"hljs-number\">0.2<\/span>,<span class=\"hljs-string\">\"cm\"<\/span>)),\r\n               data=filter(vare_tbl, ccatype==<span class=\"hljs-string\">\"bp\"<\/span>), color=<span class=\"hljs-string\">\"blue\"<\/span>) +\r\n  coord_fixed() +\r\n  theme_classic() +\r\n  theme(legend.position=<span class=\"hljs-string\">\"none\"<\/span>)<\/code><\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-148 size-medium\" src=\"https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/CCA_all_spp.jpg-300x263.jpeg\" alt=\"\" width=\"300\" height=\"263\" srcset=\"https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/CCA_all_spp.jpg-300x263.jpeg 300w, https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/CCA_all_spp.jpg-342x300.jpeg 342w, https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/CCA_all_spp.jpg.jpeg 484w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/p>\n<p>This is a little more complex than previous ggplot calls, with a call to geom_points, a calls for geom_text_repel, and a call to geom_segment to add arrows. The coord_fixed is to ensure equal scaling on x and y-axes, and there is no need for a legend. However, the plot is still rather cluttered by labels from ubiquitous species in the middle. Let\u2019s not label any species +\/- 0.5 on either axis, and for clarity use black or blue labels for the species and environmental names, controlled by scale_colour_manual<\/p>\n<pre class=\"r\"><code class=\"hljs\">critval &lt;- <span class=\"hljs-number\">0.5<\/span>\r\nvare_tbl&lt;- vare_tbl %&gt;%\r\n           mutate(vgntxt=ifelse(CCA1 &lt; critval &amp; CCA1 &gt; -critval &amp;\r\n                                CCA2 &lt; critval &amp; CCA2 &gt; -critval &amp;\r\n                                ccatype==<span class=\"hljs-string\">\"species\"<\/span>, <span class=\"hljs-string\">\"\"<\/span>, vgntxt))\r\n\r\nggplot() +\r\n  geom_point(aes(x=CCA1, y=CCA2), data=filter(vare_tbl, ccatype==<span class=\"hljs-string\">\"species\"<\/span>))  +\r\n  geom_text_repel(aes(x=CCA1, y=CCA2, label=vgntxt, size=<span class=\"hljs-number\">3.5<\/span>, colour=ccatype),\r\n                  data=vare_tbl, seed=<span class=\"hljs-number\">123<\/span>) + \r\n  geom_segment(aes(x=<span class=\"hljs-number\">0<\/span>, y=<span class=\"hljs-number\">0<\/span>, xend=CCA1, yend=CCA2), arrow=arrow(length = unit(<span class=\"hljs-number\">0.2<\/span>,<span class=\"hljs-string\">\"cm\"<\/span>)), \r\n               data=filter(vare_tbl, ccatype==<span class=\"hljs-string\">\"bp\"<\/span>), color=<span class=\"hljs-string\">\"blue\"<\/span>) +\r\n  coord_fixed() +\r\n  scale_colour_manual(values = c(<span class=\"hljs-string\">\"blue\"<\/span>, <span class=\"hljs-string\">\"black\"<\/span>)) +\r\n  theme_classic() +\r\n  theme(legend.position=<span class=\"hljs-string\">\"none\"<\/span>)<\/code><\/pre>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter wp-image-150 size-full\" src=\"https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/Final_CCA.jpg.jpeg\" alt=\"\" width=\"484\" height=\"424\" srcset=\"https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/Final_CCA.jpg.jpeg 484w, https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/Final_CCA.jpg-300x263.jpeg 300w, https:\/\/blogs.ncl.ac.uk\/mep\/files\/2018\/04\/Final_CCA.jpg-342x300.jpeg 342w\" sizes=\"auto, (max-width: 484px) 100vw, 484px\" \/><\/p>\n<p>A similar approach can be used with samples, or where the environmental variables are categorical (centroids). This now gives you a publication-quality ordination plot that is easy to interpret.<\/p>\n<p>(P.S. &#8211; thanks to Eli Patterson for giving me this challenge to solve in the first place!)<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Introduction Good communication of the results from any models or analyses to the potential end-user is essential for environmental data scientists. R has a number of excellent packages for multivariate analyses, one of the most popular being Jari Oksanen\u2019s \u201cvegan\u201d &hellip; <a href=\"https:\/\/blogs.ncl.ac.uk\/mep\/2018\/04\/08\/reproducible-publication-quality-multivariate-plots-in-r\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":3152,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-137","post","type-post","status-publish","format-standard","hentry","category-uncategorised"],"_links":{"self":[{"href":"https:\/\/blogs.ncl.ac.uk\/mep\/wp-json\/wp\/v2\/posts\/137","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.ncl.ac.uk\/mep\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.ncl.ac.uk\/mep\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.ncl.ac.uk\/mep\/wp-json\/wp\/v2\/users\/3152"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.ncl.ac.uk\/mep\/wp-json\/wp\/v2\/comments?post=137"}],"version-history":[{"count":8,"href":"https:\/\/blogs.ncl.ac.uk\/mep\/wp-json\/wp\/v2\/posts\/137\/revisions"}],"predecessor-version":[{"id":154,"href":"https:\/\/blogs.ncl.ac.uk\/mep\/wp-json\/wp\/v2\/posts\/137\/revisions\/154"}],"wp:attachment":[{"href":"https:\/\/blogs.ncl.ac.uk\/mep\/wp-json\/wp\/v2\/media?parent=137"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.ncl.ac.uk\/mep\/wp-json\/wp\/v2\/categories?post=137"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.ncl.ac.uk\/mep\/wp-json\/wp\/v2\/tags?post=137"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}