Axis Options#
Customization options for axis appearance and behavior, including labels, limits, tick formatting, and axis scaling:
Parameters |
Description |
---|---|
autorange (Literal[âxâ, âyâ] or None, default=None) |
Whether to enable auto-ranging along the x- or y-axis when zooming. Only supported by the Bokeh backend. Added in version 0.9.0. |
flip_xaxis/flip_yaxis (bool or None, default=None) |
Whether to flip the axis left to right or up and down respectively. |
framewise (bool, default=True) |
Whether to compute the axis ranges frame-by-frame when using dynamic plots. |
invert (bool, default=False) |
Swaps x- and y-axis. |
logx/logy (bool, default=False) |
Enables logarithmic x- and y-axis respectively. |
loglog (bool or None, default=None) |
Enables logarithmic x- and y-axis. |
rot (number or None, default=None) |
Rotates the axis ticks along the x-axis by the specified number of degrees. |
shared_axes (bool, default=True) |
Whether to link axes between plots. |
subcoordinate_y (bool or dict or None, default=None) |
Whether to enable sub-coordinate y systems for this plot. Accepts also a
dictionary of related options to pass down to HoloViews,
e.g. Added in version 0.11.0. |
title (str or None, default=None) |
Title for the plot. |
xaxis (str or bool or None) |
Whether to show the x-axis and whether to place it at the top or
bottom. A bare axis means that an axis line is still displayed but
there are no axis ticks and labels. Valid options include:
|
yaxis (str or bool or None) |
Whether to show the y-axis and whether to place it at the left or
right. A bare axis means that an axis line is still displayed but
there are no axis ticks and labels. Valid options include:
|
xformatter/yformatter (str or bokeh.TickFormatter or None, default=None) |
Formatter for the x-axis and y-axis (accepts printf formatter, e.g. â%.3fâ, and bokeh TickFormatter). |
xlabel/ylabel/clabel (str or None, default=None) |
Axis labels for the x-axis, y-axis, and colorbar. |
xlim/ylim (tuple or None, default=None) |
Plot limits of the x- and y-axis. One bound can be left unset by
using |
xticks/yticks/cticks (int or list or np.ndarray or None, default=None) |
Ticks along x-axis and y-axis, as an integer, list of ticks positions,
Numpy ndarray, or list of tuples of the tick positions and labels.
Also accepts a Bokeh Added in version 0.11.0: |
autorange
#
The autorange
option allows enabling autoranging on the x or y axis. When enabled, the range of the selected axis is automatically computed and updated based on the data range in that axis. Setting autorange="y"
is practical for inspecting closely long timeseries, as it zooming and panning actions will always end up focusing on the timeseries, which can be cumbersome without autoranging.
In the example below, zoom and pan the second plot to observe the effect of y-axis autoranging. Note that this feature does not require an interactive Python kernel.
import hvplot.pandas # noqa
df = hvplot.sampledata.stocks("pandas").set_index("date")["Apple"]
df.hvplot.line(autorange=None, width=300, title="No y-axis autoranging") +\
df.hvplot.line(autorange="y", width=300, shared_axes=False, title="y-axis autoranging")
flip_xaxis / flip_yaxis
#
These options allow to flip the x and y axis. The examples below show their effect, notice how the axes, when flipped, start with a value of about 2 which then decreases.
import hvplot.pandas # noqa
import pandas as pd
df = pd.DataFrame({
"x": list(range(3)), "y": list(range(3)),
"v": ["a", "b", "c"], "s": list(range(100, 700, 200)),
})
plot_opts = dict(
x="x", y="y", color="v", s="s", legend=False,
aspect=1, frame_width=200, shared_axes=False,
)
(
df.hvplot.scatter(flip_xaxis=False, flip_yaxis=False, title="None", **plot_opts) +
df.hvplot.scatter(flip_xaxis=True, flip_yaxis=False, title="flip_xaxis", **plot_opts) +
df.hvplot.scatter(flip_xaxis=False, flip_yaxis=True, title="flip_yaxis", **plot_opts) +
df.hvplot.scatter(flip_xaxis=True, flip_yaxis=True, title="flip_xaxis + flip_yaxis", **plot_opts)
).cols(2)
framewise
#
hvPlot can generate plots that are composed of multiple frames in an animation or controlled with widgets, for instance with the groupby
option. The framewise
option allows to control whether the axis ranges are computed frame-by-frame or instead normalized across all the frames. framewise
is True
by default, meaning the axis ranges are not normalized but computed frame-by-frame. Setting framewise
to False
is useful to directly compare the frames.
In the examples below update the widget value and observe the axis and colorbar ranges, you should see that they adapt to the data range with framewise=True
(default) and stay constant with framewise=False
.
import hvplot.pandas # noqa
df = hvplot.sampledata.penguins("pandas")
plot_opts = dict(x="bill_length_mm", y="bill_depth_mm", groupby="island", frame_width=300, dynamic=False)
plot_default = df.hvplot.scatter(framewise=True, title="framewise=True (default)", **plot_opts)
plot_not_framewise = df.hvplot.scatter(framewise=False, title="framewise=False", **plot_opts)
plot_default
plot_not_framewise
import hvplot.xarray # noqa
ds = hvplot.sampledata.air_temperature("xarray").isel(time=slice(0, 2))
plot_opts = dict(dynamic=False, frame_width=300)
plot_not_framewise = ds.hvplot.image(framewise=False, title="framewise=False", **plot_opts)
plot_default = ds.hvplot.image(title="framewise=True", **plot_opts)
plot_default
plot_not_framewise
See also
shared_axes
to control axis normalization and linking in a layout.
invert
#
The invert
option swaps the x- and y-axis.
import hvplot.pandas # noqa
import pandas as pd
df = pd.DataFrame({"cat": ["A", "B", "C"], "value": [20, 10, 30]})
plot_opts = dict(x="cat", y="value", aspect=1, frame_width=200)
df.hvplot.bar(invert=False, title="invert=False (default)", **plot_opts) +\
df.hvplot.bar(invert=True, title="invert=True", **plot_opts)
logx / logy
#
These options control whether the x and y axes are defined with a logarithmic scale.
import hvplot.pandas # noqa
import numpy as np
import pandas as pd
df = pd.DataFrame({"x":(x:= np.logspace(0.1, 3, 20)), "y": x ** 2})
plot_opts = dict(x="x", y="y", aspect=1, frame_width=200, shared_axes=False)
df.hvplot.scatter(logx=True, title="logx=True", **plot_opts) +\
df.hvplot.scatter(logy=True, title="logy=True", **plot_opts)
loglog
#
This controls whether both the x and y axes are defined with a logarithmic scale.
import hvplot.pandas # noqa
import numpy as np
import pandas as pd
df = pd.DataFrame({"x":(x:= np.logspace(0.1, 3, 20)), "y": x ** 2})
plot_opts = dict(x="x", y="y", aspect=1, frame_width=200, shared_axes=False)
df.hvplot.scatter(loglog=True, title="loglog=True", **plot_opts)
rot
#
The rot
option rotates the x-axis ticks by the specified number of degrees (positive values only). It is useful to avoid the overlapping of long labels, as shown in the example below.
import hvplot.pandas # noqa
import pandas as pd
df = pd.DataFrame({"name": ["Very Long Name 1", "Very Long Name 2"], "value": [10, 20]})
df.hvplot.bar(x="name", y="value", rot=45, width=150, height=300)
import hvplot.pandas # noqa
import pandas as pd
df = pd.DataFrame({"name": ["Very Long Name 1", "Very Long Name 2"], "value": [10, 20]})
df.hvplot.bar(x="name", y="value", rot=45, invert=True, height=150, width=400)
subcoordinate_y
#
hvPlot enables you to create overlays where each element has its own distinct y-axis subcoordinate system, which is particularly useful to analyse multiple timeseries. To activate this feature that automatically distributes overlay elements along the y-axis, set the subcoordinate_y
option to True
. subcoordinate_y
also accepts a dictionary of related options, for example set subcoordinate_y={"subcoordinate_scale": 2}
to increase the scale of each sub-plot, resulting in each curveâs vertical range overlapping 50% with its adjacent elements. Additionally, the y-axis wheel zoom will apply to each curveâs respective sub-coordinate y-axis, rather than the global coordinate frame. More information about this feature can be found in HoloViewsâ documentation.
Use the wheel zoom on the plots below to zoom in all the time series simultaneously.
import hvplot.pandas # noqa
df = hvplot.sampledata.stocks("pandas")
df.hvplot.line(subcoordinate_y=True, title="subcoordinate_y=True")
import hvplot.pandas # noqa
df = hvplot.sampledata.stocks("pandas")
df.hvplot.line(subcoordinate_y={"subcoordinate_scale": 2}, title="50% overlapping subcoordinate_y")
title
#
The title
option allows to set the overall plot title.
Note
For simple plots, setting the plot title with title
or with the label
option both lead to a similar visual output. However, the HoloViews object returned will only have its label
attribute set when the label
option is used.
import hvplot.pandas # noqa
df = hvplot.sampledata.penguins("pandas")
df.hvplot.scatter("bill_depth_mm", "bill_length_mm", width=400, title="Plot title")
xaxis
#
Control the x-axis location and display with xaxis
.
import hvplot.pandas # noqa
df = hvplot.sampledata.penguins("pandas")
plot_opts = dict(x="bill_depth_mm", y="bill_length_mm", frame_width=200, aspect=1)
(
df.hvplot.scatter(xaxis="bottom", title="xaxis=bottom (default)", **plot_opts) +
df.hvplot.scatter(xaxis="bottom-bare", title="xaxis=bottom-bare", **plot_opts) +
df.hvplot.scatter(xaxis="top", title="xaxis=top", **plot_opts) +
df.hvplot.scatter(xaxis="top-bare", title="xaxis=top-bare", **plot_opts) +
df.hvplot.scatter(xaxis="bare", title="xaxis=bare", **plot_opts) +
df.hvplot.scatter(xaxis=None, title="xaxis=None", **plot_opts) +
df.hvplot.scatter(xaxis=True, title="xaxis=True", **plot_opts) +
df.hvplot.scatter(xaxis=False, title="xaxis=False", **plot_opts)
).cols(2)
yaxis
#
Control the y-axis location and display with yaxis
.
import hvplot.pandas # noqa
df = hvplot.sampledata.penguins("pandas")
plot_opts = dict(x="bill_depth_mm", y="bill_length_mm", frame_width=200, aspect=1)
(
df.hvplot.scatter(yaxis="left", title="yaxis=left (default)", **plot_opts) +
df.hvplot.scatter(yaxis="left-bare", title="yaxis=left-bare", **plot_opts) +
df.hvplot.scatter(yaxis="right", title="yaxis=right", **plot_opts) +
df.hvplot.scatter(yaxis="right-bare", title="yaxis=right-bare", **plot_opts) +
df.hvplot.scatter(yaxis="bare", title="yaxis=bare", **plot_opts) +
df.hvplot.scatter(yaxis=None, title="yaxis=None", **plot_opts) +
df.hvplot.scatter(yaxis=True, title="yaxis=True", **plot_opts) +
df.hvplot.scatter(yaxis=False, title="yaxis=False", **plot_opts)
).cols(2)
xformatter / yformatter
#
These options allow to format the x and y tick labels. They accept a str
object, or a Bokeh or Matplotlib formatter instance (depending on the active plotting backend).
When set to a str
object, these formatters are:
Bokeh:
PrintfTickFormatter
(printf/old-style format string as used with the%
operator); note that Bokeh computes the labels in the front-end using the JavaScript library sprintf.js, so the implementation can slightly differ from Pythonâs printf/old-style format string.Matplotlib:
StrMethodFormatter
(new-style format string as used bystr.format
) if the string contains a reference to the format variable (available keys arex
andpos
, e.g.'{x} {pos}'
),FormatStrFormatter
(printf/old-style format string as used with the%
operator) otherwise.
Bokehâs PrintfTickFormatter
can be useful for simple number formatting and other simple cases, you can find its specification below. Matplotlibâs StrMethodFormatter
offers all the power of Pythonâs str.format
.
Bokeh PrintfTickFormatter
specification
The number format, as defined as follows:
The placeholders in the format string are marked by %
and are followed by one or more of these elements, in this order:
An optional number followed by a
$
sign that selects which argument index to use for the value. If not specified, arguments will be placed in the same order as the placeholders in the input string.An optional
+
sign that forces to precede the result with a plus or minus sign on numeric values. By default, only the-
sign is used on negative numbers.An optional padding specifier that says what character to use for padding (if specified). Possible values are
0
or any other character preceded by a'
(single quote). The default is to pad with spaces.An optional
-
sign, that causessprintf
to left-align the result of this placeholder. The default is to right-align the result.An optional number, that says how many characters the result should have. If the value to be returned is shorter than this number, the result will be padded. When used with the
j
(JSON) type specifier, the padding length specifies the tab size used for indentation.An optional precision modifier, consisting of a
.
(dot) followed by a number, that says how many digits should be displayed for floating point numbers. When used with theg
type specifier, it specifies the number of significant digits. When used on a string, it causes the result to be truncated.A type specifier that can be any of:
%
â yields a literal%
characterb
â yields an integer as a binary numberc
â yields an integer as the character with that ASCII valued
ori
â yields an integer as a signed decimal numbere
â yields a float using scientific notationu
â yields an integer as an unsigned decimal numberf
â yields a float as is; see notes on precision aboveg
â yields a float as is; see notes on precision aboveo
â yields an integer as an octal numbers
â yields a string as ist
â yieldstrue
orfalse
T
â yields the type of the argument1v
â yields the primitive value of the specified argumentx
â yields an integer as a hexadecimal number (lower-case)X
â yields an integer as a hexadecimal number (upper-case)j
â yields a JavaScript object or array as a JSON encoded string
For Bokeh plots, NumeralTickFormatter
is a much more appropriate formatter for a wider range of number format options. You can find its complete specification below (Bokehâs implementation leverages the JavaScript library numbro
, visit their format reference for more information):
Bokeh NumericalTickFormatter
specification
NUMBERS
Number |
Format |
String |
---|---|---|
10000 |
|
10,000.0000 |
10000.23 |
|
10,000 |
10000.23 |
|
+10,000 |
-10000 |
|
-10,000.0 |
10000.1234 |
|
10000.123 |
10000.1234 |
|
10000.12340 |
-10000 |
|
(10,000.0000) |
-0.23 |
|
-.23 |
-0.23 |
|
(.23) |
0.23 |
|
0.23000 |
0.23 |
|
0.23 |
1230974 |
|
1.2m |
1460 |
|
1 k |
-104000 |
|
-104k |
1 |
|
1st |
52 |
|
52nd |
23 |
|
23rd |
100 |
|
100th |
CURRENCY
Number |
Format |
String |
---|---|---|
1000.234 |
|
$1,000.23 |
1000.2 |
|
1,000.20 $ |
1001 |
|
$ 1,001 |
-1000.234 |
|
($1,000) |
-1000.234 |
|
-$1000.23 |
1230974 |
|
$ 1.23 m |
BYTES
Number |
Format |
String |
---|---|---|
100 |
|
100B |
2048 |
|
2 KB |
7884486213 |
|
7.3GB |
3467479682787 |
|
3.154 TB |
PERCENTAGES
Number |
Format |
String |
---|---|---|
1 |
|
100% |
0.974878234 |
|
97.488% |
-0.43 |
|
-43 % |
0.43 |
|
43.000 % |
TIME
Number |
Format |
String |
---|---|---|
25 |
|
0:00:25 |
238 |
|
0:03:58 |
63846 |
|
17:44:06 |
This table contains a subset of common number formats that can be set with NumeralTickFormatter
:
Format |
Example Input |
Output |
Use Case |
---|---|---|---|
|
12345.67 |
12,346 |
General whole numbers |
|
1230000 |
1.2m |
Large numbers (compact form) |
|
0.45 |
45% |
Percent values |
|
123.456 |
123.5 |
One decimal place |
|
123.456 |
123.46 |
Two decimal places |
|
12345 |
$12,345 |
Financial (whole dollar) |
|
12345.67 |
$12,345.67 |
Financial (cents included) |
|
0.0000123 |
1.23e-5 |
Scientific notation (2 decimals) |
|
123000000 |
1e+8 |
Scientific notation (rounded) |
For datetime formatting:
Bokeh offers DatetimeTickFormatter.
Matplotlib offers a few date formatters, including the simple DateFormatter that uses
strftime
format strings.
Visit this page from Bokehâs user guide to more explanation about Bokehâs formatters.
Bokeh#
This example sets a simple printf style y-formatter and a custom DatetimeTickFormatter
x-formatter that sets the date format when in the days range and a context (find more information on datetime tick context in Bokehâs documentation).
import hvplot.pandas # noqa
from bokeh.models import DatetimeTickFormatter, RELATIVE_DATETIME_CONTEXT
df = hvplot.sampledata.apple_stocks("pandas").set_index("date").loc["2023-01"]
df.hvplot.line(
y="open", width=500,
xformatter=DatetimeTickFormatter(days="%B %d", context=RELATIVE_DATETIME_CONTEXT()),
yformatter="$%.2f",
)
This example sets a NumeralTickFormatter
y-formatter to format the volume in a more consice way.
import hvplot.pandas # noqa
from bokeh.models import NumeralTickFormatter
df = hvplot.sampledata.apple_stocks("pandas").set_index("date").loc["2023-01"]
df.hvplot.line(y="volume", width=500, yformatter=NumeralTickFormatter(format="0.0a"))
Matplotlib#
These two examples set a DateFormatter
x-formatter, and an printf and a str.format y-formatters, respectively.
import hvplot.pandas # noqa
import matplotlib as mpl
hvplot.extension("matplotlib")
df = hvplot.sampledata.apple_stocks("pandas").set_index("date").loc["2023-01"]
df.hvplot.line(y="open", xformatter=mpl.dates.DateFormatter("%Y-%m-%d"), yformatter="$%.2f")
import hvplot.pandas # noqa
hvplot.extension("matplotlib")
df = hvplot.sampledata.apple_stocks("pandas").set_index("date").loc["2023-01"]
df.hvplot.line(y="open", xformatter=mpl.dates.DateFormatter("%Y-%m-%d"), yformatter="${x:.2f} | pos={pos}")
xlabel / ylabel / clabel
#
These options are useful for overwriting the default label values, which are by default automatically set from the variable names.
import hvplot.pandas # noqa
df = hvplot.sampledata.penguins("pandas")
df.hvplot.scatter(
x="bill_depth_mm", y="bill_length_mm", color="body_mass_g", width=400,
xlabel="Bill depth [mm]", ylabel="Bill length [mm]", clabel="Body mass [g]"
)
xlim / ylim
#
The x- and y-axis ranges can be defined with the xlim
and ylim
options, respectively. These options accept a 2-tuple representing the minimum and maximum bounds of the plotted ranged. One bound can be left unset by using None
(e.g. xlim=(10, None)
means there is no upper bound).
import hvplot.pandas # noqa
df = hvplot.sampledata.penguins("pandas")
plot_opts = dict(x="bill_depth_mm", y="bill_length_mm", height=200, width=200, shared_axes=False)
(
df.hvplot.scatter(xlim=(18, None), title="xlim=(18, None)", **plot_opts) +
df.hvplot.scatter(xlim=(None, 18), title="xlim=(None, 18)", **plot_opts) +
df.hvplot.scatter(xlim=(16, 20), title="xlim=(16, 20)", **plot_opts) +
df.hvplot.scatter(ylim=(45, None), title="ylim=(45, None)", **plot_opts) +
df.hvplot.scatter(ylim=(None, 45), title="ylim=(None, 45)", **plot_opts) +
df.hvplot.scatter(ylim=(40, 50), title="ylim=(40, 50)", **plot_opts)
).cols(3)
For datetime axes, the bounds are expected to be in a datetime value like a pandas.Timestamp
object.
import hvplot.pandas # noqa
import pandas as pd
df = hvplot.sampledata.stocks("pandas").set_index("date")
df.hvplot.line(width=500, xlim=(pd.Timestamp("2021"), pd.Timestamp("2023")))
xticks / yticks / cticks
#
xticks
yticks
allow to control the number and/or location of the x- and y-axis ticks. cticks
has the same effect on the colorbar axis.
import hvplot.pandas # noqa
import numpy as np
df = hvplot.sampledata.penguins("pandas")
plot_opts = dict(x="bill_depth_mm", y="bill_length_mm", frame_width=200, aspect=1, fontsize={"title": "10pt"})
(
df.hvplot.scatter(xticks=None, title="xticks=None (default)", **plot_opts) +
df.hvplot.scatter(xticks=2, title="xticks=2", **plot_opts) +
df.hvplot.scatter(xticks=[15, 17.5, 20], title="xticks=[15, 17.5, 20]", **plot_opts) +
df.hvplot.scatter(xticks=np.arange(10, 25, 1), title="xticks=np.arange(10, 25, 1)", **plot_opts) +
df.hvplot.scatter(xticks=[(15, "small"), (20, "big")], title='xticks=[(15, "small"), (20, "big")]', **plot_opts) +
df.hvplot.scatter(xaxis=None, yaxis=None, c="white", **plot_opts) +
df.hvplot.scatter(yticks=None, title="yticks=None (default)", **plot_opts) +
df.hvplot.scatter(yticks=2, title="yticks=2", **plot_opts) +
df.hvplot.scatter(yticks=[35, 45, 55], title="yticks=[35, 45, 55]", **plot_opts) +
df.hvplot.scatter(yticks=np.arange(30, 65, 5), title="yticks=np.arange(30, 65, 5)", **plot_opts) +
df.hvplot.scatter(yticks=[(35, "small"), (55, "big")], title='yticks=[(35, "small"), (55, "big")]', **plot_opts) +
df.hvplot.scatter(xaxis=None, yaxis=None, c="white", **plot_opts)
).cols(2)
import hvplot.pandas # noqa
import pandas as pd
df = hvplot.sampledata.stocks("pandas").set_index("date")
df.hvplot.line(width=500, xticks=pd.date_range("2019", "2024", freq="6ME").to_list(), rot=45)
When creating a Bokeh plot, xaxis
and yaxis
also accept a custom Bokeh ticker object.
import bokeh as bk
import hvplot.pandas # noqa
df = hvplot.sampledata.stocks("pandas").set_index("date").loc["2023-01"]
df.hvplot.line(
width=500,
xticks=bk.models.DaysTicker(days=list(range(1, 32, 7))),
yticks=bk.models.SingleIntervalTicker(interval=1),
)
cticks
accept a similar set of values.
import bokeh
import hvplot.pandas # noqa
df = hvplot.sampledata.penguins("pandas")
plot_opts = dict(
x="bill_depth_mm", y="bill_length_mm", color="body_mass_g",
frame_width=200, aspect=1, fontsize={"title": "10pt"}
)
(
df.hvplot.scatter(cticks=None, title="cticks=None (default)", **plot_opts) +
df.hvplot.scatter(cticks=2, title="cticks=2", **plot_opts) +
df.hvplot.scatter(cticks=[3000, 4500, 6000], title="cticks=[3000, 4500, 6000]", **plot_opts) +
df.hvplot.scatter(cticks=np.arange(3000, 6500, 500), title="cticks=np.arange(3000, 6500, 500)", **plot_opts) +
df.hvplot.scatter(cticks=[(3000, "small"), (6000, "big")], title='cticks=[(3000, "small"), (6000, "big")]', **plot_opts) +
df.hvplot.scatter(cticks=bokeh.models.SingleIntervalTicker(interval=1000), title='cticks=bokeh.models.Ticker()', **plot_opts)
).cols(2)