<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: LIN Chen</title>
    <description>The latest articles on DEV Community by LIN Chen (@entronad).</description>
    <link>https://dev.to/entronad</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F816218%2Fcf6e0576-b13c-4e05-81c3-504cf739f52a.jpeg</url>
      <title>DEV Community: LIN Chen</title>
      <link>https://dev.to/entronad</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/entronad"/>
    <language>en</language>
    <item>
      <title>How to Build Interactive Charts in Flutter</title>
      <dc:creator>LIN Chen</dc:creator>
      <pubDate>Tue, 01 Nov 2022 00:54:59 +0000</pubDate>
      <link>https://dev.to/entronad/how-to-build-interactive-charts-in-flutter-eb2</link>
      <guid>https://dev.to/entronad/how-to-build-interactive-charts-in-flutter-eb2</guid>
      <description>&lt;p&gt;Interactions are always important in data visualization. The Flutter charting library &lt;a href="https://github.com/entronad/graphic"&gt;Graphic&lt;/a&gt; has a well-designed interaction system for various interactive charts.&lt;/p&gt;

&lt;p&gt;This system is built on several concepts, and when you leant these concepts you will find it's quite easy and flexible to handle interactions in &lt;a href="https://github.com/entronad/graphic"&gt;Graphic&lt;/a&gt;. Some of the concepts are novel, but intuitive and easy to understand.&lt;/p&gt;

&lt;p&gt;This article will introduce these concepts to help you build interactive charts in Flutter with &lt;a href="https://github.com/entronad/graphic"&gt;Graphic&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Gesture
&lt;/h1&gt;

&lt;p&gt;As a touch-first GUI framework, interactions in Flutter is based on gestures.&lt;/p&gt;

&lt;p&gt;There are two layers of the gesture system. The first layer has raw pointer events that describe the location and movement of pointers (for example, touches, mice, and styli) across the screen.The second layer has &lt;em&gt;gestures&lt;/em&gt; that describe semantic actions that consist of one or more pointer movements. Note that gestures include not only touches, but also all other pointer kinds on multi-platforms.&lt;/p&gt;

&lt;p&gt;Since &lt;a href="https://github.com/entronad/graphic"&gt;Graphic&lt;/a&gt; is a widget level visualization library, we chose the gestures layer as the foundation for the interaction system. The &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/Gesture-class.html"&gt;Gesture&lt;/a&gt; class carries information about a gesture. It is mainly used in &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/GestureSignal-class.html"&gt;GestureSignal&lt;/a&gt;s.&lt;/p&gt;

&lt;p&gt;The widely used widget that handles gestures in Flutter is the &lt;a href="https://api.flutter.dev/flutter/widgets/GestureDetector-class.html"&gt;GestureDetector&lt;/a&gt;. It defines all the gesture types in its callback properties (like &lt;a href="https://api.flutter.dev/flutter/widgets/GestureDetector-class.html"&gt;onTap&lt;/a&gt;), and developers are familiar with them. So &lt;a href="https://github.com/entronad/graphic"&gt;Graphic&lt;/a&gt; inherits this taxonomy. The &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/GestureType.html"&gt;GestureType&lt;/a&gt;s of &lt;a href="https://github.com/entronad/graphic"&gt;Graphic&lt;/a&gt; have same names (without the &lt;code&gt;on&lt;/code&gt; prefix) and meanings to their corresponding callback properties in GestureDetector, such as &lt;code&gt;GestureType.tap&lt;/code&gt; to &lt;code&gt;GestureDetector.onTap&lt;/code&gt;. This keeps &lt;a href="https://github.com/entronad/graphic"&gt;Graphic&lt;/a&gt; consistent with the Flutter gesture system and friendly to developers.&lt;/p&gt;

&lt;h1&gt;
  
  
  Signal
&lt;/h1&gt;

