All plots have the same initial state regardless of individual configuration.
init : Model
init =
{ plot1 = Plot.init
, plot2 = Plot.init
, plot3 = Plot.init
}Plot.Msg in your MsgInclude it within a constructor for easy pattern matching in your update function:
type Msg
= MyPlotMsg (Plot.Msg Point)
| NoOpor if you need routing for several plots:
type MyPlot
= Plot1
| Plot2
type Msg
= ToPlot MyPlot (Plot.Msg Point)Naturally you need to handle the plot messages in your update function. This is what Plot.update is for.
update : Msg -> Model -> Model
update msg model =
case msg of
ToPlot plotMsg ->
{ model
| plotState =
Plot.update
plotMsg
model.plotState
}If you need routing to update multiple plots:
case msg of
ToPlot Plot1 plotMsg ->
{ model
| plot1 =
Plot.update
plotMsg
model.plot1
}
ToPlot Plot2 plotMsg ->
{ model
| plot2 =
Plot.update
plotMsg
model.plot2
}Use this configuration as a starting point when your data is just a List Point.
type alias Point =
{ x : Float, y : Float }
myPoints =
[ Point 11 120
, Point 12 121
, Point 13 120.5
]
Plot.points
{ toMsg = ToPlot
, data = myPoints
}
|> Plot.drawHtml model.plotStateUse this function to place your line chart within your view.
import Element
view model =
Element.layout
[ Element.padding 20 ]
(Plot.points
{ toMsg = ToPlot
, data = myPoints
}
|> Plot.draw model.plotState
)If you, for some reason, are not using mdgriffith/elm-ui you can use this draw function instead which outputs regular Html msg.
Customization is done by mutating the Config output from Plot.points and Plot.custom before it is inserted into draw.
Let's say that you want to customize your configuration to show legends for your different lines and also extend the right margin so that the legends don't get cut off.
Then you'll have to pipe in suitable customizers before your draw like this:
Plot.points
{ toMsg = ToPlot
, data = myPoints
}
|> Plot.showLegends True
|> Plot.marginRight 70
|> Plot.drawHtml model.plotStateSet a string for labeling of the x-axis. Adjustment of margins and label offsets could be required to get the desired result.
Default is ""
Set a string for labeling of the y-axis. Adjustment of margins and label offsets could be required to get the desired result.
Default is ""
Set whether legends for your plot lines should be drawn or not. If you turn this on you most likely also need to adjust marginRight for them to not get cut off.
Default is False.
Set the function which turns floats to strings for the axis labels (on non-time axes).
import FormatNumber
import FormatNumber.Locales
myPlotConfig
|> Plot.numberFormat
(\float ->
FormatNumber.format
FormatNumber.Locales.frenchLocale
float
)
|> Plot.draw model.myPlotDefault is:
defaultFormat : Float -> String
defaultFormat number =
FormatNumber.format
FormatNumber.Locales.usLocale
numberSet whether the x-axis should display its values as time or not.
Default is False.
Set which timezone your Time.Posix values should be converted into for your time axis tick labels.
Only matters when Plot.xIsTime True.
default is Time.utc.
Set what language dates on the time axis will be in.
Only matters when Plot.xIsTime True.
import DateFormat.Language
myPlotConfig
|> Plot.language DateFormat.Language.swedish
|> Plot.draw model.myPlotDefault is DateFormat.Language.english.
Set extra hover label row. Hoverlabels for the x and y coordinates are always on, but if you want to add something extra on a row above them you use this.
You can for example just use a string field from your data type:
myPlotConfig
|> Plot.labelFunc .rocketInventorName
|> Plot.draw model.myPlotDefault is \_ -> ""
Size in pixels of the different margins around the actual plot. This is real estate that may or may not be needed by tick labels, legends and axis labels.
Default is 60
Default is 30
Default is 30
Amount in pixels for moving around the axis labels.
Positive y adjusts upwards contrary to Svg standard.
Default is 0
Default is 0
Default is 0
Default is 0
What if your data isn't in the form of { x : Float, y : Float}?
Then you will need:
Let's say that your data is a list of this type:
import Time
type alias ExampleType =
{ time : Time.Posix
, thrust : Float
, altitude : Float
, latestBufferLine : String
, errorLog : Maybe String
}If you want to plot data like this you can't use Plot.points, because it only works with data of type List Point.
Instead you can use Plot.custom like this:
import LineChart
import LineChart.Dots as Dots
import LineChart.Colors as Colors
Plot.custom
{ lines =
[ LineChart.line
Colors.blue
Dots.circle
"rocket 1"
listOfExampleType1
, LineChart.line
Colors.purple
Dots.square
"rocket 2"
listOfExampleType2
]
, toMsg = ToPlot
, xAcc = .time >> posixToMillis >> toFloat
, yAcc = .thrust
, pointDecoder = myPointDecoder
}The inputs xAcc and yAcc are whatever functions that will turn your type into floats to be plotted on the line chart.
Most often they are just getters plus whatever functions are needed to convert their values into floats.
You may also have noticed the myPointDecoder above.
The internals of the package needs a way to convert Point back to your type.
You basically have to write a function that puts the coordinates of a Point into an "empty" instance of your type:
myPointDecoder : Point -> ExampleType
myPointDecoder { x, y } =
let
xTime =
x |> round |> millisToPosix
in
ExampleType xTime y 0 "" NothingThis package uses the fork peterszerzo/line-charts since it contains necessary updates to terezka's great original package.
I advise you to do the same (at least in projects using elm-zoom-plot).
You need to store the internal state of the plot in your model.
It can be as simple as:
or if you have multiple plots on your page: