diff --git a/src/axes.jl b/src/axes.jl index 855f8d97..43813b89 100644 --- a/src/axes.jl +++ b/src/axes.jl @@ -287,8 +287,8 @@ end function expand_extrema!(ex::Extrema, v::Number) - ex.emin = NaNMath.min(v, ex.emin) - ex.emax = NaNMath.max(v, ex.emax) + ex.emin = isfinite(v) ? min(v, ex.emin) : ex.emin + ex.emax = isfinite(v) ? max(v, ex.emax) : ex.emax ex end @@ -303,8 +303,8 @@ expand_extrema!(axis::Axis, ::Bool) = axis[:extrema] function expand_extrema!(axis::Axis, v::Tuple{MIN,MAX}) where {MIN<:Number,MAX<:Number} ex = axis[:extrema] - ex.emin = NaNMath.min(v[1], ex.emin) - ex.emax = NaNMath.max(v[2], ex.emax) + ex.emin = isfinite(v[1]) ? min(v[1], ex.emin) : ex.emin + ex.emax = isfinite(v[2]) ? max(v[2], ex.emax) : ex.emax ex end function expand_extrema!(axis::Axis, v::AVec{N}) where N<:Number @@ -326,6 +326,9 @@ function expand_extrema!(sp::Subplot, d::KW) else letter == :x ? :y : letter == :y ? :x : :z end] + if letter != :z && d[:seriestype] == :straightline && any(series[:seriestype] != :straightline for series in series_list(sp)) && data[1] != data[2] + data = [NaN] + end axis = sp[Symbol(letter, "axis")] if isa(data, Volume) diff --git a/src/backends/gr.jl b/src/backends/gr.jl index 7ff6f606..6cc3ef19 100644 --- a/src/backends/gr.jl +++ b/src/backends/gr.jl @@ -48,7 +48,7 @@ const _gr_attr = merge_with_base_supported([ :contour_labels, ]) const _gr_seriestype = [ - :path, :scatter, + :path, :scatter, :straightline, :heatmap, :pie, :image, :contour, :path3d, :scatter3d, :surface, :wireframe, :shape @@ -1014,7 +1014,11 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) x, y = convert_to_polar(x, y, (rmin, rmax)) end - if st in (:path, :scatter) + if st == :straightline + x, y = straightline_data(sp, series) + end + + if st in (:path, :scatter, :straightline) if length(x) > 1 lz = series[:line_z] segments_iterator = if lz != nothing && length(lz) > 1 @@ -1036,7 +1040,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) end # draw the line(s) - if st == :path + if st in (:path, :straightline) for (i, rng) in enumerate(segments_iterator) gr_set_line(series[:linewidth], series[:linestyle], get_linecolor(sp, series, i)) #, series[:linealpha]) arrowside = isa(series[:arrow], Arrow) ? series[:arrow].side : :none @@ -1295,7 +1299,7 @@ function gr_display(sp::Subplot{GRBackend}, w, h, viewport_canvas) st == :shape && gr_polyline(x, y) end - if st == :path + if st in (:path, :straightline) GR.settransparency(gr_alpha(series[:linealpha])) if series[:fillrange] == nothing || series[:ribbon] != nothing GR.polyline([xpos - 0.07, xpos - 0.01], [ypos, ypos]) diff --git a/src/recipes.jl b/src/recipes.jl index aa37ee5c..bfe7d0b4 100644 --- a/src/recipes.jl +++ b/src/recipes.jl @@ -79,28 +79,26 @@ function hvline_limits(axis::Axis) end @recipe function f(::Type{Val{:hline}}, x, y, z) - xmin, xmax = hvline_limits(plotattributes[:subplot][:xaxis]) n = length(y) - newx = repmat(Float64[xmin, xmax, NaN], n) + newx = repmat(Float64[-1, 1, NaN], n) newy = vec(Float64[yi for i=1:3,yi=y]) x := newx y := newy - seriestype := :path + seriestype := :straightline () end -@deps hline path +@deps hline straightline @recipe function f(::Type{Val{:vline}}, x, y, z) - ymin, ymax = hvline_limits(plotattributes[:subplot][:yaxis]) n = length(y) newx = vec(Float64[yi for i=1:3,yi=y]) - newy = repmat(Float64[ymin, ymax, NaN], n) + newy = repmat(Float64[-1, 1, NaN], n) x := newx y := newy - seriestype := :path + seriestype := :straightline () end -@deps vline path +@deps vline straightline # --------------------------------------------------------------------------- # path and scatter @@ -999,15 +997,7 @@ end # ------------------------------------------------- "Adds a+bx... straight line over the current plot, without changing the axis limits" -function abline!(plt::Plot, a, b; kw...) - xl, yl = xlims(plt), ylims(plt) - x1, x2 = max(xl[1], (yl[1] - b)/a), min(xl[2], (yl[2] - b)/a) - if x2 > x1 - plot!(plt, x -> b + a*x, x1, x2; kw...) - else - nothing - end -end +abline!(plt::Plot, a, b; kw...) = plot!(plt, [0, 1], [b, b+a]; seriestype = :straightline, kw...) abline!(args...; kw...) = abline!(current(), args...; kw...) diff --git a/src/utils.jl b/src/utils.jl index cdab41c6..8710a5af 100644 --- a/src/utils.jl +++ b/src/utils.jl @@ -1079,3 +1079,44 @@ function convert_sci_unicode(label::AbstractString) end label end + +function straightline_data(sp::Subplot, series::Series) + xl, yl = isvertical(series.d) ? (xlims(sp), ylims(sp)) : (ylims(sp), xlims(sp)) + x, y = series[:x], series[:y] + n = length(x) + if n == 2 + return straightline_data(xl, yl, x, y) + else + k, r = divrem(n, 3) + if r == 0 + xdata, ydata = fill(NaN, n), fill(NaN, n) + for i in 1:k + inds = (3 * i - 2):(3 * i - 1) + xdata[inds], ydata[inds] = straightline_data(xl, yl, x[inds], y[inds]) + end + return xdata, ydata + else + error("Misformed data. `straightline_data` either accepts vectors of length 2 or 3k. The provided series has length $n") + end + end +end + +function straightline_data(xl, yl, x, y) + if y[1] == y[2] + if x[1] == x[2] + error("Two identical points cannot be used to describe a straight line.") + else + return [xl[1], xl[2]], [y[1], y[2]] + end + elseif x[1] == x[2] + return [x[1], x[2]], [yl[1], yl[2]] + else + # get a and b from the line y = a * x + b through the points given by + # the coordinates x and x + b = y[1] - (y[1] - y[2]) * x[1] / (x[1] - x[2]) + a = (y[1] - y[2]) / (x[1] - x[2]) + # get the data values + xdata = [clamp(x[1] + (x[1] - x[2]) * (ylim - y[1]) / (y[1] - y[2]), xl...) for ylim in yl] + return xdata, a .* xdata .+ b + end +end