Merge pull request #1208 from apalugniok/polar-output

Polar plots consistency
This commit is contained in:
Michael Krabbe Borregaard 2017-11-13 05:17:46 +01:00 committed by GitHub
commit 183f399341
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 140 additions and 46 deletions

View File

@ -239,8 +239,13 @@ function get_ticks(axis::Axis)
# discrete ticks...
axis[:continuous_values], dvals
elseif ticks == :auto
# compute optimal ticks and labels
optimal_ticks_and_labels(axis)
if ispolar(axis.sps[1]) && axis[:letter] == :x
#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}
# override ticks, but get the labels
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)
amin, amax = 0.0, 1.0
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)
else
amin, amax

View File

@ -205,35 +205,62 @@ function gr_text(x, y, s)
end
end
function gr_polaraxes(rmin, rmax)
function gr_polaraxes(rmin::Real, rmax::Real, sp::Subplot)
GR.savestate()
GR.setlinetype(GR.LINETYPE_SOLID)
GR.setlinecolorind(88)
tick = 0.5 * GR.tick(rmin, rmax)
n = round(Int, (rmax - rmin) / tick + 0.5)
for i in 0:n
r = float(i) / n
if i % 2 == 0
GR.setlinecolorind(88)
if i > 0
GR.drawarc(-r, r, -r, r, 0, 359)
end
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)))
else
GR.setlinecolorind(90)
GR.drawarc(-r, r, -r, r, 0, 359)
xaxis = sp[:xaxis]
yaxis = sp[:yaxis]
α = 0:45:315
a = α .+ 90
sinf = sind.(a)
cosf = cosd.(a)
rtick_values, rtick_labels = get_ticks(yaxis)
#draw angular grid
if xaxis[:grid]
gr_set_line(xaxis[:gridlinewidth], xaxis[:gridstyle], xaxis[:foreground_color_grid])
GR.settransparency(xaxis[:gridalpha])
for i in 1:length(α)
GR.polyline([sinf[i], 0], [cosf[i], 0])
end
end
for α in 0:45:315
a = α + 90
sinf = sin(a * pi / 180)
cosf = cos(a * pi / 180)
GR.polyline([sinf, 0], [cosf, 0])
GR.settextalign(GR.TEXT_HALIGN_CENTER, GR.TEXT_VALIGN_HALF)
x, y = GR.wctondc(1.1 * sinf, 1.1 * cosf)
GR.textext(x, y, string(α, "^o"))
#draw radial grid
if yaxis[:grid]
gr_set_line(yaxis[:gridlinewidth], yaxis[:gridstyle], yaxis[:foreground_color_grid])
GR.settransparency(yaxis[:gridalpha])
for i in 1:length(rtick_values)
r = (rtick_values[i] - rmin) / (rmax - rmin)
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
GR.restorestate()
end
@ -758,9 +785,9 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas)
elseif ispolar(sp)
r = gr_set_viewport_polar()
rmin, rmax = GR.adjustrange(ignorenan_minimum(r), ignorenan_maximum(r))
# rmin, rmax = axis_limits(sp[:yaxis])
gr_polaraxes(rmin, rmax)
#rmin, rmax = GR.adjustrange(ignorenan_minimum(r), ignorenan_maximum(r))
rmin, rmax = axis_limits(sp[:yaxis])
gr_polaraxes(rmin, rmax, sp)
elseif draw_axes
if xmax > xmin && ymax > ymin

View File

@ -245,7 +245,7 @@ function _series_added(plt::Plot{InspectDRBackend}, series::Series)
#No support for polar grid... but can still perform polar transformation:
if ispolar(sp)
Θ = x; r = y
x = r.*cos(Θ); y = r.*sin(Θ)
x = r.*cos.(Θ); y = r.*sin.(Θ)
end
# doesn't handle mismatched x/y - wrap data (pyplot behaviour):

View File

@ -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.
# See "Scatter Plots" in PGFPlots documentation
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
d[:x], d[:y]
end
@ -295,19 +298,23 @@ function pgf_axis(sp::Subplot, letter)
# grid on or off
if axis[:grid] && framestyle != :none
push!(style, "$(letter)majorgrids = true")
else
push!(style, "$(letter)majorgrids = false")
end
# limits
# TODO: support zlims
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,:max)] = lims[2]
end
if !(axis[:ticks] in (nothing, false, :none)) && framestyle != :none
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
# wrap the power part of label with }
tick_labels = String[begin
@ -317,7 +324,8 @@ function pgf_axis(sp::Subplot, letter)
end for label in ticks[2]]
push!(style, string(letter, "ticklabels = {\$", join(tick_labels,"\$,\$"), "\$}"))
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
push!(style, string(letter, "ticklabels = {}"))
end
@ -405,6 +413,9 @@ function _update_plot_object(plt::Plot{PGFPlotsBackend})
axisf = PGFPlots.Axis
if sp[:projection] == :polar
axisf = PGFPlots.PolarAxis
#make radial axis vertical
kw[:xmin] = 90
kw[:xmax] = 450
end
# Search series for any gradient. In case one series uses a gradient set

View File

@ -291,6 +291,22 @@ function plotly_axis(axis::Axis, sp::Subplot)
ax
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)
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
d_out[Symbol("xaxis$spidx")] = plotly_axis(sp[:xaxis], sp)
d_out[Symbol("yaxis$spidx")] = plotly_axis(sp[:yaxis], sp)
@ -698,8 +717,9 @@ end
function plotly_polar!(d_out::KW, series::Series)
# convert polar plots x/y to theta/radius
if ispolar(series[:subplot])
d_out[:t] = rad2deg(pop!(d_out, :x))
d_out[:r] = pop!(d_out, :y)
theta, r = filter_radial_data(pop!(d_out, :x), pop!(d_out, :y), axis_limits(series[:subplot][:yaxis]))
d_out[:t] = rad2deg.(theta)
d_out[:r] = r
end
end

View File

@ -1054,6 +1054,9 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
end
py_set_scale(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)
# don't show the 0 tick label for the origin framestyle
if sp[:framestyle] == :origin && length(ticks) > 1
@ -1080,6 +1083,8 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
linewidth = axis[:gridlinewidth],
alpha = axis[:gridalpha])
ax[:set_axisbelow](true)
else
pyaxis[:grid](false)
end
py_set_axis_colors(sp, ax, axis)
end
@ -1088,7 +1093,11 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
if !sp[:xaxis][:showaxis]
kw = KW()
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"
end
ax[:xaxis][:set_tick_params](; which="both", kw...)
@ -1096,7 +1105,9 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
if !sp[:yaxis][:showaxis]
kw = KW()
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"
end
ax[:yaxis][:set_tick_params](; which="both", kw...)

View File

@ -363,15 +363,26 @@ end
function convert_to_polar(x, y, r_extrema = calc_r_extrema(x, y))
rmin, rmax = r_extrema
phi, r = x, y
theta, r = filter_radial_data(x, y, r_extrema)
r = (r - rmin) / (rmax - rmin)
n = max(length(phi), length(r))
x = zeros(n)
y = zeros(n)
x = r.*cos.(theta)
y = r.*sin.(theta)
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
x[i] = _cycle(r,i) * cos.(_cycle(phi,i))
y[i] = _cycle(r,i) * sin.(_cycle(phi,i))
x[i] = _cycle(theta, i)
y[i] = _cycle(r, i)
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
end