Merge pull request #1208 from apalugniok/polar-output
Polar plots consistency
This commit is contained in:
commit
183f399341
20
src/axes.jl
20
src/axes.jl
@ -239,8 +239,13 @@ function get_ticks(axis::Axis)
|
|||||||
# discrete ticks...
|
# discrete ticks...
|
||||||
axis[:continuous_values], dvals
|
axis[:continuous_values], dvals
|
||||||
elseif ticks == :auto
|
elseif ticks == :auto
|
||||||
# compute optimal ticks and labels
|
if ispolar(axis.sps[1]) && axis[:letter] == :x
|
||||||
optimal_ticks_and_labels(axis)
|
#force theta axis to be full circle
|
||||||
|
(collect(0:pi/4:7pi/4), string.(0:45:315))
|
||||||
|
else
|
||||||
|
# compute optimal ticks and labels
|
||||||
|
optimal_ticks_and_labels(axis)
|
||||||
|
end
|
||||||
elseif typeof(ticks) <: Union{AVec, Int}
|
elseif typeof(ticks) <: Union{AVec, Int}
|
||||||
# override ticks, but get the labels
|
# override ticks, but get the labels
|
||||||
optimal_ticks_and_labels(axis, ticks)
|
optimal_ticks_and_labels(axis, ticks)
|
||||||
@ -427,7 +432,16 @@ function axis_limits(axis::Axis, should_widen::Bool = default_should_widen(axis)
|
|||||||
if !isfinite(amin) && !isfinite(amax)
|
if !isfinite(amin) && !isfinite(amax)
|
||||||
amin, amax = 0.0, 1.0
|
amin, amax = 0.0, 1.0
|
||||||
end
|
end
|
||||||
if should_widen
|
if ispolar(axis.sps[1])
|
||||||
|
if axis[:letter] == :x
|
||||||
|
amin, amax = 0, 2pi
|
||||||
|
elseif lims == :auto
|
||||||
|
#widen max radius so ticks dont overlap with theta axis
|
||||||
|
amin, amax + 0.1 * abs(amax - amin)
|
||||||
|
else
|
||||||
|
amin, amax
|
||||||
|
end
|
||||||
|
elseif should_widen
|
||||||
widen(amin, amax)
|
widen(amin, amax)
|
||||||
else
|
else
|
||||||
amin, amax
|
amin, amax
|
||||||
|
|||||||
@ -205,35 +205,62 @@ function gr_text(x, y, s)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function gr_polaraxes(rmin, rmax)
|
function gr_polaraxes(rmin::Real, rmax::Real, sp::Subplot)
|
||||||
GR.savestate()
|
GR.savestate()
|
||||||
GR.setlinetype(GR.LINETYPE_SOLID)
|
xaxis = sp[:xaxis]
|
||||||
GR.setlinecolorind(88)
|
yaxis = sp[:yaxis]
|
||||||
tick = 0.5 * GR.tick(rmin, rmax)
|
|
||||||
n = round(Int, (rmax - rmin) / tick + 0.5)
|
α = 0:45:315
|
||||||
for i in 0:n
|
a = α .+ 90
|
||||||
r = float(i) / n
|
sinf = sind.(a)
|
||||||
if i % 2 == 0
|
cosf = cosd.(a)
|
||||||
GR.setlinecolorind(88)
|
rtick_values, rtick_labels = get_ticks(yaxis)
|
||||||
if i > 0
|
|
||||||
GR.drawarc(-r, r, -r, r, 0, 359)
|
#draw angular grid
|
||||||
end
|
if xaxis[:grid]
|
||||||
GR.settextalign(GR.TEXT_HALIGN_LEFT, GR.TEXT_VALIGN_HALF)
|
gr_set_line(xaxis[:gridlinewidth], xaxis[:gridstyle], xaxis[:foreground_color_grid])
|
||||||
x, y = GR.wctondc(0.05, r)
|
GR.settransparency(xaxis[:gridalpha])
|
||||||
GR.text(x, y, string(signif(rmin + i * tick, 12)))
|
for i in 1:length(α)
|
||||||
else
|
GR.polyline([sinf[i], 0], [cosf[i], 0])
|
||||||
GR.setlinecolorind(90)
|
|
||||||
GR.drawarc(-r, r, -r, r, 0, 359)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
for α in 0:45:315
|
|
||||||
a = α + 90
|
#draw radial grid
|
||||||
sinf = sin(a * pi / 180)
|
if yaxis[:grid]
|
||||||
cosf = cos(a * pi / 180)
|
gr_set_line(yaxis[:gridlinewidth], yaxis[:gridstyle], yaxis[:foreground_color_grid])
|
||||||
GR.polyline([sinf, 0], [cosf, 0])
|
GR.settransparency(yaxis[:gridalpha])
|
||||||
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_HALF)
|
for i in 1:length(rtick_values)
|
||||||
x, y = GR.wctondc(1.1 * sinf, 1.1 * cosf)
|
r = (rtick_values[i] - rmin) / (rmax - rmin)
|
||||||
GR.textext(x, y, string(α, "^o"))
|
if r <= 1.0 && r >= 0.0
|
||||||
|
GR.drawarc(-r, r, -r, r, 0, 359)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
GR.drawarc(-1, 1, -1, 1, 0, 359)
|
||||||
|
end
|
||||||
|
|
||||||
|
#prepare to draw ticks
|
||||||
|
GR.settransparency(1)
|
||||||
|
GR.setlinecolorind(90)
|
||||||
|
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_HALF)
|
||||||
|
|
||||||
|
#draw angular ticks
|
||||||
|
if xaxis[:showaxis]
|
||||||
|
GR.drawarc(-1, 1, -1, 1, 0, 359)
|
||||||
|
for i in 1:length(α)
|
||||||
|
x, y = GR.wctondc(1.1 * sinf[i], 1.1 * cosf[i])
|
||||||
|
GR.textext(x, y, string((360-α[i])%360, "^o"))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
#draw radial ticks
|
||||||
|
if yaxis[:showaxis]
|
||||||
|
for i in 1:length(rtick_values)
|
||||||
|
r = (rtick_values[i] - rmin) / (rmax - rmin)
|
||||||
|
if r <= 1.0 && r >= 0.0
|
||||||
|
x, y = GR.wctondc(0.05, r)
|
||||||
|
gr_text(x, y, _cycle(rtick_labels, i))
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
GR.restorestate()
|
GR.restorestate()
|
||||||
end
|
end
|
||||||
@ -758,9 +785,9 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
|
|||||||
|
|
||||||
elseif ispolar(sp)
|
elseif ispolar(sp)
|
||||||
r = gr_set_viewport_polar()
|
r = gr_set_viewport_polar()
|
||||||
rmin, rmax = GR.adjustrange(ignorenan_minimum(r), ignorenan_maximum(r))
|
#rmin, rmax = GR.adjustrange(ignorenan_minimum(r), ignorenan_maximum(r))
|
||||||
# rmin, rmax = axis_limits(sp[:yaxis])
|
rmin, rmax = axis_limits(sp[:yaxis])
|
||||||
gr_polaraxes(rmin, rmax)
|
gr_polaraxes(rmin, rmax, sp)
|
||||||
|
|
||||||
elseif draw_axes
|
elseif draw_axes
|
||||||
if xmax > xmin && ymax > ymin
|
if xmax > xmin && ymax > ymin
|
||||||
|
|||||||
@ -245,7 +245,7 @@ function _series_added(plt::Plot{InspectDRBackend}, series::Series)
|
|||||||
#No support for polar grid... but can still perform polar transformation:
|
#No support for polar grid... but can still perform polar transformation:
|
||||||
if ispolar(sp)
|
if ispolar(sp)
|
||||||
Θ = x; r = y
|
Θ = x; r = y
|
||||||
x = r.*cos(Θ); y = r.*sin(Θ)
|
x = r.*cos.(Θ); y = r.*sin.(Θ)
|
||||||
end
|
end
|
||||||
|
|
||||||
# doesn't handle mismatched x/y - wrap data (pyplot behaviour):
|
# doesn't handle mismatched x/y - wrap data (pyplot behaviour):
|
||||||
|
|||||||
@ -223,6 +223,9 @@ function pgf_series(sp::Subplot, series::Series)
|
|||||||
# If a marker_z is used pass it as third coordinate to a 2D plot.
|
# If a marker_z is used pass it as third coordinate to a 2D plot.
|
||||||
# See "Scatter Plots" in PGFPlots documentation
|
# See "Scatter Plots" in PGFPlots documentation
|
||||||
d[:x], d[:y], d[:marker_z]
|
d[:x], d[:y], d[:marker_z]
|
||||||
|
elseif ispolar(sp)
|
||||||
|
theta, r = filter_radial_data(d[:x], d[:y], axis_limits(sp[:yaxis]))
|
||||||
|
rad2deg.(theta), r
|
||||||
else
|
else
|
||||||
d[:x], d[:y]
|
d[:x], d[:y]
|
||||||
end
|
end
|
||||||
@ -295,19 +298,23 @@ function pgf_axis(sp::Subplot, letter)
|
|||||||
# grid on or off
|
# grid on or off
|
||||||
if axis[:grid] && framestyle != :none
|
if axis[:grid] && framestyle != :none
|
||||||
push!(style, "$(letter)majorgrids = true")
|
push!(style, "$(letter)majorgrids = true")
|
||||||
|
else
|
||||||
|
push!(style, "$(letter)majorgrids = false")
|
||||||
end
|
end
|
||||||
|
|
||||||
# limits
|
# limits
|
||||||
# TODO: support zlims
|
# TODO: support zlims
|
||||||
if letter != :z
|
if letter != :z
|
||||||
lims = axis_limits(axis)
|
lims = ispolar(sp) && letter == :x ? rad2deg.(axis_limits(axis)) : axis_limits(axis)
|
||||||
kw[Symbol(letter,:min)] = lims[1]
|
kw[Symbol(letter,:min)] = lims[1]
|
||||||
kw[Symbol(letter,:max)] = lims[2]
|
kw[Symbol(letter,:max)] = lims[2]
|
||||||
end
|
end
|
||||||
|
|
||||||
if !(axis[:ticks] in (nothing, false, :none)) && framestyle != :none
|
if !(axis[:ticks] in (nothing, false, :none)) && framestyle != :none
|
||||||
ticks = get_ticks(axis)
|
ticks = get_ticks(axis)
|
||||||
push!(style, string(letter, "tick = {", join(ticks[1],","), "}"))
|
#pgf plot ignores ticks with angle below 90 when xmin = 90 so shift values
|
||||||
|
tick_values = ispolar(sp) && letter == :x ? [rad2deg.(ticks[1])[3:end]..., 360, 415] : ticks[1]
|
||||||
|
push!(style, string(letter, "tick = {", join(tick_values,","), "}"))
|
||||||
if axis[:showaxis] && axis[:scale] in (:ln, :log2, :log10) && axis[:ticks] == :auto
|
if axis[:showaxis] && axis[:scale] in (:ln, :log2, :log10) && axis[:ticks] == :auto
|
||||||
# wrap the power part of label with }
|
# wrap the power part of label with }
|
||||||
tick_labels = String[begin
|
tick_labels = String[begin
|
||||||
@ -317,7 +324,8 @@ function pgf_axis(sp::Subplot, letter)
|
|||||||
end for label in ticks[2]]
|
end for label in ticks[2]]
|
||||||
push!(style, string(letter, "ticklabels = {\$", join(tick_labels,"\$,\$"), "\$}"))
|
push!(style, string(letter, "ticklabels = {\$", join(tick_labels,"\$,\$"), "\$}"))
|
||||||
elseif axis[:showaxis]
|
elseif axis[:showaxis]
|
||||||
push!(style, string(letter, "ticklabels = {", join(ticks[2],","), "}"))
|
tick_labels = ispolar(sp) && letter == :x ? [ticks[2][3:end]..., "0", "45"] : ticks[2]
|
||||||
|
push!(style, string(letter, "ticklabels = {", join(tick_labels,","), "}"))
|
||||||
else
|
else
|
||||||
push!(style, string(letter, "ticklabels = {}"))
|
push!(style, string(letter, "ticklabels = {}"))
|
||||||
end
|
end
|
||||||
@ -405,6 +413,9 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
|
|||||||
axisf = PGFPlots.Axis
|
axisf = PGFPlots.Axis
|
||||||
if sp[:projection] == :polar
|
if sp[:projection] == :polar
|
||||||
axisf = PGFPlots.PolarAxis
|
axisf = PGFPlots.PolarAxis
|
||||||
|
#make radial axis vertical
|
||||||
|
kw[:xmin] = 90
|
||||||
|
kw[:xmax] = 450
|
||||||
end
|
end
|
||||||
|
|
||||||
# Search series for any gradient. In case one series uses a gradient set
|
# Search series for any gradient. In case one series uses a gradient set
|
||||||
|
|||||||
@ -291,6 +291,22 @@ function plotly_axis(axis::Axis, sp::Subplot)
|
|||||||
ax
|
ax
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function plotly_polaraxis(axis::Axis)
|
||||||
|
ax = KW(
|
||||||
|
:visible => axis[:showaxis],
|
||||||
|
:showline => axis[:grid],
|
||||||
|
)
|
||||||
|
|
||||||
|
if axis[:letter] == :x
|
||||||
|
ax[:range] = rad2deg.(axis_limits(axis))
|
||||||
|
else
|
||||||
|
ax[:range] = axis_limits(axis)
|
||||||
|
ax[:orientation] = -90
|
||||||
|
end
|
||||||
|
|
||||||
|
ax
|
||||||
|
end
|
||||||
|
|
||||||
function plotly_layout(plt::Plot)
|
function plotly_layout(plt::Plot)
|
||||||
d_out = KW()
|
d_out = KW()
|
||||||
|
|
||||||
@ -345,6 +361,9 @@ function plotly_layout(plt::Plot)
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
elseif ispolar(sp)
|
||||||
|
d_out[Symbol("angularaxis$spidx")] = plotly_polaraxis(sp[:xaxis])
|
||||||
|
d_out[Symbol("radialaxis$spidx")] = plotly_polaraxis(sp[:yaxis])
|
||||||
else
|
else
|
||||||
d_out[Symbol("xaxis$spidx")] = plotly_axis(sp[:xaxis], sp)
|
d_out[Symbol("xaxis$spidx")] = plotly_axis(sp[:xaxis], sp)
|
||||||
d_out[Symbol("yaxis$spidx")] = plotly_axis(sp[:yaxis], sp)
|
d_out[Symbol("yaxis$spidx")] = plotly_axis(sp[:yaxis], sp)
|
||||||
@ -698,8 +717,9 @@ end
|
|||||||
function plotly_polar!(d_out::KW, series::Series)
|
function plotly_polar!(d_out::KW, series::Series)
|
||||||
# convert polar plots x/y to theta/radius
|
# convert polar plots x/y to theta/radius
|
||||||
if ispolar(series[:subplot])
|
if ispolar(series[:subplot])
|
||||||
d_out[:t] = rad2deg(pop!(d_out, :x))
|
theta, r = filter_radial_data(pop!(d_out, :x), pop!(d_out, :y), axis_limits(series[:subplot][:yaxis]))
|
||||||
d_out[:r] = pop!(d_out, :y)
|
d_out[:t] = rad2deg.(theta)
|
||||||
|
d_out[:r] = r
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -1054,6 +1054,9 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
|||||||
end
|
end
|
||||||
py_set_scale(ax, axis)
|
py_set_scale(ax, axis)
|
||||||
py_set_lims(ax, axis)
|
py_set_lims(ax, axis)
|
||||||
|
if ispolar(sp) && letter == :y
|
||||||
|
ax[:set_rlabel_position](90)
|
||||||
|
end
|
||||||
ticks = sp[:framestyle] == :none ? nothing : get_ticks(axis)
|
ticks = sp[:framestyle] == :none ? nothing : get_ticks(axis)
|
||||||
# don't show the 0 tick label for the origin framestyle
|
# don't show the 0 tick label for the origin framestyle
|
||||||
if sp[:framestyle] == :origin && length(ticks) > 1
|
if sp[:framestyle] == :origin && length(ticks) > 1
|
||||||
@ -1080,6 +1083,8 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
|||||||
linewidth = axis[:gridlinewidth],
|
linewidth = axis[:gridlinewidth],
|
||||||
alpha = axis[:gridalpha])
|
alpha = axis[:gridalpha])
|
||||||
ax[:set_axisbelow](true)
|
ax[:set_axisbelow](true)
|
||||||
|
else
|
||||||
|
pyaxis[:grid](false)
|
||||||
end
|
end
|
||||||
py_set_axis_colors(sp, ax, axis)
|
py_set_axis_colors(sp, ax, axis)
|
||||||
end
|
end
|
||||||
@ -1088,7 +1093,11 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
|||||||
if !sp[:xaxis][:showaxis]
|
if !sp[:xaxis][:showaxis]
|
||||||
kw = KW()
|
kw = KW()
|
||||||
for dir in (:top, :bottom)
|
for dir in (:top, :bottom)
|
||||||
ax[:spines][string(dir)][:set_visible](false)
|
if ispolar(sp)
|
||||||
|
ax[:spines]["polar"][:set_visible](false)
|
||||||
|
else
|
||||||
|
ax[:spines][string(dir)][:set_visible](false)
|
||||||
|
end
|
||||||
kw[dir] = kw[Symbol(:label,dir)] = "off"
|
kw[dir] = kw[Symbol(:label,dir)] = "off"
|
||||||
end
|
end
|
||||||
ax[:xaxis][:set_tick_params](; which="both", kw...)
|
ax[:xaxis][:set_tick_params](; which="both", kw...)
|
||||||
@ -1096,7 +1105,9 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
|
|||||||
if !sp[:yaxis][:showaxis]
|
if !sp[:yaxis][:showaxis]
|
||||||
kw = KW()
|
kw = KW()
|
||||||
for dir in (:left, :right)
|
for dir in (:left, :right)
|
||||||
ax[:spines][string(dir)][:set_visible](false)
|
if !ispolar(sp)
|
||||||
|
ax[:spines][string(dir)][:set_visible](false)
|
||||||
|
end
|
||||||
kw[dir] = kw[Symbol(:label,dir)] = "off"
|
kw[dir] = kw[Symbol(:label,dir)] = "off"
|
||||||
end
|
end
|
||||||
ax[:yaxis][:set_tick_params](; which="both", kw...)
|
ax[:yaxis][:set_tick_params](; which="both", kw...)
|
||||||
|
|||||||
23
src/utils.jl
23
src/utils.jl
@ -363,15 +363,26 @@ end
|
|||||||
|
|
||||||
function convert_to_polar(x, y, r_extrema = calc_r_extrema(x, y))
|
function convert_to_polar(x, y, r_extrema = calc_r_extrema(x, y))
|
||||||
rmin, rmax = r_extrema
|
rmin, rmax = r_extrema
|
||||||
phi, r = x, y
|
theta, r = filter_radial_data(x, y, r_extrema)
|
||||||
r = (r - rmin) / (rmax - rmin)
|
r = (r - rmin) / (rmax - rmin)
|
||||||
n = max(length(phi), length(r))
|
x = r.*cos.(theta)
|
||||||
x = zeros(n)
|
y = r.*sin.(theta)
|
||||||
y = zeros(n)
|
x, y
|
||||||
|
end
|
||||||
|
|
||||||
|
# Filters radial data for points within the axis limits
|
||||||
|
function filter_radial_data(theta, r, r_extrema::Tuple{Real, Real})
|
||||||
|
n = max(length(theta), length(r))
|
||||||
|
rmin, rmax = r_extrema
|
||||||
|
x, y = zeros(n), zeros(n)
|
||||||
for i in 1:n
|
for i in 1:n
|
||||||
x[i] = _cycle(r,i) * cos.(_cycle(phi,i))
|
x[i] = _cycle(theta, i)
|
||||||
y[i] = _cycle(r,i) * sin.(_cycle(phi,i))
|
y[i] = _cycle(r, i)
|
||||||
end
|
end
|
||||||
|
points = map((a, b) -> (a, b), x, y)
|
||||||
|
filter!(a -> a[2] >= rmin && a[2] <= rmax, points)
|
||||||
|
x = map(a -> a[1], points)
|
||||||
|
y = map(a -> a[2], points)
|
||||||
x, y
|
x, y
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user