|
| 1 | +# Scatter Trace Type |
| 2 | + |
| 3 | +The [`scatter`](https://plotly.com/julia/reference/scatter/) trace type can be used to represent scatter charts (one point or marker per observation), line charts (a line drawn between each point), or bubble charts (points with size proportional to a dimension of the observation). |
| 4 | + |
| 5 | +To draw a scatter chart, use the `scatter` trace type and set the `mode` parameter to `markers`; for a line plot, set `mode` to `lines`, or a combination of both. |
| 6 | + |
| 7 | +```@example line_scatter |
| 8 | +using PlotlyJS, DataFrames, CSV, Dates |
| 9 | +
|
| 10 | +const DATA_DIR = joinpath(dirname(pathof(PlotlyJS)), "..", "datasets"); # hide |
| 11 | +nothing # hide |
| 12 | +``` |
| 13 | + |
| 14 | +```@example line_scatter |
| 15 | +function linescatter1() |
| 16 | + trace1 = scatter(;x=1:4, y=[10, 15, 13, 17], mode="markers") |
| 17 | + trace2 = scatter(;x=2:5, y=[16, 5, 11, 9], mode="lines") |
| 18 | + trace3 = scatter(;x=1:4, y=[12, 9, 15, 12], mode="lines+markers") |
| 19 | + plot([trace1, trace2, trace3]) |
| 20 | +end |
| 21 | +linescatter1() |
| 22 | +``` |
| 23 | + |
| 24 | + |
| 25 | +#### Style Scatter Plots |
| 26 | + |
| 27 | +There are many properties of the scatter trace type that control different aspects of the appearance of the trace. Here are a few examples |
| 28 | + |
| 29 | +```@example |
| 30 | +using PlotlyJS |
| 31 | +
|
| 32 | +t = 0:0.1:10 |
| 33 | +trace1 = scatter(;x=t, y=sin.(t), name="sin(t)", mode="markers", marker=attr(size=10)) |
| 34 | +trace2 = scatter(;x=t, y=cos.(t), name="cos(t)", mode="markers", marker=attr(size=10)) |
| 35 | +layout = Layout(title="Styled Scatter", yaxis_zeroline=false, xaxis_zeroline=false) |
| 36 | +p = plot([trace1, trace2], layout) |
| 37 | +restyle!(p, 1, marker_size=15) |
| 38 | +restyle!(p, 2, marker_color="rgba(255, 182, 193, 0.9)") |
| 39 | +p |
| 40 | +``` |
| 41 | + |
| 42 | +## Data Labels on Hover |
| 43 | + |
| 44 | +Traces labels can be displayed by setting the mode to `text`. |
| 45 | + |
| 46 | +Traces' attributes can be set using keywords arguments while constructing the trace or accessing the trace key. Note that while constructing the trace, [`attr`](@ref attr) and `_` achieve the same result, e.g. `marker_size=12` is equivalent to `marker=attr(:size=12)` |
| 47 | + |
| 48 | +```@example line_scatter |
| 49 | +function linescatter2() |
| 50 | + trace1 = scatter(;x=1:5, y=[1, 6, 3, 6, 1], |
| 51 | + mode="markers", name="Team A", |
| 52 | + text=["A-1", "A-2", "A-3", "A-4", "A-5"], |
| 53 | + marker_size=12, textfont_family="Raleway, sans-serif") |
| 54 | +
|
| 55 | + trace2 = scatter(;x=1:5, y=[4, 1, 7, 1, 4], |
| 56 | + mode="markers+text", name="Team B", |
| 57 | + text=["B-a", "B-b", "B-c", "B-d", "B-e"], |
| 58 | + textposition="bottom center") |
| 59 | + # setting marker.size this way is _equivalent_ to what we did for trace1 |
| 60 | + trace2["marker"] = Dict(:size => 12) |
| 61 | + trace2["textfont"] = Dict(:family => "Times New Roman") |
| 62 | +
|
| 63 | + data = [trace1, trace2] |
| 64 | + layout = Layout(;title="Data Labels Hover", xaxis_range=[0.75, 5.25], |
| 65 | + yaxis_range=[0, 8], legend_y=0.5, legend_yref="paper", |
| 66 | + legend=attr(family="Arial, sans-serif", size=20, |
| 67 | + color="grey")) |
| 68 | + plot(data, layout) |
| 69 | +end |
| 70 | +linescatter2() |
| 71 | +``` |
| 72 | + |
| 73 | +```@example line_scatter |
| 74 | +function linescatter4() |
| 75 | + trace = scatter(;y=fill(5, 40), mode="markers", marker=attr(size=40, color=0:39)) |
| 76 | + layout = Layout(title="Scatter Plot with a Color Dimension") |
| 77 | + plot(trace, layout) |
| 78 | +end |
| 79 | +linescatter4() |
| 80 | +``` |
| 81 | + |
| 82 | +```@example line_scatter |
| 83 | +function linescatter5() |
| 84 | +
|
| 85 | + country = ["Switzerland (2011)", "Chile (2013)", "Japan (2014)", |
| 86 | + "United States (2012)", "Slovenia (2014)", "Canada (2011)", |
| 87 | + "Poland (2010)", "Estonia (2015)", "Luxembourg (2013)", |
| 88 | + "Portugal (2011)"] |
| 89 | +
|
| 90 | + votingPop = [40, 45.7, 52, 53.6, 54.1, 54.2, 54.5, 54.7, 55.1, 56.6] |
| 91 | + regVoters = [49.1, 42, 52.7, 84.3, 51.7, 61.1, 55.3, 64.2, 91.1, 58.9] |
| 92 | +
|
| 93 | + # notice use of `attr` function to make nested attributes |
| 94 | + trace1 = scatter(;x=votingPop, y=country, mode="markers", |
| 95 | + name="Percent of estimated voting age population", |
| 96 | + marker=attr(color="rgba(156, 165, 196, 0.95)", |
| 97 | + line_color="rgba(156, 165, 196, 1.0)", |
| 98 | + line_width=1, size=16, symbol="circle")) |
| 99 | +
|
| 100 | + trace2 = scatter(;x=regVoters, y=country, mode="markers", |
| 101 | + name="Percent of estimated registered voters") |
| 102 | + # also could have set the marker props above by using a dict |
| 103 | + trace2["marker"] = Dict(:color => "rgba(204, 204, 204, 0.95)", |
| 104 | + :line => Dict(:color => "rgba(217, 217, 217, 1.0)", |
| 105 | + :width => 1), |
| 106 | + :symbol => "circle", |
| 107 | + :size => 16) |
| 108 | +
|
| 109 | + data = [trace1, trace2] |
| 110 | + layout = Layout(Dict{Symbol,Any}(:paper_bgcolor => "rgb(254, 247, 234)", |
| 111 | + :plot_bgcolor => "rgb(254, 247, 234)"); |
| 112 | + title="Votes cast for ten lowest voting age population in OECD countries", |
| 113 | + width=600, height=600, hovermode="closest", |
| 114 | + margin=Dict(:l => 140, :r => 40, :b => 50, :t => 80), |
| 115 | + xaxis=attr(showgrid=false, showline=true, |
| 116 | + linecolor="rgb(102, 102, 102)", |
| 117 | + titlefont_color="rgb(204, 204, 204)", |
| 118 | + tickfont_color="rgb(102, 102, 102)", |
| 119 | + autotick=false, dtick=10, ticks="outside", |
| 120 | + tickcolor="rgb(102, 102, 102)"), |
| 121 | + legend=attr(font_size=10, yanchor="middle", |
| 122 | + xanchor="right"), |
| 123 | + ) |
| 124 | + plot(data, layout) |
| 125 | +end |
| 126 | +linescatter5() |
| 127 | +``` |
| 128 | + |
| 129 | +## Plotting of functions |
| 130 | + |
| 131 | +Functions can be plot directly: |
| 132 | + |
| 133 | +```@example |
| 134 | +using PlotlyJS |
| 135 | +
|
| 136 | +plot(cos, 0, 2π, mode="lines", Layout(title="cos(t)")) |
| 137 | +``` |
| 138 | + |
| 139 | +Here is a more advanced example. |
| 140 | + |
| 141 | +```@example |
| 142 | +using PlotlyJS |
| 143 | +
|
| 144 | +function batman() |
| 145 | + # reference: https://github.com/alanedelman/18.337_2015/blob/master/Lecture01_0909/The%20Bat%20Curve.ipynb |
| 146 | + σ(x) = @. √(1 - x.^2) |
| 147 | + el(x) = @. 3 * σ(x / 7) |
| 148 | + s(x) = @. 4.2 - 0.5 * x - 2.0 * σ(0.5 * x - 0.5) |
| 149 | + b(x) = @. σ(abs(2 - x) - 1) - x.^2 / 11 + 0.5x - 3 |
| 150 | + c(x) = [1.7, 1.7, 2.6, 0.9] |
| 151 | +
|
| 152 | + p(i, f; kwargs...) = scatter(;x=[-i; 0.0; i], y=[f(i); NaN; f(i)], |
| 153 | + marker_color="black", showlegend=false, |
| 154 | + kwargs...) |
| 155 | + traces = vcat(p(3:0.1:7, el; name="wings 1"), |
| 156 | + p(4:0.1:7, t -> -el(t); name="wings 2"), |
| 157 | + p(1:0.1:3, s; name="Shoulders"), |
| 158 | + p(0:0.1:4, b; name="Bottom"), |
| 159 | + p([0, 0.5, 0.8, 1], c; name="head")) |
| 160 | +
|
| 161 | + plot(traces, Layout(title="Batman")) |
| 162 | +end |
| 163 | +batman() |
| 164 | +``` |
| 165 | + |
| 166 | +## Plotting DataFrames |
| 167 | + |
| 168 | +DataFrames can be plot directly, where `x` and `y` take the corresponding DataFrame column names. Note that you can set `marker_size` via column name and generate multiple traces using `group`. |
| 169 | + |
| 170 | +```@example |
| 171 | +using PlotlyJS, DataFrames |
| 172 | +
|
| 173 | +df = PlotlyJS.dataset(DataFrame, "iris") |
| 174 | +plot(df, x=:sepal_width, y=:sepal_length, color=:species, mode="markers", |
| 175 | + marker=attr(size=:petal_length, sizeref=maximum(df.petal_length) / (20^2), sizemode="area")) |
| 176 | +``` |
| 177 | + |
| 178 | + |
| 179 | +```@example line_scatter |
| 180 | +function dumbbell() |
| 181 | + # Reference: https://plotly.com/r/dumbbell-plots/ |
| 182 | + # Source: "https://raw.githubusercontent.com/plotly/datasets/master/school_earnings.csv" |
| 183 | + # read data into DataFrame: |
| 184 | + df = CSV.read(joinpath(DATA_DIR, "school_earnings.csv"), DataFrame) |
| 185 | +
|
| 186 | + # sort dataframe by male earnings |
| 187 | + df = sort(df, :Men, rev=false) |
| 188 | +
|
| 189 | + men = scatter(df, ;y=:School, x=:Men, mode="markers", name="Men", |
| 190 | + marker=attr(color="blue", size=12)) |
| 191 | + women = scatter(df, ;y=:School, x=:Women, mode="markers", name="Women", |
| 192 | + marker=attr(color="pink", size=12)) |
| 193 | +
|
| 194 | + lines = map(eachrow(df)) do r |
| 195 | + scatter(y=fill(r.School, 2), x=[r.Women, r.Men], mode="lines", |
| 196 | + name=r.School, showlegend=false, line_color="gray") |
| 197 | + end |
| 198 | +
|
| 199 | + data = Base.typed_vcat(GenericTrace, men, women, lines) |
| 200 | + layout = Layout(width=650, height=650, margin_l=100, yaxis_title="School", |
| 201 | + xaxis_title="Annual Salary (thousands)", |
| 202 | + title="Gender earnings disparity") |
| 203 | +
|
| 204 | + plot(data, layout) |
| 205 | +end |
| 206 | +dumbbell() |
| 207 | +``` |
| 208 | + |
| 209 | +## Scatter with a Color Dimension |
| 210 | + |
| 211 | +```@example |
| 212 | +using PlotlyJS |
| 213 | +
|
| 214 | +plot(scatter(y=randn(500), mode="markers", |
| 215 | + marker=attr(size=16, color=rand(500), colorscale="Viridis", showscale=true))) |
| 216 | +``` |
| 217 | + |
| 218 | +## Error bars |
| 219 | + |
| 220 | +Error bars on the x and y points can be added with [`error_x`](https://plotly.com/javascript/reference/scatter/#scatter-error_x) and [`error_y`](https://plotly.com/javascript/reference/scatter/#scatter-error_y). |
| 221 | + |
| 222 | +```@example |
| 223 | +using PlotlyJS |
| 224 | +
|
| 225 | +trace = scatter(;x=1:4, y=[10, 15, 13, 17], |
| 226 | + error_x=Dict(:array=>[0.2, 0.4, 0.2, 0.35]), |
| 227 | + error_y=Dict(:array=>[0.6, 0.6, 1.1, 0.35]), mode="markers") |
| 228 | +plot(trace) |
| 229 | +``` |
| 230 | + |
| 231 | +Continuous error bars are implemented by adding an area to be [`fill`](https://plotly.com/javascript/reference/scatter/#scatter-fill)ed with a solid color |
| 232 | + |
| 233 | +```@example line_scatter |
| 234 | +function errorbars1() |
| 235 | + trace1 = scatter(;x=vcat(1:10, 10:-1:1), |
| 236 | + y=vcat(2:11, 9:-1:0), |
| 237 | + fill="tozerox", |
| 238 | + fillcolor="rgba(0, 100, 80, 0.2)", |
| 239 | + line_color="transparent", |
| 240 | + name="Fair", |
| 241 | + showlegend=false) |
| 242 | +
|
| 243 | + trace2 = scatter(;x=vcat(1:10, 10:-1:1), |
| 244 | + y=[5.5, 3.0, 5.5, 8.0, 6.0, 3.0, 8.0, 5.0, 6.0, 5.5, 4.75, |
| 245 | + 5.0, 4.0, 7.0, 2.0, 4.0, 7.0, 4.4, 2.0, 4.5], |
| 246 | + fill="tozerox", |
| 247 | + fillcolor="rgba(0, 176, 246, 0.2)", |
| 248 | + line_color="transparent", |
| 249 | + name="Premium", |
| 250 | + showlegend=false) |
| 251 | +
|
| 252 | + trace3 = scatter(;x=vcat(1:10, 10:-1:1), |
| 253 | + y=[11.0, 9.0, 7.0, 5.0, 3.0, 1.0, 3.0, 5.0, 3.0, 1.0, |
| 254 | + -1.0, 1.0, 3.0, 1.0, -0.5, 1.0, 3.0, 5.0, 7.0, 9.], |
| 255 | + fill="tozerox", |
| 256 | + fillcolor="rgba(231, 107, 243, 0.2)", |
| 257 | + line_color="transparent", |
| 258 | + name="Fair", |
| 259 | + showlegend=false) |
| 260 | +
|
| 261 | + trace4 = scatter(;x=1:10, y=1:10, |
| 262 | + line_color="rgb(00, 100, 80)", |
| 263 | + mode="lines", |
| 264 | + name="Fair") |
| 265 | +
|
| 266 | + trace5 = scatter(;x=1:10, |
| 267 | + y=[5.0, 2.5, 5.0, 7.5, 5.0, 2.5, 7.5, 4.5, 5.5, 5.], |
| 268 | + line_color="rgb(0, 176, 246)", |
| 269 | + mode="lines", |
| 270 | + name="Premium") |
| 271 | +
|
| 272 | + trace6 = scatter(;x=1:10, y=vcat(10:-2:0, [2, 4,2, 0]), |
| 273 | + line_color="rgb(231, 107, 243)", |
| 274 | + mode="lines", |
| 275 | + name="Ideal") |
| 276 | + data = [trace1, trace2, trace3, trace4, trace5, trace6] |
| 277 | + layout = Layout(;paper_bgcolor="rgb(255, 255, 255)", |
| 278 | + plot_bgcolor="rgb(229, 229, 229)", |
| 279 | +
|
| 280 | + xaxis=attr(gridcolor="rgb(255, 255, 255)", |
| 281 | + range=[1, 10], |
| 282 | + showgrid=true, |
| 283 | + showline=false, |
| 284 | + showticklabels=true, |
| 285 | + tickcolor="rgb(127, 127, 127)", |
| 286 | + ticks="outside", |
| 287 | + zeroline=false), |
| 288 | +
|
| 289 | + yaxis=attr(gridcolor="rgb(255, 255, 255)", |
| 290 | + showgrid=true, |
| 291 | + showline=false, |
| 292 | + showticklabels=true, |
| 293 | + tickcolor="rgb(127, 127, 127)", |
| 294 | + ticks="outside", |
| 295 | + zeroline=false)) |
| 296 | +
|
| 297 | + plot(data, layout) |
| 298 | +end |
| 299 | +errorbars1() |
| 300 | +``` |
| 301 | + |
| 302 | +```@example line_scatter |
| 303 | +function errorbars2() |
| 304 | + function random_dates(d1::DateTime, d2::DateTime, n::Int) |
| 305 | + map(Date, sort!(rand(d1:Dates.Hour(12):d2, n))) |
| 306 | + end |
| 307 | +
|
| 308 | + function _random_number(num, mul) |
| 309 | + value = [] |
| 310 | + j = 0 |
| 311 | + rand = 0 |
| 312 | + while j ≤ num + 1 |
| 313 | + rand = rand() * mul |
| 314 | + append!(value, [rand]) |
| 315 | + j += 1 |
| 316 | + end |
| 317 | + return value |
| 318 | + end |
| 319 | +
|
| 320 | + dates = random_dates(DateTime(2001, 1, 1), DateTime(2005, 12, 31), 50) |
| 321 | +
|
| 322 | + trace1 = scatter(;x=dates, |
| 323 | + y=20.0 .* rand(50), |
| 324 | + line_width=0, |
| 325 | + marker_color="444", |
| 326 | + mode="lines", |
| 327 | + name="Lower Bound") |
| 328 | +
|
| 329 | + trace2 = scatter(;x=dates, |
| 330 | + y=21.0 .* rand(50), |
| 331 | + fill="tonexty", |
| 332 | + fillcolor="rgba(68, 68, 68, 0.3)", |
| 333 | + line_color="rgb(31, 119, 180)", |
| 334 | + mode="lines", |
| 335 | + name="Measurement") |
| 336 | +
|
| 337 | + trace3 = scatter(;x=dates, |
| 338 | + y=22.0 .* rand(50), |
| 339 | + fill="tonexty", |
| 340 | + fillcolor="rgba(68, 68, 68, 0.3)", |
| 341 | + line_width=0, |
| 342 | + marker_color="444", |
| 343 | + mode="lines", |
| 344 | + name="Upper Bound") |
| 345 | +
|
| 346 | + data = [trace1, trace2, trace3] |
| 347 | + t = "Continuous, variable value error bars<br> Notice the hover text!" |
| 348 | + layout = Layout(;title=t, yaxis_title="Wind speed (m/s)") |
| 349 | + plot(data, layout) |
| 350 | +end |
| 351 | +errorbars2() |
| 352 | +``` |
| 353 | + |
| 354 | +## Bubble Scatter Plots |
| 355 | + |
| 356 | +In [bubble charts](https://en.wikipedia.org/wiki/Bubble_chart), a third dimension of the data is shown through the size of markers. For more examples, see the [bubble chart docs](https://plotly.com/julia/bubble-charts/) |
| 357 | + |
| 358 | +```@example |
| 359 | +using PlotlyJS |
| 360 | +
|
| 361 | +plot(scatter(x=1:4, y=10:13, mode="markers", marker=attr(size=40:20:100, color=0:3))) |
| 362 | +``` |
| 363 | + |
| 364 | +## Large Data Sets |
| 365 | + |
| 366 | +One can use WebGL with [`scattergl`](https://plotly.com/julia/reference/scattergl/) in place of `scatter()` for increased speed, improved interactivity, and the ability to plot even more data! |
| 367 | + |
| 368 | +```@example |
| 369 | +using PlotlyJS |
| 370 | +
|
| 371 | +N = 10000 |
| 372 | +plot(scattergl(x=randn(N), y=randn(N), mode="markers", |
| 373 | + marker=attr(color=randn(N), colorscale="Viridis", line_width=1))) |
| 374 | +``` |
0 commit comments