11 KiB
How To Draw A Sinus?
In data visualization tasks, quite often there is a need to depict mathematical functions - for example, to compare the convergence rate of a model with ideal one or to find an approximation for a given time series. Such charts have a number of features that are not inherent in most other charts: for example, visualizing the perpendicular axes (OX, OY) from (0, 0) and a large number of additional information. This can be the expected value of the function, its extremum points, deviation at various points, etc.
This article will tell you how to depict an ordinary sinus using the library Plotly.kt
so that in the end you will get a visual and informative plot.
-
Let's start with drawing perpendicular OX and OY axes. This requires to do a few things: hide default axes lines, hide zero lines (it's impossible to draw an arrow on the end of it), add perpendicular arrows using annotations (
Text
) with visible arrows on the end, but without text. After that, let's sign the axes themselves. It is also important to specify the required chart sizes (width
,height
) so that after saving the graph will look the same as in the browser.Plotly.page { // making new html page with plot layout { width = 900 // width of the plot (in px.) height = 500 // height of the plot (in px.) text { // vertical axis x = Value.of(0) // position of the top end of the arrow = (0, 1+eps) y = Value.of(1 + eps) ax = Value.of(0) // ax, ay means the offset of the bottom edge relative to the top ay = Value.of(430) // positive (negative) value is the arrow length // upwards (top down) and from right to left (from left to right) } text { // horizontal axis y = Value.of(0) // arrow left position = (2PI + eps, 0) x = Value.of(2 * PI + eps) ax = Value.of(-800) // position of the left end of the arrow ay = Value.of(0) } xaxis { // OX parameters showline = false // hide OX line zeroline = false // hide zero line } yaxis { // OY parameters showline = false // hide OY line zeroline = false // hide zero line } } }.makeFile() // making temporary file and visualing plot in the browser
-
Now we will draw the sinus function itself - for its visualization let's choose a bright blue color, contrasting with both the white background and the black ticks on the axes. After that using the variation of the
mode
parameter (ScatterMode: lines, markers
) the intersection points with the OY axis will be marked with a slightly darker shade of the same color.x1 = (-410..410).map{ it / 200 * PI } // function domain (-2PI - eps, 2PI + eps) y1 = sin(x1) // function values Plotly.page { scatter { // making Scatter plot (sinus) x.set(x1) // assigning OX values y.set(y1) // assigning OY values line { color(XKCD.CERULEAN) } // color of the line is cerulean } scatter { // making Scatter plot (OX axis dots) mode = ScatterMode.markers // visualizing only dots x(-2* PI, -PI, PI, 2* PI) // points of intersection of sinus with OX (values along the X axis) y(0, 0, 0, 0) // points of intersection of sinus with OX (values along the Y axis) line { color(XKCD.CERULEAN_BLUE) } // color of the dots is darker cerulean marker { size = 8 } // dot's diameter is 8 px. } layout { ... } }.makeFile()
-
Let's draw horizontal dashed lines on the chart, corresponding to values equal to -1, 1 (extremum lines) and 1/2. This requires changing
line.dash
parameter toDash.dash
value. The specified values will be plotted after that on the OY axis using thetickvals
andticklabels
parameters.... Plotly.page { ... layout { shape { // adding new figure (line y = 1) x0 = Value.of(-2*PI) // (-2PI, 1) and (2PI, 1) coordinates x1 = Value.of(2*PI) // will be connected by a line y0 = Value.of(1) y1 = Value.of(1) line { dash = Dash.dash } // dashed type of the line } shape { // adding new figure (line y = 1/2) x0 = Value.of(-2*PI) // coordinates (-2PI, 1/2) and (2PI, 1/2) x1 = Value.of(2*PI) // will be connected by a line y0 = Value.of(0.5) y1 = Value.of(0.5) line { color("red") // red color of the line dash = Dash.dash // dashed type of the line } } shape { // adding new figure (line y = -1) x0 = Value.of(-2*PI) // coordinates (-2PI, -1) and (2PI, -1) x1 = Value.of(2*PI) // will be connected by a line y0 = Value.of(-1) y1 = Value.of(-1) line { dash = Dash.dash } // dashed type of the line } ... } }.makeFile()
-
After that, it is worth adding vertical lines connecting points on OX, the values in which equals 1/2, and the value itself in LaTeX format. Shapes are used again for this - an array values of type
Shape.line
. To use LaTeX format you need to include theMathJax
header.... val sub = PI / 6 val xElems = listOf(-2PI + sub, -PI - sub, 0 + sub, PI - sub) // points, where sinus equals 1/2 val shapesList = mutableListOf<Shape>() // making list of lines for (x: xElems) { val shape = Shape { x0 = Value.of(x) // (x, 0) and (x, 0.5) will be connected y0 = Value.of(0) x1 = Value.of(x) y0 = Value.of(1/2) line { color("red") } // red color of the line } shapesList.add(shape) // adding new figure to the list } Plotly.page(mathJaxHeader, cdnPlotlyHeader) { scatter { // add string "1/2" mode = ScatterMode.text // visualing only text x(-0.35) // text position on the OX axis y(0.56) // text position on the OX axis text = listOf("$\Large{1/2}$") // increasing font size with ТеХ textfont { color("red") } // red color of the font showlegend = false // do not show this trace in the legend hoverinfo = "none" // do not show anything on hover } ... layout { // adding figure list to the plot shapes = shapesList ... } }.makeFile()
-
It remains to add labels on OX corresponding to the intersections of the sinus with the axis. It is done in a similar way, using axis labels (
tickvals
,ticktext
) and writing text in LaTeX format.... Plolty.page(mathJaxHeader, cdnPlotlyHeader) { ... layout { xaxis { // OX axis parameters ... anchor = "free" // axis position is set manually position = 0.43 // assigning axis position tickvals(listOf(-2 * PI-0.05, -PI - 0.15, PI - 0.05, 2 * PI + 0.1)) ticktext(listOf("\$\\huge{-2\\pi}\$", "\$\\huge{-\\pi}\$", "\$\\huge{\\pi}\$", "\$\\huge{2\\pi}\$")) // ticks positions and text } yaxis { // OY axis parameters ... anchor = "free" // axis position is set manually position = 0.485 // assigning axis position tickvals(listOf(-0.91, 0.09, 1.09)) ticktext(listOf("\$\\Large{-1}\$", "\$\\Large{0}\$", "\$\\Large{1}\$")) // ticks positions and text } ... } }.makeFile()
-
As a final improvement, let's add a legend to the plot, which will be placed in upper right corner of the graph. First you need to set the name of the corresponding line, after which with using the parameters
xanchor = right
andyanchor = top
set the position of the legend so that the coordinates specified by the parametersx = 1
,y = 1
correspond to the position in the upper right corner of the image.... Plotly.page(mathJaxHeader, cdnPlotlyHeader) { scatter { // sinus Scatter trace ... name = "\$\\Large{y = \\mathrm{sin}\\,x}\$" // the name of the plot displayed in the legend } layout { legend { // legend parameters x = 0.97 // horizontal position of the legend y = 1 // vertical position of the legend borderwidth = 1 // width of the legend border font { size = 32 } // size of the legend font xanchor = XAnchor.right // "anchoring" the position of the legend to the right corner yanchor = YAnchor.top // "anchoring" the position of the legend to the bottom of the graph } ... } }.makeFile()
-
Final picture:
Source code is available at: https://github.com/mipt-npm/plotly.kt/tree/dev/examples/src/main/kotlin/tutorials/SinusPicture.kt