From f04db1f405d5a25304cbd4edfe0bd3b9b2b2c931 Mon Sep 17 00:00:00 2001 From: Stefan Pinnow Date: Sun, 9 Mar 2025 15:14:30 +0100 Subject: [PATCH 1/2] formatting and typos --- README.md | 27 ++++---- julia/shapes.md | 179 ++++++++++++++++++++++++------------------------ 2 files changed, 106 insertions(+), 100 deletions(-) diff --git a/README.md b/README.md index 44aca83..eaca64d 100644 --- a/README.md +++ b/README.md @@ -10,27 +10,29 @@ Documentation for the Plotly Julia graphing library. ## Developer Setup - **Julia setup** -1. Download and install latest Julia from official source: https://julialang.org/downloads/ (at least version 1.6) -2. Start Julia in this repo -3. At Julia prompt press `]` to move REPL into package mode. Prompt should be `(@v1.6) pkg>` -4. At package prompt use command `activate .`. Prompt should now read `(plotlyjs.jl-docs) pkg>` -5. Install necessary Julia packages by entering `instantiate` command at package prompt +1. Download and install latest Julia from official source: https://julialang.org/downloads/ (at least version 1.6). +2. Start Julia in this repo. +3. At Julia prompt press `]` to move REPL into package mode. + Prompt should be `(@v1.6) pkg>`. +4. At package prompt use command `activate .`. + Prompt should now read `(plotlyjs.jl-docs) pkg>`. +5. Install necessary Julia packages by entering `instantiate` command at package prompt. ## Building docs -After completing installation steps above, you should be able to build the docs by running `make` or `make html` - -Note that `make` will process only modified markdown files from the `julia` directory. This will be done in a separate Julia process for each file +After completing installation steps above, you should be able to build the docs by running `make` or `make html`. -The `make html` will process ALL markdown files in the `julia` directory (even those that have not been modified) in a single Julia process with multiple threads. If you need to do a clean build of the docs the `make html` rule will be more efficient +Note that `make` will process only modified markdown files from the `julia` directory. +This will be done in a separate Julia process for each file. +The `make html` will process ALL markdown files in the `julia` directory (even those that have not been modified) in a single Julia process with multiple threads. +If you need to do a clean build of the docs the `make html` rule will be more efficient. ### Building from Julia -When working on many doc pages, it can greatly reduce Julia compiler times and overall latency to keep a Julia session runing while building. +When working on many doc pages, it can greatly reduce Julia compiler times and overall latency to keep a Julia session running while building. One common workflow would be to iteratively test if a single file can be build. @@ -44,4 +46,5 @@ include("make.jl") process_file("my-file.md") ``` -This will cause just the only file `julia/my-file.md` to be built. If, after making some changes, you want to build again run the `process_file("my-file.md")` command again. +This will cause just the only file `julia/my-file.md` to be built. +If, after making some changes, you want to build again run the `process_file("my-file.md")` command again. diff --git a/julia/shapes.md b/julia/shapes.md index e70ab30..2e95017 100644 --- a/julia/shapes.md +++ b/julia/shapes.md @@ -28,26 +28,29 @@ jupyter: As a general rule, there are two ways to add shapes (lines or polygons) to figures: -1. Trace types in the `scatter` family (e.g. `scatter`, `scatter3d`, `scattergeo` etc) can be drawn with `mode="lines"` and optionally support a `fill="self"` attribute, and so can be used to draw open or closed shapes on figures. -2. Standalone lines, ellipses and rectangles can be added to figures using `fig.add_shape()`, and they can be positioned absolutely within the figure, or they can be positioned relative to the axes of 2d cartesian subplots i.e. in data coordinates. +1. Trace types in the `scatter` family (e.g. `scatter`, `scatter3d`, `scattergeo` etc.) can be drawn with `mode="lines"` and optionally support a `fill="self"` attribute, and so can be used to draw open or closed shapes on figures. +2. Standalone lines, ellipses and rectangles can be added to figures using `fig.add_shape()`, and they can be positioned absolutely within the figure, or they can be positioned relative to the axes of 2d Cartesian subplots, i.e. in data coordinates. _Note:_ there are special functions `add_hline!`, `add_vline!`, `add_hrect!` and `add_vrect!` for the common cases of wanting to draw horizontal or vertical lines or rectangles that are fixed to data coordinates in one axis and absolutely positioned in another. The differences between these two approaches are that: - Traces can optionally support hover labels and can appear in legends. -- Shapes can be positioned absolutely or relative to data coordinates in 2d cartesian subplots only. +- Shapes can be positioned absolutely or relative to data coordinates in 2d Cartesian subplots only. - Traces cannot be positioned absolutely but can be positioned relative to date coordinates in any subplot type. - Traces also support [optional text](/julia/text-and-annotations/), although there is a [textual equivalent to shapes in text annotations](/julia/text-and-annotations/). ### Shape-drawing with Scatter traces -There are two ways to draw filled shapes: scatter traces and [layout.shapes](https://plotly.com/julia/reference/layout/shapes/#layout-shapes-items-shape-type) which is mostly useful for the 2d subplots, and defines the shape type to be drawn, and can be rectangle, circle, line, or path (a custom SVG path). You also can use [scatterpolar](https://plotly.com/julia/polar-chart/#categorical-polar-chart), scattergeo, scattermapbox to draw filled shapes on any kind of subplots. To set an area to be filled with a solid color, you need to define [scatter.fill="toself"](https://plotly.com/julia/reference/scatter/#scatter-fill) that connects the endpoints of the trace into a closed shape. If `mode=line` (default value), then you need to repeat the initial point of a shape at the of the sequence to have a closed shape. +There are two ways to draw filled shapes: scatter traces and [layout.shapes](https://plotly.com/julia/reference/layout/shapes/#layout-shapes-items-shape-type) which is mostly useful for the 2d subplots, and defines the shape type to be drawn, and can be rectangle, circle, line, or path (a custom SVG path). +You also can use [scatterpolar](https://plotly.com/julia/polar-chart/#categorical-polar-chart), scattergeo, scattermapbox to draw filled shapes on any kind of subplots. +To set an area to be filled with a solid color, you need to define [scatter.fill="toself"](https://plotly.com/julia/reference/scatter/#scatter-fill) that connects the endpoints of the trace into a closed shape. +If `mode=line` (default value), then you need to repeat the initial point of a shape at the end of the sequence to have a closed shape. ```julia using PlotlyJS -plot(scatter(x=[0,1,2,0], y=[0,2,0,0], fill="toself")) +plot(scatter(x=[0, 1, 2, 0], y=[0, 2, 0, 0], fill="toself")) ``` You can have more shapes either by adding more traces or interrupting the series with `nothing`. @@ -55,7 +58,10 @@ You can have more shapes either by adding more traces or interrupting the series ```julia using PlotlyJS -plot(scatter(x=[0,1,2,0,nothing,3,3,5,5,3], y=[0,2,0,0,nothing,0.5,1.5,1.5,0.5,0.5], fill="toself")) +plot(scatter( + x=[0, 1, 2, 0, nothing, 3, 3, 5, 5, 3], + y=[0, 2, 0, 0, nothing, 0.5, 1.5, 1.5, 0.5, 0.5], fill="toself", +)) ``` #### Vertical and Horizontal Lines Positioned Relative to the Axis Data @@ -71,7 +77,7 @@ p = plot(scatter( "Horizontal Dashed Line", "Diagonal dotted Line"], mode="text", -), Layout(xaxis_range=[0,7], yaxis_range=[0,2.5])) +), Layout(xaxis_range=[0, 7], yaxis_range=[0, 2.5])) add_shape!(p, line( x0=1, y0=0, @@ -85,7 +91,7 @@ add_shape!(p, line( color="LightSeaGreen", width=4, dash="dashdot", - ) + ), )) add_shape!(p, line( @@ -94,13 +100,13 @@ add_shape!(p, line( color="MediumPurple", width=4, dash="dot", - ) + ), )) p ``` -#### Lines Positioned Relative to the Plot & to the Axis Data +#### Lines Positioned Relative to the Plot and to the Axis Data ```julia using PlotlyJS @@ -113,12 +119,11 @@ trace = scatter( mode="text", ) - layout = Layout( # Set axes ranges - xaxis_range=[0,8], - yaxis_range=[0,2], - shapes = [ + xaxis_range=[0, 8], + yaxis_range=[0, 2], + shapes=[ line( xref="x", yref="y", x0=4, y0=0, x1=8, y1=1, @@ -135,8 +140,8 @@ layout = Layout( color="DarkOrange", width=3, ), - ) - ] + ), + ], ) plot(trace, layout) @@ -155,13 +160,13 @@ trace = scatter( ) layout = Layout( # Set axes properties - xaxis=attr(range=[0,7], showgrid=false), - yaxis_range=[0,3.5], + xaxis=attr(range=[0, 7], showgrid=false), + yaxis_range=[0, 3.5], # Add shapes shapes=[ rect( x0=1, y0=1, x1=2, y1=3, - line_color = "RoyalBlue", + line_color="RoyalBlue", xref='x', yref='y' ), rect( @@ -171,15 +176,15 @@ layout = Layout( width=2, ), fillcolor="LightSkyBlue", - xref='x', yref='y' - ) - ] + xref='x', yref='y', + ), + ], ) plot(trace, layout) ``` -#### Rectangle Positioned Relative to the Plot & to the Axis Data +#### Rectangle Positioned Relative to the Plot and to the Axis Data ```julia using PlotlyJS @@ -194,11 +199,11 @@ trace = scatter( ) layout = Layout( # Set axes properties - xaxis_range=[0,4], - yaxis_range=[0,4], + xaxis_range=[0, 4], + yaxis_range=[0, 4], shapes=[ rect( - xref="x", yref="y", + xref="x", yref="y", x0=2.5, y0=0, x1=3.5, y1=2, line=attr( @@ -215,8 +220,9 @@ layout = Layout( color="LightSeaGreen", width=3, ), - fillcolor="PaleTurquoise",) - ] + fillcolor="PaleTurquoise", + ), + ], ) plot(trace, layout) ``` @@ -224,7 +230,7 @@ plot(trace, layout) #### A Rectangle Placed Relative to the Axis Position and Length A shape can be placed relative to an axis's position on the plot by adding the -string `' domain'` to the axis reference in the `xref` or `yref` attributes for +string `"domain"` to the axis reference in the `xref` or `yref` attributes for shapes. The following code places a rectangle that starts at 60% and ends at 70% along the x-axis, starting from the left, and starts at 80% and ends at 90% along the @@ -245,9 +251,9 @@ p = plot( rect( xref="x domain", yref="y domain", x0=0.6, x1=0.7, y0=0.8, y1=0.9, - ) - ] - ) + ), + ], + ), ) ``` @@ -269,7 +275,7 @@ fig = plot(scatter( y=[-14, -17, -8, -4, -7, -10, -12, -14, -12, -7, -11, -7, -18, -14, -14, -16, -13, -7, -8, -14, -8, -3, -9, -9, -4, -13, -9, -6], mode="lines", - name="temperature" + name="temperature", )) # Add shape regions @@ -286,7 +292,6 @@ add_vrect!(fig, ) fig - ``` #### Circles Positioned Relative to the Axis Data @@ -320,11 +325,10 @@ layout = Layout( fillcolor="PaleTurquoise", x0=3, y0=3, x1=4, y1=4, line_color="LightSeaGreen", - ) - ] + ), + ], ) plot(trace, layout) - ``` #### Highlighting Clusters of Scatter Points with Circle Shapes @@ -363,11 +367,11 @@ layout = Layout( opacity=0.2, fillcolor="orange", line_color="orange", - ) - ] + ), + ], ) -plot([trace1, trace2] , layout) +plot([trace1, trace2], layout) ``` #### Venn Diagram with Circle Shapes @@ -384,8 +388,8 @@ p = plot(scatter( textfont=attr( color="black", size=18, - family="Arail", - ) + family="Arial", + ), )) # Update axes properties @@ -411,14 +415,14 @@ relayout!( circle( line_color="blue", fillcolor="blue", x0=0, y0=0, x1=2, y1=2, - opacity=0.3, xref="x", yref="y" + opacity=0.3, xref="x", yref="y", ), circle( line_color="gray", fillcolor="gray", x0=1.5, y0=0, x1=3.5, y1=2, - opacity=0.3, xref="x", yref="y" - ) - ] + opacity=0.3, xref="x", yref="y", + ), + ], ) p @@ -434,10 +438,10 @@ using PlotlyJS # Create Subplots fig = make_subplots(rows=2, cols=2, specs=fill(Spec(kind="scatter"), 2, 2)) -add_trace!(fig, scatter(x=[2, 6], y=[1,1]), row=1, col=1) -add_trace!(fig, bar(x=[1,2,3], y=[4,5,6]), row=1, col=2) -add_trace!(fig, scatter(x=[10,20], y=[40,50]), row=2, col=1) -add_trace!(fig, bar(x=[11,13,15], y=[8,11,20]), row=2, col=2) +add_trace!(fig, scatter(x=[2, 6], y=[1, 1]), row=1, col=1) +add_trace!(fig, bar(x=[1, 2, 3], y=[4, 5, 6]), row=1, col=2) +add_trace!(fig, scatter(x=[10, 20], y=[40, 50]), row=2, col=1) +add_trace!(fig, bar(x=[11, 13, 15], y=[8, 11, 20]), row=2, col=2) # Add shapes relayout!(fig, @@ -454,11 +458,10 @@ relayout!(fig, fig ``` - #### Adding the Same Shapes to Multiple Subplots -The same shape can be added to multiple facets by using the `'all'` -keyword in the `row` and `col` arguments. For example +The same shape can be added to multiple facets by using the `"all"` keyword in the `row` and `col` arguments. +For example ```julia using PlotlyJS, CSV, DataFrames @@ -467,9 +470,7 @@ df = dataset(DataFrame, "tips"); p = plot(df, x=:total_bill, y=:tip, facet_row=:smoker, facet_col=:sex, mode="markers") add_shape!(p, rect(x0=25, x1=35, y0=4, y1=6, line_color="purple"), row="all", col="all") - add_shape!(p, line(x0=20, x1=25, y0=5, y1=6, line_color="yellow"), row="all", col=2) - add_shape!(p, circle(x0=10, y0=2, x1=20, y1=7, line_color="green"), row=2, col="all") p ``` @@ -479,15 +480,14 @@ p ```julia using PlotlyJS - # Create scatter trace of text labels fig = plot(scatter( x=[2, 1, 8, 8], y=[0.25, 9, 2, 6], text=["Filled Triangle", "Filled Polygon", - "Quadratic Bezier Curves", - "Cubic Bezier Curves"], + "Quadratic Bézier Curves", + "Cubic Bézier Curves"], mode="text", )) @@ -505,46 +505,48 @@ update_yaxes!(fig, # Add shapes relayout!(fig, shapes=[ - # Quadratic Bezier Curves + # Quadratic Bézier Curves attr( type="path", - path="M 4,4 Q 6,0 8,4", + path="M 4, 4 Q 6, 0 8, 4", line_color="RoyalBlue", ), - # Cubic Bezier Curves + # Cubic Bézier Curves attr( type="path", - path="M 1,4 C 2,8 6,4 8,8", + path="M 1, 4 C 2, 8 6, 4 8, 8", line_color="MediumPurple", ), # filled Triangle attr( type="path", - path=" M 1 1 L 1 3 L 4 1 Z", + path="M 1 1 L 1 3 L 4 1 Z", fillcolor="LightPink", line_color="Crimson", ), # filled Polygon attr( type="path", - path=" M 3,7 L2,8 L2,9 L3,10, L4,10 L5,9 L5,8 L4,7 Z", + path="M 3, 7 L2, 8 L2, 9 L3, 10, L4, 10 L5, 9 L5, 8 L4, 7 Z", fillcolor="PaleTurquoise", line_color="LightSeaGreen", ), - ] + ], ) fig - ``` ### Drawing shapes with a Mouse on Cartesian plots -You can create layout shapes programmatically, but you can also draw shapes manually by setting the `dragmode` to one of the shape-drawing modes: `'drawline'`,`'drawopenpath'`, `'drawclosedpath'`, `'drawcircle'`, or `'drawrect'`. If you need to switch between different shape-drawing or other dragmodes (panning, selecting, etc.), [modebar buttons can be added](/julia/configuration-options#add-optional-shapedrawing-buttons-to-modebar) in the `config` to select the dragmode. If you switch to a different dragmode such as pan or zoom, you will need to select the drawing tool in the modebar to go back to shape drawing. +You can create layout shapes programmatically, but you can also draw shapes manually by setting the `dragmode` to one of the shape-drawing modes: `"drawline"`, `"drawopenpath"`, `"drawclosedpath"`, `"drawcircle"`, or `"drawrect"`. +If you need to switch between different shape-drawing or other dragmodes (panning, selecting, etc.), [modebar buttons can be added](/julia/configuration-options#add-optional-shapedrawing-buttons-to-modebar) in the `config` to select the dragmode. +If you switch to a different dragmode such as pan or zoom, you will need to select the drawing tool in the modebar to go back to shape drawing. This shape-drawing feature is particularly interesting for annotating graphs, in particular [image traces] or [layout images](/julia/images). -Once you have drawn shapes, you can select and modify an existing shape by clicking on its boundary (note the arrow pointer). Its fillcolor turns to pink to highlight the activated shape and then you can +Once you have drawn shapes, you can select and modify an existing shape by clicking on its boundary (note the arrow pointer). +Its fillcolor turns to pink to highlight the activated shape and then you can - drag and resize it for lines, rectangles and circles/ellipses - drag and move individual vertices for closed paths @@ -563,36 +565,37 @@ config = PlotConfig( "drawclosedpath", "drawcircle", "drawrect", - "eraseshape" + "eraseshape", ] ) text="Click and drag here
to draw a rectangle

