From a433a16caf19ce650e3d43ad4145476d6f1cd8c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Fuhrmann?= Date: Tue, 22 Jun 2021 22:47:02 +0200 Subject: [PATCH] Start plutovista (#3) PlutoVista scalarplot working for (1,1) layout and 1D/2D Co-authored-by: Juergen Fuhrmann --- Project.toml | 2 +- docs/Project.toml | 2 + docs/make.jl | 14 +++- examples/plutovista.jl | 148 +++++++++++++++++++++++++++++++++++++++++ src/GridVisualize.jl | 5 +- src/dispatch.jl | 20 ++++++ src/plutovista.jl | 74 +++++++++++++++++++++ src/pyplot.jl | 13 +++- 8 files changed, 270 insertions(+), 8 deletions(-) create mode 100644 examples/plutovista.jl create mode 100644 src/plutovista.jl diff --git a/Project.toml b/Project.toml index 51bcabd..1bedf24 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "GridVisualize" uuid = "5eed8a63-0fb0-45eb-886d-8d5a387d12b8" authors = ["Juergen Fuhrmann "] -version = "0.2.7" +version = "0.2.8" [deps] ColorSchemes = "35d6a980-a343-548e-a6ea-1d62b119f2f4" diff --git a/docs/Project.toml b/docs/Project.toml index cfa3214..c75a623 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -3,4 +3,6 @@ Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" ExtendableGrids = "cfc395e8-590f-11e8-1f13-43a2532b2fa8" GridVisualize = "5eed8a63-0fb0-45eb-886d-8d5a387d12b8" Literate = "98b081ad-f1c9-55d3-8b20-4c87d4299306" +Pluto = "c3e4b0f8-55cb-11ea-2926-15256bba5781" +PlutoVista = "646e1f28-b900-46d7-9d87-d554eb38a413" PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" diff --git a/docs/make.jl b/docs/make.jl index 191fbd8..a694c87 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,13 +1,22 @@ ENV["MPLBACKEND"]="agg" -using Documenter, ExtendableGrids, Literate, GridVisualize +using Documenter, ExtendableGrids, Literate, GridVisualize,Pluto using GridVisualize.FlippableLayout -import PyPlot +import PyPlot,PlutoVista plotting=joinpath(@__DIR__,"..","examples","plotting.jl") include(plotting) +function rendernotebook(name) + input=joinpath(@__DIR__,"..","examples",name*".jl") + output=joinpath(@__DIR__,"src",name*".html") + session = Pluto.ServerSession(); + notebook = Pluto.SessionActions.open(session, input; run_async=false) + html_contents = Pluto.generate_html(notebook) + write(output, html_contents) +end + include("makeplots.jl") @@ -17,6 +26,7 @@ example_md_dir = joinpath(@__DIR__,"src","examples") function mkdocs() Literate.markdown(plotting, example_md_dir, documenter=false,info=false) + rendernotebook("plutovista") # makeplots(example_md_dir) # generated_examples=joinpath.("examples",filter(x->endswith(x, ".md"),readdir(example_md_dir))) makedocs(sitename="GridVisualize.jl", diff --git a/examples/plutovista.jl b/examples/plutovista.jl new file mode 100644 index 0000000..a1ff55b --- /dev/null +++ b/examples/plutovista.jl @@ -0,0 +1,148 @@ +### A Pluto.jl notebook ### +# v0.14.8 + +using Markdown +using InteractiveUtils + +# This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error). +macro bind(def, element) + quote + local el = $(esc(element)) + global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : missing + el + end +end + +# ╔═╡ 6df3beed-24a7-4b26-a315-0520f4863190 +develop=true + +# ╔═╡ 9701cbe0-d048-11eb-151b-67dda7b72b71 +begin + using Pkg + Pkg.activate(mktempdir()) + Pkg.add("Revise") + using Revise + Pkg.add(["PyPlot","ExtendableGrids","PlutoUI"]) + if develop + Pkg.develop(["PlutoVista","GridVisualize"]) + else + Pkg.add(["PlutoVista","GridVisualize"]) + end + using PyPlot,PlutoVista,GridVisualize,ExtendableGrids,PlutoUI +end + +# ╔═╡ 68e2c958-b417-4ba1-9577-697304fe140a +TableOfContents() + +# ╔═╡ b35d982d-1fa9-413d-b008-892b4f241097 +md""" +# Test notebook for PlutoVista backend of GridVisualize +""" + +# ╔═╡ 00b04f6b-34a6-4e30-9864-d273305281d4 +md""" +## 1D scalar plot +""" + +# ╔═╡ a20d74c9-16da-408a-b247-0c17321888f9 +function testplot1(Plotter) + grid=simplexgrid(0:0.01:10) + scalarplot(grid,map(sin,grid),Plotter=Plotter,resolution=(600,300),markershape=:star5,markevery=20, xlabel="x",ylabel="z") +end + +# ╔═╡ cc17187f-404c-4c31-8625-fa067eea7273 +testplot1(PyPlot) + +# ╔═╡ 33482af8-3542-4723-ae43-770a789b69b3 +testplot1(PlutoVista) + +# ╔═╡ c4eeb06f-932e-4acc-8e5b-f2a7f9242a42 +function testplot2(Plotter;t=0) + p=GridVisualizer(Plotter=Plotter, resolution=(500,300),legend=:rt,xlabel="x") + grid=simplexgrid(0:0.01:10) + scalarplot!(p,grid,map(x->sin(x-t),grid),Plotter=Plotter,color=:red,label="sin",linestyle=:dash) + scalarplot!(p,grid,map(cos,grid),Plotter=Plotter,color=:green,clear=false,label="cos",linestyle=:dashdot,linewidth=3) + reveal(p) +end + +# ╔═╡ 29ca4775-6ba5-474c-bd2c-8f770b09addd +testplot2(PyPlot) + +# ╔═╡ 84192945-d4b6-4949-8f06-d94e04a7a56d +testplot2(PlutoVista) + +# ╔═╡ 63fe3259-7d79-40ec-98be-e0592e40ee6b +@bind t2 Slider(0:0.1:5,show_value=true) + +# ╔═╡ 4de6b5c9-4d2d-4bcb-bc88-c6f50a23f9b6 +testplot2(PlutoVista,t=t2) + +# ╔═╡ ae1fe1ab-4a0e-4c80-bd6f-912201fb4bb4 +md""" +## 2D Scalar plot +""" + +# ╔═╡ d5258595-60e4-406f-a71e-69111cdad8b9 +function testplot3(Plotter) + X=0:0.1:10 + grid=simplexgrid(X,X) + f=map( (x,y)->sin(x)*atan(y),grid) + scalarplot(grid,f,Plotter=Plotter,resolution=(300,300),flimits=(-π/2,π/2)) +end + +# ╔═╡ c98a90bf-1a3e-4681-a3b0-663c6844df6b +testplot3(PyPlot) + +# ╔═╡ 0998a9a7-d57a-476e-aacd-bee9396e9b8f +testplot3(PlutoVista) + +# ╔═╡ cefb38c1-159e-42db-8088-294573fcece2 +md""" +### Changeable data (experimental) +""" + +# ╔═╡ a9f4f98f-ec2f-42d6-88da-4a8a6f727e93 +begin + X=0:0.1:10 + grid=simplexgrid(X,X) + f(t)=map( (x,y)->sin(x-t)*atan(y),grid) +end + +# ╔═╡ 412c905f-050c-4b78-a66f-0d03978e7edf +vis=GridVisualizer(resolution=(300,300),Plotter=PlutoVista) + +# ╔═╡ 5608a6a1-bba5-4d20-85d6-66151c9ec4b3 +scalarplot!(vis[1,1],grid,f(0),resolution=(300,300),flimits=(-π/2,π/2),show=true) + +# ╔═╡ 6f1707ed-79ab-42dc-8ad8-d66a9e1a65b3 +md""" +t= $(@bind t Slider(-10:0.1:10, default=0, show_value=true)) +""" + +# ╔═╡ 461481ef-f88b-4e4e-b57d-ce003abbfdf1 +scalarplot!(vis[1,1],grid,f(t),resolution=(300,300),flimits=(-π/2,π/2),show=true) + +# ╔═╡ Cell order: +# ╠═6df3beed-24a7-4b26-a315-0520f4863190 +# ╠═9701cbe0-d048-11eb-151b-67dda7b72b71 +# ╠═68e2c958-b417-4ba1-9577-697304fe140a +# ╟─b35d982d-1fa9-413d-b008-892b4f241097 +# ╟─00b04f6b-34a6-4e30-9864-d273305281d4 +# ╠═a20d74c9-16da-408a-b247-0c17321888f9 +# ╠═cc17187f-404c-4c31-8625-fa067eea7273 +# ╠═33482af8-3542-4723-ae43-770a789b69b3 +# ╠═c4eeb06f-932e-4acc-8e5b-f2a7f9242a42 +# ╠═29ca4775-6ba5-474c-bd2c-8f770b09addd +# ╠═84192945-d4b6-4949-8f06-d94e04a7a56d +# ╠═63fe3259-7d79-40ec-98be-e0592e40ee6b +# ╠═4de6b5c9-4d2d-4bcb-bc88-c6f50a23f9b6 +# ╟─ae1fe1ab-4a0e-4c80-bd6f-912201fb4bb4 +# ╠═d5258595-60e4-406f-a71e-69111cdad8b9 +# ╠═c98a90bf-1a3e-4681-a3b0-663c6844df6b +# ╠═0998a9a7-d57a-476e-aacd-bee9396e9b8f +# ╟─cefb38c1-159e-42db-8088-294573fcece2 +# ╠═a9f4f98f-ec2f-42d6-88da-4a8a6f727e93 +# ╠═412c905f-050c-4b78-a66f-0d03978e7edf +# ╠═5608a6a1-bba5-4d20-85d6-66151c9ec4b3 +# ╠═461481ef-f88b-4e4e-b57d-ce003abbfdf1 +# ╟─6f1707ed-79ab-42dc-8ad8-d66a9e1a65b3 diff --git a/src/GridVisualize.jl b/src/GridVisualize.jl index 71bfb94..deec418 100644 --- a/src/GridVisualize.jl +++ b/src/GridVisualize.jl @@ -21,15 +21,16 @@ include("makie.jl") include("vtkview.jl") include("meshcat.jl") include("plots.jl") +include("plutovista.jl") export scalarplot,scalarplot! export gridplot,gridplot! export save,reveal,backend! -export isplots,isvtkview,ispyplot,ismakie +export isplots,isvtkview,ispyplot,ismakie,isplutovista export GridVisualizer, SubVisualizer export plottertype, available_kwargs export default_plotter!, default_plotter -export PyPlotType,MakieType,PlotsType,VTKViewType +export PyPlotType,MakieType,PlotsType,VTKViewType, PlutoVistaType end diff --git a/src/dispatch.jl b/src/dispatch.jl index 6d124d2..f36cffc 100644 --- a/src/dispatch.jl +++ b/src/dispatch.jl @@ -60,6 +60,13 @@ Heuristically check if Plotter is MeshCat """ ismeshcat(Plotter)= (typeof(Plotter)==Module)&&isdefined(Plotter,:Visualizer) +""" +$(SIGNATURES) + +Heuristically check if Plotter is MeshCat +""" +isplutovista(Plotter)= (typeof(Plotter)==Module)&&isdefined(Plotter,:PlutoVistaPlot) + """ $(TYPEDEF) @@ -95,6 +102,13 @@ Abstract type for dispatching on plotter """ abstract type MeshCatType end +""" +$(TYPEDEF) + +Abstract type for dispatching on plotter +""" +abstract type PlutoVistaType end + """ $(SIGNATURES) @@ -111,6 +125,8 @@ function plottertype(Plotter::Union{Module,Nothing}) return VTKViewType elseif ismeshcat(Plotter) return MeshCatType + elseif isplutovista(Plotter) + return PlutoVistaType end Nothing end @@ -248,6 +264,9 @@ default_plot_kwargs()=OrderedDict{Symbol,Pair{Any,String}}( :resolution => Pair((500,500),"Plot window resolution"), :legend => Pair(:none,"Legend (position): one of [:none, :best, :lt, :ct, :rt, :lc, :rc, :lb, :cb, :rb]"), :title => Pair("","Plot title"), + :xlabel => Pair("","x axis label"), + :ylabel => Pair("","y axis label"), + :zlabel => Pair("","z axis label"), :xlimits => Pair((1,-1),"x limits"), :ylimits => Pair((1,-1),"y limits"), :zlimits => Pair((1,-1),"z limits"), @@ -281,6 +300,7 @@ default_plot_kwargs()=OrderedDict{Symbol,Pair{Any,String}}( :fignumber => Pair(1,"Figure number (PyPlot)"), :framepos => Pair(1,"Subplot position in frame (VTKView)"), :subplot => Pair((1,1),"Private: Actual subplot"), + :backend => Pair(:default,"Backend for PlutoVista plot"), ) # diff --git a/src/plutovista.jl b/src/plutovista.jl new file mode 100644 index 0000000..08e878b --- /dev/null +++ b/src/plutovista.jl @@ -0,0 +1,74 @@ + + +function initialize!(p::GridVisualizer,::Type{PlutoVistaType}) + PlutoVista=p.context[:Plotter] + layout=p.context[:layout] + @assert(layout==(1,1)) + p.context[:scene]=PlutoVista.PlutoVistaPlot(resolution=p.context[:resolution]) + for I in CartesianIndices(layout) + ctx=p.subplots[I] + ctx[:figure]=p.context[:scene] + end +end + + +function reveal(p::GridVisualizer,::Type{PlutoVistaType}) + p.context[:scene] +end + +function reveal(ctx::SubVisualizer,TP::Type{PlutoVistaType}) + if ctx[:show]||ctx[:reveal] + reveal(ctx[:GridVisualizer],TP) + end +end + + +gridplot!(ctx, TP::Type{PlutoVistaType}, ::Type{Val{1}}, grid)=nothing +function scalarplot!(ctx, TP::Type{PlutoVistaType}, ::Type{Val{1}}, grid,func) + PlutoVista=ctx[:Plotter] + coord=grid[Coordinates] + PlutoVista.plot!(ctx[:figure],coord[1,:],func, + color=ctx[:color], + markertype=ctx[:markershape], + markercount=length(func)÷ctx[:markevery], + linestyle=ctx[:linestyle], + xlabel=ctx[:xlabel], + ylabel=ctx[:ylabel], + label=ctx[:label], + linewidth=ctx[:linewidth], + legend=ctx[:legend], + xlimits=ctx[:xlimits], + ylimits=ctx[:flimits], + clear=ctx[:clear] + ) + reveal(ctx,TP) +end + +gridplot!(ctx, TP::Type{PlutoVistaType}, ::Type{Val{2}}, grid)=nothing +function scalarplot!(ctx, TP::Type{PlutoVistaType}, ::Type{Val{2}}, grid,func) + PlutoVista=ctx[:Plotter] + pts=grid[Coordinates] + tris=grid[CellNodes] + + isolines=ctx[:isolines] + fmin,fmax=ctx[:flimits] + + if fmin "upper center", :rt => "upper right", :lc => "center left", + :cc => "center center", :rc => "center right", :lb => "lower left", :cb => "lower center", @@ -352,10 +353,12 @@ function scalarplot!(ctx, TP::Type{PyPlotType}, ::Type{Val{1}},grid, func) ax.plot(coord[1,:],func, linestyle=lstyles[ctx[:linestyle]], color=ctx[:color], + linewidth=ctx[:linewidth], label=ctx[:label]) else ax.plot(coord[1,:],func, linestyle=lstyles[ctx[:linestyle]], + linewidth=ctx[:linewidth], color=ctx[:color]) end else @@ -366,7 +369,8 @@ function scalarplot!(ctx, TP::Type{PyPlotType}, ::Type{Val{1}},grid, func) label=ctx[:label], marker=mshapes[ctx[:markershape]], markevery=ctx[:markevery], - markersize=ctx[:markersize] + markersize=ctx[:markersize], + linewidth=ctx[:linewidth] ) else ax.plot(coord[1,:],func, @@ -374,7 +378,8 @@ function scalarplot!(ctx, TP::Type{PyPlotType}, ::Type{Val{1}},grid, func) color=ctx[:color], marker=mshapes[ctx[:markershape]], markevery=ctx[:markevery], - markersize=ctx[:markersize] + markersize=ctx[:markersize], + linewidth=ctx[:linewidth] ) end end @@ -383,9 +388,11 @@ function scalarplot!(ctx, TP::Type{PyPlotType}, ::Type{Val{1}},grid, func) # mpoints=markerpoints(points,ctx[:markers],Diagonal([1,1])) # ampoints=reshape(reinterpret(Float32,mpoints),(2,length(mpoints))) # ax.scatter(ampoints[1,:], ampoints[2,:],color=ctx[:color],label="") - + end ax.grid() + ax.set_xlabel(ctx[:xlabel]) + ax.set_ylabel(ctx[:ylabel]) if ctx[:legend]!=:none ax.legend(loc=leglocs[ctx[:legend]]) end