<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title><![CDATA[Vincent du Sordet - Elastic Observability Labs]]></title>
    <description><![CDATA[Trusted security news & research from the team at Elastic.]]></description>
    <copyright><![CDATA[© 2026. Elasticsearch B.V. All Rights Reserved]]></copyright>
    <image>
      <title><![CDATA[Vincent du Sordet - Elastic Observability Labs]]></title>
      <url>https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltad972c1c27dbefc6/6a88d9782904ea5e8511d473/observability-labs-thumbnail.png</url>
      <link>https://www.elastic.co/observability-labs/author/vincent-dusordet</link>
    </image>
    <link>https://www.elastic.co/observability-labs/author/vincent-dusordet</link>
    <atom:link href="https://www.elastic.co/observability-labs/rss/author/vincent-dusordet.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[en]]></language>
    <lastBuildDate>Sat, 26 Sep 2026 01:45:38 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Kibana: How to create impactful visualisations with magic formulas ? (part 1)]]></title>
    <description><![CDATA[We will see how magic math formulas in the Kibana Lens editor can help to highlight high values.]]></description>
    <content:encoded><![CDATA[<h2 id="kibanahowtocreateimpactfulvisualizationswithmagicformulaspart1">Kibana: How to create impactful visualizations with magic formulas? (part 1)</h2>
<h3 id="introduction">Introduction</h3>
<p>In the previous blog post,<a href="https://www.elastic.co/blog/designing-intuitive-kibana-dashboards-as-a-non-designer"> Designing Intuitive Kibana Dashboards as a non-designer</a>, we highlighted the importance of creating intuitive dashboards. It demonstrated how simple changes (grouping themes, changing type charts, and more) can make a difference in understanding your data. When delivering courses like<a href="https://www.elastic.co/training/data-analysis-with-kibana"> Data Analysis with Kibana</a> or<a href="https://www.elastic.co/training/elastic-observability-engineer"> Elastic Observability Engineer</a> courses, we emphasize this blog post and how these changes help bring essential information to the surface. I like a complementary approach to reach this goal: using two colors to separate the highest data values from the common ones.</p>
<p>To illustrate this idea, we will use the <em>Sample flight data</em> dataset. Now, let’s compare two visualizations ranking the top 10 destination countries per total number of flights. Which visualization has a higher impact?</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt8828b919cb5c544d/6a9fb62c075f974b623e3a1c/blog-1-dbg-excalidraw-flights-teaser-intro-dark.png" alt="Flights: Top 10 destinations" /></p>
<p>If you chose the second one, you may be wondering how this was done with the Kibana Lens editor. While preparing for the certification last year, I found a way to achieve this result. The secret is using two different layers and some magic formulas. This post will explain how math in Lens formulas helps create two data-color visualizations.  </p>
<p>We will start with the first example that emphasizes only the highest value of the dataset we are focusing on. The second example describes how to highlight other high values (as shown in the illustration above).</p>
<p><em>[Note: the tips explained in this blog post can be applied from v 7.15]</em></p>
<h2 id="onlythehighestvalueaidonlythehighestvaluea">Only the highest value<a id="only-the-highest-value"></a></h2>
<p>To understand how math helps to separate high values from common ones, let’s start with this first example: emphasizing only the highest value.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blte079be42d799346f/6a7f0b7dc2cc099dce2494e0/blog-1-wbg-flights-1.1-teaser.png" alt="1.1 flights: " /></p>
<p>We start with a bar horizontal chart:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc6d00c95b801b771/6a7f0b8073d9bdf96429da89/blog-1-wbg-flights-1.1-kibana-bar-horizontal-setup.png" alt="1.1 flights: Lens bar horizontal chart" /></p>
<p>We need to identify the highest value of the scope we are currently examining. We will use one proper overall_* function: the <strong>overall_max()</strong>, a pipeline function (equivalent to a pipeline aggregation in Query DSL). </p>
<p>In our example, we group the flights by country(destination). This means we count the number of flights for each DestCountry (= 1 bucket). The <strong>overall_max()</strong> will select which bucket has the highest value. </p>
<p>The math trick here is to divide the number of flights per bucket by the maximum value found among all buckets. Only one bucket will return 1: the bucket matching the max value found by overall_max(). All the other buckets will return a value &lt; 1 and &gt;0. We use <strong>floor()</strong> to ensure any 0.xxx values are rounded to 0. </p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltb6b32d7d95edc90c/6a7f0b83c2cc0903c12494e4/blog-1-wbg-flights-1.1-explaination-floor.png" alt="1.1 flights: explaining floor()" /></p>
<p>Now, we can multiple it with a count() and we have our formula for the 1st layer!</p>
<p><strong><em>Layer 1</em></strong>: <code>count()*floor(count()/overall_max(count()))</code></p>
<p>From here, in Lens Editor, we duplicate the layer to adjust the formula of the second layer containing the rest of the data. We need to append another count() followed by the minus operator to the formula. This is the other trick. In this layer, we just need to ensure the highest value is not represented, which will happen only once. It is when count() = overall_max(), which is = 1 when we divide them.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt20522989d7bc223f/6a7f0b86b6b734f2cce48d5a/blog-1-wbg-flights-1.1-explaination-layer1-and-layer2.png" alt="1.1 flights: layer 1 + layer 2" /></p>
<p><strong><em>Layer 2</em></strong>: <code>count() - count()*floor(count()/overall_max(count()))</code></p>
<p>To achieve a nice merge of these two layers, we need to do the following adjustments in both:</p>
<ul>
<li><p>select <strong>bar horizontal stacked</strong></p></li>
<li><p>Vertical axis: change”Rank by” to Custom and ensure Rank function is “Count”</p></li>
</ul>
<p>Here is the final setup of the two layers:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9e00af474f98371d/6a7f0b8b05b7b54ef718b8b8/blog-1-wbg-flights-1.1-kibana-final-2layers-setup.png" alt="1.1 flights: 2layers setup" /></p>
<p><strong><em>Layer 1</em></strong>: <code>count()*floor(count()/overall_max(count()))</code></p>
<p><strong><em>Layer 2</em></strong>: <code>count() - count()*floor(count()/overall_max(count()))</code></p>
<p>This visualization also works well for time series data where you need to quickly highlight which time period (12h in the example below) had the highest number of flights:\
<img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt60d2ac3d1eb5c192/6a7f0b8d1967ea25e43306ad/blog-1-wbg-flights-1.1-timeserie-example.png" alt="1.1 flights: timeseries example" /></p>
<h2 id="abovethesurfaceaidabovethesurfacea">Above the surface<a id="above-the-surface"></a></h2>
<p>Building on what we have done earlier, we can extend the approach to get other high values above the surface. Let’s see which formula we used to create the visualization in the introduction:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt21d0e28d38824262/6a9fb68dccc7d12125a15181/blog-1-dbg-excalidraw-flights-teaser-intro-s1-dark.png" alt="2.1 Flights: Top 10 destinations" /></p>
<p>For this visualization, we used a property of the <strong>round()</strong> function. This function brings in only the values greater than 50% of the highest value.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt80275d7b0c0a1b95/6a7f0b93ead8ec2cb6baa7df/blog-1-wbg-flights-2.1-explaination-round.png" alt="2.1 flights: round() &gt; 50% of max explanation" />
</p><p>Let's duplicate our first visualization and swap out the floor() function with round().</p>
<p><strong><em>Layer 1</em></strong>: <code>count()*round(count()/overall_max(count()))</code></p>
<p><strong><em>Layer 2</em></strong>: <code>count() - count()*round(count()/overall_max(count()))</code></p>
<p>It was an easy fix.\
What if we want to extend the first layer further by adding more high values?\
For instance, we would like all the values above the average.</p>
<p>To do this, we use <strong>overall_average</strong>() as a new reference value instead of the overall_max () reference to separate the eligible values in Layer 1.</p>
<p>As we are comparing against the average value among all the buckets, the division might return values greater than 1.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt92d64a7a432beacd/6a7f0b969090b0d4c084e94d/blog-1-wbg-flights-2.2-explaination-floor.png" alt="2.2 flights: round() explanation" /></p>
<p>Here, the <strong>clamp</strong>() function nicely solves this issue. </p>
<p>According to the formula reference, clamp() "limits the value from a minimum to maximum". Combining clamp() and floor() ensures that there are only two possible output values: either the minimum value ( 0 ) or the maximum value ( 1 ) given as parameters.</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt225dd2f7ba60125d/6a7f0b99c2cc096da42494ee/blog-1-wbg-flights-2.2-explaination-clamp.png" alt="2.2 flights: clamp() explanation" /></p>
<p>Applied to our flights dataset, it highlights the country destinations that have more flights than the average:</p>
<p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt19fae0da63280f51/6a9fb72236a741330227454a/blog-1-dbg-excalidraw-flights-2.png" alt="2.2 flights: above the overall average " /></p>
<p><strong><em>Layer 1</em></strong>: <code>count()*clamp(floor(count()/overall_average(count())),0,1)</code></p>
<p><strong><em>Layer 2</em></strong>: <code>count() - count()*clamp(floor(count()/overall_average(count())),0,1)</code></p>
<p>It also opens up options for using other dynamic references. For instance, we could place all the values greater than 60% of the highest above the surface ( &gt; <code>0.6*overall_max(count())</code>). 
We can tune our formula as follow: </p>
<pre><code>count()*clamp(floor(count()/(0.6*overall_max(count()) ) ),0,1)
</code></pre>
<h2 id="conclusionaidconclusiona">Conclusion<a id="conclusion"></a></h2>
<p>In the first part, we have seen the main tips allowing us to create a two-color histogram:</p>
<ul>
<li><p>Two layers: one for the highest value and one for the remaining values</p></li>
<li><p>Visualization type: bar horizontal/vertical <strong>stacked</strong></p></li>
<li><p>To separate the data we use a formula where only the highest value return 1 otherwise 0</p></li>
</ul>
<p> </p>
<p>Then in the second part, we have seen how we can extend this principle to embrace more high values above the surface. This approach can be summarized as follows:</p>
<ul>
<li><p>Start with layer 1 focusing on the high value: count()*\</p></li>
<li><p>Duplicate the layer and adjust the formula:\
 ( count() - count()*\)</p></li>
</ul>
<p>Finally, we provide 4 generic formulas that are ready to use to spice up your dashboards:</p>
<p>|                         |                                                         |
| ----------------------- | :-----------------------------------------------------: |
| <strong>1. Only the highest</strong> |                                                         |
| Layer 1                 |      <code>count()*floor(count()/overall_max(count()))</code>      |
| Layer 2                 | <code>count() - count()*floor(count()/overall_max(count()))</code> |</p>
<p>|                                                                       |                                                         |
| --------------------------------------------------------------------- | :-----------------------------------------------------: |
| <strong>2.1. Above the surface :</strong> high values (above 50% of the max value) |                                                         |
| Layer 1                                                               |      <code>count()*floor(count()/overall_max(count()))</code>      |
| Layer 2                                                               | <code>count() - count()*floor(count()/overall_max(count()))</code> |</p>
<p>|                                                                   |                                                                        |
| ----------------------------------------------------------------- | :--------------------------------------------------------------------: |
| <strong>2.2. Above the surface :</strong> all values above the overall average |                                                                        |
| Layer 1                                                           |      <code>count()*clamp(floor(count()/overall_average(count())),0,1)</code>      |
| Layer 2                                                           | <code>count() - count()*clamp(floor(count()/overall_average(count())),0,1)</code> |</p>
<p>|                                                                             |                                                                            |
| --------------------------------------------------------------------------- | :------------------------------------------------------------------------: |
| <strong>2.2. Above the surface :</strong> all the values greater than 60% of the highest |                                                                            |
| Layer 1                                                                     |      <code>count()*clamp(floor(count()/(0.6*overall_max(count()) ) ),0,1)</code>      |
| Layer 2                                                                     | <code>count() - count()*clamp(floor(count()/(0.6*overall_max(count()) ) ),0,1)</code> |</p>
<p>Try these examples out for yourself by signing up for a <a href="https://cloud.elastic.co/registration?elektra=10-common-questions-kibana-blog">free trial of Elastic Cloud</a> or <a href="https://www.elastic.co/downloads/">download</a> the self-managed version of the Elastic Stack for free. If you have additional questions about getting started, head on over to the <a href="https://discuss.elastic.co/c/elastic-stack/kibana/7">Kibana forum</a> or check out the <a href="https://www.elastic.co/guide/en/kibana/current/index.html">Kibana documentation guide</a>.\
In the next blog post, we will see how the new function <strong>ifelse</strong>() (introduced in version 8.6) will greatly simplify the creation of visualizations with more advanced formulas.</p>
<p><strong>References</strong>:</p>
<ul>
<li><p><a href="https://www.elastic.co/blog/designing-intuitive-kibana-dashboards-as-a-non-designer">Designing intuitive Kibana dashboards as a non-designer</a></p></li>
<li><p><a href="https://www.elastic.co/guide/en/kibana/current/lens.html#lens-formulas">Kibana: Lens editor - use formula to perform math</a></p></li>
<li><p>Discovering the clamp() function <a href="https://discuss.elastic.co/t/if-condition-in-kibana-table-visualization/305751/5">in this discussion (Thanks Marco!)</a></p></li>
</ul>]]></content:encoded>
    <link>https://www.elastic.co/observability-labs/blog/kibana-impactful-visualizations-with-magic-formulas-part1</link>
    <guid isPermaLink="false">kibana-impactful-visualizations-with-magic-formulas-part1</guid>
    <category><![CDATA[Logs Analytics]]></category>
    <dc:creator><![CDATA[Vincent du Sordet]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt304c4355847436f4/6a7f0b9f77b0342b673ff43d/kibana-magic-formulas-p1.png" length="0" type="image/png"/>
    <pubDate>Mon, 09 Sep 2024 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>