Colorbar enhancements (#3346)

* CompatHelper: bump compat for "Showoff" to "1.0"

* fix series-segments for empty series

* fix wireframe on pyplot

* colorbar redesign

* minimal working version

* reduce code duplication for colorbar ticks

* fix aspect_ratio in GR with legend=:outertopright

* fix GR test failure

* new release [skip ci]

* colorbar scale supported

* Added weights example to ? histogram

Helps to clarify the use of weights (which differs from StatsBase functions)

* Update precompile_*.jl file

* minor version bump [skip ci]

* working prototype

* fixed formatting, added colorbar docs

* colorbar redesign

* minimal working version

* reduce code duplication for colorbar ticks

* fix GR test failure

* colorbar scale supported

* working prototype

* fixed formatting, added colorbar docs

Co-authored-by: Daniel Schwabeneder <daschw@disroot.org>
This commit is contained in:
Zhanibek 2021-03-25 11:22:07 +09:00 committed by GitHub
parent 9fc1d574cd
commit c0824bdc62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 532 additions and 477 deletions

View File

@ -193,6 +193,7 @@ const _plotly_min_js_filename = "plotly-1.57.1.min.js"
include("types.jl") include("types.jl")
include("utils.jl") include("utils.jl")
include("colorbars.jl")
include("axes.jl") include("axes.jl")
include("args.jl") include("args.jl")
include("components.jl") include("components.jl")

View File

@ -2,164 +2,171 @@
const _arg_desc = KW( const _arg_desc = KW(
# series args # series args
:label => "String type. The label for a series, which appears in a legend. If empty, no legend entry is added.", :label => "String type. The label for a series, which appears in a legend. If empty, no legend entry is added.",
:seriescolor => "Color Type. The base color for this series. `:auto` (the default) will select a color from the subplot's `color_palette`, based on the order it was added to the subplot", :seriescolor => "Color Type. The base color for this series. `:auto` (the default) will select a color from the subplot's `color_palette`, based on the order it was added to the subplot",
:seriesalpha => "Number in [0,1]. The alpha/opacity override for the series. `nothing` (the default) means it will take the alpha value of the color.", :seriesalpha => "Number in [0,1]. The alpha/opacity override for the series. `nothing` (the default) means it will take the alpha value of the color.",
:seriestype => "Symbol. This is the identifier of the type of visualization for this series. Choose from $(_allTypes) or any series recipes which are defined.", :seriestype => "Symbol. This is the identifier of the type of visualization for this series. Choose from $(_allTypes) or any series recipes which are defined.",
:linestyle => "Symbol. Style of the line (for path and bar stroke). Choose from $(_allStyles)", :linestyle => "Symbol. Style of the line (for path and bar stroke). Choose from $(_allStyles)",
:linewidth => "Number. Width of the line (in pixels)", :linewidth => "Number. Width of the line (in pixels)",
:linecolor => "Color Type. Color of the line (for path and bar stroke). `:match` will take the value from `:seriescolor`, (though histogram/bar types use `:black` as a default).", :linecolor => "Color Type. Color of the line (for path and bar stroke). `:match` will take the value from `:seriescolor`, (though histogram/bar types use `:black` as a default).",
:linealpha => "Number in [0,1]. The alpha/opacity override for the line. `nothing` (the default) means it will take the alpha value of linecolor.", :linealpha => "Number in [0,1]. The alpha/opacity override for the line. `nothing` (the default) means it will take the alpha value of linecolor.",
:fillrange => "Number or AbstractVector. Fills area between fillrange and y for line-types, sets the base for bar/stick types, and similar for other types.", :fillrange => "Number or AbstractVector. Fills area between fillrange and y for line-types, sets the base for bar/stick types, and similar for other types.",
:fillcolor => "Color Type. Color of the filled area of path or bar types. `:match` will take the value from `:seriescolor`.", :fillcolor => "Color Type. Color of the filled area of path or bar types. `:match` will take the value from `:seriescolor`.",
:fillalpha => "Number in [0,1]. The alpha/opacity override for the fill area. `nothing` (the default) means it will take the alpha value of fillcolor.", :fillalpha => "Number in [0,1]. The alpha/opacity override for the fill area. `nothing` (the default) means it will take the alpha value of fillcolor.",
:markershape => "Symbol, Shape, or AbstractVector. Choose from $(_allMarkers).", :markershape => "Symbol, Shape, or AbstractVector. Choose from $(_allMarkers).",
:markercolor => "Color Type. Color of the interior of the marker or shape. `:match` will take the value from `:seriescolor`.", :markercolor => "Color Type. Color of the interior of the marker or shape. `:match` will take the value from `:seriescolor`.",
:markeralpha => "Number in [0,1]. The alpha/opacity override for the marker interior. `nothing` (the default) means it will take the alpha value of markercolor.", :markeralpha => "Number in [0,1]. The alpha/opacity override for the marker interior. `nothing` (the default) means it will take the alpha value of markercolor.",
:markersize => "Number or AbstractVector. Size (radius pixels) of the markers.", :markersize => "Number or AbstractVector. Size (radius pixels) of the markers.",
:markerstrokestyle => "Symbol. Style of the marker stroke (border). Choose from $(_allStyles)", :markerstrokestyle => "Symbol. Style of the marker stroke (border). Choose from $(_allStyles)",
:markerstrokewidth => "Number. Width of the marker stroke (border. in pixels)", :markerstrokewidth => "Number. Width of the marker stroke (border. in pixels)",
:markerstrokecolor => "Color Type. Color of the marker stroke (border). `:match` will take the value from `:foreground_color_subplot`.", :markerstrokecolor => "Color Type. Color of the marker stroke (border). `:match` will take the value from `:foreground_color_subplot`.",
:markerstrokealpha => "Number in [0,1]. The alpha/opacity override for the marker stroke (border). `nothing` (the default) means it will take the alpha value of markerstrokecolor.", :markerstrokealpha => "Number in [0,1]. The alpha/opacity override for the marker stroke (border). `nothing` (the default) means it will take the alpha value of markerstrokecolor.",
:bins => "Integer, NTuple{2,Integer}, AbstractVector or Symbol. Default is :auto (the Freedman-Diaconis rule). For histogram-types, defines the approximate number of bins to aim for, or the auto-binning algorithm to use (:sturges, :sqrt, :rice, :scott or :fd). For fine-grained control pass a Vector of break values, e.g. `range(minimum(x), stop = maximum(x), length = 25)`", :bins => "Integer, NTuple{2,Integer}, AbstractVector or Symbol. Default is :auto (the Freedman-Diaconis rule). For histogram-types, defines the approximate number of bins to aim for, or the auto-binning algorithm to use (:sturges, :sqrt, :rice, :scott or :fd). For fine-grained control pass a Vector of break values, e.g. `range(minimum(x), stop = maximum(x), length = 25)`",
:smooth => "Bool. Add a regression line?", :smooth => "Bool. Add a regression line?",
:group => "AbstractVector. Data is split into a separate series, one for each unique value in `group`.", :group => "AbstractVector. Data is split into a separate series, one for each unique value in `group`.",
:x => "Various. Input data. First Dimension", :x => "Various. Input data. First Dimension",
:y => "Various. Input data. Second Dimension", :y => "Various. Input data. Second Dimension",
:z => "Various. Input data. Third Dimension. May be wrapped by a `Surface` for surface and heatmap types.", :z => "Various. Input data. Third Dimension. May be wrapped by a `Surface` for surface and heatmap types.",
:marker_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or Function `f(x,y) -> z_value`, or nothing. z-values for each series data point, which correspond to the color to be used from a markercolor gradient.", :marker_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or Function `f(x,y) -> z_value`, or nothing. z-values for each series data point, which correspond to the color to be used from a markercolor gradient.",
:line_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or Function `f(x,y) -> z_value`, or nothing. z-values for each series line segment, which correspond to the color to be used from a linecolor gradient. Note that for N points, only the first N-1 values are used (one per line-segment).", :line_z => "AbstractVector, Function `f(x,y,z) -> z_value`, or Function `f(x,y) -> z_value`, or nothing. z-values for each series line segment, which correspond to the color to be used from a linecolor gradient. Note that for N points, only the first N-1 values are used (one per line-segment).",
:fill_z => "Matrix{Float64} of the same size as z matrix, which specifies the color of the 3D surface; the default value is `nothing`.", :fill_z => "Matrix{Float64} of the same size as z matrix, which specifies the color of the 3D surface; the default value is `nothing`.",
:levels => "Integer, NTuple{2,Integer}, or AbstractVector. Levels or number of levels (or x-levels/y-levels) for a contour type.", :levels => "Integer, NTuple{2,Integer}, or AbstractVector. Levels or number of levels (or x-levels/y-levels) for a contour type.",
:orientation => "Symbol. Horizontal or vertical orientation for bar types. Values `:h`, `:hor`, `:horizontal` correspond to horizontal (sideways, anchored to y-axis), and `:v`, `:vert`, and `:vertical` correspond to vertical (the default).", :orientation => "Symbol. Horizontal or vertical orientation for bar types. Values `:h`, `:hor`, `:horizontal` correspond to horizontal (sideways, anchored to y-axis), and `:v`, `:vert`, and `:vertical` correspond to vertical (the default).",
:bar_position => "Symbol. Choose from `:overlay` (default), `:stack`. (warning: May not be implemented fully)", :bar_position => "Symbol. Choose from `:overlay` (default), `:stack`. (warning: May not be implemented fully)",
:bar_width => "nothing or Number. Width of bars in data coordinates. When nothing, chooses based on x (or y when `orientation = :h`).", :bar_width => "nothing or Number. Width of bars in data coordinates. When nothing, chooses based on x (or y when `orientation = :h`).",
:bar_edges => "Bool. Align bars to edges (true), or centers (the default)?", :bar_edges => "Bool. Align bars to edges (true), or centers (the default)?",
:xerror => "AbstractVector or 2-Tuple of Vectors. x (horizontal) error relative to x-value. If 2-tuple of vectors, the first vector corresponds to the left error (and the second to the right)", :xerror => "AbstractVector or 2-Tuple of Vectors. x (horizontal) error relative to x-value. If 2-tuple of vectors, the first vector corresponds to the left error (and the second to the right)",
:yerror => "AbstractVector or 2-Tuple of Vectors. y (vertical) error relative to y-value. If 2-tuple of vectors, the first vector corresponds to the bottom error (and the second to the top)", :yerror => "AbstractVector or 2-Tuple of Vectors. y (vertical) error relative to y-value. If 2-tuple of vectors, the first vector corresponds to the bottom error (and the second to the top)",
:ribbon => "Number or AbstractVector. Creates a fillrange around the data points.", :ribbon => "Number or AbstractVector. Creates a fillrange around the data points.",
:quiver => "AbstractVector or 2-Tuple of vectors. The directional vectors U,V which specify velocity/gradient vectors for a quiver plot.", :quiver => "AbstractVector or 2-Tuple of vectors. The directional vectors U,V which specify velocity/gradient vectors for a quiver plot.",
:arrow => "nothing (no arrows), Bool (if true, default arrows), Arrow object, or arg(s) that could be style or head length/widths. Defines arrowheads that should be displayed at the end of path line segments (just before a NaN and the last non-NaN point). Used in quiverplot, streamplot, or similar.", :arrow => "nothing (no arrows), Bool (if true, default arrows), Arrow object, or arg(s) that could be style or head length/widths. Defines arrowheads that should be displayed at the end of path line segments (just before a NaN and the last non-NaN point). Used in quiverplot, streamplot, or similar.",
:normalize => "Bool or Symbol. Histogram normalization mode. Possible values are: false/:none (no normalization, default), true/:pdf (normalize to a discrete Probability Density Function, where the total area of the bins is 1), :probability (bin heights sum to 1) and :density (the area of each bin, rather than the height, is equal to the counts - useful for uneven bin sizes).", :normalize => "Bool or Symbol. Histogram normalization mode. Possible values are: false/:none (no normalization, default), true/:pdf (normalize to a discrete Probability Density Function, where the total area of the bins is 1), :probability (bin heights sum to 1) and :density (the area of each bin, rather than the height, is equal to the counts - useful for uneven bin sizes).",
:weights => "AbstractVector. Used in histogram types for weighted counts.", :weights => "AbstractVector. Used in histogram types for weighted counts.",
:show_empty_bins => "Bool. Whether empty bins in a 2D histogram are colored as 0 (true), or transparent (the default).", :show_empty_bins => "Bool. Whether empty bins in a 2D histogram are colored as 0 (true), or transparent (the default).",
:contours => "Bool. Add contours to the side-grids of 3D plots? Used in surface/wireframe.", :contours => "Bool. Add contours to the side-grids of 3D plots? Used in surface/wireframe.",
:contour_labels => "Bool. Show labels at the contour lines?", :contour_labels => "Bool. Show labels at the contour lines?",
:match_dimensions => "Bool. For heatmap types... should the first dimension of a matrix (rows) correspond to the first dimension of the plot (x-axis)? The default is false, which matches the behavior of Matplotlib, Plotly, and others. Note: when passing a function for z, the function should still map `(x,y) -> z`.", :match_dimensions => "Bool. For heatmap types... should the first dimension of a matrix (rows) correspond to the first dimension of the plot (x-axis)? The default is false, which matches the behavior of Matplotlib, Plotly, and others. Note: when passing a function for z, the function should still map `(x,y) -> z`.",
:subplot => "Integer (subplot index) or Subplot object. The subplot that this series belongs to.", :subplot => "Integer (subplot index) or Subplot object. The subplot that this series belongs to.",
:series_annotations => "AbstractVector of String or PlotText. These are annotations which are mapped to data points/positions.", :series_annotations => "AbstractVector of String or PlotText. These are annotations which are mapped to data points/positions.",
:primary => "Bool. Does this count as a 'real series'? For example, you could have a path (primary), and a scatter (secondary) as 2 separate series, maybe with different data (see sticks recipe for an example). The secondary series will get the same color, etc as the primary.", :primary => "Bool. Does this count as a 'real series'? For example, you could have a path (primary), and a scatter (secondary) as 2 separate series, maybe with different data (see sticks recipe for an example). The secondary series will get the same color, etc as the primary.",
:hover => "nothing or vector of strings. Text to display when hovering over each data point.", :hover => "nothing or vector of strings. Text to display when hovering over each data point.",
:colorbar_entry => "Bool. Include this series in the color bar? Set to `false` to exclude.", :colorbar_entry => "Bool. Include this series in the color bar? Set to `false` to exclude.",
# plot args # plot args
:plot_title => "String. Title for the whole plot (not the subplots) (Note: Not currently implemented)", :plot_title => "String. Title for the whole plot (not the subplots) (Note: Not currently implemented)",
:background_color => "Color Type. Base color for all backgrounds.", :background_color => "Color Type. Base color for all backgrounds.",
:background_color_outside => "Color Type or `:match` (matches `:background_color`). Color outside the plot area(s)", :background_color_outside => "Color Type or `:match` (matches `:background_color`). Color outside the plot area(s)",
:foreground_color => "Color Type. Base color for all foregrounds.", :foreground_color => "Color Type. Base color for all foregrounds.",
:size => "NTuple{2,Int}. (width_px, height_px) of the whole Plot", :size => "NTuple{2,Int}. (width_px, height_px) of the whole Plot",
:pos => "NTuple{2,Int}. (left_px, top_px) position of the GUI window (note: currently unimplemented)", :pos => "NTuple{2,Int}. (left_px, top_px) position of the GUI window (note: currently unimplemented)",
:window_title => "String. Title of the standalone gui-window.", :window_title => "String. Title of the standalone gui-window.",
:show => "Bool. Should this command open/refresh a GUI/display? This allows displaying in scripts or functions without explicitly calling `display`", :show => "Bool. Should this command open/refresh a GUI/display? This allows displaying in scripts or functions without explicitly calling `display`",
:layout => "Integer (number of subplots), NTuple{2,Integer} (grid dimensions), AbstractLayout (for example `grid(2,2)`), or the return from the `@layout` macro. This builds the layout of subplots.", :layout => "Integer (number of subplots), NTuple{2,Integer} (grid dimensions), AbstractLayout (for example `grid(2,2)`), or the return from the `@layout` macro. This builds the layout of subplots.",
:link => "Symbol. How/whether to link axis limits between subplots. Values: `:none`, `:x` (x axes are linked by columns), `:y` (y axes are linked by rows), `:both` (x and y are linked), `:all` (every subplot is linked together regardless of layout position).", :link => "Symbol. How/whether to link axis limits between subplots. Values: `:none`, `:x` (x axes are linked by columns), `:y` (y axes are linked by rows), `:both` (x and y are linked), `:all` (every subplot is linked together regardless of layout position).",
:overwrite_figure => "Bool. Should we reuse the same GUI window/figure when plotting (true) or open a new one (false).", :overwrite_figure => "Bool. Should we reuse the same GUI window/figure when plotting (true) or open a new one (false).",
:html_output_format => "Symbol. When writing html output, what is the format? `:png` and `:svg` are currently supported.", :html_output_format => "Symbol. When writing html output, what is the format? `:png` and `:svg` are currently supported.",
:tex_output_standalone => "Bool. When writing tex output, should the source include a preamble for a standalone document class.", :tex_output_standalone => "Bool. When writing tex output, should the source include a preamble for a standalone document class.",
:inset_subplots => "nothing or vector of 2-tuple (parent,bbox). optionally pass a vector of (parent,bbox) tuples which are the parent layout and the relative bounding box of inset subplots", :inset_subplots => "nothing or vector of 2-tuple (parent,bbox). optionally pass a vector of (parent,bbox) tuples which are the parent layout and the relative bounding box of inset subplots",
:dpi => "Number. Dots Per Inch of output figures", :dpi => "Number. Dots Per Inch of output figures",
:thickness_scaling => "Number. Scale for the thickness of all line elements like lines, borders, axes, grid lines, ... defaults to 1.", :thickness_scaling => "Number. Scale for the thickness of all line elements like lines, borders, axes, grid lines, ... defaults to 1.",
:display_type => "Symbol (`:auto`, `:gui`, or `:inline`). When supported, `display` will either open a GUI window or plot inline.", :display_type => "Symbol (`:auto`, `:gui`, or `:inline`). When supported, `display` will either open a GUI window or plot inline.",
:extra_kwargs => "Either one of (`:plot`, `:subplot`, `:series`) to specify for which element extra keyword args are collected or a KW (Dict{Symbol,Any}) to pass a map of extra keyword args which may be specific to a backend. Default: `:series`.\n Example: `pgfplotsx(); scatter(1:5, extra_kwargs=Dict(:subplot=>Dict(\"axis line shift\" => \"10pt\"))`", :extra_kwargs => "Either one of (`:plot`, `:subplot`, `:series`) to specify for which element extra keyword args are collected or a KW (Dict{Symbol,Any}) to pass a map of extra keyword args which may be specific to a backend. Default: `:series`.\n Example: `pgfplotsx(); scatter(1:5, extra_kwargs=Dict(:subplot=>Dict(\"axis line shift\" => \"10pt\"))`",
:fontfamily => "String or Symbol. Default font family for title, legend entries, tick labels and guides", :fontfamily => "String or Symbol. Default font family for title, legend entries, tick labels and guides",
:warn_on_unsupported => "Bool. Warn on unsupported attributes, series types and marker shapes", :warn_on_unsupported => "Bool. Warn on unsupported attributes, series types and marker shapes",
# subplot args # subplot args
:title => "String. Subplot title.", :title => "String. Subplot title.",
:titlelocation => "Symbol. Position of subplot title. Values: `:left`, `:center`, `:right`", :titlelocation => "Symbol. Position of subplot title. Values: `:left`, `:center`, `:right`",
:titlefontfamily => "String or Symbol. Font family of subplot title.", :titlefontfamily => "String or Symbol. Font family of subplot title.",
:titlefontsize => "Integer. Font pointsize of subplot title.", :titlefontsize => "Integer. Font pointsize of subplot title.",
:titlefonthalign => "Symbol. Font horizontal alignment of subplot title: :hcenter, :left, :right or :center", :titlefonthalign => "Symbol. Font horizontal alignment of subplot title: :hcenter, :left, :right or :center",
:titlefontvalign => "Symbol. Font vertical alignment of subplot title: :vcenter, :top, :bottom or :center", :titlefontvalign => "Symbol. Font vertical alignment of subplot title: :vcenter, :top, :bottom or :center",
:titlefontrotation => "Real. Font rotation of subplot title", :titlefontrotation => "Real. Font rotation of subplot title",
:titlefontcolor => "Color Type. Font color of subplot title", :titlefontcolor => "Color Type. Font color of subplot title",
:background_color_subplot => "Color Type or `:match` (matches `:background_color`). Base background color of the subplot.", :background_color_subplot => "Color Type or `:match` (matches `:background_color`). Base background color of the subplot.",
:background_color_legend => "Color Type or `:match` (matches `:background_color_subplot`). Background color of the legend.", :background_color_legend => "Color Type or `:match` (matches `:background_color_subplot`). Background color of the legend.",
:background_color_inside => "Color Type or `:match` (matches `:background_color_subplot`). Background color inside the plot area (under the grid).", :background_color_inside => "Color Type or `:match` (matches `:background_color_subplot`). Background color inside the plot area (under the grid).",
:foreground_color_subplot => "Color Type or `:match` (matches `:foreground_color`). Base foreground color of the subplot.", :foreground_color_subplot => "Color Type or `:match` (matches `:foreground_color`). Base foreground color of the subplot.",
:foreground_color_legend => "Color Type or `:match` (matches `:foreground_color_subplot`). Foreground color of the legend.", :foreground_color_legend => "Color Type or `:match` (matches `:foreground_color_subplot`). Foreground color of the legend.",
:foreground_color_title => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of subplot title.", :foreground_color_title => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of subplot title.",
:color_palette => "Vector of colors (cycle through) or color gradient (generate list from gradient) or `:auto` (generate a color list using `Colors.distiguishable_colors` and custom seed colors chosen to contrast with the background). The color palette is a color list from which series colors are automatically chosen.", :color_palette => "Vector of colors (cycle through) or color gradient (generate list from gradient) or `:auto` (generate a color list using `Colors.distiguishable_colors` and custom seed colors chosen to contrast with the background). The color palette is a color list from which series colors are automatically chosen.",
:legend => "Bool (show the legend?) or (x,y) tuple or Symbol (legend position) or angle or (angle,inout) tuple. Bottom left corner of legend is placed at (x,y). Symbol values: `:none`; `:best`; `:inline`; `:inside`; `:legend`; any valid combination of `:(outer ?)(top/bottom ?)(right/left ?)`, i.e.: `:top`, `:topright`, `:outerleft`, `:outerbottomright` ... (note: only some may be supported in each backend). Legend is positioned at (angle degrees) (so (90,:outer) is roughly equivalent to :outertop), close to the inside of the axes or the outside if inout=:outer.", :legend => "Bool (show the legend?) or (x,y) tuple or Symbol (legend position) or angle or (angle,inout) tuple. Bottom left corner of legend is placed at (x,y). Symbol values: `:none`; `:best`; `:inline`; `:inside`; `:legend`; any valid combination of `:(outer ?)(top/bottom ?)(right/left ?)`, i.e.: `:top`, `:topright`, `:outerleft`, `:outerbottomright` ... (note: only some may be supported in each backend). Legend is positioned at (angle degrees) (so (90,:outer) is roughly equivalent to :outertop), close to the inside of the axes or the outside if inout=:outer.",
:legendfontfamily => "String or Symbol. Font family of legend entries.", :legendfontfamily => "String or Symbol. Font family of legend entries.",
:legendfontsize => "Integer. Font pointsize of legend entries.", :legendfontsize => "Integer. Font pointsize of legend entries.",
:legendfonthalign => "Symbol. Font horizontal alignment of legend entries: :hcenter, :left, :right or :center", :legendfonthalign => "Symbol. Font horizontal alignment of legend entries: :hcenter, :left, :right or :center",
:legendfontvalign => "Symbol. Font vertical alignment of legend entries: :vcenter, :top, :bottom or :center", :legendfontvalign => "Symbol. Font vertical alignment of legend entries: :vcenter, :top, :bottom or :center",
:legendfontrotation => "Real. Font rotation of legend entries", :legendfontrotation => "Real. Font rotation of legend entries",
:legendfontcolor => "Color Type. Font color of legend entries", :legendfontcolor => "Color Type. Font color of legend entries",
:legendtitle => "String. Legend title.", :legendtitle => "String. Legend title.",
:legendtitlefontfamily => "String or Symbol. Font family of the legend title.", :legendtitlefontfamily => "String or Symbol. Font family of the legend title.",
:legendtitlefontsize => "Integer. Font pointsize the legend title.", :legendtitlefontsize => "Integer. Font pointsize the legend title.",
:legendtitlefonthalign => "Symbol. Font horizontal alignment of the legend title: :hcenter, :left, :right or :center", :legendtitlefonthalign => "Symbol. Font horizontal alignment of the legend title: :hcenter, :left, :right or :center",
:legendtitlefontvalign => "Symbol. Font vertical alignment of the legend title: :vcenter, :top, :bottom or :center", :legendtitlefontvalign => "Symbol. Font vertical alignment of the legend title: :vcenter, :top, :bottom or :center",
:legendtitlefontrotation => "Real. Font rotation of the legend title", :legendtitlefontrotation => "Real. Font rotation of the legend title",
:legendtitlefontcolor => "Color Type. Font color of the legend title", :legendtitlefontcolor => "Color Type. Font color of the legend title",
:colorbar => "Bool (show the colorbar?) or Symbol (colorbar position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:legend` (matches legend value) (note: only some may be supported in each backend)", :colorbar => "Bool (show the colorbar?) or Symbol (colorbar position). Symbol values: `:none`, `:best`, `:right`, `:left`, `:top`, `:bottom`, `:legend` (matches legend value) (note: only some may be supported in each backend)",
:clims => "`:auto`, NTuple{2,Number}, or a function that takes series data in and returns NTuple{2,Number}. Fixes the limits of the colorbar.", :clims => "`:auto`, NTuple{2,Number}, or a function that takes series data in and returns NTuple{2,Number}. Fixes the limits of the colorbar.",
:legendfont => "Font. Font of legend items.", :colorbar_fontfamily => "String or Symbol. Font family of colobar entries.",
:legendtitlefont => "Font. Font of the legend title.", :colorbar_ticks => "Vector of numbers (set the tick values), Tuple of (tickvalues, ticklabels), or `:auto`",
:annotations => "(x,y,text) tuple(s). Can be a single tuple or a list of them. Text can be String or PlotText (created with `text(args...)`) Add one-off text annotations at the x,y coordinates.", :colorbar_tickfontfamily => "String or Symbol. Font family of colorbar tick labels.",
:projection => "Symbol or String. '3d' or 'polar'", :colorbar_tickfontsize => "Integer. Font pointsize of colorbar tick entries.",
:aspect_ratio => "Symbol (:equal or :none) or Number. Plot area is resized so that 1 y-unit is the same size as `aspect_ratio` x-units. With `:none`, images inherit aspect ratio of the plot area.", :colorbar_tickfontcolor => "Color Type. Font color of colorbar tick entries",
:margin => "Measure (multiply by `mm`, `px`, etc). Base for individual margins... not directly used. Specifies the extra padding around subplots.", :colorbar_scale => "Symbol. Scale of the colorbar axis: `:none`, `:ln`, `:log2`, `:log10`",
:left_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the left of the subplot.", :colorbar_formatter => "Function, :scientific, :plain or :auto. A method which converts a number to a string for tick labeling.",
:top_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the top of the subplot.", :legendfont => "Font. Font of legend items.",
:right_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the right of the subplot.", :legendtitlefont => "Font. Font of the legend title.",
:bottom_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the bottom of the subplot.", :annotations => "(x,y,text) tuple(s). Can be a single tuple or a list of them. Text can be String or PlotText (created with `text(args...)`) Add one-off text annotations at the x,y coordinates.",
:subplot_index => "Integer. Internal (not set by user). Specifies the index of this subplot in the Plot's `plt.subplot` list.", :projection => "Symbol or String. '3d' or 'polar'",
:colorbar_title => "String. Title of colorbar.", :aspect_ratio => "Symbol (:equal or :none) or Number. Plot area is resized so that 1 y-unit is the same size as `aspect_ratio` x-units. With `:none`, images inherit aspect ratio of the plot area.",
:framestyle => "Symbol. Style of the axes frame. Choose from $(_allFramestyles)", :margin => "Measure (multiply by `mm`, `px`, etc). Base for individual margins... not directly used. Specifies the extra padding around subplots.",
:camera => "NTuple{2, Real}. Sets the view angle (azimuthal, elevation) for 3D plots", :left_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the left of the subplot.",
:top_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the top of the subplot.",
:right_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding to the right of the subplot.",
:bottom_margin => "Measure (multiply by `mm`, `px`, etc) or `:match` (matches `:margin`). Specifies the extra padding on the bottom of the subplot.",
:subplot_index => "Integer. Internal (not set by user). Specifies the index of this subplot in the Plot's `plt.subplot` list.",
:colorbar_title => "String. Title of colorbar.",
:framestyle => "Symbol. Style of the axes frame. Choose from $(_allFramestyles)",
:camera => "NTuple{2, Real}. Sets the view angle (azimuthal, elevation) for 3D plots",
# axis args # axis args
:guide => "String. Axis guide (label).", :guide => "String. Axis guide (label).",
:guide_position => "Symbol. Position of axis guides: :top, :bottom, :left or :right", :guide_position => "Symbol. Position of axis guides: :top, :bottom, :left or :right",
:lims => "NTuple{2,Number} or Symbol. Force axis limits. Only finite values are used (you can set only the right limit with `xlims = (-Inf, 2)` for example). `:round` widens the limit to the nearest round number ie. [0.1,3.6]=>[0.0,4.0]", :lims => "NTuple{2,Number} or Symbol. Force axis limits. Only finite values are used (you can set only the right limit with `xlims = (-Inf, 2)` for example). `:round` widens the limit to the nearest round number ie. [0.1,3.6]=>[0.0,4.0]",
:ticks => "Vector of numbers (set the tick values), Tuple of (tickvalues, ticklabels), or `:auto`", :ticks => "Vector of numbers (set the tick values), Tuple of (tickvalues, ticklabels), or `:auto`",
:scale => "Symbol. Scale of the axis: `:none`, `:ln`, `:log2`, `:log10`", :scale => "Symbol. Scale of the axis: `:none`, `:ln`, `:log2`, `:log10`",
:rotation => "Number. Degrees rotation of tick labels.", :rotation => "Number. Degrees rotation of tick labels.",
:flip => "Bool. Should we flip (reverse) the axis?", :flip => "Bool. Should we flip (reverse) the axis?",
:formatter => "Function, :scientific, :plain or :auto. A method which converts a number to a string for tick labeling.", :formatter => "Function, :scientific, :plain or :auto. A method which converts a number to a string for tick labeling.",
:tickfontfamily => "String or Symbol. Font family of tick labels.", :tickfontfamily => "String or Symbol. Font family of tick labels.",
:tickfontsize => "Integer. Font pointsize of tick labels.", :tickfontsize => "Integer. Font pointsize of tick labels.",
:tickfonthalign => "Symbol. Font horizontal alignment of tick labels: :hcenter, :left, :right or :center", :tickfonthalign => "Symbol. Font horizontal alignment of tick labels: :hcenter, :left, :right or :center",
:tickfontvalign => "Symbol. Font vertical alignment of tick labels: :vcenter, :top, :bottom or :center", :tickfontvalign => "Symbol. Font vertical alignment of tick labels: :vcenter, :top, :bottom or :center",
:tickfontrotation => "Real. Font rotation of tick labels", :tickfontrotation => "Real. Font rotation of tick labels",
:tickfontcolor => "Color Type. Font color of tick labels", :tickfontcolor => "Color Type. Font color of tick labels",
:guidefontfamily => "String or Symbol. Font family of axes guides.", :guidefontfamily => "String or Symbol. Font family of axes guides.",
:guidefontsize => "Integer. Font pointsize of axes guides.", :guidefontsize => "Integer. Font pointsize of axes guides.",
:guidefonthalign => "Symbol. Font horizontal alignment of axes guides: :hcenter, :left, :right or :center", :guidefonthalign => "Symbol. Font horizontal alignment of axes guides: :hcenter, :left, :right or :center",
:guidefontvalign => "Symbol. Font vertical alignment of axes guides: :vcenter, :top, :bottom or :center", :guidefontvalign => "Symbol. Font vertical alignment of axes guides: :vcenter, :top, :bottom or :center",
:guidefontrotation => "Real. Font rotation of axes guides", :guidefontrotation => "Real. Font rotation of axes guides",
:guidefontcolor => "Color Type. Font color of axes guides", :guidefontcolor => "Color Type. Font color of axes guides",
:foreground_color_axis => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis ticks.", :foreground_color_axis => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis ticks.",
:foreground_color_border => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of plot area border (spines).", :foreground_color_border => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of plot area border (spines).",
:foreground_color_text => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of tick labels.", :foreground_color_text => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of tick labels.",
:foreground_color_guide => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis guides (axis labels).", :foreground_color_guide => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of axis guides (axis labels).",
:mirror => "Bool. Switch the side of the tick labels (right or top).", :mirror => "Bool. Switch the side of the tick labels (right or top).",
:grid => "Bool, Symbol, String or `nothing`. Show the grid lines? `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:none`, `:off`", :grid => "Bool, Symbol, String or `nothing`. Show the grid lines? `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:none`, `:off`",
:foreground_color_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of grid lines.", :foreground_color_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of grid lines.",
:gridalpha => "Number in [0,1]. The alpha/opacity override for the grid lines.", :gridalpha => "Number in [0,1]. The alpha/opacity override for the grid lines.",
:gridstyle => "Symbol. Style of the grid lines. Choose from $(_allStyles)", :gridstyle => "Symbol. Style of the grid lines. Choose from $(_allStyles)",
:gridlinewidth => "Number. Width of the grid lines (in pixels)", :gridlinewidth => "Number. Width of the grid lines (in pixels)",
:foreground_color_minor_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of minor grid lines.", :foreground_color_minor_grid => "Color Type or `:match` (matches `:foreground_color_subplot`). Color of minor grid lines.",
:minorgrid => "Bool. Adds minor grid lines and ticks to the plot. Set minorticks to change number of gridlines", :minorgrid => "Bool. Adds minor grid lines and ticks to the plot. Set minorticks to change number of gridlines",
:minorticks => "Integer. Intervals to divide the gap between major ticks into", :minorticks => "Integer. Intervals to divide the gap between major ticks into",
:minorgridalpha => "Number in [0,1]. The alpha/opacity override for the minorgrid lines.", :minorgridalpha => "Number in [0,1]. The alpha/opacity override for the minorgrid lines.",
:minorgridstyle => "Symbol. Style of the minor grid lines. Choose from $(_allStyles)", :minorgridstyle => "Symbol. Style of the minor grid lines. Choose from $(_allStyles)",
:minorgridlinewidth => "Number. Width of the minor grid lines (in pixels)", :minorgridlinewidth => "Number. Width of the minor grid lines (in pixels)",
:tick_direction => "Symbol. Direction of the ticks. `:in` or `:out`", :tick_direction => "Symbol. Direction of the ticks. `:in` or `:out`",
:showaxis => "Bool, Symbol or String. Show the axis. `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:off`", :showaxis => "Bool, Symbol or String. Show the axis. `true`, `false`, `:show`, `:hide`, `:yes`, `:no`, `:x`, `:y`, `:z`, `:xy`, ..., `:all`, `:off`",
:widen => "Bool. Widen the axis limits by a small factor to avoid cut-off markers and lines at the borders. Defaults to `true`.", :widen => "Bool. Widen the axis limits by a small factor to avoid cut-off markers and lines at the borders. Defaults to `true`.",
:draw_arrow => "Bool. Draw arrow at the end of the axis.", :draw_arrow => "Bool. Draw arrow at the end of the axis.",
) )

View File

@ -151,54 +151,54 @@ const _shape_keys = Symbol[
const _allMarkers = vcat(:none, :auto, _shape_keys) #sort(collect(keys(_shapes)))) const _allMarkers = vcat(:none, :auto, _shape_keys) #sort(collect(keys(_shapes))))
const _markerAliases = Dict{Symbol,Symbol}( const _markerAliases = Dict{Symbol,Symbol}(
:n => :none, :n => :none,
:no => :none, :no => :none,
:a => :auto, :a => :auto,
:ellipse => :circle, :ellipse => :circle,
:c => :circle, :c => :circle,
:circ => :circle, :circ => :circle,
:square => :rect, :square => :rect,
:sq => :rect, :sq => :rect,
:r => :rect, :r => :rect,
:d => :diamond, :d => :diamond,
:^ => :utriangle, :^ => :utriangle,
:ut => :utriangle, :ut => :utriangle,
:utri => :utriangle, :utri => :utriangle,
:uptri => :utriangle, :uptri => :utriangle,
:uptriangle => :utriangle, :uptriangle => :utriangle,
:v => :dtriangle, :v => :dtriangle,
:V => :dtriangle, :V => :dtriangle,
:dt => :dtriangle, :dt => :dtriangle,
:dtri => :dtriangle, :dtri => :dtriangle,
:downtri => :dtriangle, :downtri => :dtriangle,
:downtriangle => :dtriangle, :downtriangle => :dtriangle,
:> => :rtriangle, :> => :rtriangle,
:rt => :rtriangle, :rt => :rtriangle,
:rtri => :rtriangle, :rtri => :rtriangle,
:righttri => :rtriangle, :righttri => :rtriangle,
:righttriangle => :rtriangle, :righttriangle => :rtriangle,
:< => :ltriangle, :< => :ltriangle,
:lt => :ltriangle, :lt => :ltriangle,
:ltri => :ltriangle, :ltri => :ltriangle,
:lighttri => :ltriangle, :lighttri => :ltriangle,
:lighttriangle => :ltriangle, :lighttriangle => :ltriangle,
# :+ => :cross, # :+ => :cross,
:plus => :cross, :plus => :cross,
# :x => :xcross, # :x => :xcross,
:X => :xcross, :X => :xcross,
:star => :star5, :star => :star5,
:s => :star5, :s => :star5,
:star1 => :star5, :star1 => :star5,
:s2 => :star8, :s2 => :star8,
:star2 => :star8, :star2 => :star8,
:p => :pentagon, :p => :pentagon,
:pent => :pentagon, :pent => :pentagon,
:h => :hexagon, :h => :hexagon,
:hex => :hexagon, :hex => :hexagon,
:hep => :heptagon, :hep => :heptagon,
:o => :octagon, :o => :octagon,
:oct => :octagon, :oct => :octagon,
:spike => :vline, :spike => :vline,
) )
const _positionAliases = Dict{Symbol,Symbol}( const _positionAliases = Dict{Symbol,Symbol}(
@ -273,58 +273,58 @@ const _bar_width = 0.8
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
const _series_defaults = KW( const _series_defaults = KW(
:label => :auto, :label => :auto,
:colorbar_entry => true, :colorbar_entry => true,
:seriescolor => :auto, :seriescolor => :auto,
:seriesalpha => nothing, :seriesalpha => nothing,
:seriestype => :path, :seriestype => :path,
:linestyle => :solid, :linestyle => :solid,
:linewidth => :auto, :linewidth => :auto,
:linecolor => :auto, :linecolor => :auto,
:linealpha => nothing, :linealpha => nothing,
:fillrange => nothing, # ribbons, areas, etc :fillrange => nothing, # ribbons, areas, etc
:fillcolor => :match, :fillcolor => :match,
:fillalpha => nothing, :fillalpha => nothing,
:markershape => :none, :markershape => :none,
:markercolor => :match, :markercolor => :match,
:markeralpha => nothing, :markeralpha => nothing,
:markersize => 4, :markersize => 4,
:markerstrokestyle => :solid, :markerstrokestyle => :solid,
:markerstrokewidth => 1, :markerstrokewidth => 1,
:markerstrokecolor => :match, :markerstrokecolor => :match,
:markerstrokealpha => nothing, :markerstrokealpha => nothing,
:bins => :auto, # number of bins for hists :bins => :auto, # number of bins for hists
:smooth => false, # regression line? :smooth => false, # regression line?
:group => nothing, # groupby vector :group => nothing, # groupby vector
:x => nothing, :x => nothing,
:y => nothing, :y => nothing,
:z => nothing, # depth for contour, surface, etc :z => nothing, # depth for contour, surface, etc
:marker_z => nothing, # value for color scale :marker_z => nothing, # value for color scale
:line_z => nothing, :line_z => nothing,
:fill_z => nothing, :fill_z => nothing,
:levels => 15, :levels => 15,
:orientation => :vertical, :orientation => :vertical,
:bar_position => :overlay, # for bar plots and histograms: could also be stack (stack up) or dodge (side by side) :bar_position => :overlay, # for bar plots and histograms: could also be stack (stack up) or dodge (side by side)
:bar_width => nothing, :bar_width => nothing,
:bar_edges => false, :bar_edges => false,
:xerror => nothing, :xerror => nothing,
:yerror => nothing, :yerror => nothing,
:zerror => nothing, :zerror => nothing,
:ribbon => nothing, :ribbon => nothing,
:quiver => nothing, :quiver => nothing,
:arrow => nothing, # allows for adding arrows to line/path... call `arrow(args...)` :arrow => nothing, # allows for adding arrows to line/path... call `arrow(args...)`
:normalize => false, # do we want a normalized histogram? :normalize => false, # do we want a normalized histogram?
:weights => nothing, # optional weights for histograms (1D and 2D) :weights => nothing, # optional weights for histograms (1D and 2D)
:show_empty_bins => false, # should empty bins in 2D histogram be colored as zero (otherwise they are transparent) :show_empty_bins => false, # should empty bins in 2D histogram be colored as zero (otherwise they are transparent)
:contours => false, # add contours to 3d surface and wireframe plots :contours => false, # add contours to 3d surface and wireframe plots
:contour_labels => false, :contour_labels => false,
:subplot => :auto, # which subplot(s) does this series belong to? :subplot => :auto, # which subplot(s) does this series belong to?
:series_annotations => nothing, # a list of annotations which apply to the coordinates of this series :series_annotations => nothing, # a list of annotations which apply to the coordinates of this series
:primary => true, # when true, this "counts" as a series for color selection, etc. the main use is to allow :primary => true, # when true, this "counts" as a series for color selection, etc. the main use is to allow
# one logical series to be broken up (path and markers, for example) # one logical series to be broken up (path and markers, for example)
:hover => nothing, # text to display when hovering over the data points :hover => nothing, # text to display when hovering over the data points
:stride => (1,1), # array stride for wireframe/surface, the first element is the row stride and the second is the column stride. :stride => (1,1), # array stride for wireframe/surface, the first element is the row stride and the second is the column stride.
:connections => nothing, # tuple of arrays to specifiy connectivity of a 3d mesh :connections => nothing, # tuple of arrays to specifiy connectivity of a 3d mesh
:extra_kwargs => Dict() :extra_kwargs => Dict()
) )
@ -363,104 +363,115 @@ const _plot_defaults = KW(
const _subplot_defaults = KW( const _subplot_defaults = KW(
:title => "", :title => "",
:titlelocation => :center, # also :left or :right :titlelocation => :center, # also :left or :right
:fontfamily_subplot => :match, :fontfamily_subplot => :match,
:titlefontfamily => :match, :titlefontfamily => :match,
:titlefontsize => 14, :titlefontsize => 14,
:titlefonthalign => :hcenter, :titlefonthalign => :hcenter,
:titlefontvalign => :vcenter, :titlefontvalign => :vcenter,
:titlefontrotation => 0.0, :titlefontrotation => 0.0,
:titlefontcolor => :match, :titlefontcolor => :match,
:background_color_subplot => :match, # default for other bg colors... match takes plot default :background_color_subplot => :match, # default for other bg colors... match takes plot default
:background_color_legend => :match, # background of legend :background_color_legend => :match, # background of legend
:background_color_inside => :match, # background inside grid :background_color_inside => :match, # background inside grid
:foreground_color_subplot => :match, # default for other fg colors... match takes plot default :foreground_color_subplot => :match, # default for other fg colors... match takes plot default
:foreground_color_legend => :match, # foreground of legend :foreground_color_legend => :match, # foreground of legend
:foreground_color_title => :match, # title color :foreground_color_title => :match, # title color
:color_palette => :auto, :color_palette => :auto,
:legend => :best, :legend => :best,
:legendtitle => nothing, :legendtitle => nothing,
:colorbar => :legend, :colorbar => :legend,
:clims => :auto, :clims => :auto,
:legendfontfamily => :match, :colorbar_fontfamily => :match,
:legendfontsize => 8, :colorbar_ticks => :auto,
:legendfonthalign => :hcenter, :colorbar_tickfontfamily => :match,
:legendfontvalign => :vcenter, :colorbar_tickfontsize => 8,
:legendfontrotation => 0.0, :colorbar_tickfonthalign => :hcenter,
:legendfontcolor => :match, :colorbar_tickfontvalign => :vcenter,
:legendtitlefontfamily => :match, :colorbar_tickfontrotation => 0.0,
:legendtitlefontsize => 11, :colorbar_tickfontcolor => :match,
:legendtitlefonthalign => :hcenter, :colorbar_scale => :identity,
:legendtitlefontvalign => :vcenter, :colorbar_formatter => :auto,
:legendtitlefontrotation => 0.0, :colorbar_discrete_values => [],
:legendtitlefontcolor => :match, :colorbar_continuous_values => zeros(0),
:annotations => [], # annotation tuples... list of (x,y,annotation) :legendfontfamily => :match,
:projection => :none, # can also be :polar or :3d :legendfontsize => 8,
:aspect_ratio => :auto, # choose from :none or :equal :legendfonthalign => :hcenter,
:margin => 1mm, :legendfontvalign => :vcenter,
:left_margin => :match, :legendfontrotation => 0.0,
:top_margin => :match, :legendfontcolor => :match,
:right_margin => :match, :legendtitlefontfamily => :match,
:bottom_margin => :match, :legendtitlefontsize => 11,
:subplot_index => -1, :legendtitlefonthalign => :hcenter,
:colorbar_title => "", :legendtitlefontvalign => :vcenter,
:colorbar_titlefontsize => 10, :legendtitlefontrotation => 0.0,
:colorbar_title_location => :center, # also :left or :right :legendtitlefontcolor => :match,
:colorbar_fontfamily => :match, :annotations => [], # annotation tuples... list of (x,y,annotation)
:colorbar_titlefontfamily => :match, :projection => :none, # can also be :polar or :3d
:colorbar_titlefonthalign => :hcenter, :aspect_ratio => :auto, # choose from :none or :equal
:colorbar_titlefontvalign => :vcenter, :margin => 1mm,
:colorbar_titlefontrotation => 0.0, :left_margin => :match,
:colorbar_titlefontcolor => :match, :top_margin => :match,
:framestyle => :axes, :right_margin => :match,
:camera => (30,30), :bottom_margin => :match,
:extra_kwargs => Dict() :subplot_index => -1,
:colorbar_title => "",
:colorbar_titlefontsize => 10,
:colorbar_title_location => :center, # also :left or :right
:colorbar_titlefontfamily => :match,
:colorbar_titlefonthalign => :hcenter,
:colorbar_titlefontvalign => :vcenter,
:colorbar_titlefontrotation => 0.0,
:colorbar_titlefontcolor => :match,
:framestyle => :axes,
:camera => (30,30),
:extra_kwargs => Dict()
) )
const _axis_defaults = KW( const _axis_defaults = KW(
:guide => "", :guide => "",
:guide_position => :auto, :guide_position => :auto,
:lims => :auto, :lims => :auto,
:ticks => :auto, :ticks => :auto,
:scale => :identity, :scale => :identity,
:rotation => 0, :rotation => 0,
:flip => false, :flip => false,
:link => [], :link => [],
:tickfontfamily => :match, :tickfontfamily => :match,
:tickfontsize => 8, :tickfontsize => 8,
:tickfonthalign => :hcenter, :tickfonthalign => :hcenter,
:tickfontvalign => :vcenter, :tickfontvalign => :vcenter,
:tickfontrotation => 0.0, :tickfontrotation => 0.0,
:tickfontcolor => :match, :tickfontcolor => :match,
:guidefontfamily => :match, :guidefontfamily => :match,
:guidefontsize => 11, :guidefontsize => 11,
:guidefonthalign => :hcenter, :guidefonthalign => :hcenter,
:guidefontvalign => :vcenter, :guidefontvalign => :vcenter,
:guidefontrotation => 0.0, :guidefontrotation => 0.0,
:guidefontcolor => :match, :guidefontcolor => :match,
:foreground_color_axis => :match, # axis border/tick colors, :foreground_color_axis => :match, # axis border/tick colors,
:foreground_color_border => :match, # plot area border/spines, :foreground_color_border => :match, # plot area border/spines,
:foreground_color_text => :match, # tick text color, :foreground_color_text => :match, # tick text color,
:foreground_color_guide => :match, # guide text color, :foreground_color_guide => :match, # guide text color,
:discrete_values => [], :discrete_values => [],
:formatter => :auto, :formatter => :auto,
:mirror => false, :mirror => false,
:grid => true, :grid => true,
:foreground_color_grid => :match, # grid color :foreground_color_grid => :match, # grid color
:gridalpha => 0.1, :gridalpha => 0.1,
:gridstyle => :solid, :gridstyle => :solid,
:gridlinewidth => 0.5, :gridlinewidth => 0.5,
:foreground_color_minor_grid => :match, # grid color :foreground_color_minor_grid => :match, # grid color
:minorgridalpha => 0.05, :minorgridalpha => 0.05,
:minorgridstyle => :solid, :minorgridstyle => :solid,
:minorgridlinewidth => 0.5, :minorgridlinewidth => 0.5,
:tick_direction => :in, :tick_direction => :in,
:minorticks => false, :minorticks => false,
:minorgrid => false, :minorgrid => false,
:showaxis => true, :showaxis => true,
:widen => true, :widen => true,
:draw_arrow => false, :draw_arrow => false,
) )
const _suppress_warnings = Set{Symbol}([ const _suppress_warnings = Set{Symbol}([
@ -1329,10 +1340,10 @@ const _match_map = KW(
:background_color_inside => :background_color_subplot, :background_color_inside => :background_color_subplot,
:foreground_color_legend => :foreground_color_subplot, :foreground_color_legend => :foreground_color_subplot,
:foreground_color_title => :foreground_color_subplot, :foreground_color_title => :foreground_color_subplot,
:left_margin => :margin, :left_margin => :margin,
:top_margin => :margin, :top_margin => :margin,
:right_margin => :margin, :right_margin => :margin,
:bottom_margin => :margin, :bottom_margin => :margin,
:titlefontfamily => :fontfamily_subplot, :titlefontfamily => :fontfamily_subplot,
:titlefontcolor => :foreground_color_subplot, :titlefontcolor => :foreground_color_subplot,
:legendfontfamily => :fontfamily_subplot, :legendfontfamily => :fontfamily_subplot,
@ -1342,6 +1353,8 @@ const _match_map = KW(
:colorbar_fontfamily => :fontfamily_subplot, :colorbar_fontfamily => :fontfamily_subplot,
:colorbar_titlefontfamily => :fontfamily_subplot, :colorbar_titlefontfamily => :fontfamily_subplot,
:colorbar_titlefontcolor => :foreground_color_subplot, :colorbar_titlefontcolor => :foreground_color_subplot,
:colorbar_tickfontfamily => :fontfamily_subplot,
:colorbar_tickfontcolor => :foreground_color_subplot,
:plot_titlefontfamily => :fontfamily, :plot_titlefontfamily => :fontfamily,
:plot_titlefontcolor => :foreground_color, :plot_titlefontcolor => :foreground_color,
:tickfontcolor => :foreground_color_text, :tickfontcolor => :foreground_color_text,
@ -1580,6 +1593,7 @@ function _update_subplot_args(plt::Plot, sp::Subplot, plotattributes_in, subplot
lims_warned = true lims_warned = true
end end
end end
_update_subplot_colorbars(sp)
end end
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------

View File

@ -137,11 +137,10 @@ const _label_func_tex = Dict{Symbol,Function}(
labelfunc_tex(scale::Symbol) = get(_label_func_tex, scale, convert_sci_unicode) labelfunc_tex(scale::Symbol) = get(_label_func_tex, scale, convert_sci_unicode)
function optimal_ticks_and_labels(sp::Subplot, axis::Axis, ticks = nothing) function optimal_ticks_and_labels(ticks, alims, scale, formatter)
amin, amax = axis_limits(sp, axis[:letter]) amin, amax = alims
# scale the limits # scale the limits
scale = axis[:scale]
sf = RecipesPipeline.scale_func(scale) sf = RecipesPipeline.scale_func(scale)
# If the axis input was a Date or DateTime use a special logic to find # If the axis input was a Date or DateTime use a special logic to find
@ -152,7 +151,7 @@ function optimal_ticks_and_labels(sp::Subplot, axis::Axis, ticks = nothing)
# rather than on the input format # rather than on the input format
# TODO: maybe: non-trivial scale (:ln, :log2, :log10) for date/datetime # TODO: maybe: non-trivial scale (:ln, :log2, :log10) for date/datetime
if ticks === nothing && scale == :identity if ticks === nothing && scale == :identity
if axis[:formatter] == RecipesPipeline.dateformatter if formatter == RecipesPipeline.dateformatter
# optimize_datetime_ticks returns ticks and labels(!) based on # optimize_datetime_ticks returns ticks and labels(!) based on
# integers/floats corresponding to the DateTime type. Thus, the axes # integers/floats corresponding to the DateTime type. Thus, the axes
# limits, which resulted from converting the Date type to integers, # limits, which resulted from converting the Date type to integers,
@ -163,7 +162,7 @@ function optimal_ticks_and_labels(sp::Subplot, axis::Axis, ticks = nothing)
k_min = 2, k_max = 4) k_min = 2, k_max = 4)
# Now the ticks are converted back to floats corresponding to Dates. # Now the ticks are converted back to floats corresponding to Dates.
return ticks / 864e5, labels return ticks / 864e5, labels
elseif axis[:formatter] == RecipesPipeline.datetimeformatter elseif formatter == RecipesPipeline.datetimeformatter
return optimize_datetime_ticks(amin, amax; k_min = 2, k_max = 4) return optimize_datetime_ticks(amin, amax; k_min = 2, k_max = 4)
end end
end end
@ -187,14 +186,13 @@ function optimal_ticks_and_labels(sp::Subplot, axis::Axis, ticks = nothing)
# chosen ticks is not too much bigger than amin - amax: # chosen ticks is not too much bigger than amin - amax:
strict_span = false, strict_span = false,
) )
axis[:lims] = map(RecipesPipeline.inverse_scale_func(scale), (viewmin, viewmax)) # axis[:lims] = map(RecipesPipeline.inverse_scale_func(scale), (viewmin, viewmax))
else else
scaled_ticks = map(sf, (filter(t -> amin <= t <= amax, ticks))) scaled_ticks = map(sf, (filter(t -> amin <= t <= amax, ticks)))
end end
unscaled_ticks = map(RecipesPipeline.inverse_scale_func(scale), scaled_ticks) unscaled_ticks = map(RecipesPipeline.inverse_scale_func(scale), scaled_ticks)
labels = if any(isfinite, unscaled_ticks) labels = if any(isfinite, unscaled_ticks)
formatter = axis[:formatter]
if formatter in (:auto, :plain, :scientific, :engineering) if formatter in (:auto, :plain, :scientific, :engineering)
map(labelfunc(scale, backend()), Showoff.showoff(scaled_ticks, formatter)) map(labelfunc(scale, backend()), Showoff.showoff(scaled_ticks, formatter))
elseif formatter == :latex elseif formatter == :latex
@ -221,52 +219,53 @@ end
# return (continuous_values, discrete_values) for the ticks on this axis # return (continuous_values, discrete_values) for the ticks on this axis
function get_ticks(sp::Subplot, axis::Axis; update = true) function get_ticks(sp::Subplot, axis::Axis; update = true)
if update || !haskey(axis.plotattributes, :optimized_ticks) if update || !haskey(axis.plotattributes, :optimized_ticks)
dvals = axis[:discrete_values]
ticks = _transform_ticks(axis[:ticks]) ticks = _transform_ticks(axis[:ticks])
if ticks in (:none, nothing, false) axis.plotattributes[:optimized_ticks] = if ticks isa Symbol && ticks !== :none &&
axis.plotattributes[:optimized_ticks] = nothing ispolar(sp) && axis[:letter] === :x && !isempty(dvals)
collect(0:pi/4:7pi/4), string.(0:45:315)
else else
# treat :native ticks as :auto cvals = axis[:continuous_values]
ticks = ticks == :native ? :auto : ticks alims = axis_limits(sp, axis[:letter])
scale = axis[:scale]
dvals = axis[:discrete_values] formatter = axis[:formatter]
cv, dv = if typeof(ticks) <: Symbol get_ticks(ticks, cvals, dvals, alims, scale, formatter)
if !isempty(dvals)
# discrete ticks...
n = length(dvals)
rng = if ticks == :auto && n > 15
Δ = ceil(Int, n / 10)
Δ:Δ:n
else # if ticks == :all
1:n
end
axis[:continuous_values][rng], dvals[rng]
elseif 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(sp, axis)
end
elseif typeof(ticks) <: Union{AVec, Int}
if !isempty(dvals) && typeof(ticks) <: Int
rng = Int[round(Int,i) for i in range(1, stop=length(dvals), length=ticks)]
axis[:continuous_values][rng], dvals[rng]
else
# override ticks, but get the labels
optimal_ticks_and_labels(sp, axis, ticks)
end
elseif typeof(ticks) <: NTuple{2, Any}
# assuming we're passed (ticks, labels)
ticks
else
error("Unknown ticks type in get_ticks: $(typeof(ticks))")
end
axis.plotattributes[:optimized_ticks] = (cv, dv)
end end
end end
axis.plotattributes[:optimized_ticks] return axis.plotattributes[:optimized_ticks]
end end
function get_ticks(ticks::Symbol, cvals::T, dvals, args...) where T
if ticks === :none
return T[], String[]
elseif !isempty(dvals)
n = length(dvals)
if ticks === :all || n < 16
return cvals, string.(dvals)
else
Δ = ceil(Int, n / 10)
rng = Δ:Δ:n
return cvals[rng], string.(dvals[rng])
end
else
return optimal_ticks_and_labels(nothing, args...)
end
end
get_ticks(ticks::AVec, cvals, dvals, args...) = optimal_ticks_and_labels(ticks, args...)
function get_ticks(ticks::Int, dvals, cvals, args...)
if !isempty(dvals)
rng = round.(Int, range(1, stop=length(dvals), length=ticks))
cvals[rng], string.(dvals[rng])
else
optimal_ticks_and_labels(ticks, args...)
end
end
get_ticks(ticks::NTuple{2, Any}, args...) = ticks
get_ticks(::Nothing, cvals::T, args...) where T = T[], String[]
get_ticks(ticks::Bool, args...) =
ticks ? get_ticks(:auto, args...) : get_ticks(nothing, args...)
get_ticks(::T, args...) where T = error("Unknown ticks type in get_ticks: $T")
_transform_ticks(ticks) = ticks _transform_ticks(ticks) = ticks
_transform_ticks(ticks::AbstractArray{T}) where T <: Dates.TimeType = Dates.value.(ticks) _transform_ticks(ticks::AbstractArray{T}) where T <: Dates.TimeType = Dates.value.(ticks)
_transform_ticks(ticks::NTuple{2, Any}) = (_transform_ticks(ticks[1]), ticks[2]) _transform_ticks(ticks::NTuple{2, Any}) = (_transform_ticks(ticks[1]), ticks[2])

View File

@ -531,6 +531,10 @@ const _pyplot_attr = merge_with_base_supported([
:guidefontfamily, :guidefontsize, :guidefontcolor, :guidefontfamily, :guidefontsize, :guidefontcolor,
:grid, :gridalpha, :gridstyle, :gridlinewidth, :grid, :gridalpha, :gridstyle, :gridlinewidth,
:legend, :legendtitle, :colorbar, :colorbar_title, :colorbar_entry, :legend, :legendtitle, :colorbar, :colorbar_title, :colorbar_entry,
:colorbar_ticks, :colorbar_tickfontfamily, :colorbar_tickfontsize,
:colorbar_tickfonthalign, :colorbar_tickfontvalign,
:colorbar_tickfontrotation, :colorbar_tickfontcolor,
:colorbar_scale,
:marker_z, :line_z, :fill_z, :marker_z, :line_z, :fill_z,
:levels, :levels,
:ribbon, :quiver, :arrow, :ribbon, :quiver, :arrow,

View File

@ -743,7 +743,7 @@ function _update_min_padding!(sp::Subplot{GRBackend})
xticks, yticks, zticks = get_ticks(sp, xaxis), get_ticks(sp, yaxis), get_ticks(sp, zaxis) xticks, yticks, zticks = get_ticks(sp, xaxis), get_ticks(sp, yaxis), get_ticks(sp, zaxis)
# Add margin for x and y ticks # Add margin for x and y ticks
h = 0mm h = 0mm
if !(xticks in (nothing, false, :none)) if !isempty(first(xticks))
gr_set_font( gr_set_font(
tickfont(xaxis), tickfont(xaxis),
halign = (:left, :hcenter, :right)[sign(xaxis[:rotation]) + 2], halign = (:left, :hcenter, :right)[sign(xaxis[:rotation]) + 2],
@ -754,7 +754,7 @@ function _update_min_padding!(sp::Subplot{GRBackend})
l = 0.01 + last(gr_get_ticks_size(xticks, xaxis[:rotation])) l = 0.01 + last(gr_get_ticks_size(xticks, xaxis[:rotation]))
h = max(h, 1mm + get_size(sp)[2] * l * px) h = max(h, 1mm + get_size(sp)[2] * l * px)
end end
if !(yticks in (nothing, false, :none)) if !isempty(first(yticks))
gr_set_font( gr_set_font(
tickfont(yaxis), tickfont(yaxis),
halign = (:left, :hcenter, :right)[sign(yaxis[:rotation]) + 2], halign = (:left, :hcenter, :right)[sign(yaxis[:rotation]) + 2],
@ -774,7 +774,7 @@ function _update_min_padding!(sp::Subplot{GRBackend})
end end
end end
if !(zticks in (nothing, false, :none)) if !isempty(first(zticks))
gr_set_font( gr_set_font(
tickfont(zaxis), tickfont(zaxis),
halign = (zaxis[:mirror] ? :left : :right), halign = (zaxis[:mirror] ? :left : :right),
@ -825,7 +825,7 @@ function _update_min_padding!(sp::Subplot{GRBackend})
else else
# Add margin for x and y ticks # Add margin for x and y ticks
xticks, yticks = get_ticks(sp, sp[:xaxis]), get_ticks(sp, sp[:yaxis]) xticks, yticks = get_ticks(sp, sp[:xaxis]), get_ticks(sp, sp[:yaxis])
if !(xticks in (nothing, false, :none)) if !isempty(first(xticks))
gr_set_tickfont(sp, :x) gr_set_tickfont(sp, :x)
l = 0.01 + last(gr_get_ticks_size(xticks, sp[:xaxis][:rotation])) l = 0.01 + last(gr_get_ticks_size(xticks, sp[:xaxis][:rotation]))
h = 1mm + get_size(sp)[2] * l * px h = 1mm + get_size(sp)[2] * l * px
@ -835,7 +835,7 @@ function _update_min_padding!(sp::Subplot{GRBackend})
bottompad += h bottompad += h
end end
end end
if !(yticks in (nothing, false, :none)) if !isempty(first(yticks))
gr_set_tickfont(sp, :y) gr_set_tickfont(sp, :y)
l = 0.01 + first(gr_get_ticks_size(yticks, sp[:yaxis][:rotation])) l = 0.01 + first(gr_get_ticks_size(yticks, sp[:yaxis][:rotation]))
w = 1mm + get_size(sp)[1] * l * px w = 1mm + get_size(sp)[1] * l * px

View File

@ -807,31 +807,37 @@ function py_compute_axis_minval(sp::Subplot, axis::Axis)
minval minval
end end
function py_set_scale(ax, sp::Subplot, axis::Axis) function py_set_scale(ax, sp::Subplot, scale::Symbol, letter::Symbol)
scale = axis[:scale]
letter = axis[:letter]
scale in supported_scales() || return @warn("Unhandled scale value in pyplot: $scale") scale in supported_scales() || return @warn("Unhandled scale value in pyplot: $scale")
func = getproperty(ax, Symbol("set_", letter, "scale")) func = getproperty(ax, Symbol("set_", letter, "scale"))
if PyPlot.version v"3.3" # https://matplotlib.org/3.3.0/api/api_changes.html if PyPlot.version v"3.3" # https://matplotlib.org/3.3.0/api/api_changes.html
letter = Symbol("") pyletter = Symbol("")
else
pyletter = letter
end end
kw = KW() kw = KW()
arg = if scale == :identity arg = if scale == :identity
"linear" "linear"
else else
kw[Symbol(:base,letter)] = if scale == :ln kw[Symbol(:base, pyletter)] = if scale == :ln
elseif scale == :log2 elseif scale == :log2
2 2
elseif scale == :log10 elseif scale == :log10
10 10
end end
kw[Symbol(:linthresh,letter)] = NaNMath.max(1e-16, py_compute_axis_minval(sp, axis)) axis = sp[Symbol(letter, :axis)]
kw[Symbol(:linthresh, pyletter)] = NaNMath.max(1e-16, py_compute_axis_minval(sp, axis))
"symlog" "symlog"
end end
func(arg; kw...) func(arg; kw...)
end end
function py_set_scale(ax, sp::Subplot, axis::Axis)
scale = axis[:scale]
letter = axis[:letter]
py_set_scale(ax, sp, scale, letter)
end
function py_set_axis_colors(sp, ax, a::Axis) function py_set_axis_colors(sp, ax, a::Axis)
for (loc, spine) in ax.spines for (loc, spine) in ax.spines
@ -972,24 +978,31 @@ function _before_layout_calcs(plt::Plot{PyPlotBackend})
end end
cb."set_label"(sp[:colorbar_title],size=py_thickness_scale(plt, sp[:yaxis][:guidefontsize]),family=sp[:yaxis][:guidefontfamily], color = py_color(sp[:yaxis][:guidefontcolor])) cb."set_label"(sp[:colorbar_title],size=py_thickness_scale(plt, sp[:colorbar_titlefontsize]),family=sp[:colorbar_titlefontfamily], color = py_color(sp[:colorbar_titlefontcolor]))
# cb."formatter".set_useOffset(false) # This for some reason does not work, must be a pyplot bug, instead this is a workaround: # cb."formatter".set_useOffset(false) # This for some reason does not work, must be a pyplot bug, instead this is a workaround:
cb."formatter".set_powerlimits((-Inf, Inf)) cb."formatter".set_powerlimits((-Inf, Inf))
cb."update_ticks"() cb."update_ticks"()
env = "\\mathregular" # matches the outer fonts https://matplotlib.org/tutorials/text/mathtext.html
ticks = get_colorbar_ticks(sp)
if sp[:colorbar] in (:top, :bottom) if sp[:colorbar] in (:top, :bottom)
axis = sp[:xaxis] # colorbar inherits from x axis axis = sp[:xaxis] # colorbar inherits from x axis
cbar_axis = cb."ax"."xaxis" cbar_axis = cb."ax"."xaxis"
ticks_letter=:x
else else
axis = sp[:yaxis] # colorbar inherits from y axis axis = sp[:yaxis] # colorbar inherits from y axis
cbar_axis = cb."ax"."yaxis" cbar_axis = cb."ax"."yaxis"
ticks_letter=:y
end end
py_set_scale(cb.ax, sp, sp[:colorbar_scale], ticks_letter)
sp[:colorbar_ticks] == :native ? nothing : py_set_ticks(cb.ax, ticks, ticks_letter, env)
for lab in cbar_axis."get_ticklabels"() for lab in cbar_axis."get_ticklabels"()
lab."set_fontsize"(py_thickness_scale(plt, axis[:tickfontsize])) lab."set_fontsize"(py_thickness_scale(plt, sp[:colorbar_tickfontsize]))
lab."set_family"(axis[:tickfontfamily]) lab."set_family"(sp[:colorbar_tickfontfamily])
lab."set_color"(py_color(axis[:tickfontcolor])) lab."set_color"(py_color(sp[:colorbar_tickfontcolor]))
end end
# Adjust thickness of the cbar ticks # Adjust thickness of the cbar ticks

90
src/colorbars.jl Normal file
View File

@ -0,0 +1,90 @@
# These functions return an operator for use in `get_clims(::Seres, op)`
process_clims(lims::Tuple{<:Number,<:Number}) = (zlims -> ifelse.(isfinite.(lims), lims, zlims)) ignorenan_extrema
process_clims(s::Union{Symbol,Nothing,Missing}) = ignorenan_extrema
# don't specialize on ::Function otherwise python functions won't work
process_clims(f) = f
function get_clims(sp::Subplot, op=process_clims(sp[:clims]))
zmin, zmax = Inf, -Inf
for series in series_list(sp)
if series[:colorbar_entry]
zmin, zmax = _update_clims(zmin, zmax, get_clims(series, op)...)
end
end
return zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
end
function get_clims(sp::Subplot, series::Series, op=process_clims(sp[:clims]))
zmin, zmax = if series[:colorbar_entry]
get_clims(sp, op)
else
get_clims(series, op)
end
return zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
end
"""
get_clims(::Series, op=Plots.ignorenan_extrema)
Finds the limits for the colorbar by taking the "z-values" for the series and passing them into `op`,
which must return the tuple `(zmin, zmax)`. The default op is the extrema of the finite
values of the input.
"""
function get_clims(series::Series, op=ignorenan_extrema)
zmin, zmax = Inf, -Inf
z_colored_series = (:contour, :contour3d, :heatmap, :histogram2d, :surface, :hexbin)
for vals in (series[:seriestype] in z_colored_series ? series[:z] : nothing, series[:line_z], series[:marker_z], series[:fill_z])
if (typeof(vals) <: AbstractSurface) && (eltype(vals.surf) <: Union{Missing, Real})
zmin, zmax = _update_clims(zmin, zmax, op(vals.surf)...)
elseif (vals !== nothing) && (eltype(vals) <: Union{Missing, Real})
zmin, zmax = _update_clims(zmin, zmax, op(vals)...)
end
end
return zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
end
_update_clims(zmin, zmax, emin, emax) = NaNMath.min(zmin, emin), NaNMath.max(zmax, emax)
@enum ColorbarStyle cbar_gradient cbar_fill cbar_lines
function colorbar_style(series::Series)
colorbar_entry = series[:colorbar_entry]
if !(colorbar_entry isa Bool)
@warn "Non-boolean colorbar_entry ignored."
colorbar_entry = true
end
if !colorbar_entry
nothing
elseif isfilledcontour(series)
cbar_fill
elseif iscontour(series)
cbar_lines
elseif series[:seriestype] (:heatmap,:surface) ||
any(series[z] !== nothing for z [:marker_z,:line_z,:fill_z])
cbar_gradient
else
nothing
end
end
hascolorbar(series::Series) = colorbar_style(series) !== nothing
hascolorbar(sp::Subplot) = sp[:colorbar] != :none && any(hascolorbar(s) for s in series_list(sp))
function get_colorbar_ticks(sp::Subplot; update = true)
if update || !haskey(sp.attr, :colorbar_optimized_ticks)
ticks = _transform_ticks(sp[:colorbar_ticks])
cvals = sp[:colorbar_continuous_values]
dvals = sp[:colorbar_discrete_values]
clims = get_clims(sp)
scale = sp[:colorbar_scale]
formatter = sp[:colorbar_formatter]
sp.attr[:colorbar_optimized_ticks] =
get_ticks(ticks, cvals, dvals, clims, scale, formatter)
end
return sp.attr[:colorbar_optimized_ticks]
end
function _update_subplot_colorbars(sp::Subplot)
# Dynamic callback from the pipeline if needed
end

View File

@ -428,79 +428,6 @@ xlims(sp_idx::Int = 1) = xlims(current(), sp_idx)
ylims(sp_idx::Int = 1) = ylims(current(), sp_idx) ylims(sp_idx::Int = 1) = ylims(current(), sp_idx)
zlims(sp_idx::Int = 1) = zlims(current(), sp_idx) zlims(sp_idx::Int = 1) = zlims(current(), sp_idx)
# These functions return an operator for use in `get_clims(::Seres, op)`
process_clims(lims::Tuple{<:Number,<:Number}) = (zlims -> ifelse.(isfinite.(lims), lims, zlims)) ignorenan_extrema
process_clims(s::Union{Symbol,Nothing,Missing}) = ignorenan_extrema
# don't specialize on ::Function otherwise python functions won't work
process_clims(f) = f
function get_clims(sp::Subplot, op=process_clims(sp[:clims]))
zmin, zmax = Inf, -Inf
for series in series_list(sp)
if series[:colorbar_entry]
zmin, zmax = _update_clims(zmin, zmax, get_clims(series, op)...)
end
end
return zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
end
function get_clims(sp::Subplot, series::Series, op=process_clims(sp[:clims]))
zmin, zmax = if series[:colorbar_entry]
get_clims(sp, op)
else
get_clims(series, op)
end
return zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
end
"""
get_clims(::Series, op=Plots.ignorenan_extrema)
Finds the limits for the colorbar by taking the "z-values" for the series and passing them into `op`,
which must return the tuple `(zmin, zmax)`. The default op is the extrema of the finite
values of the input.
"""
function get_clims(series::Series, op=ignorenan_extrema)
zmin, zmax = Inf, -Inf
z_colored_series = (:contour, :contour3d, :heatmap, :histogram2d, :surface, :hexbin)
for vals in (series[:seriestype] in z_colored_series ? series[:z] : nothing, series[:line_z], series[:marker_z], series[:fill_z])
if (typeof(vals) <: AbstractSurface) && (eltype(vals.surf) <: Union{Missing, Real})
zmin, zmax = _update_clims(zmin, zmax, op(vals.surf)...)
elseif (vals !== nothing) && (eltype(vals) <: Union{Missing, Real})
zmin, zmax = _update_clims(zmin, zmax, op(vals)...)
end
end
return zmin <= zmax ? (zmin, zmax) : (NaN, NaN)
end
_update_clims(zmin, zmax, emin, emax) = NaNMath.min(zmin, emin), NaNMath.max(zmax, emax)
@enum ColorbarStyle cbar_gradient cbar_fill cbar_lines
function colorbar_style(series::Series)
colorbar_entry = series[:colorbar_entry]
if !(colorbar_entry isa Bool)
@warn "Non-boolean colorbar_entry ignored."
colorbar_entry = true
end
if !colorbar_entry
nothing
elseif isfilledcontour(series)
cbar_fill
elseif iscontour(series)
cbar_lines
elseif series[:seriestype] (:heatmap,:surface) ||
any(series[z] !== nothing for z [:marker_z,:line_z,:fill_z])
cbar_gradient
else
nothing
end
end
hascolorbar(series::Series) = colorbar_style(series) !== nothing
hascolorbar(sp::Subplot) = sp[:colorbar] != :none && any(hascolorbar(s) for s in series_list(sp))
iscontour(series::Series) = series[:seriestype] in (:contour, :contour3d) iscontour(series::Series) = series[:seriestype] in (:contour, :contour3d)
isfilledcontour(series::Series) = iscontour(series) && series[:fillrange] !== nothing isfilledcontour(series::Series) = iscontour(series) && series[:fillrange] !== nothing