<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged charts</title>
<link>https://coderlegion.com/tag/charts</link>
<description>Powered by Question2Answer</description>
<item>
<title>Fastchart 1.X, why I rewrote it after 0.2 release</title>
<link>https://coderlegion.com/18682/fastchart-1-x-why-i-rewrote-it-after-0-2-release</link>
<description>&lt;p&gt;Couple of weeks ago I shipped fastchart 0.2.0 and &lt;a rel=&quot;nofollow&quot; href=&quot;https://ilia.ws/blog/fastchart-0-2-0-native-php-charts-barcodes-and-qr-codes-in-one-extension&quot;&gt;wrote it up here&lt;/a&gt;. One extension, 19 chart types, server-side rendering through &lt;code&gt;ext/gd&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The idea was right, but execution not quite there.&lt;/p&gt;
&lt;p&gt;After the launch I spent a few days actually looking at the output side by side with what plutovg can do on the same primitives. The libgd-rendered charts were fine for what libgd is, which is a 1990s 2D rasterizer with no subpixel-precise anti-aliasing. Diagonal lines were jaggy. Glyph edges grainy at small sizes. The output read as &quot;a chart drawn by ext/gd in 2026&quot; instead of &quot;a chart.&quot; A couple of Reddit threads (r/PHP and r/laravel) pointed at the same thing without me having to ask.&lt;/p&gt;
&lt;p&gt;So I rewrote it. fastchart 1.1.1 is the current stable of that rewrite, following a number of stabilization tweaks and refinements, the end result being SVG promoted to the canonical render format, and the chart-family count up from 19 to 26.&lt;/p&gt;
&lt;h3 id=&quot;what-was-wrong-with-the-libgd-output&quot;&gt;What was wrong with the libgd output&lt;/h3&gt;
&lt;p&gt;libgd's anti-aliasing is &lt;code&gt;gdAntiAliased&lt;/code&gt; plus the alpha channel. It works for solid-fill regions. It falls apart on the boundary between two filled regions of different colors, on glyph rendering at body-text sizes, and on rotated text where the rotation axis isn't a 45° multiple.&lt;/p&gt;
&lt;p&gt;Specific cases I kept hitting:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Diagonal series lines in a &lt;code&gt;LineChart&lt;/code&gt; showed visible stair-stepping at 1px stroke width. libgd's &lt;code&gt;gdImageLine&lt;/code&gt; with &lt;code&gt;gdAntiAliased&lt;/code&gt; blends against the canvas background, not the local color, so a red line crossing a blue series region looked correct on the white margin and wrong inside the plot area.&lt;/li&gt;
&lt;li&gt;45° rotated X-axis labels (the default when categorical labels are long) had a noticeable diagonal moiré along the baseline. Different from the line issue: this came from libgd's FreeType bridge, which renders each glyph straight then resamples the resulting bitmap. The double rasterization loses sharpness.&lt;/li&gt;
&lt;li&gt;StockChart hollow candles drew the body outline with the same primitive as the wick, so the body edges and the wick had the same line weight even when they shouldn't. The fix would have been a separate primitive; libgd has no concept of stroke vs fill weight at the polyline level.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;None of these are libgd bugs. They are libgd doing exactly what libgd has always done. They are also not things I can fix in a wrapper.&lt;/p&gt;
&lt;h3 id=&quot;why-svg-won&quot;&gt;Why SVG won&lt;/h3&gt;
&lt;p&gt;The shortest path from &quot;I want sharper output&quot; to &quot;the output is sharper&quot; is to stop rasterizing in the render path at all. SVG is text. The render path appends strings into a &lt;code&gt;smart_str&lt;/code&gt;. The reader (a browser, an inkscape, a plutovg) does the rasterization at the resolution and pixel density it wants.&lt;/p&gt;
&lt;p&gt;That solves the visual-quality complaint by default. It also gives back DPI-independent output: a chart embedded in a PDF or rendered at retina density on a Mac no longer needs &lt;code&gt;setDpi(192)&lt;/code&gt; to look right.&lt;/p&gt;
&lt;p&gt;Not everyone wants or needs SVG, so the architecture needs a path for traditional image formats too (PNG / JPG):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Every chart family builds an SVG document.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;renderSvg()&lt;/code&gt; returns the document bytes.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;renderPng()&lt;/code&gt; / &lt;code&gt;renderJpeg()&lt;/code&gt; / &lt;code&gt;renderWebp()&lt;/code&gt; flatten the SVG's &lt;code&gt;&amp;lt;text&amp;gt;&lt;/code&gt; elements to glyph outline paths via FreeType, run the result through plutovg + plutosvg (vendored, both MIT-licensed), and encode the rasterized RGBA buffer with libpng / libjpeg-turbo / libwebp.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Same chart object, four render methods, four outputs. No second code path for rasters; the raster encoders sit downstream of the same vector builder.&lt;/p&gt;
&lt;p&gt;The cost is that fastchart now links against four codec libs instead of one. The benefit is libgd is gone, both as a build dependency (no &lt;code&gt;libgd-dev&lt;/code&gt; apt package required) and as a runtime requirement (the chart classes no longer touch &lt;code&gt;GdImage&lt;/code&gt; at all).&lt;/p&gt;
&lt;h3 id=&quot;the-1-x-arc&quot;&gt;The 1.x arc&lt;/h3&gt;
&lt;h4 id=&quot;1-0-0-the-rewrite&quot;&gt;1.0.0: the rewrite&lt;/h4&gt;
&lt;p&gt;The architectural pivot. SVG canonical, libgd dropped, plutovg + plutosvg vendored. Seven new chart families lifted the family count from 19 to 26: &lt;code&gt;BulletChart&lt;/code&gt;, &lt;code&gt;ParetoChart&lt;/code&gt;, &lt;code&gt;CalendarHeatmap&lt;/code&gt;, &lt;code&gt;SunburstChart&lt;/code&gt;, &lt;code&gt;SankeyChart&lt;/code&gt;, &lt;code&gt;MarimekkoChart&lt;/code&gt;, &lt;code&gt;VectorChart&lt;/code&gt;. All seven were sitting in the same private-extensions queue as the 0.2.0 set; pulling them into the public repo was easier once the architecture was settled.&lt;/p&gt;
&lt;p&gt;Breaking changes from 0.2.0: no more GIF support, and no more GdImage canvas input/output.&lt;/p&gt;
&lt;h4 id=&quot;1-0-1-2-build-portability&quot;&gt;1.0.(1-2): build portability&lt;/h4&gt;
&lt;p&gt;1.0.1 added prebuilt binaries via PIE for Windows (PHP 8.3 / 8.4 / 8.5, NTS + TS, x64 + x86) and Linux x86_64 / arm64 + macOS arm64 (PHP 8.4 / 8.5 NTS). 1.0.2 fixed a libjpeg soname mismatch that broke the Linux prebuilts on Debian-based PHP, including every official &lt;code&gt;php:X.Y-cli&lt;/code&gt; Docker image. The fix statically links libjpeg-turbo from a configure-time source build, with &lt;code&gt;-Wl,--exclude-libs=ALL&lt;/code&gt; so the static symbols stay local to &lt;code&gt;fastchart.so&lt;/code&gt; and don't collide with the system &lt;code&gt;ext/gd&lt;/code&gt; in the same process.&lt;/p&gt;
&lt;h4 id=&quot;1-1-0-features-on-the-new-pipeline&quot;&gt;1.1.0: features on the new pipeline&lt;/h4&gt;
&lt;p&gt;&lt;code&gt;AreaChart::setBandMode(bool)&lt;/code&gt; for confidence-interval and min-max envelope fills. &lt;code&gt;PolarChart::setInterpolation(INTERP_SMOOTH)&lt;/code&gt; for Catmull-Rom-subdivided polar curves. &lt;code&gt;PolarChart::addVectors()&lt;/code&gt; to overlay arrow vectors in &lt;code&gt;(angle, radius)&lt;/code&gt; data space. &lt;code&gt;Funnel::setStyle(STYLE_CONE)&lt;/code&gt; for a pyramid with front-facing ellipse-arc edges. &lt;code&gt;BubbleChart::setYAxisScale(SCALE_LOG)&lt;/code&gt;. And &lt;code&gt;Chart::setImageMap()&lt;/code&gt; + &lt;code&gt;getImageMap()&lt;/code&gt; for HTML image-map hot-spots on BarChart, PieChart, and ScatterChart, with allowlisted URL schemes (http / https / mailto / &lt;code&gt;/&lt;/code&gt; / &lt;code&gt;#&lt;/code&gt;) and HTML-escaped tooltip text.&lt;/p&gt;
&lt;h4 id=&quot;1-1-1-hardening&quot;&gt;1.1.1: hardening&lt;/h4&gt;
&lt;p&gt;Shipped today. No new APIs, no breaking changes. Fourteen fixes to improve code quality. A non-exhaustive sample:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;PolarChart::addVectors()&lt;/code&gt; rejects NaN / Inf at the boundary now, matching every other polar setter. The float-to-int cast it was feeding is UB per C11 §6.3.1.4p1.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MarimekkoChart::setColumns()&lt;/code&gt; running-sum overflow. Each individual segment value was &lt;code&gt;isfinite&lt;/code&gt;-guarded, but the per-column sum and cross-column total could overflow to &lt;code&gt;+Inf&lt;/code&gt; from two segments at &lt;code&gt;1e308&lt;/code&gt; each. Columns whose running sum is non-finite are now silently dropped.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;StockChart&lt;/code&gt; &lt;code&gt;STYLE_VECTOR&lt;/code&gt; climax-deque ring-buffer overflow. After 11 strictly-decreasing pushes the deque tail wrapped to the head and every subsequent bar got misclassified as a climax. The stale-front drop now runs before the push.&lt;/li&gt;
&lt;li&gt;JPEG encoder local pointers carry &lt;code&gt;volatile&lt;/code&gt; across &lt;code&gt;setjmp()&lt;/code&gt;. Per C99 §7.13.2.1 a register-spilled local that libjpeg's &lt;code&gt;longjmp&lt;/code&gt; clobbers is UB; the cleanup branch could leak or double-free.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fc_ft_measure()&lt;/code&gt; was a 1 / 2 / 3-byte UTF-8 decoder. Non-BMP codepoints (emoji, CJK extensions, mathematical alphanumeric symbols) contributed 0 to the measured width, so chart layout reservations came up systematically narrow on labels containing emoji. 4-byte branch added.&lt;/li&gt;
&lt;li&gt;Time-axis arithmetic on &lt;code&gt;setOhlcv&lt;/code&gt; timestamps near &lt;code&gt;LLONG_MIN..LLONG_MAX&lt;/code&gt; overflowed signed &lt;code&gt;zend_long&lt;/code&gt; in four call sites. Promoted to double arithmetic; out-of-range double-to-&lt;code&gt;zend_long&lt;/code&gt; casts clamped.&lt;/li&gt;
&lt;li&gt;Vendor refresh: plutosvg 0.0.7 to 0.0.8, plutovg 1.3.2 to 1.3.3. Most of fastchart's local patches (UTF-8 BOM handling, FT include, &lt;code&gt;sprintf&lt;/code&gt; to &lt;code&gt;snprintf&lt;/code&gt;, bilinear tile sampling) are now upstream. Preserved fastchart-only: the stb_image PNG palette zero-init and the &lt;code&gt;STBI_ONLY_PNG / STBI_ONLY_JPEG&lt;/code&gt; cut that drops ~70% of the stb image-loader binary.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Full list in &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/iliaal/fastchart/blob/main/CHANGELOG.md&quot;&gt;CHANGELOG.md&lt;/a&gt;.&lt;/p&gt;
&lt;h4 id=&quot;outside-contributions&quot;&gt;Outside contributions&lt;/h4&gt;
&lt;p&gt;Along the way the 1.x cycle caught the attention of &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/remicollet&quot;&gt;Remi Collet&lt;/a&gt;, who runs the &lt;a rel=&quot;nofollow&quot; href=&quot;https://rpms.remirepo.net/&quot;&gt;rpms.remirepo.net&lt;/a&gt; PHP RPM repository (the standard PHP RPM source for RHEL / Fedora / CentOS). Three merged PRs landed between 1.1.0 and 1.1.1: a test-path correction so the suite finds the build directory regardless of out-of-tree builds, a fix for an undefined &lt;code&gt;$ext_builddir&lt;/code&gt; that broke the Fedora PHP build glue, and an additional Fedora-family font-path probe (&lt;code&gt;/usr/share/fonts/lato/&lt;/code&gt;, &lt;code&gt;/usr/share/fonts/TTF/&lt;/code&gt;) for MINIT's default-font detection. The cumulative effect is that fastchart now builds and runs cleanly under Remi's RPM packaging.&lt;/p&gt;
&lt;h3 id=&quot;performance-what-each-format-actually-costs&quot;&gt;Performance: what each format actually costs&lt;/h3&gt;
&lt;p&gt;Median in-memory render time at 1920×1080 on a single core, Intel i9-13950HX, PHP 8.4 debug build, default font and DPI. SVG is the canonical output; PNG / WebP / JPG add their rasterize + encode cost on top of the SVG build.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Chart        &lt;/th&gt;&lt;th&gt;SVG ms &lt;/th&gt;&lt;th&gt;PNG ms &lt;/th&gt;&lt;th&gt;WebP ms &lt;/th&gt;&lt;th&gt;JPG ms&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;AreaChart    &lt;/td&gt;&lt;td&gt;   5.7 &lt;/td&gt;&lt;td&gt;  71.7 &lt;/td&gt;&lt;td&gt;   54.4 &lt;/td&gt;&lt;td&gt;  34.5&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;BarChart     &lt;/td&gt;&lt;td&gt;  11.0 &lt;/td&gt;&lt;td&gt;  75.8 &lt;/td&gt;&lt;td&gt;   57.0 &lt;/td&gt;&lt;td&gt;  38.8&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;BoxPlot      &lt;/td&gt;&lt;td&gt;   4.4 &lt;/td&gt;&lt;td&gt;  65.0 &lt;/td&gt;&lt;td&gt;   47.5 &lt;/td&gt;&lt;td&gt;  31.6&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;BubbleChart  &lt;/td&gt;&lt;td&gt;   2.6 &lt;/td&gt;&lt;td&gt;  90.9 &lt;/td&gt;&lt;td&gt;   62.7 &lt;/td&gt;&lt;td&gt;  38.6&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GaugeChart   &lt;/td&gt;&lt;td&gt;   1.2 &lt;/td&gt;&lt;td&gt;  69.4 &lt;/td&gt;&lt;td&gt;   49.7 &lt;/td&gt;&lt;td&gt;  29.1&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;LineChart    &lt;/td&gt;&lt;td&gt;   5.4 &lt;/td&gt;&lt;td&gt;  74.2 &lt;/td&gt;&lt;td&gt;   55.5 &lt;/td&gt;&lt;td&gt;  34.3&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;PieChart     &lt;/td&gt;&lt;td&gt;   2.8 &lt;/td&gt;&lt;td&gt;  71.6 &lt;/td&gt;&lt;td&gt;   51.9 &lt;/td&gt;&lt;td&gt;  33.0&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;StockChart   &lt;/td&gt;&lt;td&gt;   8.4 &lt;/td&gt;&lt;td&gt;  80.8 &lt;/td&gt;&lt;td&gt;   63.3 &lt;/td&gt;&lt;td&gt;  41.0&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;SVG sits between 1.2 ms and 11 ms across all 19 measured types. There is no rasterizer in that path; the backend appends strings into a &lt;code&gt;smart_str&lt;/code&gt; and returns the bytes. The raster encoders split into three bands: JPG fastest at 25 to 41 ms (libjpeg-turbo with 4:2:0 subsampling), WebP middle at 41 to 63 ms (libwebp with &lt;code&gt;WEBP_PRESET_DRAWING&lt;/code&gt; + method=2 + multi-thread, roughly 2× faster than the simple API the rewrite started with), PNG slowest at 62 to 91 ms (libpng's deflate dominates). All four formats stay under 95 ms at 1080p on one thread.&lt;/p&gt;
&lt;p&gt;Full table for all 19 measured chart types in the &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/iliaal/fastchart#-performance&quot;&gt;README perf section&lt;/a&gt;. Reproduce with &lt;code&gt;php -d extension=./modules/fastchart.so docs/bench/bench.php&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;composing-without-a-shared-canvas&quot;&gt;Composing without a shared canvas&lt;/h3&gt;
&lt;p&gt;The 0.2.0 differentiator was &lt;code&gt;draw(GdImage $canvas)&lt;/code&gt;: hand fastchart a gd canvas you owned, it drew into it, you composited multiple charts on one image. That API is gone in 1.x because v1.x owns its pixel buffer.&lt;/p&gt;
&lt;p&gt;The replacement is &lt;code&gt;drawSvgFragment()&lt;/code&gt; plus the static &lt;code&gt;svgToPng / svgToJpeg / svgToWebp&lt;/code&gt; rasterizers:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;$line = (new FastChart\LineChart(800, 600))
    -&amp;gt;setTitle('Daily active users')
    -&amp;gt;setSeries([['data' =&amp;gt; $values]]);

$bar = (new FastChart\BarChart(800, 600))
    -&amp;gt;setTitle('Quarterly revenue')
    -&amp;gt;setSeries([['data' =&amp;gt; $bars]]);

// Stitch two fragments into one outer SVG document.
$outer = &amp;lt;&amp;lt;&amp;lt;SVG
&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; width=&quot;1600&quot; height=&quot;600&quot; viewBox=&quot;0 0 1600 600&quot;&amp;gt;
  &amp;lt;g transform=&quot;translate(0,0)&quot;&amp;gt;{$line-&amp;gt;drawSvgFragment()}&amp;lt;/g&amp;gt;
  &amp;lt;g transform=&quot;translate(800,0)&quot;&amp;gt;{$bar-&amp;gt;drawSvgFragment()}&amp;lt;/g&amp;gt;
&amp;lt;/svg&amp;gt;
SVG;

// Take the stitched SVG either as bytes or rasterized in one call.
file_put_contents('/tmp/dashboard.svg', $outer);
file_put_contents('/tmp/dashboard.png', FastChart\Chart::svgToPng($outer));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Same dashboard story as the 0.2.0 example, no shared canvas. The rasterizer sees the full composed document and antialiases across fragment boundaries cleanly.&lt;/p&gt;
&lt;p&gt;On Linux with a standard fonts package installed (Ubuntu's &lt;code&gt;fonts-lato&lt;/code&gt;, Debian's &lt;code&gt;fonts-dejavu&lt;/code&gt;, etc.) fastchart's MINIT auto-probes a default. On macOS or in minimal containers, add &lt;code&gt;-&amp;gt;setFontPath('/path/to/font.ttf')&lt;/code&gt; on each chart so labels render.&lt;/p&gt;
&lt;p&gt;The SVG-canonical pipeline also gave a freebie: &lt;code&gt;svgToPng / svgToJpeg / svgToWebp&lt;/code&gt; rasterize any caller-supplied SVG bytes through the same plutovg + encoder path, not just fastchart's own output. If you need to convert an arbitrary SVG to PNG / JPG / WebP from PHP without shelling out to ImageMagick, rsvg-convert, or Inkscape, that's now in-process. The caveat is text: plutosvg has no text engine, so &lt;code&gt;&amp;lt;text&amp;gt;&lt;/code&gt; elements in caller-supplied SVG render blank. Either pre-flatten to &lt;code&gt;&amp;lt;path&amp;gt;&lt;/code&gt; (Inkscape's &quot;Object to Path&quot; works) or accept the limitation. Hard caps apply: 16 MB input, output dimensions capped at 4096 px and 16 Mpx, embedded &lt;code&gt;data:image/&lt;/code&gt; URIs rejected (plutosvg's loader bypasses the dim cap on those), &lt;code&gt;&amp;lt;use&amp;gt;&lt;/code&gt; elements rejected (the cycle detector doesn't count fan-out, so nested &lt;code&gt;&amp;lt;g&amp;gt;&amp;lt;use/&amp;gt;×10&lt;/code&gt; can hit billion-laughs expansion). Contract at &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/iliaal/fastchart/blob/main/docs/specs/svg-to-raster.md&quot;&gt;&lt;code&gt;docs/specs/svg-to-raster.md&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;try-it&quot;&gt;Try it&lt;/h3&gt;
&lt;p&gt;Full SVG + PNG + JPG + WebP gallery for every chart family at &lt;a rel=&quot;nofollow&quot; href=&quot;https://iliaal.github.io/fastchart/v1-gallery.html&quot;&gt;iliaal.github.io/fastchart/v1-gallery.html&lt;/a&gt;. Source PHP shown above each row.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;pie install iliaal/fastchart
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Repo: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/iliaal/fastchart&quot;&gt;github.com/iliaal/fastchart&lt;/a&gt;. BSD-3, PHP 8.3+, NTS or ZTS.&lt;/p&gt;
&lt;h3 id=&quot;what-0-2-0-got-right&quot;&gt;What 0.2.0 got right&lt;/h3&gt;
&lt;p&gt;The 0.2.0 framing held: PHP doesn't need a Node sidecar for charts. The breadth held: 19 chart types covering Cartesian, financial, non-Cartesian, and specialised shapes is roughly the surface most dashboards need. The fluent OO API held. What didn't hold was libgd underneath it. libgd is fine for what libgd is; it isn't a 2026 chart rasterizer. A few releases later, fastchart isn't built on top of libgd anymore, and the output reads accordingly.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/18682/fastchart-1-x-why-i-rewrote-it-after-0-2-release</guid>
<pubDate>Fri, 22 May 2026 12:16:54 +0000</pubDate>
</item>
<item>
<title>fastchart 0.2.0: Native PHP Charts, Barcodes, and QR Codes in One Extension</title>
<link>https://coderlegion.com/17588/fastchart-0-2-0-native-php-charts-barcodes-and-qr-codes-in-one-extension</link>
<description>&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;(new FastChart\StockChart())
    -&amp;gt;setSize(1200, 600)
    -&amp;gt;setTitle('AAPL last 90 days')
    -&amp;gt;setTheme(FastChart\Chart::THEME_DARK)
    -&amp;gt;setOhlcv($ohlcvRows)
    -&amp;gt;setMovingAverages([20, 50, 200])
    -&amp;gt;setVolumePane(true)
    -&amp;gt;setCandleStyle(FastChart\Chart::STYLE_HOLLOW)
    -&amp;gt;renderToFile('/tmp/aapl.png');
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That's a server-side OHLCV candlestick chart with three moving averages, a volume pane, and a hollow candle style. Roughly 68 ms on a single core at 1920×1080. No microservice, no Node sidecar, no JavaScript runtime. PHP, gd, fastchart.&lt;/p&gt;
&lt;p&gt;fastchart 0.2.0 shipped two days ago. 19 chart types behind a fluent OO API, plus a Symbol family (Code 128 barcodes and QR codes) that landed in this release. The repo is at &lt;a href=&quot;https://github.com/iliaal/fastchart&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;github.com/iliaal/fastchart&lt;/a&gt;.&lt;/p&gt;
&lt;h3 id=&quot;why-charts-in-php-again&quot;&gt;Why charts in PHP again&lt;/h3&gt;
&lt;p&gt;Twenty years ago, Rasmus and I shipped the initial release of PECL/GDChart in January 2006. It wrapped Bruce Verderaime's gdchart C library from &lt;code&gt;users.fred.net/brv/chart/&lt;/code&gt;. The PECL page is still up at &lt;a rel=&quot;nofollow&quot; href=&quot;https://pecl.php.net/package/GDChart&quot;&gt;https://pecl.php.net/package/GDChart&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Both projects died. Verderaime's gdchart library hasn't moved since the mid-2000s; the homepage at &lt;code&gt;users.fred.net/brv/chart/&lt;/code&gt; has been a tombstone for almost as long. The PECL extension followed. One release, then nothing.&lt;/p&gt;
&lt;p&gt;The PHP charting ecosystem since then has been thin. JpGraph kept moving but active development went to the commercial fork; the OSS branch is calcifying. pChart is unmaintained. Many PHP teams that need server-side charts in 2026 either reach for a Node or Python microservice (Chart.js via Puppeteer, matplotlib via subprocess) or accept that &quot;server-side rendering&quot; means &quot;render in the browser and screenshot it.&quot; Neither is good.&lt;/p&gt;
&lt;p&gt;Between PECL/GDChart and now, I've kept needing charts and graphs in PHP. Mostly charts, occasionally barcodes and QR codes. Each new project I'd reach for the easy options first: command-line tools wrapped through &lt;code&gt;shell_exec&lt;/code&gt;, pure-PHP libraries when they were fast enough, more recently chart.js renders shipped through a Puppeteer or headless-Chrome wrapper. Those work until they don't. When scale showed up the wrapper started dominating request latency, and I'd write a little PHP extension that handled the specific case causing pain.&lt;/p&gt;
&lt;p&gt;Roughly six of those extensions accumulated over the years. Each did one thing. One generated QR codes for serial numbers on physical labels. One drew two chart types for an internal reporting dashboard. One was just OHLC candlesticks with moving averages. None of them shipped. They lived in private repos, solved the immediate problem, and never got cleaned up enough to release.&lt;/p&gt;
&lt;p&gt;fastchart is the attempt to close that gap publicly. One extension, the breadth of shapes I've kept needing, a fluent OO API, BSD-licensed. StockChart got the deepest treatment in this release (seven candle styles, the full indicator stack) because the most recent of the six private extensions was the trading-chart one and it carried over almost verbatim. The other eighteen chart types and the Symbol family came from cleaning up and merging the rest.&lt;/p&gt;
&lt;h3 id=&quot;what-s-in-0-2-0&quot;&gt;What's in 0.2.0&lt;/h3&gt;
&lt;p&gt;Nineteen chart classes plus a two-class Symbol family for barcodes and QR codes. Five output formats. Two render paths. The full surface is 105 public methods covered by 97 tests. PHP 8.3+ minimum, NTS or ZTS.&lt;/p&gt;
&lt;p&gt;The chart classes split into four shapes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cartesian.&lt;/strong&gt; Line, Area, Bar (vertical, horizontal, stacked, grouped, floating, layered), Scatter, Bubble.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Financial.&lt;/strong&gt; A deep &lt;code&gt;StockChart&lt;/code&gt; class: seven candle styles (CANDLE, BAR, DIAMOND, I_CAP, HOLLOW, VOLUME, VECTOR), SMA/EMA/WMA overlays, a volume pane, and indicator panes (RSI, MACD, Bollinger Bands, Parabolic SAR, Stochastic, OBV).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Non-Cartesian.&lt;/strong&gt; Radar, Polar, Surface, Contour.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Specialised.&lt;/strong&gt; Pie (with donut hole and leader lines), Gauge, LinearMeter, Gantt (with dependencies and milestones), BoxPlot, Treemap, Funnel, Waterfall, Heatmap.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Symbol family added in 0.2.0:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Code 128.&lt;/strong&gt; ISO/IEC 15417. Auto-switches between A/B/C subsets to minimize encoded length. Mod-103 checksum appended automatically. Optional human-readable payload rendered below the bars.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;QR Code.&lt;/strong&gt; ISO/IEC 18004. Four error-correction levels (ECC_L/M/Q/H), versions 1 through 40. Encoder is the vendored nayuki/QR-Code-generator C library under MIT.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Output formats are the standard gd set plus the modern ones: PNG, JPEG, WebP, AVIF, GIF.&lt;/p&gt;
&lt;h3 id=&quot;why-barcodes-and-qr-codes-in-a-chart-library&quot;&gt;Why barcodes and QR codes in a chart library&lt;/h3&gt;
&lt;p&gt;Because they all render to a gd canvas, they all serve the same use case (server-side image generation in PHP), and they share the same painful problem: the existing PHP-native options are mostly dead or third-party packages with their own dependency stacks.&lt;/p&gt;
&lt;p&gt;The unifying thread is gd, not &quot;chart.&quot; If you're rendering a dashboard tile, a sales report PDF, an invoice with a scannable serial number, or a shipping label with a barcode, you're producing an image on the server. PHP has had &lt;code&gt;ext/gd&lt;/code&gt; since 4.0.0. fastchart treats &lt;code&gt;ext/gd&lt;/code&gt; as the substrate and adds higher-level shapes on top. The Symbol classes don't claim to be charts; they live in their own family parallel to &lt;code&gt;Chart&lt;/code&gt;, with shared base setters and the same render-format set.&lt;/p&gt;
&lt;p&gt;The public options before fastchart were mostly pure-PHP libraries shipping their own glyph tables and rasterizers, or wrappers around command-line tools like &lt;code&gt;qrencode&lt;/code&gt;. Both work. Both add a dependency surface that a &lt;code&gt;pie install&lt;/code&gt; doesn't cover. fastchart pulls QR and Code 128 into the same &lt;code&gt;.so&lt;/code&gt; as the charts. One install, one dependency (gd), one fluent API.&lt;/p&gt;
&lt;h3 id=&quot;the-compose-path&quot;&gt;The compose path&lt;/h3&gt;
&lt;p&gt;Charts let you hand fastchart a &lt;code&gt;\GdImage&lt;/code&gt; canvas you own. It draws into your canvas and returns the same canvas back. Symbols don't accept a caller-owned canvas (a barcode's quiet zone makes compositing inside an existing image ambiguous); they render fresh and you &lt;code&gt;imagecreatefromstring()&lt;/code&gt; to composite afterwards.&lt;/p&gt;
&lt;p&gt;The composability is the differentiator from JpGraph, pChart, and most JS-bridged solutions. They own the canvas. You get a finished PNG file back and composite at the file or page level, never at the pixel level. fastchart's two-path design covers both:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-php&quot;&gt;// Path 1: &quot;give me a file.&quot;
(new FastChart\LineChart(800, 600))
    -&amp;gt;setSeries([['data' =&amp;gt; $values]])
    -&amp;gt;renderToFile('/tmp/line.png');

// Path 2: &quot;draw onto my canvas.&quot; Two charts side by side on the same image.
$canvas = imagecreatetruecolor(1600, 900);

(new FastChart\LineChart(1600, 900))
    -&amp;gt;setTitle('Daily active users')
    -&amp;gt;setSeries([['data' =&amp;gt; $values]])
    -&amp;gt;setPlotRect(80, 60, 720, 820)
    -&amp;gt;draw($canvas);

(new FastChart\BarChart(1600, 900))
    -&amp;gt;setTitle('Quarterly revenue')
    -&amp;gt;setSeries([['data' =&amp;gt; $bars]])
    -&amp;gt;setPlotRect(880, 60, 1520, 820)
    -&amp;gt;draw($canvas);

// Stamp something gd-native on top.
$font = '/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf';
imagettftext($canvas, 24, 0, 20, 40, $white, $font, 'Dashboard');

imagepng($canvas, '/tmp/dashboard.png');
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A four-tile dashboard, a chart embedded in a PDF page, a chart and its legend baked together on a sprite, same primitives, no separate render passes, no temp files.&lt;/p&gt;
&lt;h3 id=&quot;performance&quot;&gt;Performance&lt;/h3&gt;
&lt;p&gt;Every chart type renders under 100 ms at 1920×1080 on a single core. The lighter types break 100 renders per second per core at dashboard-tile size (640×480). Numbers from my workstation (Intel i9-13950HX, PHP 8.4 NTS), default font and DPI.&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Chart        &lt;/th&gt;&lt;th&gt;640×480 ms &lt;/th&gt;&lt;th&gt;1920×1080 ms &lt;/th&gt;&lt;th&gt;1080p ops/sec&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;AreaChart    &lt;/td&gt;&lt;td&gt;        24 &lt;/td&gt;&lt;td&gt;          76 &lt;/td&gt;&lt;td&gt;           13&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;BarChart     &lt;/td&gt;&lt;td&gt;        39 &lt;/td&gt;&lt;td&gt;          84 &lt;/td&gt;&lt;td&gt;           12&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;BoxPlot      &lt;/td&gt;&lt;td&gt;        16 &lt;/td&gt;&lt;td&gt;          60 &lt;/td&gt;&lt;td&gt;           17&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;BubbleChart  &lt;/td&gt;&lt;td&gt;        13 &lt;/td&gt;&lt;td&gt;          62 &lt;/td&gt;&lt;td&gt;           16&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;ContourChart &lt;/td&gt;&lt;td&gt;         9 &lt;/td&gt;&lt;td&gt;          52 &lt;/td&gt;&lt;td&gt;           19&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Funnel       &lt;/td&gt;&lt;td&gt;        14 &lt;/td&gt;&lt;td&gt;          52 &lt;/td&gt;&lt;td&gt;           19&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GanttChart   &lt;/td&gt;&lt;td&gt;        18 &lt;/td&gt;&lt;td&gt;          61 &lt;/td&gt;&lt;td&gt;           16&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;GaugeChart   &lt;/td&gt;&lt;td&gt;        10 &lt;/td&gt;&lt;td&gt;          60 &lt;/td&gt;&lt;td&gt;           17&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Heatmap      &lt;/td&gt;&lt;td&gt;         9 &lt;/td&gt;&lt;td&gt;          56 &lt;/td&gt;&lt;td&gt;           18&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;LineChart    &lt;/td&gt;&lt;td&gt;        21 &lt;/td&gt;&lt;td&gt;          66 &lt;/td&gt;&lt;td&gt;           15&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;LinearMeter  &lt;/td&gt;&lt;td&gt;         9 &lt;/td&gt;&lt;td&gt;          50 &lt;/td&gt;&lt;td&gt;           20&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;PieChart     &lt;/td&gt;&lt;td&gt;        13 &lt;/td&gt;&lt;td&gt;          59 &lt;/td&gt;&lt;td&gt;           17&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;PolarChart   &lt;/td&gt;&lt;td&gt;        10 &lt;/td&gt;&lt;td&gt;          53 &lt;/td&gt;&lt;td&gt;           19&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;RadarChart   &lt;/td&gt;&lt;td&gt;        15 &lt;/td&gt;&lt;td&gt;          61 &lt;/td&gt;&lt;td&gt;           16&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;ScatterChart &lt;/td&gt;&lt;td&gt;        17 &lt;/td&gt;&lt;td&gt;          60 &lt;/td&gt;&lt;td&gt;           17&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;StockChart   &lt;/td&gt;&lt;td&gt;        21 &lt;/td&gt;&lt;td&gt;          68 &lt;/td&gt;&lt;td&gt;           15&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;SurfaceChart &lt;/td&gt;&lt;td&gt;         8 &lt;/td&gt;&lt;td&gt;          50 &lt;/td&gt;&lt;td&gt;           20&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Treemap      &lt;/td&gt;&lt;td&gt;        18 &lt;/td&gt;&lt;td&gt;          60 &lt;/td&gt;&lt;td&gt;           17&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;Waterfall    &lt;/td&gt;&lt;td&gt;        18 &lt;/td&gt;&lt;td&gt;          61 &lt;/td&gt;&lt;td&gt;           16&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;These are not &quot;we render faster than Chart.js running in Puppeteer&quot; numbers. Headless-browser rendering is slow for completely different reasons (process startup, JS runtime, layout, paint). The honest framing is that fastchart removes the JS-render path entirely from server-side image generation. The benchmark is a sanity check that the C path is fast enough to stop reaching for a sidecar, not a marketing claim.&lt;/p&gt;
&lt;p&gt;Bench source is at &lt;code&gt;docs/bench/bench.php&lt;/code&gt;. Reproduce locally with &lt;code&gt;php -d extension=gd -d extension=./modules/fastchart.so docs/bench/bench.php&lt;/code&gt;.&lt;/p&gt;
&lt;h3 id=&quot;install&quot;&gt;Install&lt;/h3&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;pie install iliaal/fastchart
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or build from source against the PHP install you want to extend:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-sh&quot;&gt;phpize
./configure --enable-fastchart
make -j
make test
sudo make install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;PHP 8.3 or newer, plus &lt;code&gt;ext/gd&lt;/code&gt;. fastchart declares &lt;code&gt;ZEND_MOD_REQUIRED(&quot;gd&quot;)&lt;/code&gt; so the engine orders MINIT correctly regardless of &lt;code&gt;php.ini&lt;/code&gt; / conf.d / &lt;code&gt;-d extension=&lt;/code&gt; load order. (Earlier 0.1.0 didn't, and &lt;code&gt;docker-php-ext-enable&lt;/code&gt;'s alphabetical &lt;code&gt;conf.d&lt;/code&gt; ordering caused fastchart to load before gd. That was the only thing 0.1.1 fixed.)&lt;/p&gt;
&lt;h3 id=&quot;twenty-years-later&quot;&gt;Twenty years later&lt;/h3&gt;
&lt;p&gt;The 2006 ext-gdchart was a hundred lines of glue around roughly 1,000 lines of upstream library. Single chart family, single output format, a tiny config surface. It worked. It died the moment its upstream did.&lt;/p&gt;
&lt;p&gt;The bet with fastchart is the opposite: own enough of the substrate that the project's lifespan isn't bound to anything external besides gd, which has been in PHP since 4.0.0. Nineteen chart types, two symbol types, the whole stack lives in this repo. No third-party chart library to outlast, no microservice to keep alive, no JS toolchain to drag along.&lt;/p&gt;
&lt;p&gt;Twenty years between PHP charting extensions is long enough.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/17588/fastchart-0-2-0-native-php-charts-barcodes-and-qr-codes-in-one-extension</guid>
<pubDate>Tue, 12 May 2026 14:46:50 +0000</pubDate>
</item>
<item>
<title>Helm Chart Testing in Production: Layers, Tools, and a Minimum CI Pipeline</title>
<link>https://coderlegion.com/11555/helm-chart-testing-in-production-layers-tools-and-a-minimum-ci-pipeline</link>
<description>
&lt;a href=&quot;https://alexandre-vazquez.com/helm-chart-testing-best-practices/&quot; title=&quot;Helm Chart Testing in Production: Layers, Tools, and a Minimum CI Pipeline&quot; rel=&quot;nofollow&quot;&gt;&lt;img width=&quot;1536&quot; height=&quot;1024&quot; src=&quot;https://mlk5tkvgfeoa.i.optimole.com/cb:s8WW.68/w:1536/h:1024/q:mauto/f:best/https://alexandre-vazquez.com/wp-content/uploads/2026/01/image.png&quot; class=&quot;webfeedsFeaturedVisual wp-post-image&quot; alt=&quot;Helm Chart Testing in Production: Layers, Tools, and a Minimum CI Pipeline&quot; style=&quot;display: block; margin: auto; margin-bottom: 5px;max-width: 100%;&quot; sizes=&quot;(max-width: 1536px) 100vw, 1536px&quot; title=&quot;Helm Chart Testing in Production: Layers, Tools, and a Minimum CI Pipeline 10&quot;&gt;&lt;/a&gt;
&lt;p&gt;When a Helm chart fails in production, the impact is immediate and visible. A misconfigured &lt;code&gt;ServiceAccount&lt;/code&gt;, a typo in a &lt;code&gt;ConfigMap&lt;/code&gt; key, or an untested conditional in templates can trigger incidents that cascade through your entire deployment pipeline. The irony is that most teams invest heavily in testing application code while treating Helm charts as &amp;ldquo;just configuration.&amp;rdquo;&lt;/p&gt;



&lt;p&gt;Chart testing is fundamental for production-quality Helm deployments. For comprehensive coverage of testing along with all other Helm best practices, visit our &lt;a rel=&quot;nofollow&quot; href=&quot;https://alexandre-vazquez.com/helm-charts-package-management-guide/&quot;&gt;complete Helm guide&lt;/a&gt;.&lt;/p&gt;



&lt;p&gt;Helm charts are infrastructure code. They define how your applications run, scale, and integrate with the cluster. Treating them with less rigor than your application logic is a risk most production environments cannot afford.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;The Real Cost of Untested Charts&lt;/h2&gt;



&lt;p&gt;In late 2024, a medium-sized SaaS company experienced a 4-hour outage because a chart update introduced a breaking change in RBAC permissions. The chart had been tested locally with &lt;code&gt;helm install --dry-run&lt;/code&gt;, but the dry-run validation doesn&amp;rsquo;t interact with the API server&amp;rsquo;s RBAC layer. The deployment succeeded syntactically but failed operationally.&lt;/p&gt;



&lt;p&gt;The incident revealed three gaps in their workflow:&lt;/p&gt;



&lt;ol class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;No schema validation against the target Kubernetes version&lt;/li&gt;



&lt;li&gt;No integration tests in a live cluster&lt;/li&gt;



&lt;li&gt;No policy enforcement for security baselines&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;



&lt;p&gt;These gaps are common. According to a &lt;a href=&quot;https://www.cncf.io/announcements/2025/07/24/cncf-end-user-survey-finds-argo-cd-as-majority-adopted-gitops-solution-for-kubernetes/&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;2024 CNCF survey on GitOps practices&lt;/a&gt;, fewer than 40% of organizations systematically test Helm charts before production deployment.&lt;/p&gt;



&lt;p&gt;The problem is not a lack of tools&amp;mdash;it&amp;rsquo;s understanding which layer each tool addresses.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Testing Layers: What Each Level Validates&lt;/h2&gt;



&lt;p&gt;Helm chart testing is not a single operation. It requires validation at multiple layers, each catching different classes of errors.&lt;/p&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;Layer 1: Syntax and Structure Validation&lt;/h3&gt;



&lt;p&gt;&lt;strong&gt;What it catches:&lt;/strong&gt; Malformed YAML, invalid chart structure, missing required fields&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Tools:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;code&gt;helm lint&lt;/code&gt;: Built-in, minimal validation following &lt;a href=&quot;https://helm.sh/docs/chart_best_practices/&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;Helm best practices&lt;/a&gt;&lt;/li&gt;



&lt;li&gt;&lt;code&gt;yamllint&lt;/code&gt;: Strict YAML formatting rules&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;Example failure caught:&lt;/strong&gt;&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;# Invalid indentation breaks the chart
resources:
  limits:
      cpu: &quot;500m&quot;
    memory: &quot;512Mi&quot;  # Incorrect indentation
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Limitation:&lt;/strong&gt; Does not validate whether the rendered manifests are valid Kubernetes objects.&lt;/p&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;Layer 2: Schema Validation&lt;/h3&gt;



&lt;p&gt;&lt;strong&gt;What it catches:&lt;/strong&gt; Manifests that would be rejected by the Kubernetes API&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Primary tool: kubeconform&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;&lt;a href=&quot;https://github.com/yannh/kubeconform&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;Kubeconform&lt;/a&gt; is the actively maintained successor to the deprecated &lt;code&gt;kubeval&lt;/code&gt;. It validates against OpenAPI schemas for specific Kubernetes versions and can include custom CRDs.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Project Profile:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;Maintenance:&lt;/strong&gt; Active, community-driven&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Strengths:&lt;/strong&gt; CRD support, multi-version validation, fast execution&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; &lt;code&gt;helm lint&lt;/code&gt; validates chart structure, but not if rendered manifests match Kubernetes schemas&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;Example failure caught:&lt;/strong&gt;&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
spec:
  replicas: 2
  template:
    metadata:
      labels:
        app: myapp
    spec:
      containers:
      - name: app
        image: nginx:latest
# Missing required field: spec.selector
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Configuration example:&lt;/strong&gt;&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;helm template my-chart . | kubeconform \
  -kubernetes-version 1.30.0 \
  -schema-location default \
  -schema-location '&lt;a href=&quot;https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json&quot; rel=&quot;nofollow&quot;&gt;https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json&lt;/a&gt;' \
  -summary
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Example CI integration:&lt;/strong&gt;&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;#!/bin/bash
set -e

KUBE_VERSION=&quot;1.30.0&quot;

echo &quot;Rendering chart...&quot;
helm template my-release ./charts/my-chart &amp;gt; manifests.yaml

echo &quot;Validating against Kubernetes $KUBE_VERSION...&quot;
kubeconform \
  -kubernetes-version &quot;$KUBE_VERSION&quot; \
  -schema-location default \
  -summary \
  -output json \
  manifests.yaml | jq -e '.summary.invalid == 0'
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Alternative:&lt;/strong&gt; &lt;code&gt;kubectl --dry-run=server&lt;/code&gt; (requires cluster access, validates against actual API server)&lt;/p&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;Layer 3: Unit Testing&lt;/h3&gt;



&lt;p&gt;&lt;strong&gt;What it catches:&lt;/strong&gt; Logic errors in templates, incorrect conditionals, wrong value interpolation&lt;/p&gt;



&lt;p&gt;Unit tests validate that given a set of input values, the chart produces the expected manifests. This is where template logic is verified before reaching a cluster.&lt;/p&gt;



&lt;h4 class=&quot;wp-block-heading&quot;&gt;Primary tool: helm-unittest&lt;/h4&gt;



&lt;p&gt;&lt;a href=&quot;https://github.com/helm-unittest/helm-unittest&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;helm-unittest&lt;/a&gt; is the most widely adopted unit testing framework for Helm charts.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Project Profile:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; 3.3k+ stars, ~100 contributors&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Maintenance:&lt;/strong&gt; Active (releases every 2-3 months)&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Primary maintainer:&lt;/strong&gt; Quentin Machu (originally @QubitProducts, now independent)&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Commercial backing:&lt;/strong&gt; None&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Bus Factor:&lt;/strong&gt; Medium-High (no institutional backing, but consistent community engagement)&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;Strengths:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Fast execution (no cluster required)&lt;/li&gt;



&lt;li&gt;Familiar test syntax (similar to Jest/Mocha)&lt;/li&gt;



&lt;li&gt;Snapshot testing support&lt;/li&gt;



&lt;li&gt;Good documentation&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Doesn&amp;rsquo;t validate runtime behavior&lt;/li&gt;



&lt;li&gt;Cannot test interactions with admission controllers&lt;/li&gt;



&lt;li&gt;No validation against actual Kubernetes API&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;Example test scenario:&lt;/strong&gt;&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;# tests/deployment_test.yaml
suite: test deployment
templates:
  - deployment.yaml
tests:
  - it: should set resource limits when provided
    set:
      resources.limits.cpu: &quot;1000m&quot;
      resources.limits.memory: &quot;1Gi&quot;
    asserts:
      - equal:
          path: spec.template.spec.containers[0].resources.limits.cpu
          value: &quot;1000m&quot;
      - equal:
          path: spec.template.spec.containers[0].resources.limits.memory
          value: &quot;1Gi&quot;

  - it: should not create HPA when autoscaling disabled
    set:
      autoscaling.enabled: false
    template: hpa.yaml
    asserts:
      - hasDocuments:
          count: 0
&lt;/code&gt;&lt;/pre&gt;



&lt;h4 class=&quot;wp-block-heading&quot;&gt;Alternative: Terratest (Helm module)&lt;/h4&gt;



&lt;p&gt;&lt;a href=&quot;https://github.com/gruntwork-io/terratest&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;Terratest&lt;/a&gt; is a Go-based testing framework from Gruntwork that includes first-class Helm support. Unlike helm-unittest, Terratest deploys charts to real clusters and allows programmatic assertions in Go.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Example Terratest test:&lt;/strong&gt;&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;func TestHelmChartDeployment(t *testing.T) {
    kubectlOptions := k8s.NewKubectlOptions(&quot;&quot;, &quot;&quot;, &quot;default&quot;)
    options := &amp;amp;helm.Options{
        KubectlOptions: kubectlOptions,
        SetValues: map[string]string{
            &quot;replicaCount&quot;: &quot;3&quot;,
        },
    }
    
    defer helm.Delete(t, options, &quot;my-release&quot;, true)
    helm.Install(t, options, &quot;../charts/my-chart&quot;, &quot;my-release&quot;)
    
    k8s.WaitUntilNumPodsCreated(t, kubectlOptions, metav1.ListOptions{
        LabelSelector: &quot;app=my-app&quot;,
    }, 3, 30, 10*time.Second)
}
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;When to use Terratest vs helm-unittest:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Use &lt;code&gt;helm-unittest&lt;/code&gt; for fast, template-focused validation in CI&lt;/li&gt;



&lt;li&gt;Use &lt;code&gt;Terratest&lt;/code&gt; when you need full integration testing with Go flexibility&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;Layer 4: Integration Testing&lt;/h3&gt;



&lt;p&gt;&lt;strong&gt;What it catches:&lt;/strong&gt; Runtime failures, resource conflicts, actual Kubernetes behavior&lt;/p&gt;



&lt;p&gt;Integration tests deploy the chart to a real (or ephemeral) cluster and verify it works end-to-end.&lt;/p&gt;



&lt;h4 class=&quot;wp-block-heading&quot;&gt;Primary tool: chart-testing (ct)&lt;/h4&gt;



&lt;p&gt;&lt;a href=&quot;https://github.com/helm/chart-testing&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;chart-testing&lt;/a&gt; is the official Helm project for testing charts in live clusters.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Project Profile:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;Ownership:&lt;/strong&gt; Official Helm project (CNCF)&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Maintainers:&lt;/strong&gt; Helm team (contributors from Microsoft, IBM, Google)&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Governance:&lt;/strong&gt; CNCF-backed with public roadmap&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;LTS:&lt;/strong&gt; Aligned with Helm release cycle&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Bus Factor:&lt;/strong&gt; Low (institutional backing from CNCF provides strong long-term guarantees)&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;Strengths:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;De facto standard for public Helm charts&lt;/li&gt;



&lt;li&gt;Built-in upgrade testing (validates migrations)&lt;/li&gt;



&lt;li&gt;Detects which charts changed in a PR (efficient for monorepos)&lt;/li&gt;



&lt;li&gt;Integration with GitHub Actions via official action&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Requires a live Kubernetes cluster&lt;/li&gt;



&lt;li&gt;Initial setup more complex than unit testing&lt;/li&gt;



&lt;li&gt;Does not include security scanning&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;What ct validates:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Chart installs successfully&lt;/li&gt;



&lt;li&gt;Upgrades work without breaking state&lt;/li&gt;



&lt;li&gt;Linting passes&lt;/li&gt;



&lt;li&gt;Version constraints are respected&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;Example ct configuration:&lt;/strong&gt;&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;# ct.yaml
target-branch: main
chart-dirs:
  - charts
chart-repos:
  - bitnami=&lt;a href=&quot;https://charts.bitnami.com/bitnami&quot; rel=&quot;nofollow&quot;&gt;https://charts.bitnami.com/bitnami&lt;/a&gt;
helm-extra-args: --timeout 600s
check-version-increment: true
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Typical GitHub Actions workflow:&lt;/strong&gt;&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;name: Lint and Test Charts

on: pull_request

jobs:
  lint-test:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Set up Helm
        uses: azure/setup-helm@v3

      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'

      - name: Set up chart-testing
        uses: helm/chart-testing-action@v2

      - name: Run chart-testing (lint)
        run: ct lint --config ct.yaml

      - name: Create kind cluster
        uses: helm/kind-action@v1

      - name: Run chart-testing (install)
        run: ct install --config ct.yaml
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;When ct is essential:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Public chart repositories (expected by community)&lt;/li&gt;



&lt;li&gt;Charts with complex upgrade paths&lt;/li&gt;



&lt;li&gt;Multi-chart repositories with CI optimization needs&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;Layer 5: Security and Policy Validation&lt;/h3&gt;



&lt;p&gt;&lt;strong&gt;What it catches:&lt;/strong&gt; Security misconfigurations, policy violations, compliance issues&lt;/p&gt;



&lt;p&gt;This layer prevents deploying charts that pass functional tests but violate organizational security baselines or contain vulnerabilities.&lt;/p&gt;



&lt;h4 class=&quot;wp-block-heading&quot;&gt;Policy Enforcement: Conftest (Open Policy Agent)&lt;/h4&gt;



&lt;p&gt;&lt;a href=&quot;https://www.conftest.dev/&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;Conftest&lt;/a&gt; is the CLI interface to &lt;a href=&quot;https://www.openpolicyagent.org/docs/latest/&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;Open Policy Agent&lt;/a&gt; for policy-as-code validation.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Project Profile:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;Parent:&lt;/strong&gt; Open Policy Agent (CNCF Graduated Project)&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Governance:&lt;/strong&gt; Strong CNCF backing, multi-vendor support&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Production adoption:&lt;/strong&gt; Netflix, Pinterest, Goldman Sachs&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Bus Factor:&lt;/strong&gt; Low (graduated CNCF project with multi-vendor backing)&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;Strengths:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Policies written in Rego (reusable, composable)&lt;/li&gt;



&lt;li&gt;Works with any YAML/JSON input (not Helm-specific)&lt;/li&gt;



&lt;li&gt;Can enforce organizational standards programmatically&lt;/li&gt;



&lt;li&gt;Integration with admission controllers (Gatekeeper)&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Rego has a learning curve&lt;/li&gt;



&lt;li&gt;Does not replace functional testing&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;Example Conftest policy:&lt;/strong&gt;&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;# policy/security.rego
package main

import future.keywords.contains
import future.keywords.if
import future.keywords.in

deny[msg] {
  input.kind == &quot;Deployment&quot;
  container := input.spec.template.spec.containers[_]
  not container.resources.limits.memory
  msg := sprintf(&quot;Container '%s' must define memory limits&quot;, [container.name])
}

deny[msg] {
  input.kind == &quot;Deployment&quot;
  container := input.spec.template.spec.containers[_]
  not container.resources.limits.cpu
  msg := sprintf(&quot;Container '%s' must define CPU limits&quot;, [container.name])
}
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Running the validation:&lt;/strong&gt;&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;helm template my-chart . | conftest test -p policy/ -
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Alternative: Kyverno&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;&lt;a href=&quot;https://kyverno.io/&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;Kyverno&lt;/a&gt; offers policy enforcement using native Kubernetes manifests instead of Rego. Policies are written in YAML and can validate, mutate, or generate resources.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Example Kyverno policy:&lt;/strong&gt;&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: require-resource-limits
spec:
  validationFailureAction: Enforce
  rules:
  - name: check-container-limits
    match:
      resources:
        kinds:
        - Pod
    validate:
      message: &quot;All containers must have CPU and memory limits&quot;
      pattern:
        spec:
          containers:
          - resources:
              limits:
                memory: &quot;?*&quot;
                cpu: &quot;?*&quot;
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Conftest vs Kyverno:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Conftest: Policies run in CI, flexible for any YAML&lt;/li&gt;



&lt;li&gt;Kyverno: Runtime enforcement in-cluster, Kubernetes-native&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;Both can coexist: Conftest in CI for early feedback, Kyverno in cluster for runtime enforcement.&lt;/p&gt;



&lt;h4 class=&quot;wp-block-heading&quot;&gt;Vulnerability Scanning: Trivy&lt;/h4&gt;



&lt;p&gt;&lt;a href=&quot;https://github.com/aquasecurity/trivy&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;Trivy&lt;/a&gt; by Aqua Security provides comprehensive security scanning for Helm charts.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Project Profile:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;Maintainer:&lt;/strong&gt; Aqua Security (commercial backing with open-source core)&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Scope:&lt;/strong&gt; Vulnerability scanning + misconfiguration detection&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Helm integration:&lt;/strong&gt; Official &lt;code&gt;trivy helm&lt;/code&gt; command&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Bus Factor:&lt;/strong&gt; Low (commercial backing + strong open-source adoption)&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;strong&gt;What Trivy scans in Helm charts:&lt;/strong&gt;&lt;/p&gt;



&lt;ol class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Vulnerabilities in referenced container images&lt;/li&gt;



&lt;li&gt;Misconfigurations (similar to Conftest but pre-built rules)&lt;/li&gt;



&lt;li&gt;Secrets accidentally committed in templates&lt;br&gt;&lt;/li&gt;
&lt;/ol&gt;



&lt;p&gt;&lt;strong&gt;Example scan:&lt;/strong&gt;&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;trivy helm ./charts/my-chart --severity HIGH,CRITICAL --exit-code 1
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Sample output:&lt;/strong&gt;&lt;/p&gt;



&lt;pre class=&quot;wp-block-code&quot;&gt;&lt;code&gt;myapp/templates/deployment.yaml (helm)
====================================

Tests: 12 (SUCCESSES: 10, FAILURES: 2)
Failures: 2 (HIGH: 1, CRITICAL: 1)

HIGH: Container 'app' of Deployment 'myapp' should set 'securityContext.runAsNonRoot' to true
&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;&amp;#9552;
Ensure containers run as non-root users

See &lt;a href=&quot;https://kubernetes.io/docs/concepts/security/pod-security-standards/&quot; rel=&quot;nofollow&quot;&gt;https://kubernetes.io/docs/concepts/security/pod-security-standards/&lt;/a&gt;
&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;&amp;#9472;
 myapp/templates/deployment.yaml:42
&lt;/code&gt;&lt;/pre&gt;



&lt;p&gt;&lt;strong&gt;Commercial support:&lt;/strong&gt;&lt;br&gt;Aqua Security offers Trivy Enterprise with advanced features (centralized scanning, compliance reporting). For most teams, the open-source version is sufficient.&lt;/p&gt;



&lt;h4 class=&quot;wp-block-heading&quot;&gt;Other Security Tools&lt;/h4&gt;



&lt;p&gt;&lt;strong&gt;Polaris (Fairwinds)&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;Polaris scores charts based on security and reliability best practices. Unlike enforcement tools, it provides a health score and actionable recommendations.&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Use case:&lt;/strong&gt; Dashboard for chart quality across a platform&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;Checkov (Bridgecrew/Palo Alto)&lt;/strong&gt;&lt;/p&gt;



&lt;p&gt;Similar to Trivy but with a broader IaC focus (Terraform, CloudFormation, Kubernetes, Helm). Pre-built policies for compliance frameworks (CIS, PCI-DSS).&lt;/p&gt;



&lt;p&gt;&lt;strong&gt;When to use Checkov:&lt;/strong&gt;&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Multi-IaC environment (not just Helm)&lt;/li&gt;



&lt;li&gt;Compliance-driven validation requirements&lt;br&gt;&lt;/li&gt;
&lt;/ul&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Enterprise Selection Criteria&lt;/h2&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;Bus Factor and Long-Term Viab&lt;/h3&gt;
</description>
<category>Other</category>
<guid isPermaLink="true">https://coderlegion.com/11555/helm-chart-testing-in-production-layers-tools-and-a-minimum-ci-pipeline</guid>
<pubDate>Sat, 14 Feb 2026 09:43:36 +0000</pubDate>
</item>
<item>
<title>Helm 4.0 Features, Breaking Changes &amp; Migration Guide 2025</title>
<link>https://coderlegion.com/11558/helm-4-0-features-breaking-changes-migration-guide-2025</link>
<description>
&lt;a href=&quot;https://alexandre-vazquez.com/helm-40/&quot; title=&quot;Helm 4.0 Features, Breaking Changes &amp;amp; Migration Guide 2025&quot; rel=&quot;nofollow&quot;&gt;&lt;img width=&quot;1024&quot; height=&quot;1024&quot; src=&quot;https://mlk5tkvgfeoa.i.optimole.com/cb:s8WW.68/w:1024/h:1024/q:mauto/f:best/https://alexandre-vazquez.com/wp-content/uploads/2025/11/A_2D_digital_illustration_features_Kubernetes_Helm.png&quot; class=&quot;webfeedsFeaturedVisual wp-post-image&quot; alt=&quot;Helm 4.0 Features, Breaking Changes &amp;amp; Migration Guide 2025&quot; style=&quot;display: block; margin: auto; margin-bottom: 5px;max-width: 100%;&quot; sizes=&quot;(max-width: 1024px) 100vw, 1024px&quot; title=&quot;Helm 4.0 Features, Breaking Changes &amp;amp; Migration Guide 2025 16&quot;&gt;&lt;/a&gt;
&lt;p&gt;&lt;a href=&quot;https://helm.sh/&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;Helm&lt;/a&gt; is one of the main utilities within the Kubernetes ecosystem, and therefore the release of a new major version, such as &lt;a href=&quot;https://helm.sh/docs/overview/&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;Helm 4.0&lt;/a&gt;, is something to consider because it is undoubtedly something that will need to be analyzed, evaluated, and managed in the coming months.&lt;/p&gt;



&lt;p&gt;Helm 4.0 represents a major milestone in Kubernetes package management. For a complete understanding of Helm from basics to advanced features, explore our .&lt;/p&gt;



&lt;p&gt;Due to this, we will see many comments and articles around this topic, so we will try to shed some light.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Helm 4.0 Key Features and Improvements&lt;/h2&gt;



&lt;p&gt;According to the project itself in its &lt;a href=&quot;https://helm.sh/es/blog/helm-4-released/&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;announcement&lt;/a&gt;, Helm 4 introduces three major blocks of changes: &lt;strong&gt;new plugin system&lt;/strong&gt;, &lt;strong&gt;better integration with Kubernetes ** and &lt;/strong&gt;internal modernization of SDK and performance**.&lt;/p&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;New Plugin System (includes WebAssembly)&lt;/h3&gt;



&lt;p&gt;The plugin system has been completely redesigned, with a special focus on security through the introduction of a new WebAssembly runtime that, while optional, is recommended as it runs in a &amp;ldquo;sandbox&amp;rdquo; mode that offers limits and guarantees from a security perspective.&lt;/p&gt;



&lt;p&gt;In any case, there is no need to worry excessively, as the &amp;ldquo;classic&amp;rdquo; plugins continue to work, but the message is clear: for security and extensibility, the direction is Wasm.&lt;/p&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;Server-Side Apply and Better Integration with Other Controllers&lt;/h3&gt;



&lt;p&gt;From this version, Helm 4 supports &lt;a href=&quot;https://kubernetes.io/docs/reference/using-api/server-side-apply/&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;Server-Side Apply (SSA)&lt;/a&gt; through the &lt;code&gt;--server-side&lt;/code&gt; flag, which has already become stable since Kubernetes version v1.22 and allows updates on objects to be handled server-side to avoid conflicts between different controllers managing the same resources.&lt;/p&gt;



&lt;p&gt;It also incorporates integration with &lt;a href=&quot;https://pkg.go.dev/sigs.k8s.io/cli-utils/pkg/kstatus/status&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;kstatus&lt;/a&gt; to ensure the state of a component in a more reliable way than what currently happens with the use of the &lt;code&gt;--wait&lt;/code&gt; parameter.&lt;/p&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Other Additional Improvements&lt;/h2&gt;



&lt;p&gt;Additionally, there is another list of improvements that, while of lesser scope, are important qualitative leaps, such as the following:&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;Installation by digest&lt;/strong&gt; in OCI registries: (&lt;code&gt;helm install myapp oci://...@sha256:&amp;lt;digest&amp;gt;&lt;/code&gt;)&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Multi-document values&lt;/strong&gt;: you can pass multiple YAML values in a single multi-doc file, facilitating complex environments/overlays.&lt;/li&gt;



&lt;li&gt;New &lt;code&gt;--set-json&lt;/code&gt; argument that allows for easily passing complex structures compared to the current solution using the &lt;code&gt;--set&lt;/code&gt; parameter&lt;/li&gt;
&lt;/ul&gt;



&lt;h2 class=&quot;wp-block-heading&quot;&gt;Why a Major (v4) and Not Another Minor of 3.x?&lt;/h2&gt;



&lt;p&gt;As explained in the &lt;a href=&quot;https://helm.sh/es/blog/helm-4-released/&quot; target=&quot;_blank&quot; rel=&quot;noopener nofollow&quot;&gt;official release post&lt;/a&gt;, there were features that the team could not introduce in v3 without breaking public SDK APIs and internal architecture:&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Strong change in the &lt;strong&gt;plugin system&lt;/strong&gt; (WebAssembly, new types, deep integration with the core).&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Restructuring of Go packages&lt;/strong&gt; and establishment of a &lt;strong&gt;stable SDK at&lt;/strong&gt; &lt;strong&gt;helm.sh/helm/v4&lt;/strong&gt;, code-incompatible with v3.&lt;/li&gt;



&lt;li&gt;Introduction and future evolution of &lt;strong&gt;Charts v3&lt;/strong&gt;, which require the SDK to support multiple versions of chart APIs.&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;With all this, continuing in the 3.x branch would have violated SemVer: the major number change is basically &amp;ldquo;paying&amp;rdquo; the accumulated technical debt to be able to move forward.&lt;/p&gt;



&lt;p&gt;Additionally, a new evolution of the charts is expected in the future, moving from v2 to a future v3 that is not yet fully defined, and currently, v2 charts run correctly in this new version.&lt;/p&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;Is Helm 4.0 Migration Required?&lt;/h3&gt;



&lt;p&gt;The short answer is: yes. And possibly the long answer is: yes, and quickly. In the official Helm 4 announcement, they specify the support schedule for Helm 3:&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;&lt;strong&gt;Helm 3 bug fixes until July 8, 2026.&lt;/strong&gt;&lt;/li&gt;



&lt;li&gt;&lt;strong&gt;Helm 3 security fixes until November 11, 2026.&lt;/strong&gt;&lt;/li&gt;



&lt;li&gt;No new features will be backported to Helm 3 during this period; only Kubernetes client libraries will be updated to support new K8s versions.&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;Practical translation:&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Organizations have approximately 1 year to plan a smooth Helm 4.0 migration with continued bug support for Helm 3.&lt;/li&gt;



&lt;li&gt;After November 2026, continuing to use Helm 3 will become increasingly risky from a security and compatibility standpoint.&lt;/li&gt;
&lt;/ul&gt;



&lt;h3 class=&quot;wp-block-heading&quot;&gt;Best Practices for Migration&lt;/h3&gt;



&lt;p&gt;To carry out the migration, it is important to remember that it is perfectly possible and feasible to have both versions installed on the same machine or agent, so a &amp;ldquo;gradual&amp;rdquo; migration can be done to ensure that the end of support for version v3 is reached with everything migrated correctly, and for that, the following steps are recommended:&lt;/p&gt;



&lt;ul class=&quot;wp-block-list&quot;&gt;
&lt;li&gt;Conduct an analysis of all Helm commands and usage from the perspective of integration pipelines, upgrade scripts, or even the import of Helm client libraries in Helm-based developments.&lt;/li&gt;



&lt;li&gt;Especially carefully review all uses of &lt;code&gt;--post-renderer&lt;/code&gt;, &lt;code&gt;helm registry login&lt;/code&gt;, &lt;code&gt;--atomic&lt;/code&gt;, &lt;code&gt;--force&lt;/code&gt;.&lt;/li&gt;



&lt;li&gt;After the analysis, start testing Helm 4 first in &lt;strong&gt;non-production environments&lt;/strong&gt;, reusing the same charts and values, reverting to Helm 3 if a problem is detected until it is resolved.&lt;/li&gt;



&lt;li&gt;If you have critical plugins, explicitly test them with Helm 4 before making the global change.&lt;/li&gt;
&lt;/ul&gt;



&lt;div id=&quot;rank-math-faq&quot; class=&quot;rank-math-block&quot;&gt;
&lt;div class=&quot;rank-math-list&quot;&gt;
&lt;div id=&quot;faq-question-1769293360&quot; class=&quot;rank-math-list-item&quot;&gt;
&lt;h3 class=&quot;rank-math-question&quot;&gt;What are the main new features in Helm 4.0?&lt;/h3&gt;
&lt;div class=&quot;rank-math-answer&quot;&gt;
&lt;p&gt;Helm 4.0 introduces three major improvements: a redesigned &lt;strong&gt;plugin system with WebAssembly support&lt;/strong&gt; for enhanced security, &lt;strong&gt;Server-Side Apply (SSA)&lt;/strong&gt; integration for better conflict resolution, and &lt;strong&gt;internal SDK modernization&lt;/strong&gt; for improved performance. Additional features include OCI digest installation and multi-document values support.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;faq-question-1769293361&quot; class=&quot;rank-math-list-item&quot;&gt;
&lt;h3 class=&quot;rank-math-question&quot;&gt;When does Helm 3 support end?&lt;/h3&gt;
&lt;div class=&quot;rank-math-answer&quot;&gt;
&lt;p&gt;Helm 3 &lt;strong&gt;bug fixes end July 8, 2026&lt;/strong&gt; and &lt;strong&gt;security fixes end November 11, 2026&lt;/strong&gt;. No new features will be backported to Helm 3. Organizations should plan migration to Helm 4.0 before November 2026 to avoid security and compatibility risks.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;faq-question-1769293362&quot; class=&quot;rank-math-list-item&quot;&gt;
&lt;h3 class=&quot;rank-math-question&quot;&gt;Are Helm 3 charts compatible with Helm 4.0?&lt;/h3&gt;
&lt;div class=&quot;rank-math-answer&quot;&gt;
&lt;p&gt;Yes, &lt;strong&gt;Helm Chart API v2 charts work correctly&lt;/strong&gt; with Helm 4.0. However, the Go SDK has breaking changes, so applications using Helm libraries need code updates. The CLI commands remain largely compatible for most use cases.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;faq-question-1769293363&quot; class=&quot;rank-math-list-item&quot;&gt;
&lt;h3 class=&quot;rank-math-question&quot;&gt;Can I run Helm 3 and Helm 4 simultaneously?&lt;/h3&gt;
&lt;div class=&quot;rank-math-answer&quot;&gt;
&lt;p&gt;Yes, both versions can be installed on the same machine, enabling &lt;strong&gt;gradual migration strategies&lt;/strong&gt;. This allows teams to test Helm 4.0 in non-production environments while maintaining Helm 3 for critical workloads during the transition period.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;faq-question-1769293364&quot; class=&quot;rank-math-list-item&quot;&gt;
&lt;h3 class=&quot;rank-math-question&quot;&gt;What should I test before migrating to Helm 4.0?&lt;/h3&gt;
&lt;div class=&quot;rank-math-answer&quot;&gt;
&lt;p&gt;Focus on testing &lt;strong&gt;critical plugins, post-renderers, and specific flags&lt;/strong&gt; like &lt;code&gt;--atomic&lt;/code&gt;, &lt;code&gt;--force&lt;/code&gt;, and &lt;code&gt;helm registry login&lt;/code&gt;. Test all charts and values in non-production environments first, and review any custom integrations using Helm SDK libraries.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div id=&quot;faq-question-1769293365&quot; class=&quot;rank-math-list-item&quot;&gt;
&lt;h3 class=&quot;rank-math-question&quot;&gt;What is Server-Side Apply in Helm 4.0?&lt;/h3&gt;
&lt;div class=&quot;rank-math-answer&quot;&gt;
&lt;p&gt;Server-Side Apply (SSA) is enabled with the &lt;code&gt;--server-side&lt;/code&gt; flag and handles resource updates on the Kubernetes API server side. This &lt;strong&gt;prevents conflicts between different controllers&lt;/strong&gt; managing the same resources and has been stable since Kubernetes v1.22.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;

</description>
<category>Other</category>
<guid isPermaLink="true">https://coderlegion.com/11558/helm-4-0-features-breaking-changes-migration-guide-2025</guid>
<pubDate>Fri, 13 Feb 2026 11:03:08 +0000</pubDate>
</item>
<item>
<title>Data Analysis -  Basic Visualizations</title>
<link>https://coderlegion.com/9377/data-analysis-basic-visualizations</link>
<description>&lt;p&gt;Building on the concepts from our post on &quot;Descriptive Statistics,&quot; we will now explore the most common charts for data visualization: &lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/en/posts/descriptive-analysis/&quot;&gt;&quot;Descriptive Statistics&quot;&lt;/a&gt;, below, we will know the most basic ways to visualize the data or information to be analyzed. Specifically:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#pie_chart&quot;&gt;Pie chart&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#line_chart&quot;&gt;Line chart&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#hierarchical_graphs&quot;&gt;Treemap &amp;amp; Subburst&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#histograms&quot;&gt;Histograms &amp;amp; Bar charts&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#density_plot&quot;&gt;Density plot&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#boxplot&quot;&gt;Boxplots&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#violin_plot&quot;&gt;Violin plots&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#scatter_plot&quot;&gt;Scatter plots&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;#pareto_chart&quot;&gt;Pareto chart&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;Note: All the examples (except for the line graphs due to its features) are based on the train.csv dataset file, which is a subset of 891 representative individuals of the population of the Titanic used for the training of models of Machine Learning.&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;pie-charts&quot;&gt;&lt;a name=&quot;pie_chart&quot;&gt;&lt;/a&gt;Pie charts&lt;/h3&gt;
&lt;p&gt;Pie charts are useful to represent the numerical proportions of the values of the data of a variable or feature with respect to its total. This type of graphs present a vast catalogue of variants and are widely used due to their simplicity of preparation and interpretation. However, these charts are often overused and misused. For more on this topic, see this excellent article on why pie charts are so controversial &lt;a rel=&quot;nofollow&quot; href=&quot;https://medium.com/@clmentviguier/the-hate-of-pie-charts-harms-good-data-visualization-cc7cfed243b6&quot;&gt;about the right use of pie charts and why these charts are so hated&lt;/a&gt;).&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Example: Proportions of Titanic passengers by socioeconomic status&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; &lt;img src=&quot;https://datalaria.com/en/posts/basic-visualizations/pie_chart.png&quot; alt=&quot;Pie_chart&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;line-charts&quot;&gt;&lt;a name=&quot;line_chart&quot;&gt;&lt;/a&gt;Line charts&lt;/h3&gt;
&lt;p&gt;Line charts are ideal for displaying how a variable changes over a continuous interval, such as time. Generally, they are used to represent trends or relationships (in a group with more variables) between the data during a continuous time interval.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Note: In order to visualize a use case in a continuous time interval, the following dataset from the Open data initiative of the Government of Spain has been used [the population data by Autonomous Communities from 1997 to 2017.](&lt;a rel=&quot;nofollow&quot; href=&quot;https://datos.gob.es/es/catalogo/ea0010587-poblacion-por-comunidades-y-ciudades-autonomas-y-tamano-de-los-municipios-anual-comunidades-&quot;&gt;https://datos.gob.es/es/catalogo/ea0010587-poblacion-por-comunidades-y-ciudades-autonomas-y-tamano-de-los-municipios-anual-comunidades-&lt;/a&gt; autonomas-official-figures-of-population-of-the-Spanish-municipalities-revision-of-padron-municipal-identifier-api-2915) *&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Example: Spanish population since 1997&lt;br&gt;
&lt;img src=&quot;https://datalaria.com/en/posts/basic-visualizations/line_graph_1.png&quot; alt=&quot;Line_graph_1&quot;&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Example: Spanish population by Autonomous Communities since 1997&lt;br&gt;
 &lt;img src=&quot;https://datalaria.com/en/posts/basic-visualizations/line_graph_2.png&quot; alt=&quot;Line_graph_2&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;treemaps-amp-sunbursts&quot;&gt;&lt;a name=&quot;hierarchical_graphs&quot;&gt;&lt;/a&gt;Treemaps &amp;amp; Sunbursts&lt;/h3&gt;
&lt;p&gt;Treemaps and sunburst graphs are visualizations to represent hierarchical data and summarize the information in areas proportional to the corresponding values.&lt;/p&gt;
&lt;p&gt;In the case of treemaps, the representation consists of rectangles with an area proportional to the value of the corresponding data with respect to the total.&lt;br&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Example: Proportion of passengers according to their socioeconomic status classified by gender (treemap)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; &lt;img src=&quot;https://datalaria.com/en/posts/basic-visualizations/treemap.png&quot; alt=&quot;Treemap&quot;&gt;&lt;/p&gt;
&lt;p&gt;In the case of sunburst, the representation consists groups of rings according to the level represented, which are divided into proportional sections corresponding to the value of the data they represent.&lt;br&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Example: Proportion of passengers according to their socioeconomic status classified by gender (sunburst)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; &lt;img src=&quot;https://datalaria.com/en/posts/basic-visualizations/sunburst.png&quot; alt=&quot;Sunburst&quot;&gt;&lt;/p&gt;
&lt;p&gt;On the example represented, you can quickly see information about the hierarchical data represented as for example that the number of male passengers was almost 2 / 3 of the crew, as well as that male passengers and low socioeconomic status represented something more than 1 / 3 of the crew.&lt;/p&gt;
&lt;h3 id=&quot;histograms-amp-bar-charts&quot;&gt;&lt;a name=&quot;histograms&quot;&gt;&lt;/a&gt;Histograms &amp;amp; Bar charts&lt;/h3&gt;
&lt;p&gt;Looking over the information already collected in the post &lt;a rel=&quot;nofollow&quot; href=&quot;https://datalaria.com/en/posts/descriptive-analysis/&quot;&gt;&quot;Descriptive Statistics&quot;&lt;/a&gt;, where these two type of representations widely used in data analysis are explained, we can check that their main objective is to represent the distribution of the data with respect to a variable or characteristic of the dataset. Thus, the histograms allow to visualize continuous data and the bar diagrams represent discrete data.&lt;br&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Example: Passenger distribution by price of the ticket&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; &lt;img src=&quot;https://datalaria.com/en/posts/basic-visualizations/histogram.png&quot; alt=&quot;Histogram&quot;&gt;&lt;br&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Example: Passenger distribution by socioeconomic status&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; &lt;img src=&quot;https://datalaria.com/en/posts/basic-visualizations/bar_chart.png&quot; alt=&quot;Bar_chart&quot;&gt;&lt;/p&gt;
&lt;p&gt;As we saw in the post &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.datalaria.com/en/post/fundamentos/2018-10-07-estadistica-descriptiva/&quot;&gt;&quot;Descriptive Statistics&quot;&lt;/a&gt;, representing on these graphs measures of descriptive statistics (such as the mean or the median), we can characterize the distribution of the variable under analysis and thereby extract more information about it.&lt;/p&gt;
&lt;h3 id=&quot;density-plot&quot;&gt;&lt;a name=&quot;density_plot&quot;&gt;&lt;/a&gt;Density plot&lt;/h3&gt;
&lt;p&gt;As known as Kernel density plots, they serve to visualize the distribution of data in a continuous interval. This type of graphics is a variation of the histograms where the shape of the distribution is smoothly represented.&lt;br&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Example: Distribution of the age of Titanic passengers  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; &lt;img src=&quot;https://datalaria.com/en/posts/basic-visualizations/density_plot.png&quot; alt=&quot;Density_plot&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;boxplots&quot;&gt;&lt;a name=&quot;boxplot&quot;&gt;&lt;/a&gt;Boxplots&lt;/h3&gt;
&lt;p&gt;The boxplots or whisker plots serve to represent a variable or characteristic depending on its range and its quartiles.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: The quartiles are the values that divide a list of ordered numbers into 4 parts in equal percentages&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The boxplot consists of a box that includes the data from the first quartile (Q1 - 25% of the data under it) to the third quartile (Q3 - 75% of the data under it) of the values of the variable represented (Interquartile Range - IQR). Within said box, the median is represented with an horizontal line and optionally, the average is represented by an asterisk or a star.&lt;/p&gt;
&lt;p&gt;In addition to the box, this plot also shows 2 horizontal lines (or &quot;fences&quot;) that represent the maximum and minimum typical values of our variable, and from which the outliers of the distribution are visualized using points.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Statistical note: The outliers are those that are numerically distant from the rest of the data of the variable. Taking the Interquartile Range (IQR), outliers are considered those that are below Q1 - 1.5 IQR or above Q3 + 1.5 IQR.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Example: Distribution of Titanic passengers by age&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; &lt;img src=&quot;https://datalaria.com/en/posts/basic-visualizations/boxplot.png&quot; alt=&quot;Boxplot&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;violin-plots&quot;&gt;&lt;a name=&quot;violin_plot&quot;&gt;&lt;/a&gt;Violin plots&lt;/h3&gt;
&lt;p&gt;Violin plots are used to visualize simultaneously the distribution of the data and its probability density. These visual graphs consist of a combination of a boxplot and a density plot. In this plot, the Intercuartile range is represented by a thick black line or small box, the typical data are represented with a thin black line and the median is visualized with a white point.&lt;br&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Example: Distribution and density of Titanic passengers by age&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; &lt;img src=&quot;https://datalaria.com/en/posts/basic-visualizations/violin_plot.png&quot; alt=&quot;Violin_plot&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;scatter-plots&quot;&gt;&lt;a name=&quot;scatter_plot&quot;&gt;&lt;/a&gt;Scatter plots&lt;/h3&gt;
&lt;p&gt;Scatter plots consist of visualizations that show the relationship of 2 variables of a dataset on two Cartesian axes. They are quite useful since they allow extracting information about the correlation between these variables.&lt;br&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Example: Representation of ticket price by age and gender of the passenger&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; &lt;img src=&quot;https://datalaria.com/en/posts/basic-visualizations/scatter_plot.png&quot; alt=&quot;Scatter_plot&quot;&gt;&lt;/p&gt;
&lt;h3 id=&quot;pareto-charts&quot;&gt;&lt;a name=&quot;pareto_chart&quot;&gt;&lt;/a&gt;Pareto charts&lt;/h3&gt;
&lt;p&gt;The Pareto charts serve to visually represent those distributions or datasets related to the Pareto principle or the 80 / 20 rule.&lt;br&gt;
Pareto principle: also known as the 80 / 20 rule, establishes that generally in a dataset related by a cause-effect relationship, approximately 80% of the results or consequences come from 20% of the causes.&lt;br&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Example: Representation of income data for tickets sold for the socioeconomic status&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; &lt;img src=&quot;https://datalaria.com/en/posts/basic-visualizations/pareto_chart_1.png&quot; alt=&quot;Pareto_chart&quot;&gt;  &lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Example: Representation of income data for tickets sold for passengers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; &lt;img src=&quot;https://datalaria.com/en/posts/basic-visualizations/pareto_chart_2.png&quot; alt=&quot;Pareto_chart_2&quot;&gt;&lt;/p&gt;
&lt;p&gt;Regarding the example, we can see the usefulness of this graph given that it is quickly visualized that 90% of the ticket sales revenues of the Titanic come from tickets sold to passengers of high socioeconomic status. Or in a more detailed way about the second graph, approximately 80% of the revenue from ticket sales came from ~ 20% of the crew's passengers.&lt;br&gt;
&lt;/p&gt;
&lt;h5 id=&quot;sources-of-interest-&quot;&gt;Sources of interest:&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;Kaggle – &lt;a rel=&quot;nofollow&quot; href=&quot;https://www.kaggle.com/c/titanic&quot;&gt;Titanic Machine Learning from Disaster&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Open data initiative of the Government of Spain – &lt;a rel=&quot;nofollow&quot; href=&quot;https://datos.gob.es/en&quot;&gt;datos.gob.es&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Medium (Clément Viguier) – &lt;a rel=&quot;nofollow&quot; href=&quot;https://medium.com/@clmentviguier/the-hate-of-pie-charts-harms-good-data-visualization-cc7cfed243b6&quot;&gt;The hate of pie charts harms good data visualization...&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Course &lt;em&gt;“&lt;a rel=&quot;nofollow&quot; href=&quot;https://courses.edx.org/courses/course-v1:Microsoft+DAT222x+1T2017/course/&quot;&gt;Essential Statistics for Data Analysis using Excel&lt;/a&gt;”&lt;/em&gt; perteneciente al Microsoft Data Science Program&lt;/li&gt;
&lt;li&gt;The Data Visualisation Catalogue - &lt;a rel=&quot;nofollow&quot; href=&quot;https://datavizcatalogue.com/index.html&quot;&gt;The Data Visualisation Catalogue&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/9377/data-analysis-basic-visualizations</guid>
<pubDate>Wed, 07 Jan 2026 20:55:59 +0000</pubDate>
</item>
</channel>
</rss>