{"id":3568,"date":"2025-12-18T14:24:25","date_gmt":"2025-12-18T19:24:25","guid":{"rendered":"https:\/\/blogs.mathworks.com\/graphics-and-apps\/?p=3568"},"modified":"2026-01-30T20:43:27","modified_gmt":"2026-01-31T01:43:27","slug":"gift-bow","status":"publish","type":"post","link":"https:\/\/blogs.mathworks.com\/graphics-and-apps\/2025\/12\/18\/gift-bow\/","title":{"rendered":"A Bow made of Ribbon"},"content":{"rendered":"&nbsp;\r\n<table style=\"background-color: #e2f0ff\">\r\n<tbody>\r\n<tr>\r\n<td style=\"width: 120px;padding: 3px;vertical-align: middle\"><img decoding=\"async\" class=\"aligncenter size-medium\" src=\"http:\/\/blogs.mathworks.com\/graphics-and-apps\/files\/2023\/10\/EricPortrait.png\" alt=\"Portrait of Eric Ludlam\" \/><\/td>\r\n<td style=\"vertical-align: middle;padding: 3px\"><strong>Guest Writer: <a href=\"https:\/\/www.mathworks.com\/matlabcentral\/profile\/authors\/869244\" target=\"_blank\" rel=\"noopener\">Eric Ludlam<\/a>\r\n<\/strong>Eric Ludlam is the development manager of MATLAB\u2019s Charting team. Eric has a whopping 27 years of experience working in MATLAB Graphics, starting in MATLAB 5.0! Eric is renowned within MathWorks for his love of trebuchets, catapults and\u00a0Punkin Chunkin. His exceptional graphics demos have appeared in MathWorks\u2019 Community blog, MATLAB blog, and in MATLAB social media feeds.<\/td>\r\n<\/tr>\r\n<\/tbody>\r\n<\/table>\r\n&nbsp;\r\n\r\n<hr \/>\r\n\r\n<div class=\"rtcContent\">\r\n<div><\/div>\r\n<div style=\"margin: 2px 10px 9px 4px;padding: 0px;line-height: 21px;min-height: 0px;font-family: Helvetica, Arial, sans-serif, Helvetica, Arial, sans-serif;font-style: normal;font-size: 14px;font-weight: 400;text-align: left\">Tis the season for a MATLAB holiday algorithm!<\/div>\r\n<div style=\"margin: 2px 10px 9px 4px;padding: 0px;line-height: 21px;min-height: 0px;font-family: Helvetica, Arial, sans-serif, Helvetica, Arial, sans-serif;font-style: normal;font-size: 14px;font-weight: 400;text-align: left\">The bow we'll make is constructed of several loops of ribbon that emanate out from the origin. We'll use a <a href=\"https:\/\/blogs.mathworks.com\/graphics-and-apps\/2024\/12\/16\/pinecode-creating-pinecones-with-fibonacci-spirals\/\" target=\"_blank\" rel=\"noopener\">Fibonacci spiral<\/a> to determine how far each ribbon loop will extend. Then we will compute the path of the ribbon loops in spherical coordinates. We'll use <span style=\"font-family: monospace\">sph2cart<\/span> to convert our theta &amp; phi values of the ribbon paths into Cartesian locations on a sphere.<\/div>\r\n<div style=\"margin: 2px 10px 9px 4px;padding: 0px;line-height: 21px;min-height: 0px;font-family: Helvetica, Arial, sans-serif, Helvetica, Arial, sans-serif;font-style: normal;font-size: 14px;font-weight: 400;text-align: left\">Once we've computed the geometry for the path of the ribbon, we use <a href=\"https:\/\/www.mathworks.com\/help\/matlab\/ref\/streamribbon.html\" target=\"_blank\" rel=\"noopener\"><span style=\"font-family: monospace\">streamribbon<\/span><\/a> to create the geometry for the ribbon.<\/div>\r\n<div style=\"margin: 2px 10px 9px 4px;padding: 0px;line-height: 21px;min-height: 0px;font-family: Helvetica, Arial, sans-serif, Helvetica, Arial, sans-serif;font-style: normal;font-size: 14px;font-weight: 400;text-align: left\">The streamribbon function is often used to compute a ribbon visualization through a volume, but you can pass in your own paths as well. Since each ribbon might be a different length, streamribbon accepts paths as a cell array of vertex arrays (<span style=\"font-family: monospace\">Nx3)<\/span>. Our ribbon is relatively simple, so once we have the geometry of the ribbons, it is easy enough to customize the returned surface objects for the holidays!<\/div>\r\n<div style=\"margin: 2px 10px 9px 4px;padding: 0px;line-height: 21px;min-height: 0px;font-family: Helvetica, Arial, sans-serif, Helvetica, Arial, sans-serif;font-style: normal;font-size: 14px;font-weight: 400;text-align: left\">If you open a version of this script in MATLAB Online using the link below, all the parameters at the beginning of the script can be manipulated with sliders and a color picker, making it easy for you to design a bow for your own gift.<\/div>\r\n<div><img decoding=\"async\" loading=\"lazy\" class=\" wp-image-3574 alignnone\" src=\"http:\/\/blogs.mathworks.com\/graphics-and-apps\/files\/2025\/12\/ribbonUI.png\" alt=\"\" width=\"363\" height=\"173\" \/><\/div>\r\n<a href=\"https:\/\/matlab.mathworks.com\/open\/github\/v1?repo=zappo2\/digital-art-with-matlab&amp;file=giftwrap\/livegiftbow.mlx\" target=\"_blank\" rel=\"nofollow noopener\"><img decoding=\"async\" class=\"\" src=\"https:\/\/www.mathworks.com\/images\/responsive\/global\/open-in-matlab-online.svg\" alt=\"Open in MATLAB Online\" \/><\/a>\r\n<div style=\"background-color: #f5f5f5;margin: 10px 15px 10px 0;min-width: 100%\">\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 4px 4px 0px 0px;padding: 6px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\">nloops = 21; <span style=\"color: #008013\">% Number of loops in the bow<\/span><\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\">lwphi = 0.2; <span style=\"color: #008013\">% Loop width across phi normalized radians<\/span><\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\">height = 1; <span style=\"color: #008013\">% Height of the bow<\/span><\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\">ribbonwidth = 0.3; <span style=\"color: #008013\">% Width of ribbon<\/span><\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\">color = <span style=\"color: #a709f5\">'red'<\/span>; <span style=\"color: #008013\">% Color of the ribbon<\/span><\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\"><\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\">npts = 21; <span style=\"color: #008013\">% Number of vertices in a loop (should be odd)<\/span><\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\"><\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\"><span style=\"color: #008013\">% Create geometry for each loop as a line in spherical coordinates<\/span><\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\"><span style=\"color: #008013\">% and then convert to cartesian.<\/span><\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\">theta=repmat((1+sqrt(5))*(1:nloops),npts,1)*pi;<\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\">phi=(linspace(.5,1,nloops).^.8+linspace(-lwphi,lwphi,npts)'.*linspace(.8,1,nloops))*pi;<\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\">R=ones(1,nloops).*(1-abs(linspace(-1,1,npts)'.^2));<\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\"><\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\">[X,Y,Z] = sph2cart(theta,phi,R);<\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\"><\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\"><span style=\"color: #008013\">% Use streamribbon to create the bow's ribbon.<\/span><\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\"><span style=\"color: #008013\">% streamribbon needs the columns of our vertices, and of the twist<\/span><\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\"><span style=\"color: #008013\">% angle to be provided as a cell array of matrices.<\/span><\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\">streamverts = mat2cell([ reshape(X,[],1) reshape(Y,[],1) reshape(Z,[],1)*height ],repelem(npts,nloops))';<\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\">twistangle = mat2cell(repmat([pi\/2;zeros(npts-1,1)],nloops,1), repelem(npts,nloops))';<\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\"><\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\"><span style=\"color: #008013\">% Display our fancy gift bow<\/span><\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\">clf<\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\">srf=streamribbon(streamverts,twistangle,ribbonwidth);<\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\">view([0 60]);<\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\">set(srf,<span style=\"color: #a709f5\">'FaceColor'<\/span>,color,<span style=\"color: #a709f5\">'EdgeColor'<\/span>,<span style=\"color: #a709f5\">'none<\/span>',<span style=\"color: #a709f5\">'FaceLighting'<\/span>,<span style=\"color: #a709f5\">'gouraud'<\/span>);<\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 0px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\">axis <span style=\"color: #a709f5\">off tight equal<\/span><\/div>\r\n<\/div>\r\n<div class=\"inlineWrapper outputs\">\r\n<div style=\"border-radius: 0px;padding: 0px 45px 4px 13px;line-height: 18.004px;min-height: 0px;font-family: Menlo, Monaco, Consolas, 'Courier New', monospace, Menlo, Monaco, Consolas, 'Courier New', monospace;font-size: 14px\">camlight<\/div>\r\n<\/div>\r\n<\/div>\r\n<img decoding=\"async\" loading=\"lazy\" width=\"840\" height=\"506\" class=\"size-full wp-image-3566 aligncenter\" src=\"http:\/\/blogs.mathworks.com\/graphics-and-apps\/files\/2025\/12\/livegiftbow2.mlx-12-10-25_1.png\" alt=\"\" \/>\r\n\r\n<\/div>\r\n<script type=\"text\/javascript\">\r\n{ let css = '.eoOutputWrapper { width: calc(90vw - 10px) !important; }';\r\nlet head = document.head || document.getElementsByTagName('head')[0];\r\nlet style = document.createElement('style');\r\nhead.appendChild(style);\r\nstyle.type = 'text\/css';\r\nif (style.styleSheet) {\r\n    style.styleSheet.cssText = css;\r\n} else {\r\n    style.appendChild(document.createTextNode(css));\r\n}\r\n\r\n\r\n}<\/script>","protected":false},"excerpt":{"rendered":"<div class=\"overview-image\"><img src=\"https:\/\/blogs.mathworks.com\/graphics-and-apps\/files\/2025\/12\/GiftBow_0.png\" class=\"img-responsive attachment-post-thumbnail size-post-thumbnail wp-post-image\" alt=\"\" decoding=\"async\" loading=\"lazy\" \/><\/div><p>&nbsp;\r\n\r\n\r\n\r\n\r\nGuest Writer: Eric Ludlam\r\nEric Ludlam is the development manager of MATLAB\u2019s Charting team. Eric has a whopping 27 years of experience working in MATLAB Graphics, starting in MATLAB... <a class=\"read-more\" href=\"https:\/\/blogs.mathworks.com\/graphics-and-apps\/2025\/12\/18\/gift-bow\/\">read more >><\/a><\/p>","protected":false},"author":198,"featured_media":3573,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[11,2],"tags":[],"_links":{"self":[{"href":"https:\/\/blogs.mathworks.com\/graphics-and-apps\/wp-json\/wp\/v2\/posts\/3568"}],"collection":[{"href":"https:\/\/blogs.mathworks.com\/graphics-and-apps\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.mathworks.com\/graphics-and-apps\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics-and-apps\/wp-json\/wp\/v2\/users\/198"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics-and-apps\/wp-json\/wp\/v2\/comments?post=3568"}],"version-history":[{"count":19,"href":"https:\/\/blogs.mathworks.com\/graphics-and-apps\/wp-json\/wp\/v2\/posts\/3568\/revisions"}],"predecessor-version":[{"id":3655,"href":"https:\/\/blogs.mathworks.com\/graphics-and-apps\/wp-json\/wp\/v2\/posts\/3568\/revisions\/3655"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics-and-apps\/wp-json\/wp\/v2\/media\/3573"}],"wp:attachment":[{"href":"https:\/\/blogs.mathworks.com\/graphics-and-apps\/wp-json\/wp\/v2\/media?parent=3568"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics-and-apps\/wp-json\/wp\/v2\/categories?post=3568"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.mathworks.com\/graphics-and-apps\/wp-json\/wp\/v2\/tags?post=3568"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}