{"id":26334474,"url":"https://github.com/asjadnaqvi/stata-graphfunctions","last_synced_at":"2026-03-04T02:02:39.842Z","repository":{"id":257887835,"uuid":"864257494","full_name":"asjadnaqvi/stata-graphfunctions","owner":"asjadnaqvi","description":"A modular grammar-of-graphics toolkit for Stata data visualizations.","archived":false,"fork":false,"pushed_at":"2025-11-25T08:41:00.000Z","size":7321,"stargazers_count":12,"open_issues_count":2,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-01-27T07:56:21.513Z","etag":null,"topics":["ado","arcs","area","dilate","functions","label","pies","rotation","shapes","spline","split","square","stata","stretch","transform","wrap"],"latest_commit_sha":null,"homepage":"","language":"Stata","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/asjadnaqvi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-09-27T19:46:54.000Z","updated_at":"2025-11-25T08:41:05.000Z","dependencies_parsed_at":"2025-11-27T12:05:35.764Z","dependency_job_id":null,"html_url":"https://github.com/asjadnaqvi/stata-graphfunctions","commit_stats":null,"previous_names":["asjadnaqvi/stata-graphfunctions"],"tags_count":8,"template":false,"template_full_name":null,"purl":"pkg:github/asjadnaqvi/stata-graphfunctions","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asjadnaqvi%2Fstata-graphfunctions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asjadnaqvi%2Fstata-graphfunctions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asjadnaqvi%2Fstata-graphfunctions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asjadnaqvi%2Fstata-graphfunctions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/asjadnaqvi","download_url":"https://codeload.github.com/asjadnaqvi/stata-graphfunctions/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asjadnaqvi%2Fstata-graphfunctions/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30069234,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-04T01:03:42.280Z","status":"online","status_checked_at":"2026-03-04T02:00:07.464Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ado","arcs","area","dilate","functions","label","pies","rotation","shapes","spline","split","square","stata","stretch","transform","wrap"],"created_at":"2025-03-16T00:19:11.595Z","updated_at":"2026-03-04T02:02:39.835Z","avatar_url":"https://github.com/asjadnaqvi.png","language":"Stata","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n![StataMin](https://img.shields.io/badge/stata-2011-blue) ![issues](https://img.shields.io/github/issues/asjadnaqvi/stata-graphfunctions) ![license](https://img.shields.io/github/license/asjadnaqvi/stata-graphfunctions) ![Stars](https://img.shields.io/github/stars/asjadnaqvi/stata-graphfunctions) ![version](https://img.shields.io/github/v/release/asjadnaqvi/stata-graphfunctions) ![release](https://img.shields.io/github/release-date/asjadnaqvi/stata-graphfunctions)\n\n[Installation](#Installation) | [Examples](#Examples) | [Feedback](#Feedback) | [Change log](#Change-log)\n\n---\n\n\n\u003cimg width=\"100%\" alt=\"graphfunctions_banner\" src=\"https://github.com/user-attachments/assets/bad6ac20-65bd-4782-b60e-b9e8edb02ea3\" /\u003e\n\n\n\n# graphfunctions v1.6\n*(19 Nov 2025)*\n\nA modular grammar-of-graphics toolkit for Stata data visualizations.\n\nThe program contains a set of programs that allow users to build custom visualizations from the bottom up.\n\nThe package is currently *beta* and might still contains bugs and errors, and might still be missing all checks and balances. Please report these by opening an [issue](https://github.com/asjadnaqvi/stata-graphfunctions/issues).\n\nThis package contains the following programs:\n\n\n|Program|Version|Updated|Description|\n|----| ---- | ---- | ----- |\n| [shapes](#shapes) | 1.4 | 19 Nov 2025 | Contains `shapes circle`, `shapes pie`, `shapes square`, `shapes rotate`, `shapes area`, `shapes translate`, `shapes dilate`, `shapes stretch`, `shapes round` |\n| [arc](#arc) | 1.3 | 19 Nov 2025 | Draw major and minor arcs between two points |\n| [radscatter](#radscatter) | 1.0 | 19 Nov 2025 | Generate scatter points and angles in polar coordinates |\n| [labsplit](#labsplit) | 1.1 | 08 Oct 2024 | Text wrapper for labels |\n| [catspline](#catspline) | 1.2 | 18 Feb 2025 | Catmull-Rom splines |\n\n\nIn the pipeline:\n\n- Options for frames, and temp frames.\n- Additional version control. Current program is v11 compatible but frames would imply v17 or higher.\n- More checks to individual programs.\n\n## Installation\n\nThe package can be installed via SSC or GitHub. The GitHub version, *might* be more recent due to bug fixes, feature updates etc, and *may* contain syntax improvements and changes in *default* values. See version numbers below. Eventually the GitHub version is published on SSC.\n\nSSC (**v1.52**):\n\n```stata\nssc install graphfunctions, replace\n```\n\nGitHub (**v1.6**):\n\n```stata\nnet install graphfunctions, from(\"https://raw.githubusercontent.com/asjadnaqvi/stata-graphfunctions/main/installation/\") replace\n```\n\nSee the help file `help graphfunctions` for details. \n\n\nIf you want to make a clean figure, then it is advisable to load a clean scheme, especially if you are not using newer Stata versions. My own setting is the following:\n\n```stata\nssc install schemepack, replace\nset scheme white_tableau  \ngraph set window fontface \"Arial Narrow\"\n```\n\n\n## labsplit \n*(v1.1: 08 Oct 2024)*\n\nThe program allows users to split text labels based on flexible or fixed character length or word positions.\n\nSyntax:\n```stata\nlabsplit variable, [ wrap(int) word(int) strict generate(newvar) ]\n```\n\nExamples:\n\n```stata\nclear\nset obs 5\ngen x = 1\ngen y = _n\n\ngen mylab = \"\"\n\nreplace mylab = \"Test this really-hyphenated label.\" in 1\nreplace mylab = \"Yet another label to test.\" in 2\nreplace mylab = \"This is the third label\" in 3\nreplace mylab = \"How about we test this label as well\" in 4\nreplace mylab = \"Finally we are at the fifth label\" in 5\n\n```\n\nLet's test the `labsplit` command:\n\n```stata\nlabsplit mylab, wrap(10) gen(newlab1)\nlabsplit mylab, wrap(10) gen(newlab2) strict\nlabsplit mylab, word(2) gen(newlab3)\n```\n\nCode for figures:\n\n```stata\ntwoway (scatter y x, mlabel(mylab)   mlabsize(3)), title(\"Standard\")\ntwoway (scatter y x, mlabel(newlab1) mlabsize(3)), title(\"Wrapping\")\n\ntwoway (scatter y x, mlabel(newlab2) mlabsize(3)), title(\"Wrapping strict\") \ntwoway (scatter y x, mlabel(newlab3) mlabsize(3)), title(\"Word wrap\")\n```\n\n\u003cimg src=\"/figures/labsplit0.png\" width=\"50%\"\u003e\u003cimg src=\"/figures/labsplit1.png\" width=\"50%\"\u003e\n\u003cimg src=\"/figures/labsplit2.png\" width=\"50%\"\u003e\u003cimg src=\"/figures/labsplit3.png\" width=\"50%\"\u003e\n\n## catspline\n*(v1.2: 18 Feb 2025)*\n\n\nThe program allows users to generate splines based on the [Catmull-Rom algorithm](https://en.wikipedia.org/wiki/Centripetal_Catmull%E2%80%93Rom_spline).\n\nSyntax:\n```stata\ncatspline y x, [ rho(num [0,1]) n(int) close sort(var) genx(str) geny(str) genid(str) genorder(str) replace ]\n```\n\nExamples:\n\n```stata\nclear\nset obs 6\nset seed 2021\n\ngen x = runiformint(1,5)\ngen y = runiformint(1,5)\n\n\ncatspline y x\n\ntwoway ///\n\t(scatter y x) ///\n\t(line _y _x,  cmissing(n))\n```\n\n\u003cimg src=\"/figures/catspline1.png\" width=\"75%\"\u003e\n\nWe can also close the loop by adding the `close` option:\n\n```stata\ncap drop _id _x _y\ncatspline y x, close \n\ntwoway ///\n\t(scatter y x) ///\n\t(line _y _x,  cmissing(n))\n```\n\n\u003cimg src=\"/figures/catspline2.png\" width=\"75%\"\u003e\n\n\nThe Stata [spider](https://github.com/asjadnaqvi/stata-spider) package uses this function. \n\n## arc\n*(v1.3: 19 Nov 2025)*\n\nDraw minor or major arcs between two points. The arc orientation and be switched using `swap`, and major arcs can be drawn using `major`.\n\nSyntax:\n\n```stata\narc, x1(num) y1(num) x2(num) y2(num) [ radius(num) n(int) swap major genx(newvar) geny(newvar) dropbase replace ]\n```\n\nExamples:\n\n\n```stata\narc, y1(-2) x1(-4) y2(4) x2(2) rad(6) replace\n\ntwoway ///\n\t(scatteri -2 -4)  (scatteri 4 2) ///\n\t(scatteri `r(ycirc)' `r(xcirc)') ///\n\t(line _y _x)  ///\n\t, legend(order(1 \"Point 1\" 2 \"Point 2\" 3 \"Circumcenter\" 4 \"Arc\") pos(6) row(1)) ///\n\txlabel(-10(2)10) ylabel(-10(2)10) aspect(1) xsize(1) ysize(1) ///\n\ttitle(\"Right of starting point - minor\")\n```\n\n\u003cimg src=\"/figures/arc1.png\" width=\"75%\"\u003e\n\n```stata\narc, y1(-2) x1(-4) y2(4) x2(2) rad(6) major replace\t\t\n\ntwoway ///\n\t(scatteri -2 -4)  (scatteri 4 2) ///\n\t(scatteri `r(ycirc)' `r(xcirc)') ///\n\t(line _y _x)  ///\n\t, legend(order(1 \"Point 1\" 2 \"Point 2\" 3 \"Circumcenter\" 4 \"Arc\") pos(6) row(1)) ///\n\txlabel(-10(2)10) ylabel(-10(2)10) aspect(1) xsize(1) ysize(1) ///\n\ttitle(\"Right of starting point - major\")\t\n\t\n```\n\n\u003cimg src=\"/figures/arc2.png\" width=\"75%\"\u003e\n\n```stata\narc, y1(-2) x1(-4) y2(4) x2(2) rad(6) swap replace\t\t\n\ntwoway ///\n\t(scatteri -2 -4)  (scatteri 4 2) ///\n\t(scatteri `r(ycirc)' `r(xcirc)') ///\n\t(line _y _x)  ///\n\t, legend(order(1 \"Point 1\" 2 \"Point 2\" 3 \"Circumcenter\" 4 \"Arc\") pos(6) row(1)) ///\n\txlabel(-10(2)10) ylabel(-10(2)10) aspect(1) xsize(1) ysize(1) ///\n\ttitle(\"Left of starting point - minor\")\n```\n\n\u003cimg src=\"/figures/arc3.png\" width=\"75%\"\u003e\n\n```stata\narc, y1(-2) x1(-4) y2(4) x2(2) rad(6) swap major replace\n\ntwoway ///\n\t(scatteri -2 -4)  (scatteri 4 2) ///\n\t(scatteri `r(ycirc)' `r(xcirc)') ///\n\t(line _y _x)  ///\n\t, legend(order(1 \"Point 1\" 2 \"Point 2\" 3 \"Circumcenter\" 4 \"Arc\") pos(6) row(1)) ///\n\txlabel(-10(2)10) ylabel(-10(2)10) aspect(1) xsize(1) ysize(1) ///\n\ttitle(\"Left of starting point - Major\")\n```\n\n\u003cimg src=\"/figures/arc4.png\" width=\"75%\"\u003e\n\n\nThe Stata [geoflow](https://github.com/asjadnaqvi/stata-geoflow) package uses this function. \n\n\n\n## shapes\n*(v1.4: 19 Nov 2025)*\n\n### shapes circle\n\n\nSyntax: \n\n```stata\nshapes circle, radius(num) [ x0(num) y0(num) n(int) rotate(degrees) genx(var) geny(var) genid(var) genorder(var) replace append ]\n```\n\n\nExamples:\n```stata\nshapes circle, replace\n\ntwoway /// \n\t\t(connected _y _x, mlabel(_order)) ///\n\t\t, xsize(1) ysize(1) aspect(1)\t///\n\t\txlabel(-10 10) ylabel(-10 10)\n```\n\n\u003cimg src=\"/figures/circle1.png\" width=\"75%\"\u003e\n\n```stata\nshapes circle, n(6) replace\n\n\ntwoway /// \n\t\t(connected _y _x, mlabel(_order)) ///\n\t\t, xsize(1) ysize(1) aspect(1)\t///\n\t\txlabel(-10 10) ylabel(-10 10)\n```\n\n\u003cimg src=\"/figures/circle2.png\" width=\"75%\"\u003e\n\n\n```stata\nshapes circle, n(6) rotate(30) replace\n\ntwoway /// \n\t\t(connected _y _x, mlabel(_order)) ///\n\t\t, xsize(1) ysize(1) aspect(1)\t///\n\t\txlabel(-10 10) ylabel(-10 10)\n```\n\n\u003cimg src=\"/figures/circle3.png\" width=\"75%\"\u003e\n\n\n```stata\nshapes circle, rotate(45) rad(8) n(4) replace\t\t\n\ntwoway /// \n\t\t(connected _y _x, mlabel(_order)) ///\n\t\t, xsize(1) ysize(1) aspect(1)\t///\n\t\txlabel(-10 10) ylabel(-10 10)\n```\n\n\u003cimg src=\"/figures/circle4.png\" width=\"75%\"\u003e\n\n\n```stata\nshapes circle, n(100) replace\t\n\ntwoway /// \n\t\t(line _y _x) ///\n\t\t, xsize(1) ysize(1) aspect(1)\t///\n\t\txlabel(-10 10) ylabel(-10 10)\n```\n\n\u003cimg src=\"/figures/circle5.png\" width=\"75%\"\u003e\n\n\n```stata\nshapes circle,    \t      n(8) replace\nshapes circle, rotate(30) n(6) rad(8) append \nshapes circle, rotate(60) n(4) rad(3)  x0(1) y0(1) append\n\ntwoway (connected _y _x, cmissing(n)), aspect(1)\n```\n\n\u003cimg src=\"/figures/circle6.png\" width=\"75%\"\u003e\n\n### shapes pie\n\nSyntax:\n\n```stata\nshapes pie, radius(num) end(degrees) [ start(degrees) x0(num) y0(num) n(int) rotate(degrees) dropbase flip genx(var) geny(var) genid(var) genorder(var) replace append ]\n```\n\nExamples:\n```stata\nshapes pie, end(60) replace\n\ntwoway (area _y _x), xlabel(-10 10) ylabel(-10 10) xsize(1) ysize(1) aspect(1)\n```\n\n\u003cimg src=\"/figures/pie1.png\" width=\"75%\"\u003e\n\n\n```stata\nshapes pie, start(0) end(270) n(200) replace\n\ntwoway (area _y _x), xlabel(-10 10) ylabel(-10 10) xsize(1) ysize(1) aspect(1)\n```\n\n\u003cimg src=\"/figures/pie2.png\" width=\"75%\"\u003e\n\n```stata\nclear\nshapes pie, start(0) end(45) ro(0)\t\trad(5) \treplace\nshapes pie, start(0) end(45) ro(30) \trad(6)  stack\nshapes pie, start(0) end(45) ro(60) \trad(7)  stack\nshapes pie, start(0) end(45) ro(90) \trad(8)  stack\nshapes pie, start(0) end(45) ro(120) \trad(9)  stack\nshapes pie, start(0) end(45) ro(150) \trad(10) stack\n\n\ntwoway (area _y _x, fcolor(%90) cmissing(n) nodropbase)\t///\n\t, xlabel(-10 10) ylabel(-10 10) xsize(1) ysize(1) aspect(1)\n```\n\n\u003cimg src=\"/figures/pie3.png\" width=\"75%\"\u003e\n\n\nwithout base:\n\n```stata\nshapes pie, start(0) end(230) rad(10) rotate(90) n(200) dropbase replace\nshapes pie, start(0) end(230) rad(9)  rotate(90) n(200) dropbase append\nshapes pie, start(0) end(200) rad(8)  rotate(90) n(200) dropbase append\nshapes pie, start(0) end(180) rad(7)  rotate(90) n(200) dropbase append\nshapes pie, start(0) end(160) rad(6)  rotate(90) n(200) dropbase append\n\ntwoway (line _y _x, cmissing(n) nodropbase)\t///\n\t, xlabel(-10 10) ylabel(-10 10) xsize(1) ysize(1) aspect(1)\n```\n\n\u003cimg src=\"/figures/pie4.png\" width=\"75%\"\u003e\n\nwithout base flipped direction:\n\n```stata\nshapes pie, start(0) end(350) rad(10) rotate(90) n(200) dropbase flip replace\nshapes pie, start(0) end(150) rad(9)  rotate(90) n(200) dropbase flip append\nshapes pie, start(0) end(130) rad(8)  rotate(90) n(200) dropbase flip append\nshapes pie, start(0) end(80) rad(7)  rotate(90) n(200) dropbase flip append\nshapes pie, start(0) end(60) rad(6)  rotate(90) n(200) dropbase flip append\n\ntwoway (line _y _x, cmissing(n) nodropbase)\t///\n\t, xlabel(-10 10) ylabel(-10 10) xsize(1) ysize(1) aspect(1)\n```\n\n\u003cimg src=\"/figures/pie5.png\" width=\"75%\"\u003e\n\n\n### shapes square\n\nSyntax:\n\n```stata\nshapes square, [ length(num) x0(num) y0(num) rotate(degrees) genx(var) geny(var) genid(var) genorder(var) replace append ]\n```\n\nExamples:\n\n```stata\nshapes square, len(8) rotate(90) replace\n\ntwoway ///\n\t(area _y _x, nodropbase fcolor(%50))\t///\n\t(scatter _y _x, mlab(_order))\t///\n\t\t, ///\n\t\tlegend(off) ///\n\t\txlabel(-10(2)10) ylabel(-10(2)10) xsize(1) ysize(1) aspect(1)\n```\n\n\u003cimg src=\"/figures/square1.png\" width=\"75%\"\u003e\n\n\n```stata\nshapes square, x0(1) y0(1) len(10) rotate(40) replace\nshapes square, x0(1) y0(1) len(9) rotate(30) append\nshapes square, x0(1) y0(1) len(8) rotate(20) append\nshapes square, x0(1) y0(1) len(7) rotate(10) append\nshapes square, x0(1) y0(1) len(6) rotate(0)  append\t\t\n\n\ntwoway ///\n\t(area _y _x, cmissing(n) nodropbase fcolor(%100) lw(0.1) lc(white))\t///\n\t\t, ///\n\t\tlegend(off) ///\n\t\txlabel(-10(2)10) ylabel(-10(2)10) xsize(1) ysize(1) aspect(1)\n```\t\t\n\n\u003cimg src=\"/figures/square2.png\" width=\"75%\"\u003e\n\n\n### shapes translate\n\n\nSyntax:\n\n```stata\nshapes translate \u003cyvar\u003e \u003cxvar\u003e [if] [in], [ x(num) y(num) genx(var) geny(var) replace ]\n```\n\n\u003cimg src=\"/figures/_translate.png\" width=\"30%\"\u003e\n\n\nMove the object by `x(a)` and `y(b)` points:\n\n$$ \nx = x + a\n$$\n\n$$\ny = y + b\n$$\n\n\n### shapes dilate\n\n\n\nSyntax:\n\n```stata\nshapes dilate \u003cyvar\u003e \u003cxvar\u003e [if] [in], [ factor(num) genx(var) geny(var) replace ]\n```\n\n\u003cimg src=\"/figures/_dilate.png\" width=\"30%\"\u003e\n\n\nExpand or reduce the object by factor `factor(a)`:\n\n$$ \nx = x \\times a\n$$\n\n$$\ny = y \\times a\n$$\n\n\n\n\n### shapes stretch\n\n\n\nSyntax:\n\n```stata\nshapes stretch \u003cyvar\u003e \u003cxvar\u003e [if] [in], [ x(num) y(num) replace ]\n```\n\n\u003cimg src=\"/figures/_stretch.png\" width=\"30%\"\u003e\n\n\nStretch the object by factors `x(a)` and `y(b)`:\n\n$$ \nx = x \\times (1 + a)\n$$\n\n$$\ny = y \\times (1 + b)\n$$\n\n### shapes rotate\n\n\n\nSyntax:\n\n```stata\nshapes rotate \u003cyvar\u003e \u003cxvar\u003e [if] [in], [ rotate(degrees) x0(num) y0(num) center genx(var) geny(var) replace ]\n```\n\n\n\u003cimg src=\"/figures/_rotate.png\" width=\"30%\"\u003e\n\n\nRotate the shape by `rot(angle)` at points `x0(a)` and `y0(b)`:\n\n$$ \nx = (x - a) \\times cos(angle) - (y - b) \\times sin(angle)\n$$\n\n$$\ny = (x - a) \\times sin(angle) + (y - b) \\times cos(angle)\n$$\n\nBy default $(a,b) = (0,0)$.\n\n\nLet's generate a basic shape:\n\n```stata\nshapes square, x0( 5) y0(0) len(5) replace\nshapes square, x0(-5) y0(0) len(5) append\n\ntwoway ///\n\t(area _y _x, cmissing(n) nodropbase fcolor(%80) lw(0.1) lc(white))\t///\n\t(scatteri 0 0) ///\n\t\t, ///\n\t\tlegend(off) ///\n\t\txlabel(-10(2)10) ylabel(-10(2)10) xsize(1) ysize(1) aspect(1)\t\n```\n\n\u003cimg src=\"/figures/rotate1.png\" width=\"75%\"\u003e\n\n\n\n```stata\nshapes rotate _y _x, rotate(30)\n\n\ntwoway ///\n\t(area _y _x, cmissing(n) nodropbase fcolor(%80) lw(0.1) lc(white))\t///\n\t(area ynew  xnew, cmissing(n) nodropbase fcolor(%80) lw(0.1) lc(white))\t///\n\t(scatteri 0 0) ///\n\t\t, ///\n\t\tlegend(off) ///\n\t\txlabel(-10(2)10) ylabel(-10(2)10) xsize(1) ysize(1) aspect(1)\t\n```\n\n\u003cimg src=\"/figures/rotate2.png\" width=\"75%\"\u003e\n\n\n```stata\nshapes rotate _y _x, rotate(30) x0(5) y0(5) genx(xnew) geny(ynew)\n\ntwoway ///\n\t(area _y _x, cmissing(n) nodropbase fcolor(%80) lw(0.1) lc(white))\t///\n\t(area ynew  xnew, cmissing(n) nodropbase fcolor(%80) lw(0.1) lc(white))\t///\n\t(scatteri 0 0) ///\n\t\t, ///\n\t\tlegend(off) ///\n\t\txlabel(-10(2)10) ylabel(-10(2)10) xsize(1) ysize(1) aspect(1)\t\n```\n\n\u003cimg src=\"/figures/rotate2.png\" width=\"75%\"\u003e\n\n\n```stata\nshapes rotate _y _x, rotate(60) center genx(xnew2) geny(ynew2)\t\t\n\ntwoway ///\n\t(area _y _x, cmissing(n) nodropbase fcolor(%80) lw(0.1) lc(white))\t///\n\t(area ynew2  xnew2, cmissing(n) nodropbase fcolor(%80) lw(0.1) lc(white))\t///\n\t(scatteri 0 0) ///\n\t\t, ///\n\t\tlegend(off) ///\n\t\txlabel(-10(2)10) ylabel(-10(2)10) xsize(1) ysize(1) aspect(1)\t\n```\n\n\u003cimg src=\"/figures/rotate3.png\" width=\"75%\"\u003e\n\n\n```stata\nshapes rotate _y _x, rotate(30) center by(_id) genx(xnew3) geny(ynew3)\t\t\t\n\t\ntwoway ///\n\t(area _y _x, cmissing(n) nodropbase fcolor(%80) lw(0.1) lc(white))\t///\n\t(area ynew3  xnew3, cmissing(n) nodropbase fcolor(%80) lw(0.1) lc(white))\t///\n\t(scatteri 0 0) ///\n\t\t, ///\n\t\tlegend(off) ///\n\t\txlabel(-10(2)10) ylabel(-10(2)10) xsize(1) ysize(1) aspect(1)\n```\n\n\u003cimg src=\"/figures/rotate4.png\" width=\"75%\"\u003e\n\n\n### shapes round\n\n\n\nSyntax:\n\n```stata\nshapes round \u003cyvar\u003e \u003cxvar\u003e [if] [in], roundness(num) [ n(num) factor(num) genx(var) geny(var) genid(var) genorder(var) gensegvar(var) replace append ]\n```\n\n\u003cimg src=\"/figures/_round.png\" width=\"50%\"\u003e\n\nThis command will generate rounded edges with radius `roundness()`. The size of the rounding is determined by `factor()`. \n\nNOTE: If `roundness()` is larger than the shape length, then usual edges might be drawn so calibrate carefully.\n\nThe option `factor(1)` implies that center point of the arc is the exact middle of the edges. A larger factor moves the point away from the minor arc making it less curvy. If rounding is done on figures a large number of edges, e.g. hexagon, octagon, or higher, then reducing the rounding might fit better with the figure. So calibrate this option also carefully.\n\n\nThis command will generate or overwrite five new variables: `_rx, _ry, _rid, _rorder, _segvar`, or their respective custom names.\n\nEach shape with rounded edges is assigned an `_rid` that is carried forward from the original shape `_id`. The shape is split into two segment types: lines and arcs, which are identitied by the `_segvar` variable, and `_rorder` is the drawing order of each segment variable. The `_rid`, `_segvar`, and `_rorder` give a unique sort and order that needs to be respected to draw the shapes correctly.\n\n\nTODO: Add examples.\n\n\n### shapes area\n\nSyntax:\n\n```stata\nshapes area \u003cyvar\u003e \u003cxvar\u003e, [ {opt by(var} generate(var) replace ]\n```\n\nExamples:\n```stata\nclear\nshapes pie, start(0) end(45) ro(0)\t\trad(5) \treplace\nshapes pie, start(0) end(45) ro(30) \trad(6)  stack\nshapes pie, start(0) end(45) ro(60) \trad(7)  stack\nshapes pie, start(0) end(45) ro(90) \trad(8)  stack\nshapes pie, start(0) end(45) ro(120) \trad(9)  stack\nshapes pie, start(0) end(45) ro(150) \trad(10) stack\n\n\ntwoway (area _y _x, fcolor(%90) cmissing(n) nodropbase)\t///\n\t, xlabel(-10 10) ylabel(-10 10) xsize(1) ysize(1) aspect(1)\n```\n\n\u003cimg src=\"/figures/area1.png\" width=\"75%\"\u003e\n\n\nCalculate the areas\n\n```stata\nshapes area _y _x, by(_id) \n```\n\nGenerate some ranking of areas and plot\n\n\n```stata\nxtile grps = _area, n(4)\t\n\nlevelsof _id, local(lvls)\n\nforeach x of local lvls {\n\tcolorpalette reds, nograph\n\tlocal myarea `myarea' (area _y _x if _id==`x', fcolor(\"`r(p`x')'%90\") lc(\"`r(p`x')'\") cmissing(n) nodropbase)\t\n}\n\n\n\ntwoway ///\n\t`myarea'\t///\n\t, ///\n\t\txlabel(-10 10) ylabel(-10 10) ///\n\t\tlegend(off) ///\n\t\txsize(1) ysize(1) aspect(1)\n```\n\n\n\u003cimg src=\"/figures/area2.png\" width=\"75%\"\u003e\n\n## radscatter\n*(v1.0: 19 Nov 2025)*\n\nSyntax:\n\n```stata\nradscatter [ numvar ] [if] [in], [ start(angle) end(angle) center rotate(angle) radius(num) flip displace(num) genx(str) geny(str) genangle(var) genheight(var) replace ]\n```\n\nIf `radscatter \u003cvariable\u003e` is specified, the the variable values will be used to normalize the heights for the given `radius()`. The `displace()` option, displaced the final coordinates by the specified number of points. \n\nIf the heights are expected to stay exactly the same for all the points determined by `radius()` and `displace()`, then just specify `radscatter if !missing(\u003cvar\u003e), \u003coptions\u003e`.\n\nPrepare the data\n\n```stata\nuse \"https://github.com/asjadnaqvi/stata-graphfunctions/blob/main/data/demo_r_pjangrp3_clean.dta?raw=true\", clear\n\nren y2023 pop\nkeep if nuts0==\"CH\"\t\t\ncollapse (sum) pop, by(nuts2 nuts2_label) \ngsort -pop    \t\ngen group = _n  \n```\n\n\n```stata\nradscatter if !missing(pop), replace\ntwoway (scatter _rady _radx, mlabel(nuts2_label)), aspect(1)\n```\n\n\u003cimg src=\"/figures/radscatter1.png\" width=\"75%\"\u003e\n\n```stata\nradscatter pop, replace\ntwoway (scatter _rady _radx, mlabel(nuts2_label)), aspect(1)\n```\n\n\u003cimg src=\"/figures/radscatter2.png\" width=\"75%\"\u003e\n\n```stata\nradscatter pop, replace labangle\n\n\nlevelsof _radid, local(lvls)\n\nforeach x of local lvls {\n\tsumm _labangle if _radid==`x', meanonly\n\tlocal myscatter `myscatter' (scatter _rady _radx if _radid==`x', mlabel(nuts2_label) mlabangle(`r(mean)') mlabpos(0))\n}\n\ntwoway ///\n\t`myscatter' ///\n\t, aspect(1) legend(off) xlabel(-6(2)6) ylabel(-6(2)6) xsize(1) ysize(1)\n```\n\n\u003cimg src=\"/figures/radscatter3.png\" width=\"75%\"\u003e\n\n\nUse a custom range:\n\n```stata\nradscatter  if !missing(pop), replace start(0) end(90) \ntwoway (scatter _rady _radx, mlabel(_radid) ), aspect(1) xsize(1) ysize(1) xlabel(0(1)5) ylabel(0(1)5)\n```\n\u003cimg src=\"/figures/radscatter4.png\" width=\"75%\"\u003e\n\n\nCenter the points on the arcs:\n\n```stata\nradscatter  if !missing(pop), replace start(0) end(90) center \ntwoway (scatter _rady _radx, mlabel(_radid) ), aspect(1) xsize(1) ysize(1) xlabel(0(1)5) ylabel(0(1)5)\n```\n\n\u003cimg src=\"/figures/radscatter5.png\" width=\"75%\"\u003e\n\n\nLet's combine `shapes pie` + `radscatter`, to generate a script that one can also easily adapt:\n\n```stata\ncap drop _x _y _id _order\t\n\n// predefine the angle\nlocal maxangle = 90\nlocal maxradius = 5\n\t\nlevelsof nuts2\nlocal items = `r(r)'\n\t\t\t\t\t\nsumm pop, meanonly\nlocal mymax = r(max)\t\n\nlocal size = `maxangle' / `items'\t\n\nlocal shift = 0\n\t\nforval i = 1/`items' {\n\t\n\tsumm pop if group==`i', meanonly\n\tlocal factor = (r(max) / `mymax') * `maxradius'\n\t \t\t\t\n\tshapes pie, start(0) end(`size') rotate(`shift') n(30) rad(`factor') append\n\n\tlocal shift = `shift' + `size' \n}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\nradscatter  pop if !missing(pop), replace start(0) end(`maxangle') radius(`maxradius') center displace(0.2)\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\ntwoway ///\n\t(area _y _x, cmissing(no) nodropbase fcolor(%30))\t///\n\t(scatter _rady _radx, mlabel(_radid))\t///\n\t, ///\n\tlegend(off)\t///\n\txsize(1) ysize(1) aspect(1)\t\t///\t\t\t\n\t\txlabel(0 5) ylabel(0 5) ///\n\t\t\txscale(off) yscale(off)\t///\n\t\t\txlabel(, nogrid) ylabel(, nogrid) \t\n```\n\n\n\u003cimg src=\"/figures/radscatter6.png\" width=\"75%\"\u003e\n\n\n## Examples\n\n\n\n### Example 1: Custom radial bar plot with rounded edges and polar labels.\n\nThis example was showcased in the Stata Switzerland 2025 conference (Bern, 21 Nov 2025).\n\nLoad cleaned regional population file from Eurostat: \n\n```stata\nuse \"https://github.com/asjadnaqvi/stata-graphfunctions/blob/main/data/demo_r_pjangrp3_clean.dta?raw=true\", clear\n\nren y2023 pop\nkeep if nuts0==\"CH\"\t\t// Keep Switzerland\ncollapse (sum) pop, by(nuts2 nuts2_label) // keep NUTS2 regions \ngsort -pop    \t// reserve sort on population\ngen group = _n  // generate order variable\n```\n\nFor each group generate a square of length 10, whose bottom-left point is at the origin (default):\n\n```stata\nlevelsof nuts2\nlocal items = `r(r)'\n\nlocal i = 1\n\nwhile `i' \u003c= `items' {\n\tshapes square, len(10) append\n\tlocal ++i\n}\n```\n\nPlot and check:\n\n```stata\ntwoway ///\n\t(area _y _x, cmissing(n) nodropbase fcolor(%80) lw(0.1) lc(white))\t///\n\t(scatteri 0 0) ///\n\t\t, ///\n\t\tlegend(off) ///\n\t\txsize(1) ysize(1) aspect(1)\t\t\n```\n\n\u003cimg src=\"/figures/example1_1.png\" width=\"75%\"\u003e\n\nLet's now stretch each square based on the population size:\n\n\n```stata\nsumm pop, meanonly\nlocal mymax = r(max)\t\n\nlevelsof nuts2\nlocal items = `r(r)'\n\t\nforval i = 1/`items' {\n\tsumm pop if group==`i', meanonly\n\tlocal factor = r(max) / `mymax'\n\tshapes stretch _y _x  if _id==`i', y(0.2) x(`factor') replace\n}\n```\n\nand plot it again:\n\n```stata\ntwoway ///\n\t(area _y _x, cmissing(n) nodropbase fcolor(%30) lw(0.1) lc(black))\t///\n\t\t, ///\n\t\tlegend(off) ///\n\t\txline(0) yline(0) ///\n\t\txlabel(-10 10) ylabel(-10 10) ///\n\t\txsize(1) ysize(1) aspect(1)\n```\n\n\u003cimg src=\"/figures/example1_2.png\" width=\"75%\"\u003e\n\n\nWe can also move these blocks down by one point to center on the x-axis:\n\n```stata\nshapes translate _y _x, y(-1) replace\t\n```\n\nWe can also check this:\n\n```stata\ntwoway ///\n\t(area _y _x, cmissing(n) nodropbase fcolor(%30) lw(0.1) lc(black))\t///\n\t\t, ///\n\t\tlegend(off) ///\n\t\txline(0) yline(0) ///\n\t\txlabel(-10 10) ylabel(-10 10) ///\n\t\txsize(1) ysize(1) aspect(1)\n```\n\n\u003cimg src=\"/figures/example1_3.png\" width=\"75%\"\u003e\n\n\nWe can now rotate and distribute the shapes on a circle:\n\n```stata\nlevelsof nuts2\nlocal items = `r(r)'\t\n\t\nforval i = 1/`items' {\t\n\tlocal angle = (`i' - 1) / `items' * 360\n\tshapes rotate _y _x if _id==`i', rotate(`angle') replace\n}\t\n``` \n\nLet's see what it looks like:\n\n```stata\ntwoway ///\n\t(area _y _x, cmissing(n) nodropbase fcolor(%30) lw(0.1) lc(black))\t///\n\t\t, ///\n\t\tlegend(off) ///\n\t\txline(0) yline(0) ///\n\t\txlabel(-10 10) ylabel(-10 10) ///\n\t\txsize(1) ysize(1) aspect(1)\n```\n\n\u003cimg src=\"/figures/example1_4.png\" width=\"75%\"\u003e\n\n\n\nWe can now round the edges:\n\n```stata\nlevelsof nuts2\nlocal items = `r(r)'\t\n\nforval i = 1/`items' {\n\tshapes round _y _x if _id==`i', r(0.5) n(20) append\n}\t\n```\n\n```stata\ntwoway ///\n\t(area _ry _rx , cmissing(no) nodropbase fcolor(%40) lw(0.1) lc(black))\t///\n\t\t, ///\n\t\tlegend(off) ///\n\t\txline(0) yline(0) ///\n\t\txlabel(-10 10) ylabel(-10 10) ///\n\t\txsize(1) ysize(1) aspect(1)\t\n```\n\n\u003cimg src=\"/figures/example1_5.png\" width=\"75%\"\u003e\n\n\nLet's add some colors:\n\n```stata\nlevelsof group, local(lvls)\nlocal items = `r(r)'\n\nforeach x of local lvls {\n\t\n\tcolorpalette CET L20, nograph n(`items') reverse\n\t\n\tlocal myarea `myarea' (area _ry _rx if _rid==`x', cmissing(no) nodropbase fi(100) fcolor(\"`r(p`x')'%80\") lw(0.1) lc(black))\n\t\t\n}\n\n\ntwoway ///\n\t`myarea'\t///\n\t\t, ///\n\t\tlegend(off) ///\n\t\txlabel(-10 10) ylabel(-10 10) ///\n\t\t\txscale(off) yscale(off)\t///\n\t\t\txlabel(, nogrid) ylabel(, nogrid) ///\n\t\t\t\txsize(1) ysize(1) aspect(1)\t\t\n```\n\n\u003cimg src=\"/figures/example1_6.png\" width=\"75%\"\u003e\n\n\nWhich gives us a neat figure. But labels are missing. Since we don't want users to struggle with polar coordinates, we can use `radscatter` to generate the points:\n\n```stata\nradscatter pop, replace labangle rad(10) displace(2)\n```\n\nThe option labangle gives us the angle that allows us to align the label to the ray from the original. Let's add this to our plot:\n\n```stata\n\t\t\nlevelsof group, local(lvls)\nlocal items = `r(r)'\n\nforeach x of local lvls {\n\t\n\tcolorpalette CET L20, nograph n(`items') reverse\n\t\t\n\tlocal myarea `myarea' (area _ry _rx if _rid==`x', cmissing(no) nodropbase fi(100) fcolor(\"`r(p`x')'%80\") lw(0.1) lc(black))\n\t\n\tsumm _labangle if _radid==`x', meanonly\n\tlocal myscatter `myscatter' (scatter _rady _radx if _radid==`x', mcolor(none) mlabel(nuts2_label) mlabangle(`r(mean)') mlabpos(0) mlabsize(2))\n\t\n}\n\n\ntwoway ///\n\t`myarea'\t///\n\t`myscatter' ///\n\t\t, ///\n\t\tlegend(off) ///\n\t\txlabel(-12 12) ylabel(-12 12) ///\n\t\txsize(1) ysize(1) aspect(1)\t\t///\n\t\t\txscale(off) yscale(off)\t///\n\t\t\txlabel(, nogrid) ylabel(, nogrid) \n```\n\n\u003cimg src=\"/figures/example1_7.png\" width=\"75%\"\u003e\n\n\n\nWe can of course get rid of all the intermediate plots and do all the calculations and just plots the final figure. Or we can even create our own program that generate this plot type.\n\n\n### Example 2: Custom pie graph\n\nThis example was showcased in the Stata Switzerland 2025 conference (Bern, 21 Nov 2025).\n\n\nPrepare the data (as above):\n\n\n```stata\nuse \"https://github.com/asjadnaqvi/stata-graphfunctions/blob/main/data/demo_r_pjangrp3_clean.dta?raw=true\", clear\n\nren y2023 pop\nkeep if nuts0==\"CH\"\t\t// Keep Switzerland\ncollapse (sum) pop, by(nuts2 nuts2_label) // keep NUTS2 regions \ngsort -pop    \t// reserve sort on population\ngen group = _n  // generate order variable\n```\n\n\nLet's generate a pie for each NUTS2 where each pie has a fixed angle but the height is normalized to the `pop` variable and rotate by a certain angle:\n\n```stata\t\t\nlevelsof nuts2\nlocal items = `r(r)'\n\t\t\t\t\t\t\nsumm pop, meanonly\nlocal mymax = r(max)\t\n\t\nlocal shift = 0\n\t\nforval i = 1/`items' {\n\t\n\tsumm pop if group==`i', meanonly\n\tlocal factor = (r(max) / `mymax') * 10\n\t \t\t\t\n\tshapes pie, start(0) end(60) rotate(`shift') n(30) rad(`factor') append\n\n\tlocal _range = 270\n\t\t\n\tlocal shift = `shift' + `_range' / `=`items' - 1'\n\t\n}\n```\n\nTest the plot:\n\n```stata\ntwoway (area _y _x, cmissing(no) nodropbase fcolor(%30))\t///\n\t, ///\n\txsize(1) ysize(1) aspect(1)\t\t///\t\t\t\n\t\txlabel(-10 10) ylabel(-10 10) ///\n\t\t\txscale(off) yscale(off)\t///\n\t\t\txlabel(, nogrid) ylabel(, nogrid) \n```\n\n\u003cimg src=\"/figures/example2_1.png\" width=\"75%\"\u003e\n\n\nLet's make it nicer:\n\n```stata\nlocal myarea\n\nlevelsof _id, local(lvls) \nlocal items = `r(r)'\n\nforeach x of local lvls {\n\tcolorpalette CET L20, nograph n(`items')\n\tlocal myarea `myarea' (area _y _x if _id==`x', cmissing(no) nodropbase fi(100) fcolor(\"`r(p`x')'%100\") lw(0.1) lc(black))\n\t\t\n}\n\t\t\t\n\t\t\t\ntwoway `myarea'\t///\n\t, ///\n\tlegend(off)\t///\n\txsize(1) ysize(1) aspect(1)\t\t///\t\t\t\n\t\txlabel(-10 10) ylabel(-10 10) ///\n\t\t\txscale(off) yscale(off)\t///\n\t\t\txlabel(, nogrid) ylabel(, nogrid) \n\t\t\t\n```\n\n\u003cimg src=\"/figures/example2_2.png\" width=\"75%\"\u003e\n\n\nLet modify and add scatter points:\n\n```stata\ncap drop _x _y _id _order\t\n\n// predefine the angle\nlocal maxangle = 270\nlocal maxradius = 5\n\t\nlevelsof nuts2\nlocal items = `r(r)'\n\t\t\t\t\t\nsumm pop, meanonly\nlocal mymax = r(max)\t\n\nlocal size = `maxangle' / `items'\t\n\nlocal shift = 0\n\t\nforval i = 1/`items' {\n\t\n\tsumm pop if group==`i', meanonly\n\tlocal factor = (r(max) / `mymax') * `maxradius'\n\t \t\t\t\n\tshapes pie, start(0) end(`size') rotate(`shift') n(30) rad(`factor') append\n\n\tlocal shift = `shift' + `size' \n}\n\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\nradscatter  pop if !missing(pop), replace start(0) end(`maxangle') radius(`maxradius') center displace(0.3)\tlabangle\t\t\t\t\t\t\t\t\n\t\t\t\nreplace _labangle = _labangle + 90\tif _radx \u003c 0\t\t\nreplace _labangle = _labangle - 90\tif _radx \u003e= 0\n\t\t\t\nlocal myarea\nlocal myscatter\n\nlevelsof _id, local(lvls) \nlocal items = `r(r)'\n\nforeach x of local lvls {\n\tcolorpalette CET L19, nograph n(`items') reverse\n\tlocal myarea `myarea' (area _y _x if _id==`x', cmissing(no) nodropbase fi(100) fcolor(\"`r(p`x')'%100\") lw(0.1) lc(black))\n\t\n\tsumm _labangle if _radid==`x', meanonly\n\tlocal myscatter `myscatter' (scatter _rady _radx if _radid==`x', mcolor(none) mlabel(nuts2_label) mlabangle(`r(mean)') mlabpos(0) mlabsize(2))\n\t\n\t\t\n}\n\t\t\t\n\t\t\t\ntwoway ///\n\t`myarea'\t///\n\t`myscatter'\t///\n\t, ///\n\tlegend(off)\t///\n\txsize(1) ysize(1) aspect(1)\t\t///\t\t\t\n\t\txlabel(-5 5) ylabel(-5 5) ///\n\t\t\txscale(off) yscale(off)\t///\n\t\t\txlabel(, nogrid) ylabel(, nogrid) \n```\n\n\u003cimg src=\"/figures/example2_3.png\" width=\"75%\"\u003e\n\n\n\n### Example 3: Custom radial race plot\n\nPrepare the data as above:\n\n```stata\nuse \"https://github.com/asjadnaqvi/stata-graphfunctions/blob/main/data/demo_r_pjangrp3_clean.dta?raw=true\", clear\n\nren y2023 pop\nkeep if nuts0==\"CH\"\t\t// Keep Switzerland\ncollapse (sum) pop, by(nuts2 nuts2_label) // keep NUTS2 regions \ngsort -pop    \t// reserve sort on population\ngen group = _n  // generate order variable\n```\n\nNow we generate arcs whose radii decrease in size by a value of one. The maximum length of the arcs is capped till the 3rd quadrant, or 270 degrees:\n\n\n```stata\nsumm pop, meanonly\nlocal mymax = r(max)\t\n\t\n\nlevelsof nuts2\nlocal items = `r(r)'\n\n\t\nforval i = 1/`items' {\n\t\n\tsumm pop if group==`i', meanonly\n\tlocal factor = (r(max) / `mymax') * 270\n\t\n\tlocal myradius = `items' + 5 - `i' \n\t\n\tshapes pie, start(0) end(`factor') n(50) rad(`myradius') append dropbase flip rotate(90)\n\n}\n```\n\nTest what we have:\n\n```stata\ntwoway (line _y _x, cmissing(no) nodropbase fcolor(%30))\t///\n\t, xsize(1) ysize(1) aspect(1)\t\t\t\t\t\n```\n\n\u003cimg src=\"/figures/example3_1.png\" width=\"75%\"\u003e\n\n\nAdd scatter points at the starting line:\n\n```stata\nlevelsof group, local(lvls) \nlocal items = `r(r)'\n\t\t\ncap drop _sy _sx\ngen _sy = `items' + 5 - group \tif !missing(group)\ngen _sx = -0.2 \t\t\t\t\tif !missing(group)\n\ncap drop _mylab\ngen _mylab = nuts2_label + \" (\" + string(pop, \"%15.0fc\") + \")\" if !missing(group)\n```\n\nAdd colors and labels:\n\n```stata\nsumm pop, meanonly\nlocal mymax = r(max)\t\n\nlevelsof _id, local(lvls) \nlocal items = `r(r)'\n\nforeach x of local lvls {\n\t\n\tsumm pop if group==`x', meanonly\n\tlocal mylwid = (r(max) / `mymax') * 0.7 + 0.3\n\t\n\tcolorpalette CET L06, nograph n(`items') \n\tlocal mylines `mylines' (line _y _x if _id==`x', cmissing(no) nodropbase lcolor(\"`r(p`x')'%100\") lw(`mylwid') )\n\t\t\n}\n\t\t\t\n\t\t\t\ntwoway ///\n\t`mylines'\t///\n\t(scatter _sy _sx, mlabel(_mylab) mlabpos(9) mcolor(none) mlabsize(1.8) ) ///\n\t, ///\n\tlegend(off)\t///\n\txsize(1) ysize(1) aspect(1)\t\t///\t\t\t\n\t\txlabel(-10 10) ylabel(-10 10) ///\n\t\t\txscale(off) yscale(off)\t///\n\t\t\txlabel(, nogrid) ylabel(, nogrid) \n\t\t\t\t\t\t\n```\n\n\u003cimg src=\"/figures/example3_2.png\" width=\"75%\"\u003e\n\n\n### Example 4: Transformed shapes\n\nPrepare the data as above:\n\n\n```stata\nuse \"https://github.com/asjadnaqvi/stata-graphfunctions/blob/main/data/demo_r_pjangrp3_clean.dta?raw=true\", clear\n\nren y2023 pop\nkeep if nuts0==\"CH\"\t\t// Keep Switzerland\ncollapse (sum) pop, by(nuts2 nuts2_label) // keep NUTS2 regions \ngsort -pop    \t// reserve sort on population\ngen group = _n  // generate order variable\n```\n\nGenerate hexagons that are have radius normalized by the population:\n\n```stata\nlevelsof nuts2\nlocal items = `r(N)'\n\nlocal myrotate = 0\t\t\t\t\t\n\t\t\t\t\t\nsumm pop, meanonly\nlocal mymax = r(max)\t\n\t\n\nforval i = 1/`items' {\n\tsumm pop if group==`i', meanonly\n\tlocal factor = (r(max) / `mymax') * 10\n\t\n\tshapes circle, rad(`factor') n(6) rotate(`myrotate')  append\n}\n```\n\nPlot and check:\n\n\n```stata\ntwoway (area _y _x, cmissing(no) nodropbase fcolor(%30))\t///\n\t, xsize(1) ysize(1) aspect(1)\n```\n\n\u003cimg src=\"/figures/example4_1.png\" width=\"75%\"\u003e\n\n\nAdd colors:\n\n```stata\nlocal myarea\nlevelsof group, local(lvls) \nlocal items = `r(N)'\n\nforeach x of local lvls {\n\t\tcolorpalette CET L20, nograph  n(`items')\n\t\t\n\t\tlocal myarea `myarea' (area _y _x if _id==`x', cmissing(no) nodropbase fi(100) fcolor(\"`r(p`x')'%100\") lw(0.1) lc(white))\n}\n\t\t\t\n\t\t\t\t\ntwoway `myarea'\t///\n\t, legend(off)\t///\n\txsize(1) ysize(1) aspect(1)\t\t///\t\t\t\n\t\txlabel(-10 10) ylabel(-10 10) ///\n\t\t\txscale(off) yscale(off)\t///\n\t\t\txlabel(, nogrid) ylabel(, nogrid) \n```\n\n\u003cimg src=\"/figures/example4_2.png\" width=\"75%\"\u003e\n\n\nLet's displace these shapes away from the origin, and rotate (or pivot) them on the origin:\n\n```\nlevelsof _id, local(lvls)\n\nlocal myrot = 0\n\nforeach x of local lvls {\n\t\n\tshapes translate _y _x if _id==`x', x(15) replace\n\t\n\tshapes rotate _y _x if _id==`x', rotate(`myrot') replace\n\t\n\tlocal myrot = `myrot' + 20\t\n}\n```\n\nAnd test the plot:\n\n```stata\nlocal myarea\nlevelsof group, local(lvls) \nlocal items = `r(N)'\n\n\nforeach x of local lvls {\n\t\tcolorpalette CET L20, nograph  n(`items')\n\t\t\n\t\tlocal myarea `myarea' (area _y _x if _id==`x', cmissing(no) nodropbase fi(100) fcolor(\"`r(p`x')'%100\") lw(0.1) lc(white))\n}\n\t\t\t\n\t\t\t\ntwoway `myarea'\t///\n\t, legend(off)\t///\n\txsize(1) ysize(1) aspect(1)\t\t///\t\t\t\n\t\txlabel(-20 30) ylabel(-20 30) ///\n\t\t\txscale(off) yscale(off)\t///\n\t\t\txlabel(, nogrid) ylabel(, nogrid) \t\n```\n\n\u003cimg src=\"/figures/example4_3.png\" width=\"75%\"\u003e\n\n\nLet's round the edges as well:\n\n```stata\nlevelsof _id, local(lvls)\n\nforeach x of local lvls {\n\tshapes round _y _x if _id==`x', round(1) n(20) factor(1.2) append\t\n}\n```\n\nGenerate the scatter points and plot the figure:\n\n```stata\n// specifying it here manually in case the code is run separate blocks\n// this value should equal the final one specified in the loop above\n\nlocal myrot = 175 \n\nradscatter if !missing(pop), replace radius(25) end(`myrot') labangle\n\n\nlocal myarea\nlocal myscatter\n\nlevelsof _rid, local(lvls) \nlocal items = `r(r)'\n\n\nforeach x of local lvls {\n\t\tcolorpalette matplotlib spring, nograph  n(`items') reverse\n\t\t\n\t\tlocal myarea `myarea' (area _ry _rx if _rid==`x', cmissing(no) nodropbase fi(100) fcolor(\"`r(p`x')'%100\") lw(0.1) lc(gs4))\n\t\t\n\tsumm _labangle if _radid==`x', meanonly\n\tlocal myscatter `myscatter' (scatter _rady _radx if _radid==`x', mcolor(none) mlabel(nuts2_label) mlabangle(`r(mean)') mlabpos(0) mlabsize(1.8))\n\t\t\t\n\t\t\n}\n\t\t\t\n\ntwoway ///\n\t`myarea'\t///\n\t`myscatter'\t///\n\t, legend(off)\t///\n\txsize(1) ysize(1) aspect(1)\t\t///\t\t\t\n\t\txlabel(-26 26) ylabel(-26 26) ///\n\t\t\txscale(off) yscale(off)\t///\n\t\t\txlabel(, nogrid) ylabel(, nogrid) \n```\n\n\u003cimg src=\"/figures/example4_4.png\" width=\"75%\"\u003e\n\n\n\n## Feedback\n\nPlease open an [issue](https://github.com/asjadnaqvi/stata-graphfunctions/issues) to report errors, feature enhancements, and/or other requests.\n\n\n## Change log\n\n\n**v1.6 (19 Nov 2025)**\n- `shapes` updated to v1.4 to include better options for `shapes square`, `shapes pie`, `shapes cirle`, and `shapes rotate`. New commands include `shapes translate`, `shapes dilate`, `shapes stretch`, `shapes round`.\n- `arc` updated with better options. `dropbase` added to ensure continuity across stacked arcs.\n- New command `radscatter` added.\n- Major rehaul of base routines, various bug fixes, better scripts that stack variables.\n\n\n**v1.52 (18 Feb 2025)**\n- `catspline` now generate the stated number of points.\n- `catspline` now respects `if/in` conditions.\n- Minor corrections and bug fixes.\n\n**v1.51 (28 Nov 2024)**\n- Fixed `catspline` to correct generate splines. Added options to replace variables. Change in routine to make it more efficient in computations.\n- Added `replace`, `append` to `arc`. Various bug fixes.\n- Added `append` as a substitute for `stack` in `shapes`. \n- Added `square` in `shapes.\n\n**v1.5 (05 Nov 2024)**\n- `shapes square` added for squares. Note that `shapes circle, n(4)` also returns a square but here we define the center-to-corner length using the radius, where as `shapes square` generates a side with a predefined length. Hence the area of `shapes circle, n(4) rad(5)` \u003e `shapes square, len(5)`.\n- `shapes rotate` added for generation rotations at specific points or center of shapes. Note that this is a more advanced rotation than what each individual function provides.\n- `shapes area` added for calculating the areas (currently in undefined units) using [Meister's shoelace formula](https://en.wikipedia.org/wiki/Shoelace_formula). \n- Option `append` added as a substitute for `stack`. This is more in line with standard Stata syntax.\n- Option `flip` added to change the drawing direction. This flips from counter-clockwise (Stata default) to clockwise.\n- Better information added for rotations, orientations, and starting points.\n- Cleanup of helpfiles.\n\n**v1.4 (15 Oct 2024)**\n- `shapes` is now also mirrored as `shape`.\n- `shape circle` updated, and `shape pie` added.\n- In `shapes`, users can now also define an origin using `x0()` and `y0()` options.\n- More controls and checks.\n\n**v1.3 (13 Oct 2024)**\n- `shapes` added. Minor fixes to index tracking.\n- `arc` bug fixes plus code cleanup.\n\n**v1.2 (08 Oct 2024)**\n- `arc` added.\n- Bug fixes in `labsplit`.\n- Additional checks in programs.\n\n**v1.1 (04 Oct 2024)**\n- `catspline` added.\n\n**v1.0 (28 Sep 2024)**\n- `labsplit` added.\n- Public release.\n\n\n\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fasjadnaqvi%2Fstata-graphfunctions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fasjadnaqvi%2Fstata-graphfunctions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fasjadnaqvi%2Fstata-graphfunctions/lists"}