Exploring Time Series Data Visualization
In my earlier post, I demonstrated how to implement a linear fluid dynamics simulation (linear convection equation) using primitive Java arrays in a one-dimensional setting. The example showed how the flow velocity array gets recalculated and overwritten during each loop iteration, with each loop representing a time step in our simulation.
While some readers might be satisfied with just seeing the final result, others are likely curious the process that produces the final outcome. What if we could watch this process in real-time? What patterns emerge as the simulation progresses?
This time, I want to show how to create a simple, but more engaging and interactive visualization. Instead of simply overwriting arrays as we iterate through our simulation loop, we will accumulate each result into a sequence.
Once gain, we’ll use the 1-D linear convection equation from fluid dynamics as our playground (and reuse some code from the previous post). The main focus of this post is on creating interactive plots that make simulation results more visually interesting, so we won’t dive too deep into physical implications (though the visual results might just inspire you to explore that side too! 😉).
Understanding the Data
Before we jump into the data visualization, let’s briefly set our initial data and what it represents.
The Setup
- x: Sliced positions along a one-dimensional space (think of points along a line)
- y: The flow velocity(
u
) at each positionx
- nt: The number of time steps we’ll simulate
A Real World Analogy (Just to add a bit of fun)
Imagine a rain gutter on a rainy day with water steadily flowing through it. Now, picture slicing a section of this gutter and marking specific positions along its length- these become our x
coordinates. The water continues to flow, then suddenly, a bird overhead drops a stone into the gutter, creating a sudden disturbance or “shock” in the water flow. And this becomes our initial condition.
Initial Conditions: The stone drop becomes our starting point(t = 0
), and at the moment of the impact, and the velocity at affected points jumps to 2 as a localized region (in our case, between 0.5
and 1.0
of x
is where the imaginary bird dropped a stone), while the rest of the gutter maintains its normal flow velocity of 1
.
Our initial parameters and plot configuration are:
:x-start 0, :x-end 2, :nx 41, :nt 100, :dx 1/20, :dt 0.025, :c 1} {
Simulation Code
Here is a simulation function we will use to accumulate the results:
defn simulate-accumulate!
("Simulate linear convection for given a given numer of times(nt) and accumulate
all intermediate states.
Args:
- array-u: initial velocity field as a mutable array
(note: we're reusing some codes from the previous post)
- params: a config map with required keys: nt, nx, c, dx, and dt
Returns a vector of (nt + 1) velocity field vectors, where each vector represents
the velocity field at a specific time step."
:keys [nt]
[array-u {:as params}]
loop [n 0
(transient [(vec array-u)])]
!cum (if (= n nt)
(persistent! !cum)
(recur (inc n) (conj! !cum (vec (lin-conv/mutate-linear-convection-u array-u params))))))) (
Then we run the simulation and store the accumulated results:
def accumulated-u (simulate-accumulate! initial-arr-u init-params)) (
Data Visualization
We have a vector of numbers representing velocity values. With certain conditions, we want to visualize how these numbers change over time. We will use Vega-Lite’s line plots for our visualization.
First, we need a function that transforms accumulated results into Vega-Lite data format by flattening time-series velocity fields into individual data points with time step indices:
defn accumulated-u->vega-data-values [{:keys [array-x accumulated-u]}]
(apply concat
(
(map-indexedfn [idx u-i]
(map #(hash-map :idx idx :x % :y %2) array-x u-i))
( accumulated-u)))
Multi-Series Overlay Plot
In this first visualization, we show the simulation results as changes over time in one plot. Since showing all 101 time steps in one plot may not be very useful, we take every 10th result, and overlay each of those line plots into a single one.
The plotting data is grouped by idx
(time step), which produces a multi-series colored line plot.
let [[init-u & rest-u] accumulated-u
(->> rest-u
plot-data (10)
(partition-all map last)
(into [init-u])
(assoc plot-params :accumulated-u)
(
(accumulated-u->vega-data-values))]merge default-plot-width-height-map
(kind/vega-lite (:data {:values plot-data}
{:mark "line"
:encoding {:x {:field "x" :type "quantitative" :title "X"}
:y {:field "y" :type "quantitative" :title "Flow Velocity" :scale {:domain default-y-domain}}
:color {:field "idx" :type "nominal" :legend nil}}})))
Interactive Time Step Plot
In this second visualization, the plot includes an interactive slider that allows you to select a particular time step(idx
) to visualize the velocity field at that specific moment.
This interactive slider is implemented using Vega-Lite’s parameter binding feature.
let [select-dt-name "selectedDt"
(0
initial-dt 1
dt-step "idx"]
dt-field merge
(kind/vega-lite (
default-plot-width-height-map:data {:values (accumulated-u->vega-data-values plot-params)}
{:transform [{:filter (str "datum." dt-field " == " select-dt-name)}]
:params [{:name select-dt-name
:value initial-dt
:bind {:input "range"
:name "Time interval idx: "
:min initial-dt
:max (:nt plot-params)
:step dt-step}}]
:mark "line"
:encoding {:x {:field "x"
:type "quantitative"
:title "X"}
:y {:field "y"
:type "quantitative"
:title "Flow Velocity"
:scale {:domain default-y-domain}}}})))
Wrapping Up
What started as simple primitive Java array manipulation has evolved into something much more engaging! By accumulating our simulation states instead of overwriting those, we’ve made some progress to create interactive visualizations to be able to describe the temporal dynamics of our fluid dynamics simulation.
This exploration originally began while I was preparing a talk for the SciCloj Light conference, where I wanted to explore better storytelling through data visualization.
So far, I’ve only scratched the surface of what’s possible. Beyond Vega-Lite, many other visualization tools offer diverse options to be creative and make data come alive. I believe interactive visualizations can transform dry numbers into compelling stories.
I’ll continue exploring these possibilities and share more discoveries along the way if I find any! ✨