{"id":3177,"date":"2020-04-12T16:24:51","date_gmt":"2020-04-12T15:24:51","guid":{"rendered":"https:\/\/www.itersdesktop.com\/?p=3177"},"modified":"2020-05-10T10:01:26","modified_gmt":"2020-05-10T09:01:26","slug":"how-to-build-and-render-data-in-json-format-with-grails","status":"publish","type":"post","link":"https:\/\/www.itersdesktop.com\/vi\/2020\/04\/12\/how-to-build-and-render-data-in-json-format-with-grails\/","title":{"rendered":"How to build and render data in JSON format with Grails"},"content":{"rendered":"\n<p class=\"has-drop-cap wp-block-paragraph\">Nowadays, an awful lot of web based applications are using <a href=\"https:\/\/en.wikipedia.org\/wiki\/JSON\">JSON<\/a> as a principal data to load and render information rapidly. While some applications store data into persistence volume as JSON string, the others still use relational databases as the primary storages. Loading data from these relational databases from backend, then building JSON objects and sending them to frontend are all things a web developer often does on a daily basis.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In this post, I will show you how to build JSON objects and pass them to client, such as JavaScript where you have to use the data for displaying or reprocessing.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To ease reading and absorbing the knowledge I am writing here, let&#8217;s play with a simple project. The project aims to retrieve organisms and the number of models classified in each organism from <a href=\"https:\/\/www.ebi.ac.uk\/biomodels\">BioModels<\/a>, then make a a bubble chart using <a href=\"https:\/\/d3js.org\">D3js<\/a> library. Thus, you can conceive the idea from getting data from the backend and plotting data to the frontend.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"576\" src=\"https:\/\/www.itersdesktop.com\/wp-content\/uploads\/2020\/04\/ITersDesktopBlog2.001-1024x576.jpeg\" alt=\"\" class=\"wp-image-3183\" srcset=\"https:\/\/www.itersdesktop.com\/wp-content\/uploads\/2020\/04\/ITersDesktopBlog2.001-1024x576.jpeg 1024w, https:\/\/www.itersdesktop.com\/wp-content\/uploads\/2020\/04\/ITersDesktopBlog2.001-300x169.jpeg 300w, https:\/\/www.itersdesktop.com\/wp-content\/uploads\/2020\/04\/ITersDesktopBlog2.001-768x432.jpeg 768w, https:\/\/www.itersdesktop.com\/wp-content\/uploads\/2020\/04\/ITersDesktopBlog2.001.jpeg 1280w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><figcaption><em>The graphical representation of the illustrated application<\/em><\/figcaption><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Obviously, the query to fetch all organisms will give you a result in JSON or XML format, so then you can use that format data directly into the view (i.e. frontend) without converting it again. In reality, we often re-process data returned external API before embedding them to internal services. Also, it is very often to obtain data from multiple calls and combine the results before using them in a different place. Moreover, I create a class named Organism to capture the properties such as name, label, taxonomy accession and the number of models for the specific purpose in this post.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Note<\/strong>: This project was built in <a href=\"https:\/\/grails.github.io\/grails2-doc\/2.5.x\/guide\/single.html\">grails 2.5.6<\/a>, therefore, it would be valuable if you have experienced and familiarised with it before making your hands dirty.<\/p>\n\n\n\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_85 counter-hierarchy ez-toc-counter ez-toc-light-blue ez-toc-container-direction\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<label for=\"ez-toc-cssicon-toggle-item-6a3c88554e800\" class=\"ez-toc-cssicon-toggle-label\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/label><input type=\"checkbox\"  id=\"ez-toc-cssicon-toggle-item-6a3c88554e800\"  aria-label=\"Toggle\" \/><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/www.itersdesktop.com\/vi\/2020\/04\/12\/how-to-build-and-render-data-in-json-format-with-grails\/#create-organism-class\" >Create Organism class<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/www.itersdesktop.com\/vi\/2020\/04\/12\/how-to-build-and-render-data-in-json-format-with-grails\/#output\" >Output<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/www.itersdesktop.com\/vi\/2020\/04\/12\/how-to-build-and-render-data-in-json-format-with-grails\/#source-code\" >Source Code<\/a><\/li><\/ul><\/nav><\/div>\n<h2 class=\"wp-block-heading\" id=\"create-organism-class\"><span class=\"ez-toc-section\" id=\"create-organism-class\"><\/span>Create Organism class<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Now, we need to fetch from <a href=\"https:\/\/www.ebi.ac.uk\/ebisearch\/overview.ebi\/about\">EBI Search Server<\/a> data related to BioModels repository. To retrieve data via RESTful API with <a href=\"https:\/\/grails.org\">Grails<\/a>, I have recently posted an article <a href=\"https:\/\/www.itersdesktop.com\/2020\/04\/11\/how-to-consume-web-services-in-grails\/\">how to consume web services in Grails<\/a> which you are free to read and test it. Below is the snippet in <a href=\"https:\/\/www.ebi.ac.uk\/biomodels\/dev\">BiomodelService<\/a> to do what has been addressed.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">package com.itersdesktop.javatechs.grails\n\nimport grails.plugins.rest.client.RestBuilder\nimport grails.transaction.Transactional\n\n@Transactional\nclass BiomodelsService {\n\n    def fetchAllOrganisms() {\n        final String BM_SEARCH_URL = \"https:\/\/wwwdev.ebi.ac.uk\/ebisearch\/ws\/rest\/biomodels\/topterms\"\n        String queryURL = \"${BM_SEARCH_URL}\/TAXONOMY?facetfield:label&amp;size=500&amp;format=json\"\n        println queryURL\n        RestBuilder rest = new RestBuilder(connectTimeout: 10000, readTimeout: 100000, proxy: null)\n        def response = rest.get(queryURL) {\n            accept(\"application\/json\")\n            accept(\"application\/xml\")\n            contentType(\"application\/json;charset=UTF-8\")\n        }\n        if (response.status == 200) {\n            return response.json\n        }\n        return null\n    }\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The result we hope to get if the application is running looks like the output of the curl command below.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"shell\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">curl -X GET 'https:\/\/wwwdev.ebi.ac.uk\/ebisearch\/ws\/rest\/biomodels\/topterms\/TAXONOMY?facetfield:label&amp;size=500&amp;format=json' -H \"application\/json\"<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">We expect to receive the output like<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"json\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">{\"totalTermCount\":1745,\"topTerms\":[{\"text\":\"9606\",\"docFreq\":713},{\"text\":\"4932\",\"docFreq\":137},{\"text\":\"10090\",\"docFreq\":114},{\"text\":\"40674\",\"docFreq\":95},{\"text\":\"131567\",\"docFreq\":77},{\"text\":\"562\",\"docFreq\":45},{\"text\":\"10114\",\"docFreq\":36},{\"text\":\"2759\",\"docFreq\":30},{\"text\":\"8355\",\"docFreq\":27},{\"text\":\"10116\",\"docFreq\":24},{\"text\":\"3702\",\"docFreq\":22},{\"text\":\"9986\",\"docFreq\":17},{\"text\":\"33090\",\"docFreq\":14},{\"text\":\"3701\",\"docFreq\":12},{\"text\":\"10141\",\"docFreq\":12},{\"text\":\"9615\",\"docFreq\":11},{\"text\":\"7711\",\"docFreq\":11},{\"text\":\"7227\",\"docFreq\":11},{\"text\":\"5691\",\"docFreq\":10},{\"text\":\"39107\",\"docFreq\":10},{\"text\":\"5141\",\"docFreq\":7},{\"text\":\"4896\",\"docFreq\":7},{\"text\":\"9913\",\"docFreq\":5},{\"text\":\"83333\",\"docFreq\":5},{\"text\":\"33208\",\"docFreq\":5},{\"text\":\"2242\",\"docFreq\":5},{\"text\":\"1773\",\"docFreq\":5},{\"text\":\"10088\",\"docFreq\":5},{\"text\":\"8782\",\"docFreq\":4},{\"text\":\"8292\",\"docFreq\":4},{\"text\":\"7742\",\"docFreq\":4},{\"text\":\"7215\",\"docFreq\":4},{\"text\":\"5658\",\"docFreq\":4},{\"text\":\"559292\",\"docFreq\":4},{\"text\":\"33154\",\"docFreq\":4},{\"text\":\"3193\",\"docFreq\":4},{\"text\":\"2208\",\"docFreq\":4},{\"text\":\"210\",\"docFreq\":4},{\"text\":\"1423\",\"docFreq\":4},{\"text\":\"1358\",\"docFreq\":4},{\"text\":\"9685\",\"docFreq\":3},{\"text\":\"5833\",\"docFreq\":3},{\"text\":\"4952\",\"docFreq\":3},{\"text\":\"4922\",\"docFreq\":3},{\"text\":\"2\",\"docFreq\":3},{\"text\":\"11676\",\"docFreq\":3},{\"text\":\"11320\",\"docFreq\":3},{\"text\":\"10117\",\"docFreq\":3},{\"text\":\"10095\",\"docFreq\":3},{\"text\":\"9984\",\"docFreq\":2},{\"text\":\"9940\",\"docFreq\":2},{\"text\":\"9796\",\"docFreq\":2},{\"text\":\"9544\",\"docFreq\":2},{\"text\":\"7787\",\"docFreq\":2},{\"text\":\"746128\",\"docFreq\":2},{\"text\":\"70448\",\"docFreq\":2},{\"text\":\"6678\",\"docFreq\":2},{\"text\":\"6618\",\"docFreq\":2},{\"text\":\"64495\",\"docFreq\":2},{\"text\":\"6035\",\"docFreq\":2},{\"text\":\"5518\",\"docFreq\":2},{\"text\":\"5507\",\"docFreq\":2},{\"text\":\"5501\",\"docFreq\":2},{\"text\":\"5482\",\"docFreq\":2},{\"text\":\"5478\",\"docFreq\":2},{\"text\":\"5476\",\"docFreq\":2},{\"text\":\"5346\",\"docFreq\":2},{\"text\":\"5306\",\"docFreq\":2},{\"text\":\"5297\",\"docFreq\":2},{\"text\":\"5270\",\"docFreq\":2},{\"text\":\"5207\",\"docFreq\":2},{\"text\":\"520\",\"docFreq\":2},{\"text\":\"5180\",\"docFreq\":2},{\"text\":\"51453\",\"docFreq\":2},{\"text\":\"5062\",\"docFreq\":2},{\"text\":\"5061\",\"docFreq\":2},{\"text\":\"5057\",\"docFreq\":2},{\"text\":\"5037\",\"docFreq\":2},{\"text\":\"4959\",\"docFreq\":2},{\"text\":\"4924\",\"docFreq\":2},{\"text\":\"4897\",\"docFreq\":2},{\"text\":\"4837\",\"docFreq\":2},{\"text\":\"40563\",\"docFreq\":2},{\"text\":\"40559\",\"docFreq\":2},{\"text\":\"38033\",\"docFreq\":2},{\"text\":\"3704\",\"docFreq\":2},{\"text\":\"36914\",\"docFreq\":2},{\"text\":\"36911\",\"docFreq\":2},{\"text\":\"36630\",\"docFreq\":2},{\"text\":\"34099\",\"docFreq\":2},{\"text\":\"336810\",\"docFreq\":2},{\"text\":\"33188\",\"docFreq\":2},{\"text\":\"33178\",\"docFreq\":2},{\"text\":\"329376\",\"docFreq\":2},{\"text\":\"3055\",\"docFreq\":2},{\"text\":\"29883\",\"docFreq\":2},{\"text\":\"28985\",\"docFreq\":2},{\"text\":\"262014\",\"docFreq\":2},{\"text\":\"197043\",\"docFreq\":2},{\"text\":\"186490\",\"docFreq\":2},{\"text\":\"155892\",\"docFreq\":2},{\"text\":\"1496\",\"docFreq\":2},{\"text\":\"148305\",\"docFreq\":2},{\"text\":\"140110\",\"docFreq\":2},{\"text\":\"13684\",\"docFreq\":2},{\"text\":\"117187\",\"docFreq\":2},{\"text\":\"109871\",\"docFreq\":2},{\"text\":\"1063\",\"docFreq\":2},{\"text\":\"1047171\",\"docFreq\":2},{\"text\":\"104341\",\"docFreq\":2},{\"text\":\"9989\",\"docFreq\":1},{\"text\":\"9823\",\"docFreq\":1},{\"text\":\"9598\",\"docFreq\":1},{\"text\":\"9541\",\"docFreq\":1},{\"text\":\"9031\",\"docFreq\":1},{\"text\":\"85569\",\"docFreq\":1},{\"text\":\"83332\",\"docFreq\":1},{\"text\":\"7955\",\"docFreq\":1},{\"text\":\"7668\",\"docFreq\":1},{\"text\":\"7108\",\"docFreq\":1},{\"text\":\"70699\",\"docFreq\":1},{\"text\":\"7029\",\"docFreq\":1},{\"text\":\"672\",\"docFreq\":1},{\"text\":\"6499\",\"docFreq\":1},{\"text\":\"644223\",\"docFreq\":1},{\"text\":\"63577\",\"docFreq\":1},{\"text\":\"629395\",\"docFreq\":1},{\"text\":\"61434\",\"docFreq\":1},{\"text\":\"58853\",\"docFreq\":1},{\"text\":\"5850\",\"docFreq\":1},{\"text\":\"5791\",\"docFreq\":1},{\"text\":\"5782\",\"docFreq\":1},{\"text\":\"5548\",\"docFreq\":1},{\"text\":\"5544\",\"docFreq\":1},{\"text\":\"53533\",\"docFreq\":1},{\"text\":\"511145\",\"docFreq\":1},{\"text\":\"5076\",\"docFreq\":1},{\"text\":\"49990\",\"docFreq\":1},{\"text\":\"4930\",\"docFreq\":1},{\"text\":\"4929\",\"docFreq\":1},{\"text\":\"4894\",\"docFreq\":1},{\"text\":\"4892\",\"docFreq\":1},{\"text\":\"4547\",\"docFreq\":1},{\"text\":\"452646\",\"docFreq\":1},{\"text\":\"44689\",\"docFreq\":1},{\"text\":\"416870\",\"docFreq\":1},{\"text\":\"4113\",\"docFreq\":1},{\"text\":\"4097\",\"docFreq\":1},{\"text\":\"402676\",\"docFreq\":1},{\"text\":\"39782\",\"docFreq\":1},{\"text\":\"3847\",\"docFreq\":1},{\"text\":\"381512\",\"docFreq\":1},{\"text\":\"36420\",\"docFreq\":1},{\"text\":\"33169\",\"docFreq\":1},{\"text\":\"32524\",\"docFreq\":1},{\"text\":\"317\",\"docFreq\":1},{\"text\":\"314146\",\"docFreq\":1},{\"text\":\"29875\",\"docFreq\":1},{\"text\":\"294746\",\"docFreq\":1},{\"text\":\"272634\",\"docFreq\":1},{\"text\":\"272563\",\"docFreq\":1},{\"text\":\"267377\",\"docFreq\":1},{\"text\":\"227321\",\"docFreq\":1},{\"text\":\"2257\",\"docFreq\":1},{\"text\":\"215813\",\"docFreq\":1},{\"text\":\"211044\",\"docFreq\":1},{\"text\":\"2104\",\"docFreq\":1},{\"text\":\"2099\",\"docFreq\":1},{\"text\":\"197911\",\"docFreq\":1},{\"text\":\"1758\",\"docFreq\":1},{\"text\":\"173629\",\"docFreq\":1},{\"text\":\"162425\",\"docFreq\":1},{\"text\":\"1590\",\"docFreq\":1},{\"text\":\"1472294\",\"docFreq\":1},{\"text\":\"132504\",\"docFreq\":1},{\"text\":\"11292\",\"docFreq\":1},{\"text\":\"11276\",\"docFreq\":1},{\"text\":\"11103\",\"docFreq\":1},{\"text\":\"1034331\",\"docFreq\":1},{\"text\":\"10239\",\"docFreq\":1},{\"text\":\"10160\",\"docFreq\":1},{\"text\":\"101201\",\"docFreq\":1},{\"text\":\"10036\",\"docFreq\":1},{\"text\":\"10029\",\"docFreq\":1},{\"text\":\"10026\",\"docFreq\":1},{\"text\":\"1\",\"docFreq\":1}]}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">From the JSON output, we am going to build a list of Organism object which are rendered as JSON to be sent to views\/frontend. The methods are located in BiomodelService under the name toJsonFromString() and buildOrganisms().<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">def toJsonFromString(final String jsonString) {\n    def slurper = new JsonSlurper()\n    slurper.parseText(jsonString)\n}\n\n Map buildOrganisms(final String jsonString) {\n    def parsedJson = toJsonFromString(jsonString)\n    def totalTermCount = parsedJson.totalTermCount as long\n    def jsonOrganisms = parsedJson.topTerms\n    List topTerms = new ArrayList&lt;Organism>()\n    for (def entry : jsonOrganisms) {\n        String taxonomy = entry.text\n        long count = entry.docFreq\n        String name = resolveTaxonomyTerm(taxonomy)\n        topTerms.add(new Organism(name: name, \n            taxonomy: taxonomy, count: count))\n    }\n    return [totalTermCount: totalTermCount, topTerms: topTerms]\n}\n\nString resolveTaxonomyTerm(String s) {\n   String serviceURL = \"https:\/\/www.ebi.ac.uk\/ebisearch\/ws\/rest\/taxonomy\/entry\"\n   serviceURL = \"${serviceURL}\/$s?fields=name\"\n   RestBuilder rest = new RestBuilder(connectTimeout: 10000,   \n                               readTimeout: 100000, proxy: null)\n   def response = rest.get(serviceURL) {\n       accept(\"application\/xml\")\n       contentType(\"application\/xml;charset=UTF-8\")\n   }\n   if (response.status == 200) {\n       return response.xml\n   }\n   return null\n}\n\ndef build() {\n    def jsonString = '''\n{\"totalTermCount\":1745,\"topTerms\":[{\"text\":\"9606\",\"docFreq\":713},{\"text\":\"4932\",\"docFreq\":137},{\"text\":\"10090\",\"docFreq\":114}]}\n    \/\/ Remember to fetch the full JSON string\n    def result = buildOrganisms(jsonString)\n    def organismsMap = result[\"topTerms\"].collect { entry ->\n        [name: \"${entry.name} (${entry.taxonomy})\" as String,\n         count: entry.count as Integer,\n         taxonomy: entry.taxonomy as String]\n    }\n    organismsMap\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s inspect these methods and understand mechanism behind the scene. At the end of buildOrganism, a list of Organism objects look like <\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">class com.itersdesktop.javatechs.grails.Organism\nclass com.itersdesktop.javatechs.grails.Organism\nclass com.itersdesktop.javatechs.grails.Organism\nclass com.itersdesktop.javatechs.grails.Organism\nclass com.itersdesktop.javatechs.grails.Organism\nclass com.itersdesktop.javatechs.grails.Organism<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The second important build is the method build where the list of Organism objects will be converted to a map of looked-like-Organism objects including three properties needed to be populated for the chart.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The list of Organism will be populated to the view, i.e. the bubble nut chart presented in the further section. The key thing here is to <strong>build POJOs and render them as JSON in JavaScript<\/strong>, i.e. view\/client, where the data will be embedded into charts as well as visualisations. Below is the simple snippet of the output in JSON format.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"json\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">{\n  \"topTerms\": [\n    {\n      \"name\": \"Homo sapiens (9606)\",\n      \"count\": \"713\"\n    },\n    {\n      \"name\": \"Saccharomyces cerevisiae (4932)\",\n      \"count\": \"137\"\n    },\n    {\n      \"name\": \"Mus musculus (10090)\",\n      \"count\": \"114\"\n    },\n    {\n      \"name\": \"Mammalia (40674)\",\n      \"count\": \"95\"\n    },\n    {\n      \"name\": \"cellular organisms (131567)\",\n      \"count\": \"77\"\n    },\n    {\n      \"name\": \"Escherichia coli (562)\",\n      \"count\": \"45\"\n    }\n  ]\n}<\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now, it is the time to render this data in graphical presentation with d3js. Because of making a bubble chart, the <strong>topTerms<\/strong> key will be replaced with <strong>children<\/strong>. What you can see in the controller and view looks like<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">def visualise() {\n    def organisms = [\"children\": biomodelsService.build()] as JSON\n    render(view: \"visualise\", model: [organisms: organisms])\n }<\/pre>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\"><p>The highlights below should be taken more consideration<\/p><cite>def organismsMap = result[&#8220;topTerms&#8221;].collect { entry -><br \/>        [name: &#8220;${entry.name} (${entry.taxonomy})&#8221; as String,<br \/>         count: entry.count as Integer,<br \/>         taxonomy: entry.taxonomy as String]<br \/> }<br \/><br \/>And<br \/><br \/>def organisms = [&#8220;children&#8221;: biomodelsService.build()] as JSON<br \/><\/cite><\/blockquote>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">&lt;%@ page contentType=\"text\/html;charset=UTF-8\" %>\n&lt;html>\n&lt;head>\n    &lt;meta name=\"layout\" content=\"main\"\/>\n    &lt;title>Visualisation of Organisms from BioModels&lt;\/title>\n    &lt;script type=\"text\/javascript\" src=\"https:\/\/d3js.org\/d3.v4.min.js\">&lt;\/script>\n&lt;\/head>\n\n&lt;body>\n&lt;div id=\"organismsChart\" class=\"div-center-content\">&lt;\/div>\n&lt;g:javascript>\n    var dataset = JSON.parse(\"${organisms}\");\n    console.log(dataset);\n    var width = 600, height = 600, diameter = 600;\n    var color = d3.scaleOrdinal(d3.schemeCategory20);\n    var bubble = d3.pack(dataset).size([diameter, diameter]).padding(1.5);\n\n    var svg = d3.select(\"#organismsChart\")\n        .append(\"svg\")\n        .attr(\"width\", width)\n        .attr(\"height\", height)\n        .attr(\"class\", \"bubble\");\n\n    var nodes = d3.hierarchy(dataset)\n        .sum(function(d) {\n            return d.count; });\n\n    var node = svg.selectAll(\".node\")\n        .data(bubble(nodes).descendants())\n        .enter()\n        .filter(function(d){\n        return  !d.children\n        })\n        .append(\"g\")\n        .attr(\"class\", \"node\")\n        .attr(\"transform\", function(d) {\n            console.log(d);\n        return \"translate(\" + d.x + \",\" + d.y + \")\";\n    });\n\n    node.append(\"title\")\n        .text(function(d) {\n            return d.data.name + \": \" + d.data.count;\n    });\n\n    node.append(\"circle\")\n        .attr(\"r\", function(d) {\n        return d.r;\n    })\n        .style(\"fill\", function(d,i) {\n        return color(i);\n    });\n\n    node.append(\"text\")\n        .attr(\"dy\", \".2em\")\n        .style(\"text-anchor\", \"middle\")\n        .text(function(d) {return d.data.name.substring(0, d.r \/ 3);})\n        .attr(\"font-family\", \"sans-serif\")\n        .attr(\"font-size\", function(d) {return d.r\/5;})\n        .attr(\"fill\", \"white\");\n\n    node.append(\"text\")\n        .attr(\"dy\", \"1.3em\")\n        .style(\"text-anchor\", \"middle\")\n        .text(function(d) { return d.data.count;})\n        .attr(\"font-family\",  \"Gill Sans\", \"Gill Sans MT\")\n        .attr(\"font-size\", function(d) { return d.r\/5;})\n        .attr(\"fill\", \"white\");\n\n    d3.select(self.frameElement)\n        .style(\"height\", diameter + \"px\");\n    node.on('click', function(d) {\n        console.log(d);\n        var label = d[\"data\"][\"name\"];\n        var value = d[\"data\"][\"count\"];\n        var taxonomy = d[\"data\"][\"taxonomy\"];\n        var serverURL = \"https:\/\/www.ebi.ac.uk\/biomodels\";\n        var fixedSearchURL = \"\/search?domain=biomodels&amp;query=*%3A*+AND+TAXONOMY%3A\";\n        var prefixSearchURL = serverURL + fixedSearchURL;\n        var queryURL = prefixSearchURL + taxonomy;\n        window.open(queryURL, '_blank');\n    });\n\n&lt;\/g:javascript>\n&lt;\/body>\n&lt;\/html><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Run .\/grailsw to start grails wrapper for downloading grails 2.5.6 framework, then start the application by running run-app from grails prompt. Remember to <a href=\"https:\/\/www.itersdesktop.com\/2020\/04\/08\/how-to-change-default-server-port-for-grails-application\/\">change your application http port<\/a> if there are multiple grails applications running on your system.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"output\"><span class=\"ez-toc-section\" id=\"output\"><\/span>Output<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">If the application starts properly, accessing the link <a href=\"http:\/\/localhost:8181\/build-render-json-demo\/biomodels\/visualise\">http:\/\/localhost:8181\/build-render-json-demo\/biomodels\/visualise<\/a> will take you to the page where the bubble chart is shown like the screenshot below.<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"960\" height=\"738\" src=\"https:\/\/www.itersdesktop.com\/wp-content\/uploads\/2020\/04\/Screenshot-2020-04-12-at-16.20.33.png\" alt=\"\" class=\"wp-image-3179\" srcset=\"https:\/\/www.itersdesktop.com\/wp-content\/uploads\/2020\/04\/Screenshot-2020-04-12-at-16.20.33.png 960w, https:\/\/www.itersdesktop.com\/wp-content\/uploads\/2020\/04\/Screenshot-2020-04-12-at-16.20.33-300x231.png 300w, https:\/\/www.itersdesktop.com\/wp-content\/uploads\/2020\/04\/Screenshot-2020-04-12-at-16.20.33-768x590.png 768w\" sizes=\"auto, (max-width: 960px) 100vw, 960px\" \/><figcaption><em>Bubble chart representing model distribution on organisms in <a href=\"https:\/\/www.ebi.ac.uk\/biomodels\">BioModels<\/a><\/em><\/figcaption><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"source-code\"><span class=\"ez-toc-section\" id=\"source-code\"><\/span>Source Code<span class=\"ez-toc-section-end\"><\/span><\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The runnable <a href=\"https:\/\/bitbucket.org\/itersdesktop\/build-render-json-demo\/\">source code<\/a> of this article has been pushed to <a href=\"https:\/\/bitbucket.org\">bitbucket<\/a> as the common place for most illustrated projects for our blogs.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Hopefully, this post would bring to you a convenient approach to build and render JSON elements for views in your Grails applications.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">All constructive comments are welcomed. If you are willing to contribute financial support for our website, please follow the instructions below.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Nowadays, an awful lot of web based applications are using JSON as a principal data to load and render information rapidly. While some applications store data into persistence volume as&hellip; <\/p>\n","protected":false},"author":2,"featured_media":3183,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[593,10,641,133,4,222],"tags":[701,698,693,702,668,703,699,708,707],"class_list":["post-3177","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-grails","category-java-techs","category-javascript","category-jquery","category-web-engineering","category-web-programming","tag-bubble-chart","tag-build-json","tag-consume-restful-services","tag-d3js","tag-data-visualisation","tag-organisms","tag-render-json","tag-rest-client","tag-restful-api"],"_links":{"self":[{"href":"https:\/\/www.itersdesktop.com\/vi\/wp-json\/wp\/v2\/posts\/3177","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.itersdesktop.com\/vi\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.itersdesktop.com\/vi\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.itersdesktop.com\/vi\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.itersdesktop.com\/vi\/wp-json\/wp\/v2\/comments?post=3177"}],"version-history":[{"count":6,"href":"https:\/\/www.itersdesktop.com\/vi\/wp-json\/wp\/v2\/posts\/3177\/revisions"}],"predecessor-version":[{"id":3186,"href":"https:\/\/www.itersdesktop.com\/vi\/wp-json\/wp\/v2\/posts\/3177\/revisions\/3186"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.itersdesktop.com\/vi\/wp-json\/wp\/v2\/media\/3183"}],"wp:attachment":[{"href":"https:\/\/www.itersdesktop.com\/vi\/wp-json\/wp\/v2\/media?parent=3177"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.itersdesktop.com\/vi\/wp-json\/wp\/v2\/categories?post=3177"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.itersdesktop.com\/vi\/wp-json\/wp\/v2\/tags?post=3177"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}