{"id":720,"date":"2024-08-27T09:28:48","date_gmt":"2024-08-27T07:28:48","guid":{"rendered":"https:\/\/www.syntera.ch\/blog\/?p=720"},"modified":"2025-03-27T14:22:33","modified_gmt":"2025-03-27T13:22:33","slug":"building-gantt-charts-with-power-bi","status":"publish","type":"post","link":"https:\/\/www.syntera.ch\/blog\/2024\/08\/27\/building-gantt-charts-with-power-bi\/","title":{"rendered":"Building native Gantt Charts in Power BI"},"content":{"rendered":"\n<div class=\"wp-block-columns is-layout-flex wp-container-core-columns-is-layout-f56f613f wp-block-columns-is-layout-flex\">\n<div class=\"wp-block-column is-layout-flow wp-block-column-is-layout-flow\"><div class=\"wp-block-post-author has-medium-font-size\"><div class=\"wp-block-post-author__avatar\"><img alt='' src='https:\/\/secure.gravatar.com\/avatar\/9cbefca9184e6b8146d83f72900473b791b31bc6c2a10a8e57f77e9c41f11b45?s=48&#038;d=mm&#038;r=g' srcset='https:\/\/secure.gravatar.com\/avatar\/9cbefca9184e6b8146d83f72900473b791b31bc6c2a10a8e57f77e9c41f11b45?s=96&#038;d=mm&#038;r=g 2x' class='avatar avatar-48 photo' height='48' width='48' \/><\/div><div class=\"wp-block-post-author__content\"><p class=\"wp-block-post-author__byline\">LEAD BUSINESS INTELLIGENCE<\/p><p class=\"wp-block-post-author__name\">Dimitri B\u00fctikofer<\/p><\/div><\/div><\/div>\n\n\n\n<div class=\"wp-block-column is-vertically-aligned-top is-layout-flow wp-block-column-is-layout-flow\">\n<ul class=\"wp-block-outermost-social-sharing alignright has-small-icon-size has-icon-color is-style-logos-only is-content-justification-left is-layout-flex wp-container-outermost-social-sharing-is-layout-fa5e4718 wp-block-outermost-social-sharing-is-layout-flex\"><li style=\"color: #1a4548\" class=\"outermost-social-sharing-link outermost-social-sharing-link-linkedin has-primary-color wp-block-outermost-social-sharing-link\">\n\t<a href=\"https:\/\/www.linkedin.com\/shareArticle?mini=true&#038;url=https%3A%2F%2Fwww.syntera.ch%2Fblog%2F2024%2F08%2F27%2Fbuilding-gantt-charts-with-power-bi%2F&#038;title=Building%20native%20Gantt%20Charts%20in%20Power%20BI\" aria-label=\"Share on LinkedIn\" rel=\"noopener nofollow\" target=\"_blank\" class=\"wp-block-outermost-social-sharing-link-anchor\">\n\t\t<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" version=\"1.1\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M19.7,3H4.3C3.582,3,3,3.582,3,4.3v15.4C3,20.418,3.582,21,4.3,21h15.4c0.718,0,1.3-0.582,1.3-1.3V4.3 C21,3.582,20.418,3,19.7,3z M8.339,18.338H5.667v-8.59h2.672V18.338z M7.004,8.574c-0.857,0-1.549-0.694-1.549-1.548 c0-0.855,0.691-1.548,1.549-1.548c0.854,0,1.547,0.694,1.547,1.548C8.551,7.881,7.858,8.574,7.004,8.574z M18.339,18.338h-2.669 v-4.177c0-0.996-0.017-2.278-1.387-2.278c-1.389,0-1.601,1.086-1.601,2.206v4.249h-2.667v-8.59h2.559v1.174h0.037 c0.356-0.675,1.227-1.387,2.526-1.387c2.703,0,3.203,1.779,3.203,4.092V18.338z\"><\/path><\/svg>\t\t<span class=\"wp-block-outermost-social-sharing-link-label screen-reader-text\">\n\t\t\tShare on LinkedIn\t\t<\/span>\n\t<\/a>\n<\/li>\n\n\n<li style=\"color: #1a4548\" class=\"outermost-social-sharing-link outermost-social-sharing-link-mail has-primary-color wp-block-outermost-social-sharing-link\">\n\t<a href=\"mailto:?subject=Building%20native%20Gantt%20Charts%20in%20Power%20BI&#038;body=Building%20native%20Gantt%20Charts%20in%20Power%20BI%20&mdash;%20https%3A%2F%2Fwww.syntera.ch%2Fblog%2F2024%2F08%2F27%2Fbuilding-gantt-charts-with-power-bi%2F\" aria-label=\"Email this Page\"  class=\"wp-block-outermost-social-sharing-link-anchor\">\n\t\t<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" version=\"1.1\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M20,4H4C2.895,4,2,4.895,2,6v12c0,1.105,0.895,2,2,2h16c1.105,0,2-0.895,2-2V6C22,4.895,21.105,4,20,4z M20,8.236l-8,4.882 L4,8.236V6h16V8.236z\"><\/path><\/svg>\t\t<span class=\"wp-block-outermost-social-sharing-link-label screen-reader-text\">\n\t\t\tEmail this Page\t\t<\/span>\n\t<\/a>\n<\/li>\n\n\n<li style=\"color: #1a4548\" class=\"outermost-social-sharing-link outermost-social-sharing-link-whatsapp has-primary-color wp-block-outermost-social-sharing-link\">\n\t<a href=\"https:\/\/api.whatsapp.com\/send?text=Building%20native%20Gantt%20Charts%20in%20Power%20BI%20&mdash;%20https%3A%2F%2Fwww.syntera.ch%2Fblog%2F2024%2F08%2F27%2Fbuilding-gantt-charts-with-power-bi%2F\" aria-label=\"Share on WhatsApp\" rel=\"noopener nofollow\" target=\"_blank\" class=\"wp-block-outermost-social-sharing-link-anchor\">\n\t\t<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" version=\"1.1\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M 12.011719 2 C 6.5057187 2 2.0234844 6.478375 2.0214844 11.984375 C 2.0204844 13.744375 2.4814687 15.462563 3.3554688 16.976562 L 2 22 L 7.2324219 20.763672 C 8.6914219 21.559672 10.333859 21.977516 12.005859 21.978516 L 12.009766 21.978516 C 17.514766 21.978516 21.995047 17.499141 21.998047 11.994141 C 22.000047 9.3251406 20.962172 6.8157344 19.076172 4.9277344 C 17.190172 3.0407344 14.683719 2.001 12.011719 2 z M 12.009766 4 C 14.145766 4.001 16.153109 4.8337969 17.662109 6.3417969 C 19.171109 7.8517969 20.000047 9.8581875 19.998047 11.992188 C 19.996047 16.396187 16.413812 19.978516 12.007812 19.978516 C 10.674812 19.977516 9.3544062 19.642812 8.1914062 19.007812 L 7.5175781 18.640625 L 6.7734375 18.816406 L 4.8046875 19.28125 L 5.2851562 17.496094 L 5.5019531 16.695312 L 5.0878906 15.976562 C 4.3898906 14.768562 4.0204844 13.387375 4.0214844 11.984375 C 4.0234844 7.582375 7.6067656 4 12.009766 4 z M 8.4765625 7.375 C 8.3095625 7.375 8.0395469 7.4375 7.8105469 7.6875 C 7.5815469 7.9365 6.9355469 8.5395781 6.9355469 9.7675781 C 6.9355469 10.995578 7.8300781 12.182609 7.9550781 12.349609 C 8.0790781 12.515609 9.68175 15.115234 12.21875 16.115234 C 14.32675 16.946234 14.754891 16.782234 15.212891 16.740234 C 15.670891 16.699234 16.690438 16.137687 16.898438 15.554688 C 17.106437 14.971687 17.106922 14.470187 17.044922 14.367188 C 16.982922 14.263188 16.816406 14.201172 16.566406 14.076172 C 16.317406 13.951172 15.090328 13.348625 14.861328 13.265625 C 14.632328 13.182625 14.464828 13.140625 14.298828 13.390625 C 14.132828 13.640625 13.655766 14.201187 13.509766 14.367188 C 13.363766 14.534188 13.21875 14.556641 12.96875 14.431641 C 12.71875 14.305641 11.914938 14.041406 10.960938 13.191406 C 10.218937 12.530406 9.7182656 11.714844 9.5722656 11.464844 C 9.4272656 11.215844 9.5585938 11.079078 9.6835938 10.955078 C 9.7955938 10.843078 9.9316406 10.663578 10.056641 10.517578 C 10.180641 10.371578 10.223641 10.267562 10.306641 10.101562 C 10.389641 9.9355625 10.347156 9.7890625 10.285156 9.6640625 C 10.223156 9.5390625 9.737625 8.3065 9.515625 7.8125 C 9.328625 7.3975 9.131125 7.3878594 8.953125 7.3808594 C 8.808125 7.3748594 8.6425625 7.375 8.4765625 7.375 z\"><\/path><\/svg>\t\t<span class=\"wp-block-outermost-social-sharing-link-label screen-reader-text\">\n\t\t\tShare on WhatsApp\t\t<\/span>\n\t<\/a>\n<\/li>\n<\/ul>\n<\/div>\n<\/div>\n\n\n\n<p class=\"wp-block-paragraph\">In a recent project, a customer needed a report that provided an overview of the major projects within the company for the current and upcoming year. A Gantt chart is an ideal tool for displaying such data, offering both high-level and detailed views. Given that Power BI is widely regarded as one of the best, if not the best, reporting tools available, this should be a simple task, right? Unfortunately, Power BI does not have a native Gantt chart visual, and workarounds using other visuals often come with significant trade-offs, making them impractical.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">While several custom visuals are available for creating Gantt charts in the Power BI marketplace, most come with aggressive pricing (monthly per-user fees), which is too costly for a larger company just beginning to transition reports to Power BI. The free alternatives are often limited, buggy, and lack full integration with Power BI&#8217;s interface and features. Furthermore, the free and paid options alike restrict the amount of additional data that can be added into the visual, which reduces their overall utility.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In summary, we couldn&#8217;t find a satisfactory, long-term solution. So, we decided to develop a custom approach. Although it requires a bit of effort to set up, you can create a fully customizable Gantt chart using a measure that ouputs the desired SVG, which Power BI can render. This method is robust, integrates seamlessly with existing Power BI visuals like matrices (retaining all Power BI functionalities), and allows you to customize the layout to your needs.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In this blog, we&#8217;ll provide you with a step-by-step guide to setting up this custom Gantt chart in your Power BI project.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">Implementation<\/h4>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"2095\" height=\"1156\" src=\"https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/01_Overview.png\" alt=\"\" class=\"wp-image-721\" srcset=\"https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/01_Overview.png 2095w, https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/01_Overview-300x166.png 300w, https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/01_Overview-1024x565.png 1024w, https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/01_Overview-768x424.png 768w, https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/01_Overview-1536x848.png 1536w, https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/01_Overview-2048x1130.png 2048w\" sizes=\"auto, (max-width: 2095px) 100vw, 2095px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The solution consists of two parts:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Setting up a timeline on the Gantt chart to enable the user to reference the Gantt bars to the respective month and year.<\/li>\n\n\n\n<li>Generating the Gantt bars and positioning them according to the timeline.<\/li>\n<\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s start by creating the Measure to generate the Gantt bars. Simply copy the code below and update the column names to align with your data model (Tip: You can quickly modify all occurances of a selected term by pressing Ctrl + Shift + L):<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Gantt Bars = \n-- Define dimensions\nVAR _ColumnWidth = 450\nVAR _RowHeight = 16\n\n-- Calculate Minimum Date\nVAR _MinDateGlobal = FIRSTDATE('Date'&#91;Date])\nVAR _MinDateConditional = \n    IF(\n        CALCULATE(MIN(Projects&#91;StartDate]), ALLSELECTED(Projects)) &gt; _MinDateGlobal,\n        CALCULATE(MIN(Projects&#91;StartDate]), ALLSELECTED(Projects)),\n        _MinDateGlobal\n    )\n\n-- Calculate Project Durations and Scaling\nVAR _MaxDuration = \n    DATEDIFF(\n        _MinDateConditional,\n        CALCULATE(MAX(Projects&#91;EndDate]), ALLSELECTED(Projects)),\n        DAY\n    )\nVAR _ProjectDuration = \n    DATEDIFF(\n        MIN(Projects&#91;StartDate]),\n        MAX(Projects&#91;EndDate]),\n        DAY\n    )\n\n-- Calculate Bar Start Position\nVAR _BarStart = \n    DATEDIFF(_MinDateConditional, MIN(Projects&#91;StartDate]), DAY) \n    * DIVIDE(_ColumnWidth, _MaxDuration)\nVAR _BarStartAdjusted = \n    SWITCH(\n        TRUE(),\n        _BarStart &lt; 4, 4,\n        _BarStart &gt; (_ColumnWidth - 6), (_ColumnWidth - 6),\n        _BarStart\n    )\nVAR _TextStartAdjusted = \n    IF(\n        _BarStartAdjusted &lt; (_ColumnWidth * 0.88), \n        _BarStartAdjusted + 8, \n        _BarStartAdjusted - 38\n    )\n\n-- Calculate Bar Width\nVAR _BarWidth = \n    _ProjectDuration * DIVIDE(_ColumnWidth, _MaxDuration)\n\n-- Get Start Date\nVAR _StartDate = FORMAT(MIN(Projects&#91;StartDate]), \"DD.MM.YY\")\n\n-- Calculate Today's Marker Position\nVAR _TodayMarker = \n    DATEDIFF(_MinDateConditional, TODAY(), DAY) \n    * DIVIDE(_ColumnWidth, _MaxDuration)\n\n-- Define Colors\nVAR _ColourBarFill = \"rgb(115,181,192)\"\nVAR _ColourBarStart = \"rgb(22,131,150)\"\nVAR _ColourBarEnd = \"rgb(22,131,150)\"\nVAR _ColourTodayMarker = \"rgb(255,0,0)\"\nVAR _WidthTodayMarker = \"1\"\n\n-- Generate SVG\nVAR _SVG = \n    \"data:image\/svg+xml;utf8,&lt;svg width='\" &amp; _ColumnWidth &amp; \"' height='\" &amp; _RowHeight &amp; \"' xmlns='http:\/\/www.w3.org\/2000\/svg' xmlns:xlink='http:\/\/www.w3.org\/1999\/xlink'&gt;\" &amp;\n        \"&lt;rect x='\" &amp; _BarStart &amp; \"' y='4' width='\" &amp; _BarWidth &amp; \"' height='\" &amp; _RowHeight &amp; \"' fill='\" &amp; _ColourBarFill &amp; \"' stroke='rgb(255, 100, 30)' stroke-width='0.1' \/&gt;\" &amp;\n        \"&lt;polygon points='\" &amp; _BarStart &amp; \",4 \" &amp; _BarStart + 4 &amp; \",4 \" &amp; _BarStart + 4 &amp; \",12 \" &amp; _BarStart &amp; \",16 ' fill='\" &amp; _ColourBarStart &amp; \"' \/&gt;\" &amp;\n        \"&lt;polygon points='\" &amp; _BarStart + _BarWidth &amp; \",4 \" &amp; _BarStart - 4 + _BarWidth &amp; \",4 \" &amp; _BarStart - 4 + _BarWidth &amp; \",12 \" &amp; _BarStart + _BarWidth &amp; \",16 ' fill='\" &amp; _ColourBarEnd &amp; \"' \/&gt;\" &amp;\n        \"&lt;line x1='\" &amp; _TodayMarker &amp; \"' y1='0' x2='\" &amp; _TodayMarker &amp; \"' y2='16' style='stroke:\" &amp; _ColourTodayMarker &amp; \";stroke-width:\" &amp; _WidthTodayMarker &amp; \"' \/&gt;\" &amp;\n    \"&lt;\/svg&gt;\"\n\n-- Return SVG if Description is not blank\nRETURN\nIF(\n    SELECTEDVALUE(Projects&#91;Description]) = BLANK(), \n    BLANK(), \n    _SVG\n)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Insert the measure into your matrix, and you\u2019ll notice the unformatted SVG code appearing as a result:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1684\" height=\"940\" src=\"https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/02_SVG_raw.png\" alt=\"\" class=\"wp-image-723\" srcset=\"https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/02_SVG_raw.png 1684w, https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/02_SVG_raw-300x167.png 300w, https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/02_SVG_raw-1024x572.png 1024w, https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/02_SVG_raw-768x429.png 768w, https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/02_SVG_raw-1536x857.png 1536w\" sizes=\"auto, (max-width: 1684px) 100vw, 1684px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">To ensure Power BI renders the SVG correctly, select your measure and set the <strong>Data category<\/strong> under <strong>Measure tools<\/strong> to <strong>Image URL<\/strong>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Depending on the available space in your matrix and the height of your rows, you may need to adjust the <strong>_ColumnWidth <\/strong>and <strong>_RowHeight <\/strong>variables. If the formatting looks off after these changes, it\u2019s because the matrix is using an image size that doesn\u2019t align with your intended dimensions. To correct this, select your visual, go to the <strong>Format <\/strong>tab, and scroll down to the <strong>Image size<\/strong> setting. Adjust the height and width to reflect the values you set in the Measure.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The outcome should look roughly like this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"1935\" height=\"1078\" src=\"https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/03_Bars.png\" alt=\"\" class=\"wp-image-724\" srcset=\"https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/03_Bars.png 1935w, https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/03_Bars-300x167.png 300w, https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/03_Bars-1024x570.png 1024w, https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/03_Bars-768x428.png 768w, https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/03_Bars-1536x856.png 1536w\" sizes=\"auto, (max-width: 1935px) 100vw, 1935px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">You can change the look of the Gantt bars by changing the variables defined under <strong>&#8212; Define Colors<\/strong> in the measure. Once you are happy we can move forward with creating the measure to generate the SVG code for the timeline:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Gantt TimeLine = \n-- Define dimensions\nVAR _ColumnWidth = 450\nVAR _RowHeight = 40\n\n-- Calculate Minimum Date\nVAR _MinDateGlobal = FIRSTDATE('Date'&#91;Date])\nVAR _MinDateConditional = \n    CALCULATE(MIN(Projects&#91;StartDate]), ALLSELECTED(Projects))\nVAR _MinDate = \n    IF(\n        ISBLANK(_MinDateConditional) || _MinDateConditional &lt;= _MinDateGlobal, \n        _MinDateGlobal, \n        _MinDateConditional\n    )\n\n-- Calculate Maximum Date\nVAR _MaxDateFromData = \n    CALCULATE(MAX(Projects&#91;EndDate]), ALLSELECTED(Projects))\nVAR _MaxDate = \n    IF(\n        ISBLANK(_MaxDateFromData), \n        TODAY(), \n        _MaxDateFromData\n    )\n\n-- Scaling and Markers\nVAR _MaxDuration = DATEDIFF(_MinDate, _MaxDate, DAY)\nVAR _Scaling = DIVIDE(_ColumnWidth, _MaxDuration)\nVAR _TodayMarker = DATEDIFF(_MinDate, TODAY(), DAY) * _Scaling\n\n-- Styling\nVAR _FontSizeSmall = \"8\"\nVAR _ColorTimeLine = \"rgb(65, 58, 57)\"\nVAR _ColorTodayMarker = \"rgb(255,0,0)\"\nVAR _WidthTodayMarker = \"1\"\n\n-- Year Lines and Text\nVAR _YearLines =\n    CONCATENATEX(\n        FILTER(\n            ADDCOLUMNS(\n                GENERATESERIES(_MinDate, _MaxDate, 1),\n                \"EndOfYear\", IF(&#91;Value] = DATE(YEAR(&#91;Value]), 12, 31), &#91;Value]),\n                \"PosYearLine\", DATEDIFF(_MinDate, &#91;Value], DAY) * _Scaling\n            ),\n            NOT(ISBLANK(&#91;EndOfYear]))\n        ),\n        \"&lt;line x1='\" &amp; &#91;PosYearLine] &amp; \"' y1='0' x2='\" &amp; &#91;PosYearLine] &amp; \"' y2='33' style='stroke:\" &amp; _ColorTimeLine &amp; \"; stroke-width:\" &amp; _WidthTodayMarker &amp; \"' \/&gt;\"\n    )\n\nVAR _YearText =\n    CONCATENATEX(\n        FILTER(\n            ADDCOLUMNS(\n                GENERATESERIES(_MinDate, _MaxDate, 1),\n                \"EndOfYear\", IF(&#91;Value] = DATE(YEAR(&#91;Value]), 12, 31), &#91;Value]),\n                \"PosYearLine\", DATEDIFF(_MinDate, &#91;Value], DAY) * _Scaling,\n                \"YearText\", YEAR(&#91;Value]) + 1\n            ),\n            NOT(ISBLANK(&#91;EndOfYear]))\n        ),\n        \"&lt;text x='\" &amp; &#91;PosYearLine] + 5 &amp; \"' y='13' font-family='Arial' font-size='10' fill='\" &amp; _ColorTimeLine &amp; \"'&gt;\" &amp; &#91;YearText] &amp; \"&lt;\/text&gt;\"\n    )\nVAR _YearTextFinal = \n    IF(\n        NOT ISBLANK(_YearText), \n        _YearText, \n        \"&lt;text x='5' y='13' font-family='Arial' font-size='10' fill='\" &amp; _ColorTimeLine &amp; \"'&gt;\" &amp; YEAR(_MinDate) &amp; \"&lt;\/text&gt;\"\n    )\n\n-- Month Lines and Text\nVAR _MonthLines =\n    CONCATENATEX(\n        FILTER(\n            ADDCOLUMNS(\n                GENERATESERIES(_MinDate, _MaxDate, 1),\n                \"EndOfMonth\", IF(&#91;Value] = EOMONTH(&#91;Value], 0), &#91;Value]),\n                \"PosMonthLine\", DATEDIFF(_MinDate, &#91;Value], DAY) * _Scaling\n            ),\n            NOT(ISBLANK(&#91;EndOfMonth]))\n        ),\n        \"&lt;line x1='\" &amp; &#91;PosMonthLine] &amp; \"' y1='18' x2='\" &amp; &#91;PosMonthLine] &amp; \"' y2='28' style='stroke:\" &amp; _ColorTimeLine &amp; \"; stroke-width:\" &amp; _WidthTodayMarker &amp; \"' \/&gt;\"\n    )\n\nVAR _MonthText =\n    CONCATENATEX(\n        ADDCOLUMNS(\n            FILTER(\n                ADDCOLUMNS(\n                    GENERATESERIES(_MinDate, _MaxDate, 1),\n                    \"EndOfMonth\", IF(&#91;Value] = EOMONTH(&#91;Value], 0), &#91;Value]),\n                    \"PosMonthLine\", DATEDIFF(_MinDate, &#91;Value], DAY) * _Scaling,\n                    \"PosNextMonthLine\", DATEDIFF(_MinDate, EOMONTH(&#91;Value], 1), DAY) * _Scaling,\n                    \"MonthText\", LEFT(FORMAT(EOMONTH(&#91;Value], 1), \"mmm\"), 1)\n                ),\n                NOT(ISBLANK(&#91;EndOfMonth]))\n            ),\n            \"Gap\", &#91;PosNextMonthLine] - &#91;PosMonthLine]\n        ),\n        \"&lt;text x='\" &amp; (&#91;PosMonthLine] + DIVIDE(&#91;Gap], 2)) &amp; \"' y='26' text-anchor='middle' font-family='Arial' font-size='\" &amp; _FontSizeSmall &amp; \"' fill='\" &amp; _ColorTimeLine &amp; \"'&gt;\" &amp; &#91;MonthText] &amp; \"&lt;\/text&gt;\"\n    )\n\n-- Final SVG Construction\nVAR _SVG = \n    \"data:image\/svg+xml;utf8,&lt;svg width='\" &amp; _ColumnWidth &amp; \"' height='\" &amp; _RowHeight &amp; \"' xmlns='http:\/\/www.w3.org\/2000\/svg' xmlns:xlink='http:\/\/www.w3.org\/1999\/xlink'&gt;\" &amp;\n        _YearLines &amp; _YearTextFinal &amp; _MonthLines &amp; _MonthText &amp;\n        \"&lt;line x1='0' y1='18' x2='512' y2='18' style='stroke:\" &amp; _ColorTimeLine &amp; \";stroke-width:\" &amp; _WidthTodayMarker &amp; \"' \/&gt;\" &amp;\n        \"&lt;line x1='\" &amp; _TodayMarker &amp; \"' y1='0' x2='\" &amp; _TodayMarker &amp; \"' y2='39' style='stroke:\" &amp; _ColorTodayMarker &amp; \";stroke-width:\" &amp; _WidthTodayMarker &amp; \"' \/&gt;\" &amp;\n        \"&lt;rect x='0' y='16' width='2' height='5' fill='rgb(144,142,142)' \/&gt;\" &amp;\n    \"&lt;\/svg&gt;\"\n\nRETURN _SVG<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Set the <strong>Data category<\/strong> to <strong>Image URL<\/strong> as we did with the Gantt bars measure. Add a matrix visual to your report and add the measure to the <strong>Values <\/strong>field. Remember to adjust the image&#8217;s height and width under the <strong>Image size<\/strong> setting in the <strong>Format<\/strong> tab. Next, carefully resize the matrix and position it over your Gantt bars matrix. Use the red line marking today&#8217;s date to align the timeline. The resulting Gantt chart should look roughly like this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"2095\" height=\"1156\" src=\"https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/00_Tumbonailu.png\" alt=\"\" class=\"wp-image-726\" srcset=\"https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/00_Tumbonailu.png 2095w, https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/00_Tumbonailu-300x166.png 300w, https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/00_Tumbonailu-1024x565.png 1024w, https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/00_Tumbonailu-768x424.png 768w, https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/00_Tumbonailu-1536x848.png 1536w, https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/00_Tumbonailu-2048x1130.png 2048w\" sizes=\"auto, (max-width: 2095px) 100vw, 2095px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">More about Power BI:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/www.syntera.ch\/blog\/2023\/03\/21\/static-and-dynamic-row-level-security-in-power-bi\/\">Static and dynamic Row-level-Security in Power BI<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.syntera.ch\/blog\/2024\/03\/19\/automated-power-bi-testing-with-selenium\/\">Automated Power BI Testing with Selenium<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.syntera.ch\/blog\/2024\/04\/03\/single-date-picker-in-power-bi\/\">Single Date Picker in Power BI<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/www.syntera.ch\/blog\/2024\/01\/16\/analyse-bexio-data-with-power-bi\/\">Analyse bexio Data with Power BI<\/a><\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>In a recent project, a customer needed a report that provided an overview of the major projects within the company for the current and upcoming year. A Gantt chart is an ideal tool for displaying such data, offering both high-level and detailed views. Given that Power BI is widely regarded as one of the best, [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":726,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[6,31],"class_list":["post-720","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-business-intelligence","tag-power-bi","tag-visualization"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v21.8 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Building native Gantt Charts in Power BI - Syntera<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.syntera.ch\/blog\/2024\/08\/27\/building-gantt-charts-with-power-bi\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Building native Gantt Charts in Power BI - Syntera\" \/>\n<meta property=\"og:description\" content=\"In a recent project, a customer needed a report that provided an overview of the major projects within the company for the current and upcoming year. A Gantt chart is an ideal tool for displaying such data, offering both high-level and detailed views. Given that Power BI is widely regarded as one of the best, [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.syntera.ch\/blog\/2024\/08\/27\/building-gantt-charts-with-power-bi\/\" \/>\n<meta property=\"og:site_name\" content=\"Syntera\" \/>\n<meta property=\"article:published_time\" content=\"2024-08-27T07:28:48+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-03-27T13:22:33+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/00_Tumbonailu.png\" \/>\n\t<meta property=\"og:image:width\" content=\"2095\" \/>\n\t<meta property=\"og:image:height\" content=\"1156\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Dimitri B\u00fctikofer\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Dimitri B\u00fctikofer\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"4 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.syntera.ch\/blog\/2024\/08\/27\/building-gantt-charts-with-power-bi\/\",\"url\":\"https:\/\/www.syntera.ch\/blog\/2024\/08\/27\/building-gantt-charts-with-power-bi\/\",\"name\":\"Building native Gantt Charts in Power BI - Syntera\",\"isPartOf\":{\"@id\":\"https:\/\/www.syntera.ch\/blog\/#website\"},\"datePublished\":\"2024-08-27T07:28:48+00:00\",\"dateModified\":\"2025-03-27T13:22:33+00:00\",\"author\":{\"@id\":\"https:\/\/www.syntera.ch\/blog\/#\/schema\/person\/843f812ce16de687e4d4527aee313034\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.syntera.ch\/blog\/2024\/08\/27\/building-gantt-charts-with-power-bi\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.syntera.ch\/blog\/2024\/08\/27\/building-gantt-charts-with-power-bi\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.syntera.ch\/blog\/2024\/08\/27\/building-gantt-charts-with-power-bi\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.syntera.ch\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Building native Gantt Charts in Power BI\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.syntera.ch\/blog\/#website\",\"url\":\"https:\/\/www.syntera.ch\/blog\/\",\"name\":\"Syntera\",\"description\":\"translating data into business value.\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.syntera.ch\/blog\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.syntera.ch\/blog\/#\/schema\/person\/843f812ce16de687e4d4527aee313034\",\"name\":\"Dimitri B\u00fctikofer\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.syntera.ch\/blog\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/9cbefca9184e6b8146d83f72900473b791b31bc6c2a10a8e57f77e9c41f11b45?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/9cbefca9184e6b8146d83f72900473b791b31bc6c2a10a8e57f77e9c41f11b45?s=96&d=mm&r=g\",\"caption\":\"Dimitri B\u00fctikofer\"},\"sameAs\":[\"http:\/\/www.syntera.ch\"],\"url\":\"https:\/\/www.syntera.ch\/blog\/author\/dimitri\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Building native Gantt Charts in Power BI - Syntera","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.syntera.ch\/blog\/2024\/08\/27\/building-gantt-charts-with-power-bi\/","og_locale":"en_US","og_type":"article","og_title":"Building native Gantt Charts in Power BI - Syntera","og_description":"In a recent project, a customer needed a report that provided an overview of the major projects within the company for the current and upcoming year. A Gantt chart is an ideal tool for displaying such data, offering both high-level and detailed views. Given that Power BI is widely regarded as one of the best, [&hellip;]","og_url":"https:\/\/www.syntera.ch\/blog\/2024\/08\/27\/building-gantt-charts-with-power-bi\/","og_site_name":"Syntera","article_published_time":"2024-08-27T07:28:48+00:00","article_modified_time":"2025-03-27T13:22:33+00:00","og_image":[{"width":2095,"height":1156,"url":"https:\/\/www.syntera.ch\/blog\/wp-content\/uploads\/2024\/08\/00_Tumbonailu.png","type":"image\/png"}],"author":"Dimitri B\u00fctikofer","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Dimitri B\u00fctikofer","Est. reading time":"4 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.syntera.ch\/blog\/2024\/08\/27\/building-gantt-charts-with-power-bi\/","url":"https:\/\/www.syntera.ch\/blog\/2024\/08\/27\/building-gantt-charts-with-power-bi\/","name":"Building native Gantt Charts in Power BI - Syntera","isPartOf":{"@id":"https:\/\/www.syntera.ch\/blog\/#website"},"datePublished":"2024-08-27T07:28:48+00:00","dateModified":"2025-03-27T13:22:33+00:00","author":{"@id":"https:\/\/www.syntera.ch\/blog\/#\/schema\/person\/843f812ce16de687e4d4527aee313034"},"breadcrumb":{"@id":"https:\/\/www.syntera.ch\/blog\/2024\/08\/27\/building-gantt-charts-with-power-bi\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.syntera.ch\/blog\/2024\/08\/27\/building-gantt-charts-with-power-bi\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.syntera.ch\/blog\/2024\/08\/27\/building-gantt-charts-with-power-bi\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.syntera.ch\/blog\/"},{"@type":"ListItem","position":2,"name":"Building native Gantt Charts in Power BI"}]},{"@type":"WebSite","@id":"https:\/\/www.syntera.ch\/blog\/#website","url":"https:\/\/www.syntera.ch\/blog\/","name":"Syntera","description":"translating data into business value.","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.syntera.ch\/blog\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.syntera.ch\/blog\/#\/schema\/person\/843f812ce16de687e4d4527aee313034","name":"Dimitri B\u00fctikofer","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.syntera.ch\/blog\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/9cbefca9184e6b8146d83f72900473b791b31bc6c2a10a8e57f77e9c41f11b45?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/9cbefca9184e6b8146d83f72900473b791b31bc6c2a10a8e57f77e9c41f11b45?s=96&d=mm&r=g","caption":"Dimitri B\u00fctikofer"},"sameAs":["http:\/\/www.syntera.ch"],"url":"https:\/\/www.syntera.ch\/blog\/author\/dimitri\/"}]}},"_links":{"self":[{"href":"https:\/\/www.syntera.ch\/blog\/wp-json\/wp\/v2\/posts\/720","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.syntera.ch\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.syntera.ch\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.syntera.ch\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.syntera.ch\/blog\/wp-json\/wp\/v2\/comments?post=720"}],"version-history":[{"count":7,"href":"https:\/\/www.syntera.ch\/blog\/wp-json\/wp\/v2\/posts\/720\/revisions"}],"predecessor-version":[{"id":898,"href":"https:\/\/www.syntera.ch\/blog\/wp-json\/wp\/v2\/posts\/720\/revisions\/898"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.syntera.ch\/blog\/wp-json\/wp\/v2\/media\/726"}],"wp:attachment":[{"href":"https:\/\/www.syntera.ch\/blog\/wp-json\/wp\/v2\/media?parent=720"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.syntera.ch\/blog\/wp-json\/wp\/v2\/categories?post=720"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.syntera.ch\/blog\/wp-json\/wp\/v2\/tags?post=720"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}