&lt;p&gt;To represent interactions, there are two levels of abstraction: &lt;em&gt;signals&lt;/em&gt; and &lt;em&gt;selections&lt;/em&gt;. These two concepts are referred to Vega, yet there are some differences in &lt;a href="https://github.com/entronad/graphic"&gt;Graphic&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pub.dev/documentation/graphic/latest/graphic/Signal-class.html"&gt;Signal&lt;/a&gt;s are also called "events" in some other systems. They are emitted when users or external changes interact with the chart. They carry information about the interaction. Signals are mainly used in updaters, like &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/RectCoord/horizontalRangeUpdater.html"&gt;RectCoord.horizontalRangeUpdater&lt;/a&gt;, or trigger selections internally.&lt;/p&gt;

&lt;p&gt;Although the same name, signals in &lt;a href="https://github.com/entronad/graphic"&gt;Graphic&lt;/a&gt; have different meaning to &lt;a href="https://vega.github.io/vega/docs/signals/"&gt;signals in Vega&lt;/a&gt;. In Vega, signals are dynamic variables that parameterize a visualization, that means they provide values persistently, whether there are interactions or not. But in &lt;a href="https://github.com/entronad/graphic"&gt;Graphic&lt;/a&gt;, signals are avatars of interactions, so they only occur when triggered and carry the whole information of the interaction, not only a variable value.&lt;/p&gt;

&lt;p&gt;Except the &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/GestureSignal-class.html"&gt;GestureSignal&lt;/a&gt; for user interactions, there are also &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/ChangeDataSignal-class.html"&gt;ChangeDataSignal&lt;/a&gt; and &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/ResizeSignal-class.html"&gt;ResizeSignal&lt;/a&gt; for the external changes that effects the chart, which are also "interactions" in a broad sense.&lt;/p&gt;

&lt;p&gt;Internally, different signals, no matter its kind or emitter, will be broadcasted by a reducer to all signal updaters. This makes developers unconstrained to decide which signal the updater will respond to.&lt;/p&gt;

&lt;h1&gt;
  
  
  Selection
&lt;/h1&gt;

&lt;p&gt;A &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/Selection-class.html"&gt;selection&lt;/a&gt; is a data query driven by gestures. They are the result of signals. When a selection is triggered, data tuples become either selected or unselected states, thus may causing their aesthetic attributes change if &lt;code&gt;Attr.onSelection&lt;/code&gt; is defined.&lt;/p&gt;

&lt;p&gt;The rules of selections in &lt;a href="https://github.com/entronad/graphic"&gt;Graphic&lt;/a&gt; are mainly from &lt;a href="https://vega.github.io/vega-lite/docs/selection.html"&gt;selections in Vega-Lite&lt;/a&gt;, so there are &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/IntervalSelection-class.html"&gt;IntervalSelection&lt;/a&gt; and &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/PointSelection-class.html"&gt;PointSelection&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Unlike most other visualization libraries, a selection in &lt;a href="https://github.com/entronad/graphic"&gt;Graphic&lt;/a&gt; is tested in data value space, not by graphical shape intersections. The pointer coordinates will be inverted into data values in each dimension, and these values will be searched in data list to find the results. This approach is more "data-driven" and performs better than shape intersection test in big data.&lt;/p&gt;

&lt;p&gt;Generally speaking, signals are raw and more flexible to use, while selections are more concise and focus on the data domain.&lt;/p&gt;

&lt;h1&gt;
  
  
  Updater
&lt;/h1&gt;

&lt;p&gt;In &lt;a href="https://github.com/entronad/graphic"&gt;Graphic&lt;/a&gt;, the basic idea of how interactions affect the chart is that they do not provide values to the chart directly, instead, they update existing property values in the chart and cause a reactive rendering. The calculation of property value and updating are in different operators, and the initial value (usually indicated in the specification) will be kept:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--toOkrOuv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uaur229zlkxw5we2v2pi.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--toOkrOuv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uaur229zlkxw5we2v2pi.jpg" alt="Image description" width="455" height="207"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Updaters are callback functions to update property values according to interactions, like &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/RectCoord/horizontalRangeUpdater.html"&gt;RectCoord.horizontalRangeUpdater&lt;/a&gt; or &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/Attr/updaters.html"&gt;Attr.updaters&lt;/a&gt;. Since there are two kinds of interaction, there are two kinds of updaters correspondingly, &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/SignalUpdater.html"&gt;SignalUpdater&lt;/a&gt; and &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/SelectionUpdater.html"&gt;SelectionUpdater&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SignalUpdater&amp;lt;V&amp;gt; = V Function(
  V initialValue,
  V preValue,
  Signal signal
)