or select another shape
in the modebar" fig = plot(Layout( annotations=[ - attr( x=0.5, + attr( + x=0.5, y=0.5, text=text, xref="paper", yref="paper", showarrow=false, - font_size=20) + font_size=20), ], - # shape defined programatically + # shape defined programmatically shapes=[ attr(editable=true, - x0=-1, x1=0, y0=2, y1=3, - xref='x', yref='y' - ) + x0=-1, x1=0, y0=2, y1=3, + xref='x', yref='y', + ), ], - dragmode="drawrect" + dragmode="drawrect", ), config=config) - ``` ### Style of user-drawn shapes -The layout `newshape` attribute controls the visual appearance of new shapes drawn by the user. `newshape` attributes have the same names as layout shapes. +The layout `newshape` attribute controls the visual appearance of new shapes drawn by the user. +`newshape` attributes have the same names as layout shapes. _Note on shape opacity_: having a new shape's opacity > 0.5 makes it possible to activate a shape by clicking inside the shape (for opacity <= 0.5 you have to click on the border of the shape), but you cannot start a new shape within an existing shape (which is possible for an opacity <= 0.5). @@ -611,8 +614,8 @@ fig = plot( xref="paper", yref="paper", showarrow=false, - font_size=20 - ) + font_size=20, + ), ], shapes=[ attr( @@ -621,8 +624,8 @@ fig = plot( opacity=0.4, editable=true, x0=0, x1=1, y0=2, y1=3, - xref="x", yref="y" - ) + xref="x", yref="y", + ), ], dragmode="drawrect", @@ -630,8 +633,8 @@ fig = plot( newshape=attr( line_color="yellow", fillcolor="turquoise", - opacity=0.5 - ) + opacity=0.5, + ), ), config=PlotConfig( modeBarButtonsToAdd=[ @@ -640,12 +643,12 @@ fig = plot( "drawclosedpath", "drawcircle", "drawrect", - "eraseshape" - ] - ) + "eraseshape", + ], + ), ) ``` ### Reference -See https://plotly.com/julia/reference/layout/shapes/ for more information and chart attribute options! +See for more information and chart attribute options! From 323e15a4ed127e5e8f0d2e8cfc88027ac90765e8 Mon Sep 17 00:00:00 2001 From: Stefan Pinnow Date: Sun, 9 Mar 2025 16:03:15 +0100 Subject: [PATCH 2/2] fix: use `line()`, `rect()`, `circle()` in `shapes[]` so `add_...!` can be used without that an error is thrown (see ). Remaining is `path()` which doesn't work or exist (see ) --- julia/shapes.md | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/julia/shapes.md b/julia/shapes.md index 2e95017..f03ba24 100644 --- a/julia/shapes.md +++ b/julia/shapes.md @@ -446,14 +446,25 @@ add_trace!(fig, bar(x=[11, 13, 15], y=[8, 11, 20]), row=2, col=2) # Add shapes relayout!(fig, shapes=[ - attr(type="line", xref="x", yref="y", - x0=3, y0=0.5, x1=5, y1=0.8, line_width=3), - attr(type="rect", xref="x2", yref="y4", - x0=4, y0=2, x1=5, y1=6), - attr(type="rect", xref="x3", yref="y3", - x0=10, y0=20, x1=15, y1=30), - attr(type="circle", xref="x4", yref="y4", - x0=5, y0=12, x1=10, y1=18)]) + line( + xref="x", yref="y", + x0=3, y0=0.5, x1=5, y1=0.8, + line_width=3, + ), + rect( + xref="x2", yref="y4", + x0=4, y0=2, x1=5, y1=6, + ), + rect( + xref="x3", yref="y3", + x0=10, y0=20, x1=15, y1=30, + ), + circle( + xref="x4", yref="y4", + x0=5, y0=12, x1=10, y1=18, + ), + ], +) fig ```