terezka/elm-plot/5.0.2

NOTE: this package is not compatible with Elm 0.19.1

Plot

Series

viewSeries : List (Series data msg) -> data -> Html msg

A series is a list of data points possibly joined by some sort of interpolation. The example below renders an area, with the coordinates of the last argument given to viewSeries, where the coordinates are emphasized with a circle.

view : Svg msg
view =
  viewSeries
    [ area (List.map (\{ x, y } -> circle x y)) ]
    [ { x = 0, y = 1 }
    , { x = 2, y = 2 }
    , { x = 3, y = 3 }
    , { x = 4, y = 5 }
    , { x = 5, y = 8 }
    ]

Simple series

dots : (data -> List (DataPoint msg)) -> Series data msg
line : (data -> List (DataPoint msg)) -> Series data msg
area : (data -> List (DataPoint msg)) -> Series data msg

Simple data points

Data points are the coordinates which make up your series. They come with views or without. Pass your x and y coordinates, respectively, to create a data point for your series.

clear : Float -> Float -> DataPoint msg

A data point without a view.

square : Float -> Float -> DataPoint msg
circle : Float -> Float -> DataPoint msg
diamond : Float -> Float -> DataPoint msg
triangle : Float -> Float -> DataPoint msg

Custom series

type alias Series data msg =
{ axis : Axis
, interpolation : Interpolation
, toDataPoints : data -> List (DataPoint msg)
}

The series configuration allows you to specify your own interpolation and how your data is transformed into series data points, but also a vertical axis relating to the series' scale. This way it's made sure you never have more than one y-axis per data set, because that would be just crazy.

= None
| Linear (Maybe String) (List (Attribute Never))
| Monotone (Maybe String) (List (Attribute Never))

Interpolation is basically the line that goes between your data points. Your current options are:

  • None: No interpolation (a scatter plot).
  • Linear: A straight line.
  • Monotone: A nice looking curvy line which doesn't extend outside the y values of the two points involved (Huh? Here's an illustration).

All but None takes a color which determines whether it draws the area below the interpolation and a list of attributes which you can use for styling your interpolation.

Axis
-> Interpolation
-> (data -> List (DataPoint msg))
-> Series data msg

Make your own series! The standard line series looks like this on the inside:

line : (data -> List (DataPoint msg)) -> Series data msg
line toDataPoints =
  { axis = normalAxis
  , interpolation = Linear Nothing [ stroke pinkStroke ]
  , toDataPoints = toDataPoints
  }

Maybe pink isn't really your color and you want to make it green. No problem! You just add some different attributes to the interpolation. If you want a different interpolation or an area under that interpolation, look at the Interpolation type for more info.

type alias DataPoint msg =
{ view : Maybe (Svg msg)
, xLine : Maybe (AxisSummary -> LineCustomizations)
, yLine : Maybe (AxisSummary -> LineCustomizations)
, xTick : Maybe TickCustomizations
, yTick : Maybe TickCustomizations
, hint : Maybe (Html Never)
, x : Float
, y : Float
}

The data point. Here you can do tons of crazy stuff, although most importantly, you can specify the coordinates of your plot with the x and y properties. Besides that you can:

  • view: Add an SVG view at your data point.
  • xLine: Provide a summary of the vertical axis, you can create a horizontal line. Useful when hovering your point.
  • yLine: Same as xLine, but vertically.
  • xTick: So this is for the progressive plotter. Tufte recommends placing a tick where the actual data point is. Adding a tick view to this, will cast a tick to the horizontal axis and allow you to make a plot as in the link.
  • yTick: Like xTick, but vertically.
  • hint: The view added here will show up in the hint container (Whose view can be customized in the PlotCustomizations).
dot : Svg msg -> Float -> Float -> DataPoint msg

Makes a data point provided a view, an x and a y.

hintDot : Svg msg -> Maybe Point -> Float -> Float -> DataPoint msg

Like dot, except it also takes a maybe coordinates to know if it should add a hint view/vertical line or not.

rangeFrameDot : Svg msg -> Float -> Float -> DataPoint msg

This dot implements a special plot in Tuftes book. It basically just adds ticks to your axis where your data points are! You might want to use clearAxis to remove all the other useless chart junk, now that you have all these nice ticks.

emphasizedDot : Svg msg -> Float -> Float -> DataPoint msg

Really a silly surprise dot you can use if you want to be flashy. Try it if you're feeling lucky.

Maybe (Svg msg)
-> Maybe (AxisSummary -> LineCustomizations)
-> Maybe (AxisSummary -> LineCustomizations)
-> Maybe TickCustomizations
-> Maybe TickCustomizations
-> Maybe (Html Never)
-> Float
-> Float
-> DataPoint msg

Just do whatever you want.

Small helper views

Just thought you might want a hand with all the views you need for your data points.

viewCircle : Float -> String -> Svg msg

Pass radius and color to make a circle!

viewSquare : Float -> String -> Svg msg

Pass width and color to make a square!

viewDiamond : Float -> Float -> String -> Svg msg

Pass width, height and color to make a diamond and impress with your classy plot!

viewTriangle : String -> Svg msg