SelectionUpdater&amp;lt;V&amp;gt; = V Function(
  V initialValue
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see that the advantage of such structure is that user can control the value status better by the initial value and prior value stored in the operators. &lt;/p&gt;

&lt;h1&gt;
  
  
  Interaction Channel
&lt;/h1&gt;

&lt;p&gt;For common cases of interaction, features above are enough. But we introduced &lt;em&gt;interaction channels&lt;/em&gt; for advanced usage.&lt;/p&gt;

&lt;p&gt;The interaction channel is a way for two-way communication with the chart. You can input and output interaction information through it. That is to say, you can manually emit a signal or selection to the chart and get noticed from the chart when a signal or selection occurs. It makes a more flexible and precise control of interaction.&lt;/p&gt;

&lt;p&gt;To achieve this, we consider about the idea of Functional Reactive Programming (FRP). Fortunately, the Dart language has a built-in &lt;a href="https://dart.dev/tutorials/language/streams"&gt;asynchronous stream system&lt;/a&gt;, which is an simple implementation for FRP. The &lt;a href="https://api.dart.dev/stable/2.18.3/dart-async/StreamController-class.html"&gt;StreamController&lt;/a&gt; class can play the role of interaction channels.&lt;/p&gt;

&lt;p&gt;A good field to show the advantage of interaction channels is chart coupling. Think about that there are two different charts, coupling means when interacting with one chart, the other one acts the same, and vice versa.&lt;/p&gt;

&lt;p&gt;For example, two charts show the prices and volumes of a stock respectively, touch on one chart to show the auxiliary line, the other should show the same:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XVW1Vfwe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ho9v8f35999r107abq33.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XVW1Vfwe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ho9v8f35999r107abq33.gif" alt="Image description" width="400" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You just need to let the two charts share the same gesture signal channel, and they will share all gestures, without any redundant input and output properties:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;final priceVolumeChannel = StreamController&amp;lt;GestureSignal&amp;gt;.broadcast();

// the price chart
Chart(
  ...
  gestureChannel: priceVolumeChannel,
)

// the volume chart
Chart(
  ...
  gestureChannel: priceVolumeChannel,
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another example is two charts always select the same day:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eHP_Q2_D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/loqwylugiojk5gw580jr.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eHP_Q2_D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/loqwylugiojk5gw580jr.gif" alt="Image description" width="398" height="365"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A shared selection channel of the two elements will do:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;final heatmapChannel = StreamController&amp;lt;Selected?&amp;gt;.broadcast();

// the above chart
Chart(
  ...
  elements: [PolygonElement(
    selectionChannel: heatmapChannel,
  )]
)

// the below chart
Chart(
  ...
  elements: [PolygonElement(
    selectionChannel: heatmapChannel,
  )]
)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The complete code of the two examples above is &lt;a href="https://github.com/entronad/graphic/blob/main/example/lib/pages/interaction_channel_dynamic.dart"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>mobile</category>
      <category>programming</category>
    </item>
    <item>
      <title>The Grammar of Graphics in Flutter Charts</title>
      <dc:creator>LIN Chen</dc:creator>
      <pubDate>Wed, 16 Feb 2022 07:07:29 +0000</pubDate>
      <link>https://dev.to/entronad/the-grammar-of-graphics-in-flutter-charts-3fhj</link>
      <guid>https://dev.to/entronad/the-grammar-of-graphics-in-flutter-charts-3fhj</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;The new version of Flutter visualization library &lt;a href="https://github.com/entronad/graphic" rel="noopener noreferrer"&gt;Graphic&lt;/a&gt; optimized its declarative specification grammar, so that it can better represent the nature of the Grammar of Graphics.&lt;/p&gt;

&lt;p&gt;In this article, we vary a specification several times, thus transform a bar chart to a pie chart. This work displays the flexibility and diversity of the Grammar of Graphics, and also shows beginners the basic concepts of the Grammar of Graphics.&lt;/p&gt;

&lt;p&gt;If you have never learned the Grammar of Graphics before, there is no problem to read this article. It is also a starting handbook of &lt;a href="https://github.com/entronad/graphic" rel="noopener noreferrer"&gt;Graphic&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Bar charts and pie charts are both very common in data visualization. They look quite different at first sight, but they have the same nature. Why? Let's transform a bar chart to a pie chart step by step, to look into the intrinsic reasons.&lt;/p&gt;

&lt;p&gt;Let's start with a simple bar chart. The data is the same as the &lt;a href="https://echarts.apache.org/examples/editor.html?c=doc-example/getting-started" rel="noopener noreferrer"&gt;starting example&lt;/a&gt; of ECharts:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;'category'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'Shirts'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'sales'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;'category'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'Cardigans'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'sales'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;'category'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'Chiffons'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'sales'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;36&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;'category'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'Pants'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'sales'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;'category'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'Heels'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'sales'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;'category'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'Socks'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'sales'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
  
  
  Declarative Specification
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://github.com/entronad/graphic" rel="noopener noreferrer"&gt;Graphic&lt;/a&gt; adopts a declarative specification. All grammars of visualization is specified in the constructor of the &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/Chart-class.html" rel="noopener noreferrer"&gt;Chart&lt;/a&gt; widget:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="n"&gt;Chart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;data:&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;variables:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;'category'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Variable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;accessor:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'category'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s"&gt;'sales'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Variable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;accessor:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'sales'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kt"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nl"&gt;elements:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;IntervalElement&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
  &lt;span class="nl"&gt;axes:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;Defaults&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;horizontalAxis&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Defaults&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;verticalAxis&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
  
  
  Data and Variable
&lt;/h1&gt;

&lt;p&gt;The data of a chart is imported by the &lt;code&gt;data&lt;/code&gt; property. It can be a &lt;code&gt;List&lt;/code&gt; of any type. Inside the chart, the data items are converted to uniform &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/Tuple.html" rel="noopener noreferrer"&gt;Tuple&lt;/a&gt; objects. How &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/Tuple.html" rel="noopener noreferrer"&gt;Tuple&lt;/a&gt; fields are extracted from data items is defined by &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/Variable-class.html" rel="noopener noreferrer"&gt;Variable&lt;/a&gt;s.&lt;/p&gt;

&lt;p&gt;We can see from the example code that the grammar of the specification is concise, yet the &lt;code&gt;variables&lt;/code&gt; definition takes half the length. Since Dart is a strict typed language, in order to allow any input datum type, detailed &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/Variable-class.html" rel="noopener noreferrer"&gt;Variable&lt;/a&gt; definitions are quite necessary.&lt;/p&gt;
&lt;h1&gt;
  
  
  Geometry Element
&lt;/h1&gt;

&lt;p&gt;The greatest idea of the Grammar of Graphics is distinguishing the difference between abstract &lt;em&gt;graph&lt;/em&gt; and perceivable &lt;em&gt;graphic&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;For instance, whether a datum is an &lt;em&gt;interval&lt;/em&gt; of values or a &lt;em&gt;point&lt;/em&gt; of a value, is called the &lt;em&gt;graph&lt;/em&gt;; whether the item on canvas is a bar or a triangle, the width, and the height, is called the &lt;em&gt;graphic&lt;/em&gt;. The steps to create a graph and a graphic are called geometry and aesthetic, respectively.&lt;/p&gt;

&lt;p&gt;The concepts of graph and graphic reach the intrinsic relationship between data and graphics. They are the key for the Grammar of Graphics to get free from the constraints of chart typologies.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/GeomElement-class.html" rel="noopener noreferrer"&gt;GeomElement&lt;/a&gt; is where these two concepts are defined. Its types determine the graph type, and they are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/graphic/latest/graphic/PointElement-class.html" rel="noopener noreferrer"&gt;PointElement&lt;/a&gt;: points.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/graphic/latest/graphic/LineElement-class.html" rel="noopener noreferrer"&gt;LineElement&lt;/a&gt;: a line connecting points.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/graphic/latest/graphic/AreaElement-class.html" rel="noopener noreferrer"&gt;AreaElement&lt;/a&gt;: an area between lines.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/graphic/latest/graphic/IntervalElement-class.html" rel="noopener noreferrer"&gt;IntervalElement&lt;/a&gt;: intervals between two points.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/graphic/latest/graphic/PolygonElement-class.html" rel="noopener noreferrer"&gt;PolygonElement&lt;/a&gt;: polygons partitioning a plane.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The height of a bar in the chart represents the interval between 0 and the datum value, so we choose &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/IntervalElement-class.html" rel="noopener noreferrer"&gt;IntervalElement&lt;/a&gt;. Thus we get a very common &lt;strong&gt;bar chart&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff31o4v0mc11lo19uxiqi.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff31o4v0mc11lo19uxiqi.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's get back to the beginning quest. The angles in a pie chart also display intervals, so we should also choose the &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/IntervalElement-class.html" rel="noopener noreferrer"&gt;IntervalElement&lt;/a&gt;. But why a bar chart renders rectangles, while a pie chart renders sectors?&lt;/p&gt;
&lt;h1&gt;
  
  
  Coordinate
&lt;/h1&gt;

&lt;p&gt;A coordinate assigns variables into different dimensions in the plane. For rectangle coordinates (&lt;a href="https://pub.dev/documentation/graphic/latest/graphic/RectCoord-class.html" rel="noopener noreferrer"&gt;RectCoord&lt;/a&gt;), the dimensions are horizontal and vertical; and for polar coordinates (&lt;a href="https://pub.dev/documentation/graphic/latest/graphic/PolarCoord-class.html" rel="noopener noreferrer"&gt;PolarCoord&lt;/a&gt;), dimensions are angle and radius.&lt;/p&gt;

&lt;p&gt;The example above doesn't indicate the &lt;code&gt;coord&lt;/code&gt; property, so a default rectangle coordinate is set. Since the pie chart display intervals with angles, it should be a polar coordinate. We add a definition to indicate that:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="nl"&gt;coord:&lt;/span&gt; &lt;span class="n"&gt;PolarCoord&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then the chart becomes a &lt;strong&gt;rose chart&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqn6sysvbn3wt27yb3us7.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqn6sysvbn3wt27yb3us7.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This seems getting close to a pie chart. But the graphics looks imperfect. It needs some fixing.&lt;/p&gt;

&lt;h1&gt;
  
  
  Scale
&lt;/h1&gt;

&lt;p&gt;The first problem is, the proportions of the sector radiuses seem not equal to the proportions of the &lt;code&gt;salse&lt;/code&gt; values.&lt;/p&gt;

&lt;p&gt;This problem revolves an important concept of the Grammar of Graphics: the &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/Scale-class.html" rel="noopener noreferrer"&gt;Scale&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The original data values could be numbers, strings, or time. Even only of numbers, the values may range several orders of magnitude. So before used in the chart, they should be normalized. This step is called scaling.&lt;/p&gt;

&lt;p&gt;The continuous data, such as numbers and time, should be normalized to &lt;code&gt;[0, 1]&lt;/code&gt;; while the discrete data, such as strings, should be mapped to natural number indexes like 0, 1, 2, 3...&lt;/p&gt;

&lt;p&gt;Every variable has a responsive scale, which is set in &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/Variable-class.html" rel="noopener noreferrer"&gt;Variable&lt;/a&gt;'s &lt;code&gt;scale&lt;/code&gt; property. The variable values in &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/Tuple.html" rel="noopener noreferrer"&gt;Tuple&lt;/a&gt;s can be one of &lt;code&gt;num&lt;/code&gt;, &lt;code&gt;DateTime&lt;/code&gt;, or &lt;code&gt;String&lt;/code&gt;, so the scale is classified by the input value types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/graphic/latest/graphic/LinearScale-class.html" rel="noopener noreferrer"&gt;LinearScale&lt;/a&gt;: normalizes a range of numbers to &lt;code&gt;[0, 1]&lt;/code&gt;, continuous.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/graphic/latest/graphic/TimeScale-class.html" rel="noopener noreferrer"&gt;TimeScale&lt;/a&gt;: normalizes a range of time to &lt;code&gt;[0, 1]&lt;/code&gt; numbers, continuous.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pub.dev/documentation/graphic/latest/graphic/OrdinalScale-class.html" rel="noopener noreferrer"&gt;OrdinalScale&lt;/a&gt;: maps strings to natural number indexes in order, discrete.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For numbers, The default &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/LinearScale-class.html" rel="noopener noreferrer"&gt;LinearScale&lt;/a&gt; will determine the range by input data, so the range minimum may not be 0. For a bar chart, this makes the chart focus on height differences of bars. But it is not fit for the rose chart, because people tend to regard radius ratios as value ratios.&lt;/p&gt;

&lt;p&gt;So, the range minimum of &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/LinearScale-class.html" rel="noopener noreferrer"&gt;LinearScale&lt;/a&gt; should be set to 0 manually:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="s"&gt;'sales'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Variable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;accessor:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'sales'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kt"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;scale:&lt;/span&gt; &lt;span class="n"&gt;LinearScale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;min:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;),&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
  
  
  Aesthetic Attribute
&lt;/h1&gt;

&lt;p&gt;The second problem is, since the sectors are adjacent, their colors should be distinguishable. And people prefer to use labels, not axis, to annotate the rose chart.&lt;/p&gt;

&lt;p&gt;Attributes for perceiving graphics, like color or label, are called aesthetic attributes. In &lt;a href="https://github.com/entronad/graphic" rel="noopener noreferrer"&gt;Graphic&lt;/a&gt; they are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;position&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;shape&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;color&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gradient&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;elevation&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;label&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;size&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Except &lt;code&gt;position&lt;/code&gt;, each of them are defined in &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/GeomElement-class.html" rel="noopener noreferrer"&gt;GeomElement&lt;/a&gt; by a corresponding &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/Attr-class.html" rel="noopener noreferrer"&gt;Attr&lt;/a&gt; class. According to definition properties, they can be specified in these ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Indicates the &lt;code&gt;value&lt;/code&gt; directly.&lt;/li&gt;
&lt;li&gt;Indicates corresponding &lt;code&gt;variable&lt;/code&gt;, and target attribute &lt;code&gt;values&lt;/code&gt; and &lt;code&gt;stopes&lt;/code&gt;. The variable values will be interpolated or mapped to attribute values. These kind of attributes are called &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/ChannelAttr-class.html" rel="noopener noreferrer"&gt;ChannelAttr&lt;/a&gt;s.&lt;/li&gt;
&lt;li&gt;Indicates how a tuple is encoded to an attribute value by &lt;code&gt;encoder&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this example, we specify colors and labels in the second way:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="nl"&gt;elements:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;IntervalElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;ColorAttr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;variable:&lt;/span&gt; &lt;span class="s"&gt;'category'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;values:&lt;/span&gt; &lt;span class="n"&gt;Defaults&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;colors10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nl"&gt;label:&lt;/span&gt; &lt;span class="n"&gt;LabelAttr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;encoder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'category'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Thus we get a better rose chart:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9x2omokrfok20zyz3vrs.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9x2omokrfok20zyz3vrs.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But how to transform the rose chart to a pie chart?&lt;/p&gt;

&lt;h1&gt;
  
  
  Transpose Coordinate
&lt;/h1&gt;

&lt;p&gt;Variables of data often have a function relation: &lt;code&gt;y = f(x)&lt;/code&gt;. We say that the x is in the domain dimension, and the y is in the measure dimension. Customarily, for a plane, the rectangle coordinate assigns the domain dimension to the horizontal direction and the measure dimension to the vertical direction; while the polar coordinate assigns the domain dimension to angles and the measure dimension to radiuses.&lt;/p&gt;

&lt;p&gt;A rose chart displays values with radiuses, while a pie chart displays values with angles. So the first step is to switch the correspondence of dimensions. This is called transposing:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="nl"&gt;coord:&lt;/span&gt; &lt;span class="n"&gt;PolarCoord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;transposed:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then the graphics transform to a &lt;strong&gt;racing chart&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe4vgxehmpu39ecxglrsj.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe4vgxehmpu39ecxglrsj.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It seems to get closer to a pie chart.&lt;/p&gt;

&lt;h1&gt;
  
  
  Variable Transform
&lt;/h1&gt;

&lt;p&gt;The sectors in a pie chart compose a whole circle, the ratios of arcs to the perimeter is the ratios of values to the sum. But in the above chart, the sum of arcs is obviously larger than the perimeter.&lt;/p&gt;

&lt;p&gt;One solution is to set the scale range of &lt;code&gt;sales&lt;/code&gt; between 0 and the sum of all &lt;code&gt;sales&lt;/code&gt;, then the scaled &lt;code&gt;sales&lt;/code&gt; values are the ratios to the sum. But for dynamic data, we usually don't know the values when defining the chart.&lt;/p&gt;

&lt;p&gt;Another solution is that if the measure dimension variable is the proportion of &lt;code&gt;sales&lt;/code&gt;, then we only need to set the scale range to &lt;code&gt;[0, 1]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That is why we need &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/VariableTransform-class.html" rel="noopener noreferrer"&gt;VariableTransform&lt;/a&gt;. It can apply statistical transforms to current variables, to modify the tuples or create new variables. Here we use &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/Proportion-class.html" rel="noopener noreferrer"&gt;Proportion&lt;/a&gt;, which calculates the proportions of &lt;code&gt;sales&lt;/code&gt; values and assign them to a new &lt;code&gt;percent&lt;/code&gt; variable, whose default scale range is &lt;code&gt;[0, 1]&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="nl"&gt;transforms:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="n"&gt;Proportion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;variable:&lt;/span&gt; &lt;span class="s"&gt;'sales'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'percent'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
  
  
  Graphics Algebra
&lt;/h1&gt;

&lt;p&gt;A new problem occurs after we applied the transform. The tuple had only two variables &lt;code&gt;category&lt;/code&gt; and &lt;code&gt;sales&lt;/code&gt; before, and they happens can be assigned to the two dimensions respectively. Nothing need to set. But now, an additional variable &lt;code&gt;percent&lt;/code&gt; is added. How to assign three chestnuts to two monkeys? There needs a clear specification.&lt;/p&gt;

&lt;p&gt;To define the relation between variables and dimensions, we need the graphics algebra.&lt;/p&gt;

&lt;p&gt;The graphics algebra specifies the variables relations and how they are assigned to dimensions with an expression that connects &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/Varset-class.html" rel="noopener noreferrer"&gt;Varset&lt;/a&gt;s (variable sets) with operators. There are tree operators:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;*&lt;/code&gt;: cross, which assigns two operands to two dimensions in order.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;+&lt;/code&gt;: blend, which assigns two operands to a same dimension in order.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/&lt;/code&gt;: nest, which groups all tuples according to the second operand.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We need to assign &lt;code&gt;category&lt;/code&gt; and transformed &lt;code&gt;percent&lt;/code&gt; to the domain dimension and the measure dimension respectively. Benefited form the operator overriding of Dart, &lt;a href="https://github.com/entronad/graphic" rel="noopener noreferrer"&gt;Graphic&lt;/a&gt; implements all graphics algebra by the &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/Varset-class.html" rel="noopener noreferrer"&gt;Varset&lt;/a&gt; class. So we define &lt;code&gt;position&lt;/code&gt; as:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="nl"&gt;position:&lt;/span&gt; &lt;span class="n"&gt;Varset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'category'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;Varset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'percent'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After variable transform and graphics algebra are set, the graphics become:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsmi13sut63eynwyzidgm.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsmi13sut63eynwyzidgm.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Grouping and Modifier
&lt;/h1&gt;

&lt;p&gt;The arc length of sectors are handled, then we should "splice" them. The first step of splicing is to adjust their positions to end to end.&lt;/p&gt;

&lt;p&gt;This position adjusting is specified by &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/Modifier-class.html" rel="noopener noreferrer"&gt;Modifier&lt;/a&gt;s. The object of the adjusting is not single tuples, but tuple groups. So we should group the tuples by &lt;code&gt;category&lt;/code&gt;. Thus for the example data, each group will have a single tuple. The grouping is specified by nest operator of the graphics algebra. And after that we can set the &lt;a href="https://pub.dev/documentation/graphic/latest/graphic/StackModifier-class.html" rel="noopener noreferrer"&gt;StackModifier&lt;/a&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="nl"&gt;elements:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;IntervalElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="nl"&gt;position:&lt;/span&gt; &lt;span class="n"&gt;Varset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'category'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;Varset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'percent'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;Varset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'category'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nl"&gt;modifiers:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;StackModifier&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
&lt;span class="p"&gt;)]&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Since we have made the total arc length equals to the perimeter, the sectors become end to end after stacked, which can be regarded as a &lt;strong&gt;sunrise chart&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjaluvmbwbmc7lwmfxovv.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjaluvmbwbmc7lwmfxovv.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Coordinate Dimensions
&lt;/h1&gt;

