diff --git a/Project.toml b/Project.toml index 0000954..feba12e 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "GR" uuid = "28b8d3ca-fb5f-59d9-8090-bfdbd6d07a71" author = ["Josef Heinen (@jheinen)"] -version = "0.73.5" +version = "0.73.7" [deps] Artifacts = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" @@ -22,12 +22,13 @@ TOML = "fa267f1f-6049-4f14-aa54-33bafae1ed76" Tar = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" p7zip_jll = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" +Qt6Wayland_jll = "e99dba38-086e-5de3-a5b1-6e4c66e897c3" [compat] Artifacts = "1" DelimitedFiles = "1" Downloads = "1" -GR_jll = "=0.73.5" +GR_jll = "=0.73.7" HTTP = "0.8, 0.9, 1" JSON = "0.20, 0.21, 1" Preferences = "1" diff --git a/build_tarballs.jl b/build_tarballs.jl index 24c5ec7..aece154 100644 --- a/build_tarballs.jl +++ b/build_tarballs.jl @@ -3,13 +3,13 @@ using BinaryBuilder name = "GR" -version = v"0.73.5" +version = v"0.73.7" # Collection of sources required to complete build sources = [ - GitSource("https://github.com/sciapp/gr.git", "bdd3f65bd994eb146129565f035abe03edb92d3f.sha512 + GitSource("https://github.com/sciapp/gr.git", "a8f4f0b867ad8e40e9a927d72e4ada571fdca461"), FileSource("https://github.com/sciapp/gr/releases/download/v$version/gr-$version.js", - "186e9f15c4eb410b42b9ca19d87a548d3de7d81d21a11d3f7eb4783440117376", "gr.js"), + "89a114eac7e96f0a32441da01e1929068aeaa286ad2ea22f923420cff8d4e2a4", "gr.js"), ArchiveSource("https://github.com/phracker/MacOSX-SDKs/releases/download/10.15/MacOSX10.14.sdk.tar.xz", "0f03869f72df8705b832910517b47dd5b79eb4e160512602f593ed243b28715f") ] @@ -92,19 +92,20 @@ dependencies = [ Dependency("Cairo_jll"; compat="1.16.1"), Dependency("FFMPEG_jll"), Dependency("Fontconfig_jll"), + Dependency("FreeType2_jll"; compat="2.10.4"), Dependency("GLFW_jll"), Dependency("JpegTurbo_jll"), Dependency("libpng_jll"), Dependency("Libtiff_jll"; compat="~4.5.1"), Dependency("Pixman_jll"), HostBuildDependency("Qt6Base_jll"), - Dependency("Qt6Base_jll"; compat="~6.5.2"), # Never allow upgrading more than the minor version without recompilation + Dependency("Qt6Base_jll"; compat="~6.7.1"), # Never allow upgrading more than the minor version without recompilation BuildDependency("Xorg_libX11_jll"), BuildDependency("Xorg_xproto_jll"), Dependency("Zlib_jll"), ] # Build the tarballs, and possibly a `build.jl` as well. -# GCC version 10 because of Qt6.5 +# GCC version 10 because of Qt6.7 build_tarballs(ARGS, name, version, sources, script, platforms, products, dependencies; preferred_gcc_version = v"10", julia_compat="1.6") diff --git a/examples/gtk4_plots_ex.jl b/examples/gtk4_plots_ex.jl new file mode 100644 index 0000000..375666f --- /dev/null +++ b/examples/gtk4_plots_ex.jl @@ -0,0 +1,35 @@ +using Gtk4 +using Plots +using Printf + +c = GtkCanvas() + +function _plot(ctx, w, h) + ENV["GKS_WSTYPE"] = "142" + ENV["GKSconid"] = @sprintf("%lu", UInt64(ctx.ptr)) + gr(show=true) + plot(randn(10, 3), size=(w, h)) +end + +@guarded draw(c) do widget + ctx = getgc(c) + w = width(c) + h = height(c) + @show w, h + rectangle(ctx, 0, 0, w, h) + set_source_rgb(ctx, 1, 1, 1) + fill(ctx) + _plot(ctx, w, h) +end + +win = GtkWindow("Gtk4 example", 600, 450) +win[] = c + +e = GtkEventControllerMotion(c) + +function on_motion(controller, x, y) + win.title = @sprintf("(%g, %g)", x, y) + reveal(c) # triggers a redraw +end + +signal_connect(on_motion, e, "motion") diff --git a/examples/imgui_ex.jl b/examples/imgui_ex.jl index 9892996..b0ef5e6 100644 --- a/examples/imgui_ex.jl +++ b/examples/imgui_ex.jl @@ -1,27 +1,16 @@ -# This example requires CImGui#master -# -# import Pkg; Pkg.add(name="CImGui", rev="master") -# using CImGui -using CImGui.ImGuiGLFWBackend -using CImGui.ImGuiGLFWBackend.LibCImGui -using CImGui.ImGuiGLFWBackend.LibGLFW -using CImGui.ImGuiOpenGLBackend -using CImGui.ImGuiOpenGLBackend.ModernGL +using CImGui.lib using CImGui.CSyntax using CImGui.CSyntax.CStatic -using Printf + +import GLFW +import ModernGL as GL using GR using LaTeXStrings +using Printf -glfwDefaultWindowHints() -glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3) -glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2) -if Sys.isapple() - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE) # 3.2+ only - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE) # required on Mac -end +CImGui.set_backend(:GlfwOpenGL3) function draw(phi) formulas = ( @@ -48,78 +37,70 @@ function draw(phi) updatews() end -# create window -window = glfwCreateWindow(960, 720, "Demo", C_NULL, C_NULL) -@assert window != C_NULL -glfwMakeContextCurrent(window) -glfwSwapInterval(1) # enable vsync +function gr_demo(; engine=nothing) + # setup Dear ImGui context + ctx = CImGui.CreateContext() -# create OpenGL and GLFW context -window_ctx = ImGuiGLFWBackend.create_context(window) -gl_ctx = ImGuiOpenGLBackend.create_context() + # enable docking and multi-viewport + io = CImGui.GetIO() + io.ConfigFlags = unsafe_load(io.ConfigFlags) | CImGui.ImGuiConfigFlags_DockingEnable + io.ConfigFlags = unsafe_load(io.ConfigFlags) | CImGui.ImGuiConfigFlags_ViewportsEnable -# setup Dear ImGui context -ctx = CImGui.CreateContext() + # setup Dear ImGui style + CImGui.StyleColorsDark() -# create texture for image drawing -img_width, img_height = 500, 500 -image_id = ImGuiOpenGLBackend.ImGui_ImplOpenGL3_CreateImageTexture(img_width, img_height) + # When viewports are enabled we tweak WindowRounding/WindowBg so platform windows can look identical to regular ones. + style = Ptr{ImGuiStyle}(CImGui.GetStyle()) + if unsafe_load(io.ConfigFlags) & ImGuiConfigFlags_ViewportsEnable == ImGuiConfigFlags_ViewportsEnable + style.WindowRounding = 5.0f0 + col = CImGui.c_get(style.Colors, CImGui.ImGuiCol_WindowBg) + CImGui.c_set!(style.Colors, CImGui.ImGuiCol_WindowBg, ImVec4(col.x, col.y, col.z, 1.0f0)) + end -ENV["GKS_WSTYPE"] = "100" -image = rand(GLuint, img_width, img_height) # allocate the memory -mem = Printf.@sprintf("%p",pointer(image)) -conid = Printf.@sprintf("!%dx%d@%s.mem", img_width, img_height, mem[3:end]) + # create texture for image drawing + img_width, img_height = 500, 500 + image_id = nothing -# setup Platform/Renderer bindings -ImGuiGLFWBackend.init(window_ctx) -ImGuiOpenGLBackend.init(gl_ctx) + ENV["GKS_WSTYPE"] = "100" + image = rand(GL.GLubyte, 4, img_width, img_height) + mem = Printf.@sprintf("%p",pointer(image)) + conid = Printf.@sprintf("!%dx%d@%s.mem", img_width, img_height, mem[3:end]) -try clear_color = Cfloat[0.45, 0.55, 0.60, 1.00] - while glfwWindowShouldClose(window) == 0 - glfwPollEvents() - # start the Dear ImGui frame - ImGuiOpenGLBackend.new_frame(gl_ctx) - ImGuiGLFWBackend.new_frame(window_ctx) - CImGui.NewFrame() - - # show image example - CImGui.Begin("GR Demo") + image_id = nothing + CImGui.render(ctx; engine, clear_color=Ref(clear_color)) do @cstatic phi = Cfloat(0.0) begin + CImGui.Begin("GR Demo") + if isnothing(image_id) + image_id = CImGui.create_image_texture(img_width, img_height) + end + @c CImGui.SliderFloat("Angle", &phi, 0, 360, "%.4f") + + size = CImGui.GetWindowSize() + canvas = CImGui.GetWindowPos() + mouse_x = unsafe_load(CImGui.GetIO().MousePos.x) + mouse_y = unsafe_load(CImGui.GetIO().MousePos.y) + x = (mouse_x - canvas.x) / size.x + y = 1 - (mouse_y - canvas.y) / size.y + if 0 <= x <= 1 && 0 <= y <= 1 + @c CImGui.Text("($(round(x, digits=4)), $(round(y, digits=4)))") + end + CImGui.SetCursorPos(0, 0) + beginprint(conid) draw(phi * π/180) endprint() - ImGuiOpenGLBackend.ImGui_ImplOpenGL3_UpdateImageTexture(image_id, image, img_width, img_height) + CImGui.update_image_texture(image_id, image, img_width, img_height) CImGui.Image(Ptr{Cvoid}(image_id), CImGui.ImVec2(img_width, img_height)) CImGui.End() end - - # rendering - CImGui.Render() - glfwMakeContextCurrent(window) - - width, height = Ref{Cint}(), Ref{Cint}() #! need helper fcn - glfwGetFramebufferSize(window, width, height) - display_w = width[] - display_h = height[] - - glViewport(0, 0, display_w, display_h) - glClearColor(clear_color...) - glClear(GL_COLOR_BUFFER_BIT) - ImGuiOpenGLBackend.render(gl_ctx) - - glfwMakeContextCurrent(window) - glfwSwapBuffers(window) end -catch e - @error "Error in renderloop!" exception=e - Base.show_backtrace(stderr, catch_backtrace()) -finally - ImGuiOpenGLBackend.shutdown(gl_ctx) - ImGuiGLFWBackend.shutdown(window_ctx) - CImGui.DestroyContext(ctx) - glfwDestroyWindow(window) +end + +# Run automatically if the script is launched from the command-line +if !isempty(Base.PROGRAM_FILE) + gr_demo() end diff --git a/examples/snoop.jl b/examples/snoop.jl index f624526..f74dfc7 100644 --- a/examples/snoop.jl +++ b/examples/snoop.jl @@ -150,7 +150,10 @@ if !haskey(ENV, "GRDISPLAY") surface(x, y, z, 5) contour(x, y, h, z, 0) polymarker(xd, yd) - GR.axes(0.25, 0.25, -2, -2, 2, 2, 0.01) + + x_axis = axis('X', tick=0.25, org=-2, major_count=2, tick_size=0.01) + y_axis = axis('Y', tick=0.25, org=-2, major_count=2, tick_size=0.01) + drawaxes(x_axis, y_axis, GR.AXES_SIMPLE_AXES) updatews() end diff --git a/src/GR.jl b/src/GR.jl index 5e3c53e..5c4f247 100644 --- a/src/GR.jl +++ b/src/GR.jl @@ -24,6 +24,11 @@ module GR Base.Experimental.@optlevel 1 end +if haskey(ENV, "WAYLAND_DISPLAY") || get(ENV, "XDG_SESSION_TYPE", "") == "wayland" + # loading this automatially on Wayland ensures that applications run natively on Wayland without user intervention + using Qt6Wayland_jll +end + import Base64 import Libdl @@ -189,6 +194,10 @@ export inqmathfont, setclipregion, inqclipregion, + setclipsector, + inqclipsector, + getformat, + ftoa, # Convenience functions jlgr, colormap, @@ -244,7 +253,13 @@ export isinline, inline, displayname, - mainloop + mainloop, + axis, + drawaxis, + drawaxes, + GRAxis, + GRTick, + GRTickLabel const ENCODING_LATIN1 = 300 const ENCODING_UTF8 = 301 @@ -3631,6 +3646,13 @@ const XFORM_LOGLOG = 3 const XFORM_CUBIC = 4 const XFORM_EQUALIZED = 5 +const AXES_SIMPLE_AXES = 1 +const AXES_TWIN_AXES = 2 +const AXES_WITH_GRID = 4 + +const REGION_RECTANGLE = 0 +const REGION_ELLIPSE = 1 + # GR3 functions include("gr3.jl") @@ -3651,6 +3673,59 @@ Base.show(io::IO, ::MIME"image/svg+xml", x::SVG) = write(io, x.s) Base.show(io::IO, ::MIME"image/png", x::PNG) = write(io, x.s) Base.show(io::IO, ::MIME"text/html", x::HTML) = print(io, x.s) +struct c_tick_t + value::Cdouble + is_major::Cint +end + +struct c_tick_label_t + tick::Cdouble + label::Cstring + width::Cdouble +end + +Base.@kwdef mutable struct c_axis_t + min::Cdouble = NaN + max::Cdouble = NaN + tick::Cdouble = NaN + org::Cdouble = NaN + position::Cdouble = NaN + major_count::Cint = 1 + num_ticks::Cint = 0 + ticks::Ptr{c_tick_t} = C_NULL + tick_size::Cdouble = NaN + num_tick_labels::Cint = 0 + tick_labels::Ptr{c_tick_label_t} = C_NULL + label_position::Cdouble = NaN + draw_axis_line::Cint = 1 +end + +mutable struct GRTick + value::Real + is_major::Int +end + +mutable struct GRTickLabel + tick::Real + label::String + width::Real +end + +Base.@kwdef mutable struct GRAxis + min::Real = NaN + max::Real = NaN + tick::Real = NaN + org::Real = NaN + position::Real = NaN + major_count::Int = 1 + num_ticks::Int = 0 + ticks::Vector{GRTick} = nothing + tick_size::Real = NaN + tick_labels::Vector{GRTickLabel} = nothing + label_position::Real = NaN + draw_axis_line::Int = 1 +end + function _readfile(path) data = Array{UInt8}(undef, filesize(path)) s = open(path, "r") @@ -4380,6 +4455,127 @@ function inqclipregion() return _region[1] end +function setclipsector(start_angle::Real, end_angle::Real) + ccall( libGR_ptr(:gr_setclipsector), + Nothing, + (Cdouble, Cdouble), + start_angle, end_angle) +end + +function inqclipsector() + _start_angle = Cdouble[0] + _end_angle = Cdouble[0] + ccall( libGR_ptr(:gr_inqclipsector), + Nothing, + (Ptr{Cdouble}, Ptr{Cdouble}), + _start_angle, _end_angle) + return _start_angle[1], _end_angle[1] +end + +function getformat(origin::Real, amin::Real, amax::Real, tick::Real, major::Int) + _format = Cint[0, 0] + ccall( libGR_ptr(:gr_getformat), + Nothing, + (Ptr{Cint}, Cdouble, Cdouble, Cdouble, Cdouble, Cint), + _format, origin, amin, amax, tick, major) + return Int32[_format...] +end + +function ftoa(value::Real, format::Vector{Int32}) + string = Vector{UInt8}(undef, 256) + s = ccall( libGR_ptr(:gr_ftoa), + Cstring, + (Ptr{UInt8}, Cdouble, Ptr{Cint}), + string, value, format) + return unsafe_string(s) +end + +function axis(which::Char; min::Real = NaN, max::Real = NaN, tick::Real = NaN, org::Real = NaN, position::Real = NaN, major_count::Int = 1, ticks::Union{Vector{GRTick}, Nothing} = nothing, tick_size::Real = NaN, tick_labels::Union{Vector{GRTickLabel}, Nothing} = nothing, label_position::Real = NaN, draw_axis_line::Int = 1)::GRAxis + c_axis = c_axis_t(min=min, max=max, tick=tick, org=org, position=position, major_count=major_count, tick_size=tick_size, label_position=label_position, draw_axis_line=draw_axis_line) + if ticks != nothing + c_axis.ticks = pointer(ticks) + c_axis.num_ticks = size(ticks)[1] + else + c_axis.ticks = C_NULL + c_axis.num_ticks = 0 + end + if tick_labels != nothing + c_axis.tick_labels = pointer(tick_labels) + c_axis.num_tick_labels = size(tick_labels)[1] + else + c_axis.tick_labels = C_NULL + c_axis.num_tick_labels = 0 + end + ccall( libGR_ptr(:gr_axis), + Nothing, + (Cchar, Ptr{c_axis_t}), + which, Ref(c_axis)) + + ticks = GRTick[] + for i in 1:c_axis.num_ticks + tick = unsafe_load(c_axis.ticks, i) + push!(ticks, GRTick(tick.value, tick.is_major)) + end + + tick_labels = GRTickLabel[] + for i in 1:c_axis.num_tick_labels + tick_label = unsafe_load(c_axis.tick_labels, i) + if tick_label.label != C_NULL + push!(tick_labels, GRTickLabel(tick_label.tick, unsafe_string(tick_label.label), tick_label.width)) + end + end + + return GRAxis(min=c_axis.min, max=c_axis.max, tick=c_axis.tick, org=c_axis.org, position=c_axis.position, major_count=c_axis.major_count, ticks=ticks, tick_size=c_axis.tick_size, tick_labels=tick_labels, label_position=c_axis.label_position, draw_axis_line=c_axis.draw_axis_line) +end + +function to_c_axis(axis::GRAxis)::c_axis_t + c_axis = c_axis_t(min=axis.min, max=axis.max, tick=axis.tick, org=axis.org, position=axis.position, major_count=axis.major_count, tick_size=axis.tick_size, label_position=axis.label_position, draw_axis_line=axis.draw_axis_line) + if axis.ticks != nothing + ticks = c_tick_t[] + for tick in axis.ticks + push!(ticks, c_tick_t(tick.value, tick.is_major)) + end + c_axis.ticks = pointer(ticks) + c_axis.num_ticks = size(axis.ticks)[1] + else + c_axis.ticks = C_NULL + c_axis.num_ticks = 0 + end + if axis.tick_labels != nothing + tick_labels = c_tick_label_t[] + for tick_label in axis.tick_labels + push!(tick_labels, c_tick_label_t(tick_label.tick, pointer(tick_label.label), tick_label.width)) + end + c_axis.tick_labels = pointer(tick_labels) + c_axis.num_tick_labels = size(axis.tick_labels)[1] + else + c_axis.tick_labels = C_NULL + c_axis.num_tick_labels = 0 + end + c_axis +end + +function drawaxis(which::Char, axis::GRAxis) + c_axis = to_c_axis(axis) + ccall( libGR_ptr(:gr_drawaxis), + Nothing, + (Cchar, Ptr{c_axis_t}), + which, Ref(c_axis)) +end + +function drawaxes(x_axis::Union{GRAxis, Nothing}, y_axis::Union{GRAxis, Nothing}, options::Int=AXES_SIMPLE_AXES|AXES_TWIN_AXES|AXES_WITH_GRID) + if x_axis !== nothing + c_x_axis = to_c_axis(x_axis) + end + if y_axis !== nothing + c_y_axis = to_c_axis(y_axis) + end + ccall( libGR_ptr(:gr_drawaxes), + Nothing, + (Ptr{c_axis_t}, Ptr{c_axis_t}, Cint), + x_axis !== nothing ? Ref(c_x_axis) : C_NULL, y_axis !== nothing ? Ref(c_y_axis) : C_NULL, options) +end + # JS functions include("js.jl") diff --git a/src/downloader.jl b/src/downloader.jl index caac597..d76987d 100644 --- a/src/downloader.jl +++ b/src/downloader.jl @@ -9,7 +9,7 @@ using Tar using Downloads using p7zip_jll -const version = v"0.73.5" +const version = v"0.73.7" """ get_grdir() diff --git a/src/jlgr.jl b/src/jlgr.jl index a517625..ca8cf5f 100644 --- a/src/jlgr.jl +++ b/src/jlgr.jl @@ -61,8 +61,6 @@ shade, setpanzoom, mainloop -signif(x, digits; base = 10) = round(x, sigdigits = digits, base = base) - const PlotArg = Union{AbstractString, AbstractVector, AbstractMatrix, Function} const kw_args = [:accelerate, :algorithm, :alpha, :backgroundcolor, :barwidth, :baseline, :clabels, :clines, :color, :colormap, :figsize, :font, :isovalue, :labels, :levels, :location, :nbins, :rotation, :size, :tilt, :title, :where, :xflip, :xform, :xlabel, :xlim, :xlog, :yflip, :ylabel, :ylim, :ylog, :zflip, :zlabel, :zlim, :zlog, :clim, :subplot, :linewidth, :grid, :scale, :theta_direction, :theta_zero_location, :dpi, :keepaspect] @@ -503,8 +501,10 @@ function set_window(kind, plt=plt[]) plt.kvs[:window] = xmin, xmax, ymin, ymax if !(kind === :polar || kind === :polarhist || kind === :polarheatmap || kind === :nonuniformpolarheatmap) GR.setwindow(xmin, xmax, ymin, ymax) + GR.setclipregion(GR.REGION_RECTANGLE) else GR.setwindow(-1, 1, -1, 1) + GR.setclipregion(GR.REGION_ELLIPSE) end if kind === :wireframe || kind === :surface || kind === :plot3 || kind === :scatter3 || kind === :trisurf || kind === :volume rotation = get(plt.kvs, :rotation, 40) @@ -590,19 +590,26 @@ function draw_axes(kind, pass=1, plt=plt[]) else charheight = max(0.018 * diag, 0.012) GR.setcharheight(charheight) - if kind === :heatmap || kind === :nonuniformheatmap || kind === :shade + if kind === :heatmap || kind === :nonuniformheatmap || kind === :shade || kind === :contourf ticksize = -ticksize - else - drawgrid && GR.grid(xtick, ytick, 0, 0, majorx, majory) + if kind === :shade + drawgrid = false + end end if haskey(plt.kvs, :xticklabels) || haskey(plt.kvs, :yticklabels) + drawgrid && GR.grid(xtick, ytick, 0, 0, majorx, majory) fx = get(plt.kvs, :xticklabels, identity) |> ticklabel_fun fy = get(plt.kvs, :yticklabels, identity) |> ticklabel_fun GR.axeslbl(xtick, ytick, xorg[1], yorg[1], majorx, majory, ticksize, fx, fy) else - GR.axes(xtick, ytick, xorg[1], yorg[1], majorx, majory, ticksize) + x_axis = GR.axis('X', tick=xtick, org=xorg[1], major_count=majorx, tick_size=ticksize) + y_axis = GR.axis('Y', tick=ytick, org=yorg[1], major_count=majory, tick_size=ticksize) + options = GR.AXES_SIMPLE_AXES|GR.AXES_TWIN_AXES + if drawgrid + options |= GR.AXES_WITH_GRID + end + GR.drawaxes(x_axis, y_axis, options) end - GR.axes(xtick, ytick, xorg[2], yorg[2], -majorx, -majory, -ticksize) end if haskey(plt.kvs, :title) @@ -628,7 +635,7 @@ function draw_axes(kind, pass=1, plt=plt[]) end end -function draw_polar_axes(plt=plt[]) +function draw_polar_axes(pass=1, plt=plt[]) viewport = plt.kvs[:viewport] vp = plt.kvs[:vp] diag = sqrt((viewport[2] - viewport[1])^2 + (viewport[4] - viewport[3])^2) @@ -638,49 +645,70 @@ function draw_polar_axes(plt=plt[]) rmin, rmax = window[3], window[4] GR.savestate() - GR.setcharheight(charheight) GR.setlinetype(GR.LINETYPE_SOLID) + GR.setcharheight(charheight) tick = auto_tick(rmin, rmax) n = trunc(Int, (rmax - rmin) / tick) - for i in 0:n - r = rmin + i * tick / (rmax - rmin) - if i % 2 == 0 - GR.setlinecolorind(88) - if i > 0 - GR.drawarc(-r, r, -r, r, 0, 360) - end - else - GR.setlinecolorind(90) - GR.drawarc(-r, r, -r, r, 0, 360) - end + if n <= 4 + tick /= 2 + n *= 2 end - sign = if get(plt.kvs, :theta_direction, 1) > 0 1 else -1 end - offs = theta_zero_location[get(plt.kvs, :theta_zero_location, "E")] - for alpha in 0:45:315 - sinf = sin((alpha * sign) * π / 180 + offs) - cosf = cos((alpha * sign) * π / 180 + offs) + if pass == 1 + GR.selntran(1) + for i in 0:n + r = i * tick / (rmax - rmin) + if 0 < r < 1 + if i % 2 == 0 + GR.setlinecolorind(88) + GR.drawarc(-r, r, -r, r, 0, 360) + else + GR.setlinecolorind(90) + GR.drawarc(-r, r, -r, r, 0, 360) + end + end + end + GR.setclip(0) GR.setlinecolorind(88) - GR.polyline([cosf, 0], [sinf, 0]) - GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_HALF) - x, y = GR.wctondc(1.1 * cosf, 1.1 * sinf) - GR.text(x, y, string(alpha, "°")) - end - - for i in 0:n - r = rmin + i * tick / (rmax - rmin) - if i % 2 == 0 || i == n - GR.settextalign(GR.TEXT_HALIGN_LEFT, GR.TEXT_VALIGN_HALF) - x, y = GR.wctondc(0.05, r) - GR.text(x, y, string(signif(rmin + i * tick, 12))) + GR.drawarc(-1, 1, -1, 1, 0, 360) + + GR.setclip(1) + sign = if get(plt.kvs, :theta_direction, 1) > 0 1 else -1 end + offs = theta_zero_location[get(plt.kvs, :theta_zero_location, "E")] + for alpha in 0:45:315 + sinf = sin((alpha * sign) * π / 180 + offs) + cosf = cos((alpha * sign) * π / 180 + offs) + GR.setlinecolorind(88) + GR.polyline([cosf, 0], [sinf, 0]) + GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_HALF) + x, y = GR.wctondc(1.1 * cosf, 1.1 * sinf) + GR.text(x, y, string(alpha, "°")) + end + + if haskey(plt.kvs, :title) + GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP) + text(0.5 * (viewport[1] + viewport[2]), vp[4] - 0.02, plt.kvs[:title]) end end - if haskey(plt.kvs, :title) - GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_TOP) - text(0.5 * (viewport[1] + viewport[2]), vp[4] - 0.02, plt.kvs[:title]) + if pass == 2 + start = trunc(Int, floor(rmin / tick)) + for i in 0:n + j = start + i + if j * tick >= rmin + r = i * tick / (rmax - rmin) + if i % 2 == 0 + GR.settextalign(GR.TEXT_HALIGN_LEFT, GR.TEXT_VALIGN_HALF) + x, y = GR.wctondc(0.05, r) + fmt = GR.getformat(start, rmin, rmax, tick, 2) + s = GR.ftoa(j * tick, fmt) + GR.text(x, y, s) + end + end + end end + GR.restorestate() end @@ -801,6 +829,7 @@ function colorbar(off=0, colors=256, plt=plt[]) end h = 0 ###0.5 * (zmax - zmin) / (colors - 1) GR.setwindow(0, 1, zmin, zmax) + GR.setclipregion(GR.REGION_RECTANGLE) GR.setviewport(viewport[2] + 0.02 + off, viewport[2] + 0.05 + off, viewport[3], viewport[4]) l = Int32[round(1000 + _i * 255, RoundNearestTiesUp) for _i in linspace(0, 1, colors)] @@ -811,10 +840,12 @@ function colorbar(off=0, colors=256, plt=plt[]) GR.setcharheight(charheight) if plt.kvs[:scale] & GR.OPTION_Z_LOG == 0 ztick = auto_tick(zmin, zmax) - GR.axes(0, ztick, 1, zmin, 0, 1, 0.005) + y_axis = GR.axis('Y', position=1, tick=ztick, org=zmin, major_count=1, tick_size=0.005) + GR.drawaxis('Y', y_axis) else GR.setscale(GR.OPTION_Y_LOG) - GR.axes(0, 2, 1, zmin, 0, 1, 0.005) + y_axis = GR.axis('Y', position=1, tick=2, org=zmin, major_count=1, tick_size=0.005) + GR.drawaxis('Y', y_axis) end GR.restorestate() end @@ -1129,7 +1160,7 @@ function plot_polar(θ, ρ, plt=plt[]) rmin, rmax = window[3], window[4] sign = if get(plt.kvs, :theta_direction, 1) > 0 1 else -1 end offs = theta_zero_location[get(plt.kvs, :theta_zero_location, "E")] - ρ = ρ ./ rmax + ρ = (ρ .- rmin) ./ (rmax - rmin) n = length(ρ) x, y = zeros(n), zeros(n) for i in 1:n @@ -1412,6 +1443,7 @@ function plot_data(flag=true, plt=plt[]) GR.setfillintstyle(GR.INTSTYLE_HOLLOW) GR.fillarc(-ρ[i], ρ[i], -ρ[i], ρ[i], θ[i-1], θ[i]) end + draw_polar_axes(2) elseif kind === :polarheatmap || kind === :nonuniformpolarheatmap w, h = size(z) cmap = colormap() @@ -1432,7 +1464,8 @@ function plot_data(flag=true, plt=plt[]) θ = x * 180/π GR.nonuniformpolarcellarray(θ, ρ, w, h, colors) end - draw_polar_axes() + draw_polar_axes(1) + draw_polar_axes(2) plt.kvs[:zrange] = cmin, cmax colorbar(0.025) elseif kind === :contour @@ -1565,6 +1598,7 @@ function plot_data(flag=true, plt=plt[]) elseif kind === :polar GR.uselinespec(spec) plot_polar(x, y) + draw_polar_axes(2) elseif kind === :trisurf GR.trisurface(x, y, z) draw_axes(kind, 2) diff --git a/src/js.jl b/src/js.jl index a07d3c7..dabfba8 100644 --- a/src/js.jl +++ b/src/js.jl @@ -341,7 +341,7 @@ function recv(name::Cstring, id::Int32, msg::Cstring) # receives string from C and sends it to JS via Comm global draw_end_condition - id = string(UUIDs.uuid4()); + id = string(Base.UUID(rand(UInt128))) jsterm_send(unsafe_string(msg), id) return convert(Int32, 1) end @@ -391,7 +391,7 @@ function ws_cb(webs) end const plutoisinit = Ref(false) -const jssource = Ref("https://gr-framework.org/downloads/gr-0.73.5.js") +const jssource = Ref("https://gr-framework.org/downloads/gr-0.73.7.js") function init_pluto(source=jssource[]::String) plutoisinit[] = true @@ -406,7 +406,6 @@ function initjs() send_c[] = @cfunction(send, Cstring, (Cstring, Int32)) recv_c[] = @cfunction(recv, Int32, (Cstring, Int32, Cstring)) @eval js begin - import UUIDs import JSON end if haskey(ENV, "GR_JS") diff --git a/src/libgr_syms.jl b/src/libgr_syms.jl index 0f371fc..6f2e43e 100644 --- a/src/libgr_syms.jl +++ b/src/libgr_syms.jl @@ -163,4 +163,11 @@ :gr_inqmathfont :gr_setclipregion :gr_inqclipregion +:gr_setclipsector +:gr_inqclipsector +:gr_getformat +:gr_ftoa +:gr_axis +:gr_drawaxis +:gr_drawaxes ]