Pass a color to make a triangle! Great for academic looking plots.

Bars

viewBars : Bars data msg -> data -> Html msg

This is for viewing a bar chart! The example below renders four groups of two bars each, labeled Q1, Q2, Q3, Q4 respectively.

view : Svg msg
view =
  viewBars
    (groups (List.map (\data -> group data.label data.heights)))
    [ { label = "Q1", heights = [ 1, 2 ] }
    , { label = "Q2", heights = [ 3, 4 ] }
    , { label = "Q3", heights = [ 4, 5 ] }
    , { label = "Q4", heights = [ 3, 2 ] }
    ]

Simple bars

groups : (data -> List BarGroup) -> Bars data msg

For pink and blue bar groups. If you have more than two colors, you have to make your own group. Under this documentation, it looks like this:

groups : (data -> List BarGroup) -> Bars data msg
groups toGroups =
  { axis = normalAxis
  , toGroups = toGroups
  , styles = [ [ fill pinkFill ], [ fill blueFill ] ]
  , maxWidth = Percentage 75
  }

So you can just go right ahead and add a third pastel to those styles!

group : String -> List Float -> BarGroup

A pretty plain group, nothing fancy.

histogram : (data -> List BarGroup) -> Bars data msg

For histograms! Meaning that there is only one bar in each group and it's always one horizontal unit wide.

histogramBar : Float -> BarGroup

Custom bars

type alias Bars data msg =
{ axis : Axis
, toGroups : data -> List BarGroup
, styles : List (List (Attribute msg))
, maxWidth : MaxBarWidth
}

The bar configurations allows you to specify the styles of your bars, the max width of your bars, how your data is transformed into bar groups, as well the vertical axis related to your bar series.

type alias BarGroup =
{ label : Float -> LabelCustomizations
, hint : Float -> Maybe (Svg Never)
, verticalLine : Float -> Maybe (AxisSummary -> LineCustomizations)
, bars : List Bar
}

A bar group is, well, a group of bars attached to a single data point on the horizontal axis.

  • The bars property specify the height and label of each bar in your group.
  • The label is what will show up on the horizontal axis at that data point. This is a function as you don't get to pick your own x. This is because bar charts, per design, are supposed to be scattered at a consistent interval.
  • The hint property is the view which will show up in your hint when hovering the group.
  • The verticalLine property is an option to add a vertical line. Nice when you have a hint.
= Percentage Int
| Fixed Float

The width options of your bars. If Percentage is used, it will be maximum that percentage of one unit on the horizontal axis wide. Similarily, using Fixed will set your bar to be maximum the provided float in pixels.

hintGroup : Maybe Point -> String -> List Float -> BarGroup

For groups with a hint.

Axis
-> (data -> List BarGroup)
-> List (List (Attribute msg))
-> MaxBarWidth
-> Bars data msg

For special bar charts.

(Float -> LabelCustomizations)
-> (Float -> Maybe (Svg Never))
-> (Float -> Maybe (AxisSummary -> LineCustomizations))
-> List Bar
-> BarGroup

For your special groups.

Custom plot

type alias PlotCustomizations msg =
{ attributes : List (Attribute msg)
, id : String
, width : Int
, height : Int
, defs : List (Svg msg)
, margin :
{ top : Int
, right : Int
, bottom : Int
, left : Int
}
, onHover : Maybe (Maybe Point -> msg)
, hintContainer : PlotSummary -> List (Html Never) -> Html Never
, horizontalAxis : Axis
, grid :
{ horizontal : Grid
, vertical : Grid
}
, junk : PlotSummary -> List (JunkCustomizations msg)
, toDomainLowest : Float -> Float
, toDomainHighest : Float -> Float
, toRangeLowest : Float -> Float
, toRangeHighest : Float -> Float
}

