Elm Line Charts Part I: Times and Timezones
data-visualization elmElm has a very fine third-party line chart library
which I've enjoyed using in my passion project,
Chicago Test Out. It's well-documented
as a library, but if I haven't used it in a while, I find myself struggling
to get started with it. I end up starting at the middle or near the end and
then clumsily working backwards from where I want to end up. For this reason,
I'm working on writing a step-by-step guide for working with
terezka/line-charts
based on my own preferences and assuming a high-degree
of customization apart from the defaults, using
Chicago Test Out as a model.
One of my preferences is that a linechart almost always be used with time on the x-axis, and you can't use a time without knowing the time zone, so we'll start there.
Step 1: Add a Time.Zone
field to your model.
Timezones have to be fetched asynchronously, which means
- Open the file that has your model record in it and, if you have not already,
import Time
. - Add a field of type
Time.Zone
to yourModel
type record. - In your model initialization, initialize your timezone field to Time.utc.
- Compile.
If you haven't already used elm/time
somewhere, the elm compiler may
object and insist that you install the dependency, which it will walk you
through Assuming you don't have a lot of different functions that initialize
a new
model, this should bring your code to a compiling state. I am including the
full source for src/Models.elm from Chicago Test out below for reference.
module Models exposing (..)
import Hospitalization exposing (Hospitalization)
import TestDay exposing (TestDay)
import Time
type alias Model =
{ days : List TestDay
, hospitalizations : List Hospitalization
, mode : Mode
, zone: Time.Zone
}
type Mode = Test | HospitalizationMode
init : Model
init =
{ days = []
, hospitalizations = []
, mode = Test
, zone = Time.utc
}
Step 2: Add a time zone update message
- Open the file containing your Elm messages. (Mine is in src/Msg.elm.)
- If you haven't already,
import Time
into that module. - Add an
UpdateZone
type that takes aTime.Zone
parameter, like so:
module Msg exposing (..)
import Hospitalization exposing (Hospitalization)
import Http
import Json.Encode
import Models exposing (Mode(..))
import RawTestDay exposing (RawTestDay)
import Time
type Msg = GotRawTestDays (Result Http.Error (List RawTestDay))
| SetMode Mode
| UpdateHospitalizationDays Json.Encode.Value
| UpdateZone Time.Zone
- Implement your new message in your
update
method of your elm application, likely located in src/Main.elm. (You may need toimport Time
here as well.) - Compile.
Your code should be once again in a compiling state.
Get the Timezone from a Task
Now, just hook a
Task to get
Time.here
into your new message, and you should be up and running with
time zones.
This example shows how to do
it from init
, but in Chicago Test Out, I want to fetch the time zone after
I've run a fetch, so I'm going to hook in from the end of my fetch event.
This is what I mean:
update : Msg -> Model -> (Model, Cmd Msg)
update msg model =
case msg of
GotRawTestDays result ->
case result of
Ok response ->
TestDay.fromRaws response
|> \days -> ({model | days = days}
, Task.perform UpdateZone Time.here
)
Err e ->
case e of
.
.
.
That's a lot to look at, but as you can see I'm calling Task.perform
if the
response from GotRawTestDays
is Ok
. If the Task is successfull, the
current time zone, Time.here
will be passed to the message handler of
UpdateZone
.
A word on modeling times in Elm
As a reminder, Elm rejects ISO 8601 as a standard for dates. If you want dates
along the x-axis of your chart, you need to have those dates passed as a
posix number. For line charts, this should be a Float
type. The steps to
get your data will vary, so I won't enumerate them here, but keep that in mind
as you work on fetching your line chart dataset: You need a Float
for a date.
In Conclusion
This pretty well covers our prerequisites for working with line charts. In the next post, I'll start to scaffold a real chart.
I write to learn, so I welcome your constructive criticism. Report issues on GitLab.