Building Blocks
Traces
A Plot
instance will have a vector of trace
s. These should each be a subtype of AbstractTrace
.
PlotlyJS.jl defines one such subtype:
mutable struct GenericTrace{T <: AbstractDict{Symbol,Any}} <: AbstractTrace
fields::T
end
The fields
is an AbstractDict object that maps trace attributes to their values.
We create this wrapper around a Dict to provide some convnient syntax as described below.
Let’s consider an example. Suppose we would like to build the following JSON object:
{
"type": "scatter",
"x": [1, 2, 3, 4, 5],
"y": [1, 6, 3, 6, 1],
"mode": "markers+text",
"name": "Team A",
"text": ["A-1", "A-2", "A-3", "A-4", "A-5"],
"textposition": "top center",
"textfont": {
"family": "Raleway, sans-serif"
},
"marker": { "size": 12 }
}
One way to do this in Julia is:
fields = Dict{Symbol,Any}(:type => "scatter",
:x => [1, 2, 3, 4, 5],
:y => [1, 6, 3, 6, 1],
:mode => "markers+text",
:name => "Team A",
:text => ["A-1", "A-2", "A-3", "A-4", "A-5"],
:textposition => "top center",
:textfont => Dict(:family => "Raleway, sans-serif"),
:marker => Dict(:size => 12))
GenericTrace("scatter", fields)
scatter with fields marker, mode, name, text, textfont, textposition, type, x, and y
A more convenient syntax is:
t1 = scatter(;x=[1, 2, 3, 4, 5],
y=[1, 6, 3, 6, 1],
mode="markers+text",
name="Team A",
text=["A-1", "A-2", "A-3", "A-4", "A-5"],
textposition="top center",
textfont_family="Raleway, sans-serif",
marker_size=12)
scatter with fields marker, mode, name, text, textfont, textposition, type, x, and y
Notice a few things:
-
The trace
type
became the function name. There is a similar method for all
plotly.js traces types.
-
All other trace attributes were set using keyword arguments. This allows us
to avoid typing out the symbol prefix (:
) and the arrows (=>
) that were necessary when constructing the Dict
-
We can set nested attributes using underscores. Notice that the JSON
"marker": { "size": 12 }
was written marker_size=12
.
We can verify that this is indeed equivalent JSON by printing the JSON: (note the order of the attributes is different, but the content is identical):
print(JSON.json(t1, 2))
{ "textfont": { "family": "Raleway, sans-serif" }, "mode": "markers+text", "marker": { "size": 12 }, "textposition": "top center", "y": [ 1, 6, 3, 6, 1 ], "type": "scatter", "name": "Team A", "text": [ "A-1", "A-2", "A-3", "A-4", "A-5" ], "x": [ 1, 2, 3, 4, 5 ] }
Accessing attributes
If we then wanted to extract a particular attribute, we can do so using getindex(t1, :attrname)
, or the syntactic sugar t1[:attrname]
. Note that both symbols and strings can be used in a call to getindex
:
julia> t1["marker"]
Dict{Any, Any} with 1 entry:
:size => 12
julia> t1[:marker]
Dict{Any, Any} with 1 entry:
:size => 12
To access a nested property use parent.child
julia> t1["textfont.family"]
"Raleway, sans-serif"
Setting additional attributes
We can also set additional attributes. Suppose we wanted to set marker.color
to be red. We can do this with a call to setindex!(t1, "red", :marker_color)
, or equivalently t1["marker_color"] = "red"
:
julia> t1["marker_color"] = "red"
"red"
julia> println(JSON.json(t1, 2))
{
"textfont": {
"family": "Raleway, sans-serif"
},
"mode": "markers+text",
"marker": {
"color": "red",
"size": 12
},
"textposition": "top center",
"y": [
1,
6,
3,
6,
1
],
"type": "scatter",
"name": "Team A",
"text": [
"A-1",
"A-2",
"A-3",
"A-4",
"A-5"
],
"x": [
1,
2,
3,
4,
5
]
}
Notice how the color
attribute was correctly added within the existing marker
attribute (alongside size
), instead of replacing the marker
attribute.
You can also use this syntax to add completely new nested attributes:
julia> t1["line_width"] = 5
5
julia> println(JSON.json(t1, 2))
{
"textfont": {
"family": "Raleway, sans-serif"
},
"mode": "markers+text",
"marker": {
"color": "red",
"size": 12
},
"line": {
"width": 5
},
"textposition": "top center",
"y": [
1,
6,
3,
6,
1
],
"type": "scatter",
"name": "Team A",
"text": [
"A-1",
"A-2",
"A-3",
"A-4",
"A-5"
],
"x": [
1,
2,
3,
4,
5
]
}
Layouts
The Layout
type is defined as
mutable struct Layout{T <: AbstractDict{Symbol,Any}} <: AbstractLayout
fields::T
subplots::_Maybe{Subplots}
end
You can construct a layout using the same convenient keyword argument syntax that we used for traces:
julia> l = Layout(;title="Penguins",
xaxis_range=[0, 42.0], xaxis_title="fish",
yaxis_title="Weight",
xaxis_showgrid=true, yaxis_showgrid=true,
legend_y=1.15, legend_x=0.7)
layout with fields legend, margin, template, title, xaxis, and yaxis
julia> println(JSON.json(l, 2))
{
"xaxis": {
"showgrid": true,
"range": [
0.0,
42.0
],
"title": {
"text": "fish"
}
},
"template": {
"data": {
"scatterpolargl": [
{
"type": "scatterpolargl",
"marker": {
"colorbar": {
"ticks": "",
"outlinewidth": 0
}
}
}
],
"carpet": [
{
"baxis": {
"gridcolor": "white",
"endlinecolor": "#2a3f5f",
"minorgridcolor": "white",
"startlinecolor": "#2a3f5f",
"linecolor": "white"
},
"type": "carpet",
"aaxis": {
"gridcolor": "white",
"endlinecolor": "#2a3f5f",
"minorgridcolor": "white",
"startlinecolor": "#2a3f5f",
"linecolor": "white"
}
}
],
"scatterpolar": [
{
"type": "scatterpolar",
"marker": {
"colorbar": {
"ticks": "",
"outlinewidth": 0
}
}
}
],
"parcoords": [
{
"line": {
"colorbar": {
"ticks": "",
"outlinewidth": 0
}
},
"type": "parcoords"
}
],
"scatter": [
{
"type": "scatter",
"marker": {
"colorbar": {
"ticks": "",
"outlinewidth": 0
}
}
}
],
"histogram2dcontour": [
{
"colorbar": {
"ticks": "",
"outlinewidth": 0
},
"type": "histogram2dcontour",
"colorscale": [
[
0.0,
"#0d0887"
],
[
0.1111111111111111,
"#46039f"
],
[
0.2222222222222222,
"#7201a8"
],
[
0.3333333333333333,
"#9c179e"
],
[
0.4444444444444444,
"#bd3786"
],
[
0.5555555555555556,
"#d8576b"
],
[
0.6666666666666666,
"#ed7953"
],
[
0.7777777777777778,
"#fb9f3a"
],
[
0.8888888888888888,
"#fdca26"
],
[
1.0,
"#f0f921"
]
]
}
],
"contour": [
{
"colorbar": {
"ticks": "",
"outlinewidth": 0
},
"type": "contour",
"colorscale": [
[
0.0,
"#0d0887"
],
[
0.1111111111111111,
"#46039f"
],
[
0.2222222222222222,
"#7201a8"
],
[
0.3333333333333333,
"#9c179e"
],
[
0.4444444444444444,
"#bd3786"
],
[
0.5555555555555556,
"#d8576b"
],
[
0.6666666666666666,
"#ed7953"
],
[
0.7777777777777778,
"#fb9f3a"
],
[
0.8888888888888888,
"#fdca26"
],
[
1.0,
"#f0f921"
]
]
}
],
"scattercarpet": [
{
"type": "scattercarpet",
"marker": {
"colorbar": {
"ticks": "",
"outlinewidth": 0
}
}
}
],
"mesh3d": [
{
"colorbar": {
"ticks": "",
"outlinewidth": 0
},
"type": "mesh3d"
}
],
"surface": [
{
"colorbar": {
"ticks": "",
"outlinewidth": 0
},
"type": "surface",
"colorscale": [
[
0.0,
"#0d0887"
],
[
0.1111111111111111,
"#46039f"
],
[
0.2222222222222222,
"#7201a8"
],
[
0.3333333333333333,
"#9c179e"
],
[
0.4444444444444444,
"#bd3786"
],
[
0.5555555555555556,
"#d8576b"
],
[
0.6666666666666666,
"#ed7953"
],
[
0.7777777777777778,
"#fb9f3a"
],
[
0.8888888888888888,
"#fdca26"
],
[
1.0,
"#f0f921"
]
]
}
],
"scattermapbox": [
{
"type": "scattermapbox",
"marker": {
"colorbar": {
"ticks": "",
"outlinewidth": 0
}
}
}
],
"scattergeo": [
{
"type": "scattergeo",
"marker": {
"colorbar": {
"ticks": "",
"outlinewidth": 0
}
}
}
],
"histogram": [
{
"type": "histogram",
"marker": {
"colorbar": {
"ticks": "",
"outlinewidth": 0
}
}
}
],
"pie": [
{
"type": "pie",
"automargin": true
}
],
"choropleth": [
{
"colorbar": {
"ticks": "",
"outlinewidth": 0
},
"type": "choropleth"
}
],
"heatmapgl": [
{
"colorbar": {
"ticks": "",
"outlinewidth": 0
},
"type": "heatmapgl",
"colorscale": [
[
0.0,
"#0d0887"
],
[
0.1111111111111111,
"#46039f"
],
[
0.2222222222222222,
"#7201a8"
],
[
0.3333333333333333,
"#9c179e"
],
[
0.4444444444444444,
"#bd3786"
],
[
0.5555555555555556,
"#d8576b"
],
[
0.6666666666666666,
"#ed7953"
],
[
0.7777777777777778,
"#fb9f3a"
],
[
0.8888888888888888,
"#fdca26"
],
[
1.0,
"#f0f921"
]
]
}
],
"bar": [
{
"type": "bar",
"error_y": {
"color": "#2a3f5f"
},
"error_x": {
"color": "#2a3f5f"
},
"marker": {
"line": {
"color": "#E5ECF6",
"width": 0.5
}
}
}
],
"heatmap": [
{
"colorbar": {
"ticks": "",
"outlinewidth": 0
},
"type": "heatmap",
"colorscale": [
[
0.0,
"#0d0887"
],
[
0.1111111111111111,
"#46039f"
],
[
0.2222222222222222,
"#7201a8"
],
[
0.3333333333333333,
"#9c179e"
],
[
0.4444444444444444,
"#bd3786"
],
[
0.5555555555555556,
"#d8576b"
],
[
0.6666666666666666,
"#ed7953"
],
[
0.7777777777777778,
"#fb9f3a"
],
[
0.8888888888888888,
"#fdca26"
],
[
1.0,
"#f0f921"
]
]
}
],
"contourcarpet": [
{
"colorbar": {
"ticks": "",
"outlinewidth": 0
},
"type": "contourcarpet"
}
],
"table": [
{
"type": "table",
"header": {
"line": {
"color": "white"
},
"fill": {
"color": "#C8D4E3"
}
},
"cells": {
"line": {
"color": "white"
},
"fill": {
"color": "#EBF0F8"
}
}
}
],
"scatter3d": [
{
"line": {
"colorbar": {
"ticks": "",
"outlinewidth": 0
}
},
"type": "scatter3d",
"marker": {
"colorbar": {
"ticks": "",
"outlinewidth": 0
}
}
}
],
"scattergl": [
{
"type": "scattergl",
"marker": {
"colorbar": {
"ticks": "",
"outlinewidth": 0
}
}
}
],
"histogram2d": [
{
"colorbar": {
"ticks": "",
"outlinewidth": 0
},
"type": "histogram2d",
"colorscale": [
[
0.0,
"#0d0887"
],
[
0.1111111111111111,
"#46039f"
],
[
0.2222222222222222,
"#7201a8"
],
[
0.3333333333333333,
"#9c179e"
],
[
0.4444444444444444,
"#bd3786"
],
[
0.5555555555555556,
"#d8576b"
],
[
0.6666666666666666,
"#ed7953"
],
[
0.7777777777777778,
"#fb9f3a"
],
[
0.8888888888888888,
"#fdca26"
],
[
1.0,
"#f0f921"
]
]
}
],
"scatterternary": [
{
"type": "scatterternary",
"marker": {
"colorbar": {
"ticks": "",
"outlinewidth": 0
}
}
}
],
"barpolar": [
{
"type": "barpolar",
"marker": {
"line": {
"color": "#E5ECF6",
"width": 0.5
}
}
}
]
},
"layout": {
"xaxis": {
"gridcolor": "white",
"zerolinewidth": 2,
"title": {
"standoff": 15
},
"ticks": "",
"zerolinecolor": "white",
"automargin": true,
"linecolor": "white"
},
"hovermode": "closest",
"paper_bgcolor": "white",
"geo": {
"showlakes": true,
"showland": true,
"landcolor": "#E5ECF6",
"bgcolor": "white",
"subunitcolor": "white",
"lakecolor": "white"
},
"colorscale": {
"sequential": [
[
0.0,
"#0d0887"
],
[
0.1111111111111111,
"#46039f"
],
[
0.2222222222222222,
"#7201a8"
],
[
0.3333333333333333,
"#9c179e"
],
[
0.4444444444444444,
"#bd3786"
],
[
0.5555555555555556,
"#d8576b"
],
[
0.6666666666666666,
"#ed7953"
],
[
0.7777777777777778,
"#fb9f3a"
],
[
0.8888888888888888,
"#fdca26"
],
[
1.0,
"#f0f921"
]
],
"diverging": [
[
0,
"#8e0152"
],
[
0.1,
"#c51b7d"
],
[
0.2,
"#de77ae"
],
[
0.3,
"#f1b6da"
],
[
0.4,
"#fde0ef"
],
[
0.5,
"#f7f7f7"
],
[
0.6,
"#e6f5d0"
],
[
0.7,
"#b8e186"
],
[
0.8,
"#7fbc41"
],
[
0.9,
"#4d9221"
],
[
1,
"#276419"
]
],
"sequentialminus": [
[
0.0,
"#0d0887"
],
[
0.1111111111111111,
"#46039f"
],
[
0.2222222222222222,
"#7201a8"
],
[
0.3333333333333333,
"#9c179e"
],
[
0.4444444444444444,
"#bd3786"
],
[
0.5555555555555556,
"#d8576b"
],
[
0.6666666666666666,
"#ed7953"
],
[
0.7777777777777778,
"#fb9f3a"
],
[
0.8888888888888888,
"#fdca26"
],
[
1.0,
"#f0f921"
]
]
},
"yaxis": {
"gridcolor": "white",
"zerolinewidth": 2,
"title": {
"standoff": 15
},
"ticks": "",
"zerolinecolor": "white",
"automargin": true,
"linecolor": "white"
},
"shapedefaults": {
"line": {
"color": "#2a3f5f"
}
},
"font": {
"color": "#2a3f5f"
},
"annotationdefaults": {
"arrowhead": 0,
"arrowwidth": 1,
"arrowcolor": "#2a3f5f"
},
"plot_bgcolor": "#E5ECF6",
"title": {
"x": 0.05
},
"coloraxis": {
"colorbar": {
"ticks": "",
"outlinewidth": 0
}
},
"hoverlabel": {
"align": "left"
},
"mapbox": {
"style": "light"
},
"polar": {
"angularaxis": {
"gridcolor": "white",
"ticks": "",
"linecolor": "white"
},
"bgcolor": "#E5ECF6",
"radialaxis": {
"gridcolor": "white",
"ticks": "",
"linecolor": "white"
}
},
"autotypenumbers": "strict",
"ternary": {
"aaxis": {
"gridcolor": "white",
"ticks": "",
"linecolor": "white"
},
"bgcolor": "#E5ECF6",
"caxis": {
"gridcolor": "white",
"ticks": "",
"linecolor": "white"
},
"baxis": {
"gridcolor": "white",
"ticks": "",
"linecolor": "white"
}
},
"scene": {
"xaxis": {
"gridcolor": "white",
"gridwidth": 2,
"backgroundcolor": "#E5ECF6",
"ticks": "",
"showbackground": true,
"zerolinecolor": "white",
"linecolor": "white"
},
"zaxis": {
"gridcolor": "white",
"gridwidth": 2,
"backgroundcolor": "#E5ECF6",
"ticks": "",
"showbackground": true,
"zerolinecolor": "white",
"linecolor": "white"
},
"yaxis": {
"gridcolor": "white",
"gridwidth": 2,
"backgroundcolor": "#E5ECF6",
"ticks": "",
"showbackground": true,
"zerolinecolor": "white",
"linecolor": "white"
}
},
"colorway": [
"#636efa",
"#EF553B",
"#00cc96",
"#ab63fa",
"#FFA15A",
"#19d3f3",
"#FF6692",
"#B6E880",
"#FF97FF",
"#FECB52"
]
}
},
"legend": {
"y": 1.15,
"x": 0.7
},
"margin": {
"l": 50,
"b": 50,
"r": 50,
"t": 60
},
"title": "Penguins",
"yaxis": {
"showgrid": true,
"title": {
"text": "Weight"
}
}
}
attr
There is a special function named attr
that allows you to apply the same keyword magic we saw in the trace and layout functions, but to nested attributes. Let’s revisit the previous example, but use attr
to build up our xaxis
and legend
:
julia> l2 = Layout(;title="Penguins",
xaxis=attr(range=[0, 42.0], title="fish", showgrid=true),
yaxis_title="Weight", yaxis_showgrid=true,
legend=attr(x=0.7, y=1.15))
layout with fields legend, margin, template, title, xaxis, and yaxis
julia> println(JSON.json(l2, 2))
{
"xaxis": {
"showgrid": true,
"range": [
0.0,
42.0
],
"title": "fish"
},
"template": {
"data": {
"scatterpolargl": [
{
"type": "scatterpolargl",
"marker": {
"colorbar": {
"ticks": "",
"outlinewidth": 0
}
}
}
],
"carpet": [
{
"baxis": {
"gridcolor": "white",
"endlinecolor": "#2a3f5f",
"minorgridcolor": "white",
"startlinecolor": "#2a3f5f",
"linecolor": "white"
},
"type": "carpet",
"aaxis": {
"gridcolor": "white",
"endlinecolor": "#2a3f5f",
"minorgridcolor": "white",
"startlinecolor": "#2a3f5f",
"linecolor": "white"
}
}
],
"scatterpolar": [
{
"type": "scatterpolar",
"marker": {
"colorbar": {
"ticks": "",
"outlinewidth": 0
}
}
}
],
"parcoords": [
{
"line": {
"colorbar": {
"ticks": "",
"outlinewidth": 0
}
},
"type": "parcoords"
}
],
"scatter": [
{
"type": "scatter",
"marker": {
"colorbar": {
"ticks": "",
"outlinewidth": 0
}
}
}
],
"histogram2dcontour": [
{
"colorbar": {
"ticks": "",
"outlinewidth": 0
},
"type": "histogram2dcontour",
"colorscale": [
[
0.0,
"#0d0887"
],
[
0.1111111111111111,
"#46039f"
],
[
0.2222222222222222,
"#7201a8"
],
[
0.3333333333333333,
"#9c179e"
],
[
0.4444444444444444,
"#bd3786"
],
[
0.5555555555555556,
"#d8576b"
],
[
0.6666666666666666,
"#ed7953"
],
[
0.7777777777777778,
"#fb9f3a"
],
[
0.8888888888888888,
"#fdca26"
],
[
1.0,
"#f0f921"
]
]
}
],
"contour": [
{
"colorbar": {
"ticks": "",
"outlinewidth": 0
},
"type": "contour",
"colorscale": [
[
0.0,
"#0d0887"
],
[
0.1111111111111111,
"#46039f"
],
[
0.2222222222222222,
"#7201a8"
],
[
0.3333333333333333,
"#9c179e"
],
[
0.4444444444444444,
"#bd3786"
],
[
0.5555555555555556,
"#d8576b"
],
[
0.6666666666666666,
"#ed7953"
],
[
0.7777777777777778,
"#fb9f3a"
],
[
0.8888888888888888,
"#fdca26"
],
[
1.0,
"#f0f921"
]
]
}
],
"scattercarpet": [
{
"type": "scattercarpet",
"marker": {
"colorbar": {
"ticks": "",
"outlinewidth": 0
}
}
}
],
"mesh3d": [
{
"colorbar": {
"ticks": "",
"outlinewidth": 0
},
"type": "mesh3d"
}
],
"surface": [
{
"colorbar": {
"ticks": "",
"outlinewidth": 0
},
"type": "surface",
"colorscale": [
[
0.0,
"#0d0887"
],
[
0.1111111111111111,
"#46039f"
],
[
0.2222222222222222,
"#7201a8"
],
[
0.3333333333333333,
"#9c179e"
],
[
0.4444444444444444,
"#bd3786"
],
[
0.5555555555555556,
"#d8576b"
],
[
0.6666666666666666,
"#ed7953"
],
[
0.7777777777777778,
"#fb9f3a"
],
[
0.8888888888888888,
"#fdca26"
],
[
1.0,
"#f0f921"
]
]
}
],
"scattermapbox": [
{
"type": "scattermapbox",
"marker": {
"colorbar": {
"ticks": "",
"outlinewidth": 0
}
}
}
],
"scattergeo": [
{
"type": "scattergeo",
"marker": {
"colorbar": {
"ticks": "",
"outlinewidth": 0
}
}
}
],
"histogram": [
{
"type": "histogram",
"marker": {
"colorbar": {
"ticks": "",
"outlinewidth": 0
}
}
}
],
"pie": [
{
"type": "pie",
"automargin": true
}
],
"choropleth": [
{
"colorbar": {
"ticks": "",
"outlinewidth": 0
},
"type": "choropleth"
}
],
"heatmapgl": [
{
"colorbar": {
"ticks": "",
"outlinewidth": 0
},
"type": "heatmapgl",
"colorscale": [
[
0.0,
"#0d0887"
],
[
0.1111111111111111,
"#46039f"
],
[
0.2222222222222222,
"#7201a8"
],
[
0.3333333333333333,
"#9c179e"
],
[
0.4444444444444444,
"#bd3786"
],
[
0.5555555555555556,
"#d8576b"
],
[
0.6666666666666666,
"#ed7953"
],
[
0.7777777777777778,
"#fb9f3a"
],
[
0.8888888888888888,
"#fdca26"
],
[
1.0,
"#f0f921"
]
]
}
],
"bar": [
{
"type": "bar",
"error_y": {
"color": "#2a3f5f"
},
"error_x": {
"color": "#2a3f5f"
},
"marker": {
"line": {
"color": "#E5ECF6",
"width": 0.5
}
}
}
],
"heatmap": [
{
"colorbar": {
"ticks": "",
"outlinewidth": 0
},
"type": "heatmap",
"colorscale": [
[
0.0,
"#0d0887"
],
[
0.1111111111111111,
"#46039f"
],
[
0.2222222222222222,
"#7201a8"
],
[
0.3333333333333333,
"#9c179e"
],
[
0.4444444444444444,
"#bd3786"
],
[
0.5555555555555556,
"#d8576b"
],
[
0.6666666666666666,
"#ed7953"
],
[
0.7777777777777778,
"#fb9f3a"
],
[
0.8888888888888888,
"#fdca26"
],
[
1.0,
"#f0f921"
]
]
}
],
"contourcarpet": [
{
"colorbar": {
"ticks": "",
"outlinewidth": 0
},
"type": "contourcarpet"
}
],
"table": [
{
"type": "table",
"header": {
"line": {
"color": "white"
},
"fill": {
"color": "#C8D4E3"
}
},
"cells": {
"line": {
"color": "white"
},
"fill": {
"color": "#EBF0F8"
}
}
}
],
"scatter3d": [
{
"line": {
"colorbar": {
"ticks": "",
"outlinewidth": 0
}
},
"type": "scatter3d",
"marker": {
"colorbar": {
"ticks": "",
"outlinewidth": 0
}
}
}
],
"scattergl": [
{
"type": "scattergl",
"marker": {
"colorbar": {
"ticks": "",
"outlinewidth": 0
}
}
}
],
"histogram2d": [
{
"colorbar": {
"ticks": "",
"outlinewidth": 0
},
"type": "histogram2d",
"colorscale": [
[
0.0,
"#0d0887"
],
[
0.1111111111111111,
"#46039f"
],
[
0.2222222222222222,
"#7201a8"
],
[
0.3333333333333333,
"#9c179e"
],
[
0.4444444444444444,
"#bd3786"
],
[
0.5555555555555556,
"#d8576b"
],
[
0.6666666666666666,
"#ed7953"
],
[
0.7777777777777778,
"#fb9f3a"
],
[
0.8888888888888888,
"#fdca26"
],
[
1.0,
"#f0f921"
]
]
}
],
"scatterternary": [
{
"type": "scatterternary",
"marker": {
"colorbar": {
"ticks": "",
"outlinewidth": 0
}
}
}
],
"barpolar": [
{
"type": "barpolar",
"marker": {
"line": {
"color": "#E5ECF6",
"width": 0.5
}
}
}
]
},
"layout": {
"xaxis": {
"gridcolor": "white",
"zerolinewidth": 2,
"title": {
"standoff": 15
},
"ticks": "",
"zerolinecolor": "white",
"automargin": true,
"linecolor": "white"
},
"hovermode": "closest",
"paper_bgcolor": "white",
"geo": {
"showlakes": true,
"showland": true,
"landcolor": "#E5ECF6",
"bgcolor": "white",
"subunitcolor": "white",
"lakecolor": "white"
},
"colorscale": {
"sequential": [
[
0.0,
"#0d0887"
],
[
0.1111111111111111,
"#46039f"
],
[
0.2222222222222222,
"#7201a8"
],
[
0.3333333333333333,
"#9c179e"
],
[
0.4444444444444444,
"#bd3786"
],
[
0.5555555555555556,
"#d8576b"
],
[
0.6666666666666666,
"#ed7953"
],
[
0.7777777777777778,
"#fb9f3a"
],
[
0.8888888888888888,
"#fdca26"
],
[
1.0,
"#f0f921"
]
],
"diverging": [
[
0,
"#8e0152"
],
[
0.1,
"#c51b7d"
],
[
0.2,
"#de77ae"
],
[
0.3,
"#f1b6da"
],
[
0.4,
"#fde0ef"
],
[
0.5,
"#f7f7f7"
],
[
0.6,
"#e6f5d0"
],
[
0.7,
"#b8e186"
],
[
0.8,
"#7fbc41"
],
[
0.9,
"#4d9221"
],
[
1,
"#276419"
]
],
"sequentialminus": [
[
0.0,
"#0d0887"
],
[
0.1111111111111111,
"#46039f"
],
[
0.2222222222222222,
"#7201a8"
],
[
0.3333333333333333,
"#9c179e"
],
[
0.4444444444444444,
"#bd3786"
],
[
0.5555555555555556,
"#d8576b"
],
[
0.6666666666666666,
"#ed7953"
],
[
0.7777777777777778,
"#fb9f3a"
],
[
0.8888888888888888,
"#fdca26"
],
[
1.0,
"#f0f921"
]
]
},
"yaxis": {
"gridcolor": "white",
"zerolinewidth": 2,
"title": {
"standoff": 15
},
"ticks": "",
"zerolinecolor": "white",
"automargin": true,
"linecolor": "white"
},
"shapedefaults": {
"line": {
"color": "#2a3f5f"
}
},
"font": {
"color": "#2a3f5f"
},
"annotationdefaults": {
"arrowhead": 0,
"arrowwidth": 1,
"arrowcolor": "#2a3f5f"
},
"plot_bgcolor": "#E5ECF6",
"title": {
"x": 0.05
},
"coloraxis": {
"colorbar": {
"ticks": "",
"outlinewidth": 0
}
},
"hoverlabel": {
"align": "left"
},
"mapbox": {
"style": "light"
},
"polar": {
"angularaxis": {
"gridcolor": "white",
"ticks": "",
"linecolor": "white"
},
"bgcolor": "#E5ECF6",
"radialaxis": {
"gridcolor": "white",
"ticks": "",
"linecolor": "white"
}
},
"autotypenumbers": "strict",
"ternary": {
"aaxis": {
"gridcolor": "white",
"ticks": "",
"linecolor": "white"
},
"bgcolor": "#E5ECF6",
"caxis": {
"gridcolor": "white",
"ticks": "",
"linecolor": "white"
},
"baxis": {
"gridcolor": "white",
"ticks": "",
"linecolor": "white"
}
},
"scene": {
"xaxis": {
"gridcolor": "white",
"gridwidth": 2,
"backgroundcolor": "#E5ECF6",
"ticks": "",
"showbackground": true,
"zerolinecolor": "white",
"linecolor": "white"
},
"zaxis": {
"gridcolor": "white",
"gridwidth": 2,
"backgroundcolor": "#E5ECF6",
"ticks": "",
"showbackground": true,
"zerolinecolor": "white",
"linecolor": "white"
},
"yaxis": {
"gridcolor": "white",
"gridwidth": 2,
"backgroundcolor": "#E5ECF6",
"ticks": "",
"showbackground": true,
"zerolinecolor": "white",
"linecolor": "white"
}
},
"colorway": [
"#636efa",
"#EF553B",
"#00cc96",
"#ab63fa",
"#FFA15A",
"#19d3f3",
"#FF6692",
"#B6E880",
"#FF97FF",
"#FECB52"
]
}
},
"legend": {
"y": 1.15,
"x": 0.7
},
"margin": {
"l": 50,
"b": 50,
"r": 50,
"t": 60
},
"title": "Penguins",
"yaxis": {
"showgrid": true,
"title": {
"text": "Weight"
}
}
}
Notice we got the exact same output as before, but we didn’t have to resort to building the Dict
by hand or prefixing multiple arguments with xaxis_
or legend_
.
Using DataFrame
s
New in version 0.6.0 |
You can also construct traces using the columns of any subtype of AbstractDataFrame
(e.g. the DataFrame
type from DataFrames.jl).
To demonstrate this functionality let’s load the famous iris data set:
julia> using DataFrames, RDatasets
julia> iris = dataset("datasets", "iris");
julia> first(iris, 10)
10×5 DataFrame
│ Row │ SepalLength │ SepalWidth │ PetalLength │ PetalWidth │ Species │
│ │ Float64 │ Float64 │ Float64 │ Float64 │ Cat… │
├─────┼─────────────┼────────────┼─────────────┼────────────┼─────────┤
│ 1 │ 5.1 │ 3.5 │ 1.4 │ 0.2 │ setosa │
│ 2 │ 4.9 │ 3.0 │ 1.4 │ 0.2 │ setosa │
│ 3 │ 4.7 │ 3.2 │ 1.3 │ 0.2 │ setosa │
│ 4 │ 4.6 │ 3.1 │ 1.5 │ 0.2 │ setosa │
│ 5 │ 5.0 │ 3.6 │ 1.4 │ 0.2 │ setosa │
│ 6 │ 5.4 │ 3.9 │ 1.7 │ 0.4 │ setosa │
│ 7 │ 4.6 │ 3.4 │ 1.4 │ 0.3 │ setosa │
│ 8 │ 5.0 │ 3.4 │ 1.5 │ 0.2 │ setosa │
│ 9 │ 4.4 │ 2.9 │ 1.4 │ 0.2 │ setosa │
│ 10 │ 4.9 │ 3.1 │ 1.5 │ 0.1 │ setosa │
Suppose that we wanted to construct a scatter trace with the SepalLength
column as the x variable and the SepalWidth
columns as the y variable. We do this by calling
julia> my_trace = scatter(iris, x=:SepalLength, y=:SepalWidth, marker_color=:red)
scatter with fields marker, type, x, and y
julia> [my_trace[:x][1:5] my_trace[:y][1:5]]
5×2 Array{Float64,2}:
5.1 3.5
4.9 3.0
4.7 3.2
4.6 3.1
5.0 3.6
julia> my_trace[:marker_color]
:red
How does this work? The basic rule is that if the value of any keyword argument is a Julia Symbol (i.e. created with :something
), then the function creating the trace checks if that symbol is one of the column names in the DataFrame. If so, it extracts the column from the DataFrame and sets that as the value for the keyword argument. Otherwise it passes the symbol directly through.
In the above example, when we constructed my_trace
the value of the keyword argument x
was set to the Symbol :SepalLength
. This did match a column name from iris
so that column was extracted and replaced :SepalLength
as the value for the x
argument. The same holds for y
and SepalWidth
.
However, when setting marker_color=:red
we found that :red
is not one of the column names, so the value for the marker_color
keyword argument remained :red
.
The DataFrame interface becomes more useful when constructing whole plots. See the convenience methods section of the documentation for more information.
New in version 0.9.0 |
As of version 0.9.0, you can construct groups of traces using the DataFrame api. This is best understood by example, so let’s see it in action:
julia> iris = dataset("datasets", "iris");
julia> unique(iris[:Species])
3-element Array{String,1}:
"setosa"
"versicolor"
"virginica"
julia> traces = scatter(
iris, group=:Species, x=:SepalLength, y=:SepalWidth, mode="markers", marker_size=8
)
3-element Array{GenericTrace,1}:
GenericTrace{Dict{Symbol,Any}}(Dict{Symbol,Any}(:x => [5.1, 4.9, 4.7, 4.6, 5.0, 5.4, 4.6, 5.0, 4.4, 4.9 … 5.0, 4.5, 4.4, 5.0, 5.1, 4.8, 5.1, 4.6, 5.3, 5.0],:mode => "markers",:y => [3.5, 3.0, 3.2, 3.1, 3.6, 3.9, 3.4, 3.4, 2.9, 3.1 … 3.5, 2.3, 3.2, 3.5, 3.8, 3.0, 3.8, 3.2, 3.7, 3.3],:type => "scatter",:name => CategoricalValue{String,UInt8} "setosa",:marker => Dict{Any,Any}(:size => 8)))
GenericTrace{Dict{Symbol,Any}}(Dict{Symbol,Any}(:x => [7.0, 6.4, 6.9, 5.5, 6.5, 5.7, 6.3, 4.9, 6.6, 5.2 … 5.5, 6.1, 5.8, 5.0, 5.6, 5.7, 5.7, 6.2, 5.1, 5.7],:mode => "markers",:y => [3.2, 3.2, 3.1, 2.3, 2.8, 2.8, 3.3, 2.4, 2.9, 2.7 … 2.6, 3.0, 2.6, 2.3, 2.7, 3.0, 2.9, 2.9, 2.5, 2.8],:type => "scatter",:name => CategoricalValue{String,UInt8} "versicolor",:marker => Dict{Any,Any}(:size => 8)))
GenericTrace{Dict{Symbol,Any}}(Dict{Symbol,Any}(:x => [6.3, 5.8, 7.1, 6.3, 6.5, 7.6, 4.9, 7.3, 6.7, 7.2 … 6.7, 6.9, 5.8, 6.8, 6.7, 6.7, 6.3, 6.5, 6.2, 5.9],:mode => "markers",:y => [3.3, 2.7, 3.0, 2.9, 3.0, 3.0, 2.5, 2.9, 2.5, 3.6 … 3.1, 3.1, 2.7, 3.2, 3.3, 3.0, 2.5, 3.0, 3.4, 3.0],:type => "scatter",:name => CategoricalValue{String,UInt8} "virginica",:marker => Dict{Any,Any}(:size => 8)))
julia> [t[:name] for t in traces]
3-element CategoricalArray{String,1,UInt8}:
"setosa"
"versicolor"
"virginica"
Notice how there are three Species
in the iris
DataFrame, and when passing group=:Species
to scatter
we obtained three traces.
We can pass a Vector{Symbol}
as group, to split the data on the value in more than one column:
julia> tips = dataset("reshape2", "tips");
julia> unique(tips[:Sex])
2-element Array{String,1}:
"Female"
"Male"
julia> unique(tips[:Day])
4-element Array{String,1}:
"Sun"
"Sat"
"Thur"
"Fri"
julia> traces = violin(tips, group=[:Sex, :Day], x=:TotalBill, orientation="h")
8-element Array{GenericTrace,1}:
GenericTrace{Dict{Symbol,Any}}(Dict{Symbol,Any}(:type => "violin",:name => "(Female, Fri)",:orientation => "h",:x => [5.75, 16.32, 22.75, 11.35, 15.38, 13.42, 15.98, 16.27, 10.09]))
GenericTrace{Dict{Symbol,Any}}(Dict{Symbol,Any}(:type => "violin",:name => "(Female, Sat)",:orientation => "h",:x => [20.29, 15.77, 19.65, 15.06, 20.69, 16.93, 26.41, 16.45, 3.07, 17.07 … 10.59, 10.63, 12.76, 13.27, 28.17, 12.9, 30.14, 22.12, 35.83, 27.18]))
GenericTrace{Dict{Symbol,Any}}(Dict{Symbol,Any}(:type => "violin",:name => "(Female, Sun)",:orientation => "h",:x => [16.99, 24.59, 35.26, 14.83, 10.33, 16.97, 10.29, 34.81, 25.71, 17.31, 29.85, 25.0, 13.39, 16.21, 17.51, 9.6, 20.9, 18.15]))
GenericTrace{Dict{Symbol,Any}}(Dict{Symbol,Any}(:type => "violin",:name => "(Female, Thur)",:orientation => "h",:x => [10.07, 34.83, 10.65, 12.43, 24.08, 13.42, 12.48, 29.8, 14.52, 11.38 … 18.64, 11.87, 19.81, 43.11, 13.0, 12.74, 13.0, 16.4, 16.47, 18.78]))
GenericTrace{Dict{Symbol,Any}}(Dict{Symbol,Any}(:type => "violin",:name => "(Male, Fri)",:orientation => "h",:x => [28.97, 22.49, 40.17, 27.28, 12.03, 21.01, 12.46, 12.16, 8.58, 13.42]))
GenericTrace{Dict{Symbol,Any}}(Dict{Symbol,Any}(:type => "violin",:name => "(Male, Sat)",:orientation => "h",:x => [20.65, 17.92, 39.42, 19.82, 17.81, 13.37, 12.69, 21.7, 9.55, 18.35 … 15.69, 11.61, 10.77, 15.53, 10.07, 12.6, 32.83, 29.03, 22.67, 17.82]))
GenericTrace{Dict{Symbol,Any}}(Dict{Symbol,Any}(:type => "violin",:name => "(Male, Sun)",:orientation => "h",:x => [10.34, 21.01, 23.68, 25.29, 8.77, 26.88, 15.04, 14.78, 10.27, 15.42 … 34.63, 34.65, 23.33, 45.35, 23.17, 40.55, 20.69, 30.46, 23.1, 15.69]))
GenericTrace{Dict{Symbol,Any}}(Dict{Symbol,Any}(:type => "violin",:name => "(Male, Thur)",:orientation => "h",:x => [27.2, 22.76, 17.29, 19.44, 16.66, 32.68, 15.98, 13.03, 18.28, 24.71 … 9.78, 7.51, 28.44, 15.48, 16.58, 7.56, 10.34, 13.51, 18.71, 20.53]))
julia> [t[:name] for t in traces]
8-element Array{String,1}:
"(Female, Fri)"
"(Female, Sat)"
"(Female, Sun)"
"(Female, Thur)"
"(Male, Fri)"
"(Male, Sat)"
"(Male, Sun)"
"(Male, Thur)"
Also new in version 0.9.0, when using the DataFrame API you are allowed to pass a function as the value for a keyword argument. When the each trace is constructed, the value will be replaced by calling the function on whatever DataFrame is being used. When used in conjunction with the group
argument, this allows you to compute group specific trace attributes on the fly.
See the docstring for GenericTrace
and the violin_side_by_side
example on the Violin example page more details.
Facets
New in PlotlyBase version 0.6.5 (PlotlyJS version 0.16.4) |
When plotting a DataFrame
(let’s call it df
), the keyword arguments facet_row
and facet_col
allow you to create a matrix of subplots. The rows of this matrix correspond unique(df[:facet_row])
, where :facet_row
is a placeholder for the actual value passed as the facet_row
argument. Similarly, the columns of the matrix of subplots come from unique(df[:facet_col])
.
Each subplot will have the same structure, as defined by the keyword arguments passed to plot
, but will only show data for a single value of facet_row
and facet_col
at a time.
Below is an example of how this works
julia> using PlotlyJS, CSV, DataFrames
julia> df = dataset(DataFrame, "tips")
244×7 DataFrame
Row │ total_bill tip sex smoker day time size
│ Float64 Float64 String7 String3 String7 String7 Int64
─────┼────────────────────────────────────────────────────────────────
1 │ 16.99 1.01 Female No Sun Dinner 2
2 │ 10.34 1.66 Male No Sun Dinner 3
3 │ 21.01 3.5 Male No Sun Dinner 3
4 │ 23.68 3.31 Male No Sun Dinner 2
5 │ 24.59 3.61 Female No Sun Dinner 4
6 │ 25.29 4.71 Male No Sun Dinner 4
7 │ 8.77 2.0 Male No Sun Dinner 2
8 │ 26.88 3.12 Male No Sun Dinner 4
⋮ │ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮
238 │ 32.83 1.17 Male Yes Sat Dinner 2
239 │ 35.83 4.67 Female No Sat Dinner 3
240 │ 29.03 5.92 Male No Sat Dinner 3
241 │ 27.18 2.0 Female Yes Sat Dinner 2
242 │ 22.67 2.0 Male Yes Sat Dinner 2
243 │ 17.82 1.75 Male No Sat Dinner 2
244 │ 18.78 3.0 Female No Thur Dinner 2
229 rows omitted
julia> plot(
df, x=:total_bill, y=:tip, xbingroyp="x", ybingroup="y", kind="histogram2d",
facet_row=:sex, facet_col=:smoker
)
data: [
"histogram2d with fields type, x, xaxis, xbingroyp, y, yaxis, and ybingroup",
"histogram2d with fields type, x, xaxis, xbingroyp, y, yaxis, and ybingroup",
"histogram2d with fields type, x, xaxis, xbingroyp, y, yaxis, and ybingroup",
"histogram2d with fields type, x, xaxis, xbingroyp, y, yaxis, and ybingroup"
]
layout: "layout with fields annotations, legend, margin, template, xaxis, xaxis2, xaxis3, xaxis4, yaxis, yaxis2, yaxis3, and yaxis4"