The plot customizations. Here you may:

  • Add attributes to your whole plot (Useful when you want to do events for your plot).
  • Add an id (the id in here will overrule an id attribute you add in .attributes).
  • Change the width or height of your plot. I recommend the golden ratio!
  • Add SVG defs for all kinds tricks.
  • Change the margin (useful when you can't see your ticks!).
  • Add a message which will be sent when your hover over a point on your plot!
  • Add your own container for your hints or use the predefined ones.
  • Add a more exciting horizontal axis. Maybe try axisAtMin or make your own?
  • Add a grid, but do consider whether that will actually improve the readability of your plot.
  • Change the bounds of your plot. For example, if you want your plot to start atleast at -5 on the y-axis, then add toDomainLowest = min -5.

Note: The id is particularily important when you have several plots in your dom.

type alias PlotSummary =
{ x : AxisSummary
, y : AxisSummary
}
defaultSeriesPlotCustomizations : PlotCustomizations msg

The default series plot customizations.

viewSeriesCustom : PlotCustomizations msg -> List (Series data msg) -> data -> Html msg

Plot your series with special needs!

defaultBarsPlotCustomizations : PlotCustomizations msg

The default bars plot customizations.

viewBarsCustom : PlotCustomizations msg -> Bars data msg -> data -> Html msg

Plot your bar series with special needs!

Hint customizations

type alias Point =
Point

Just an x and a y property.

normalHintContainer : PlotSummary -> List (Html Never) -> Html Never

A view located at the bottom left corner of your plot, holding the hint views you (maybe) added in your data points or groups.

(Bool -> List (Html Never) -> Html Never)
-> Maybe Point
-> PlotSummary
-> List (Html Never)
-> Html Never

A view holding your hint views which flies around on your plot following the hovered x.

normalHintContainerInner : Bool -> List (Html Never) -> Html Never

The normal hint view.

Grid customizations

type Grid
{ attributes : List (Attribute Never)
, position : Float
}
decentGrid : Grid

A grid with decent spacing. Uses the decentPositions function to calculate the positions of the grid lines. This also means that if you use decentPositions to calculate your tick positions, then they will match.

clearGrid : Grid

No grid. Tufte would be proud of you. 💛

Junk

type alias JunkCustomizations msg =
{ x : Float
, y : Float
, view : Svg msg
}

Just add whatever you want. A title might be an idea though.

junk : Svg msg -> Float -> Float -> JunkCustomizations msg

Takes a view, an x coordinate and a y coordinate, and you can put your junk anywhere! If you want to add a title, which I assume is the real reason why you're here, you can do this:

title : Svg msg
title =
  viewLabel
    [ fill "bleak-capitalistic-color"
    , style "text-anchor: end; font-style: italic;"
    ]
    "Ca$h earned"


view : Svg.Svg a
view =
  viewSeriesCustom
    { defaultSeriesPlotCustomizations
    | ...
    , junk = \summary -> [ junk title summary.x.max summary.y.max  ]
    , ...
    }
    [ customLine ]
    data

Not sure if this is self explanatory, but summary.x.min/max, summary.y.min/max are just floats which you can do anything you'd like with.

You can of course also put other junk here, like legends for example.

Axis customizations

type Axis
type alias AxisSummary =
{ min : Float
, max : Float
, dataMin : Float
, dataMax : Float
, marginLower : Float
, marginUpper : Float
, length : Float
, all : List Float
}

A summary of information about an axis.

type alias TickCustomizations =
{ attributes : List (Attribute Never)
, length : Float
, position : Float
}
type alias LabelCustomizations =
{ view : Svg Never
, position : Float
}
type alias LineCustomizations =
{ attributes : List (Attribute Never)
, start : Float
, end : Float
}

Various axis

normalAxis : Axis

A super regular axis.

So because there is extra funky labels added to your bar groups, your axis should not be cluttered up with other random numbers. So use this one.

When you don't have an axis, which is only sometimes.

clearAxis : Axis

An axis closest to zero, but doesn't look like much unless you use the rangeFrameDot.

axisAtMin : Axis

An axis which is placed at the minimum of your axis! Meaning if you use it as a vertical axis, then it will end up to the far left, and if you use it as a horizontal axis, then it will end up in the bottom.

axisAtMax : Axis

Like axisAtMin, but opposite.

customAxis : (AxisSummary -> AxisCustomizations) -> Axis

When you want to make your own axis. This is where the fun starts! The normalAxis looks like this on the inside:

normalAxis : Axis
normalAxis =
  customAxis <| \summary ->
    { position = closestToZero
    , axisLine = Just (simpleLine summary)
    , ticks = List.map simpleTick (decentPositions summary |> remove 0)
    , labels = List.map simpleLabel (decentPositions summary |> remove 0)
    , flipAnchor = False
    }

But the special snowflake you are, you might want something different.

closestToZero : Float -> Float -> Float

A helper to position your axis as close to zero as possible, meaning if your range is 4 - 10, then the x-axis will be a 4, as that's the closest to zero it gets. Useful for avoiding confusion when your axis disappears below the reach of your plot because zero is not in your plot.

Position helpers

decentPositions : AxisSummary -> List Float

For decently spaced positions. Useful in tick/label and grid configurations.

interval : Float -> Float -> AxisSummary -> List Float

For ticks with a particular interval. The first value passed is the offset, and the second value is the actual interval. The offset is useful when you want two sets of ticks with different views. For example, if you want a long tick at every 2 * x and a small tick at every 2 * x + 1.

remove : Float -> List Float -> List Float

If you regret a particular position. Typically used for removing the label at the origin. Use like this:

normalAxis : Axis
normalAxis =
  axis <| \summary ->
    { position = ClosestToZero
    , axisLine = Just (simpleLine summary)
    , ticks = List.map simpleTick (decentPositions summary |> remove 0)
    , labels = List.map simpleLabel (decentPositions summary |> remove 0)
    }

See how in the normal axis we make a bunch of ticks, but then remove the one we don't want. You can do the same!

Small axis helpers

simpleLine : AxisSummary -> LineCustomizations

A nice grey line which goes from one side of your plot to the other.

simpleTick : Float -> TickCustomizations

A simple but powerful tick.

simpleLabel : Float -> LabelCustomizations

A simple label. You might want to try an make your own!

fullLine : List (Attribute Never) -> AxisSummary -> LineCustomizations

A line which goes from one end of the plot to the other.

viewLabel : List (Attribute msg) -> String -> Svg msg
displace : Float -> Float -> Attribute msg