&lt;p&gt;Since the angles of sectors are in position, there needs only one final step: to inflate the radiuses so that the sectors make a hole pie.&lt;/p&gt;

&lt;p&gt;Let's look into the radius dimension. We have just assigned the &lt;code&gt;category&lt;/code&gt; variable to it by algebra, so the sectors fall into different "tracks" respectively. But in fact, we don't want they differ in the radius dimension. We only need they vary in angles. In another word, we prefer the polar coordinate to be a 1D coordinate.&lt;/p&gt;

&lt;p&gt;We just need to indicate the coordinate dimension count to 1, and remove &lt;code&gt;category&lt;/code&gt; from the algebra expression:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="nl"&gt;coord:&lt;/span&gt; &lt;span class="n"&gt;PolarCoord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;transposed:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;dimCount:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="nl"&gt;position:&lt;/span&gt; &lt;span class="n"&gt;Varset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'percent'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;Varset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'category'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then the sectors inflates the circle radius, and we finished the &lt;strong&gt;pie chart&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flmv3dtszgzvr5zqg5gea.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flmv3dtszgzvr5zqg5gea.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;The complete specification is:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;

&lt;span class="n"&gt;Chart&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;data:&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;variables:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s"&gt;'category'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Variable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;accessor:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'category'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="s"&gt;'sales'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Variable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;accessor:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Map&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'sales'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kt"&gt;num&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;scale:&lt;/span&gt; &lt;span class="n"&gt;LinearScale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;min:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nl"&gt;transforms:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;Proportion&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;variable:&lt;/span&gt; &lt;span class="s"&gt;'sales'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;'percent'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="nl"&gt;elements:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;IntervalElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;position:&lt;/span&gt; &lt;span class="n"&gt;Varset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'percent'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;Varset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;'category'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nl"&gt;groupBy:&lt;/span&gt; &lt;span class="s"&gt;'category'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;modifiers:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;StackModifier&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
    &lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;ColorAttr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;variable:&lt;/span&gt; &lt;span class="s"&gt;'category'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nl"&gt;values:&lt;/span&gt; &lt;span class="n"&gt;Defaults&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;colors10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nl"&gt;label:&lt;/span&gt; &lt;span class="n"&gt;LabelAttr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;encoder:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Label&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;'category'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;LabelStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Defaults&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;runeStyle&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;)],&lt;/span&gt;
  &lt;span class="nl"&gt;coord:&lt;/span&gt; &lt;span class="n"&gt;PolarCoord&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;transposed:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;dimCount:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In the process above, we transformed the graphics incessantly by changing the specifications such as the coordinate, scales, aesthetic attributes, variable transforms, and modifiers. And we got a bar chart, a rose chart, a racing chart, a sunrise chart, and a pie chart of traditional chart typologies in order:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqrku2fx3wgf4ned2iwxu.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqrku2fx3wgf4ned2iwxu.jpg" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can conclude that the Grammar of Graphics jumps out of the constraint of traditional chart typologies, and can generates more visualization graphics with better flexibility and extensibility. More importantly, It reveals the intrinsic relations of different visualization graphics, and provides a theory foundation for data visualization science.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>dart</category>
      <category>android</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
