diff --git a/doc/users/next_whats_new/axes_class.rst b/doc/users/next_whats_new/axes_class.rst new file mode 100644 index 000000000000..19b80c6a6e8a --- /dev/null +++ b/doc/users/next_whats_new/axes_class.rst @@ -0,0 +1,4 @@ +add_subplot/add_axes gained an *axes_class* parameter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +In particular, ``mpl_toolkits`` axes subclasses can now be idiomatically used +using e.g. ``fig.add_subplot(axes_class=mpl_toolkits.axislines.Axes)`` diff --git a/examples/axes_grid1/demo_axes_divider.py b/examples/axes_grid1/demo_axes_divider.py index 5fa1f278cc33..d27f4b810e26 100644 --- a/examples/axes_grid1/demo_axes_divider.py +++ b/examples/axes_grid1/demo_axes_divider.py @@ -33,10 +33,12 @@ def demo_locatable_axes_hard(fig): divider = SubplotDivider(fig, 2, 2, 2, aspect=True) # axes for image - ax = Axes(fig, divider.get_position()) + ax = fig.add_axes(divider.get_position(), axes_class=Axes) # axes for colorbar - ax_cb = Axes(fig, divider.get_position()) + # (the label prevents Axes.add_axes from incorrectly believing that the two + # axes are the same) + ax_cb = fig.add_axes(divider.get_position(), axes_class=Axes, label="cb") h = [Size.AxesX(ax), # main axes Size.Fixed(0.05), # padding, 0.1 inch @@ -51,9 +53,6 @@ def demo_locatable_axes_hard(fig): ax.set_axes_locator(divider.new_locator(nx=0, ny=0)) ax_cb.set_axes_locator(divider.new_locator(nx=2, ny=0)) - fig.add_axes(ax) - fig.add_axes(ax_cb) - ax_cb.axis["left"].toggle(all=False) ax_cb.axis["right"].toggle(ticks=True) diff --git a/examples/axes_grid1/parasite_simple2.py b/examples/axes_grid1/parasite_simple2.py index cbf768e892c7..a49e005c4df7 100644 --- a/examples/axes_grid1/parasite_simple2.py +++ b/examples/axes_grid1/parasite_simple2.py @@ -6,7 +6,7 @@ """ import matplotlib.transforms as mtransforms import matplotlib.pyplot as plt -from mpl_toolkits.axes_grid1.parasite_axes import SubplotHost +from mpl_toolkits.axes_grid1.parasite_axes import HostAxes obs = [["01_S1", 3.88, 0.14, 1970, 63], ["01_S4", 5.6, 0.82, 1622, 150], @@ -16,7 +16,7 @@ fig = plt.figure() -ax_kms = SubplotHost(fig, 1, 1, 1, aspect=1.) +ax_kms = fig.add_subplot(axes_class=HostAxes, aspect=1) # angular proper motion("/yr) to linear velocity(km/s) at distance=2.3kpc pm_to_kms = 1./206265.*2300*3.085e18/3.15e7/1.e5 @@ -25,8 +25,6 @@ ax_pm = ax_kms.twin(aux_trans) ax_pm.set_viewlim_mode("transform") -fig.add_subplot(ax_kms) - for n, ds, dse, w, we in obs: time = ((2007 + (10. + 4/30.)/12) - 1988.5) v = ds / time * pm_to_kms diff --git a/examples/axisartist/axis_direction.py b/examples/axisartist/axis_direction.py index b9bd6a30cde1..7cf49f9cfa14 100644 --- a/examples/axisartist/axis_direction.py +++ b/examples/axisartist/axis_direction.py @@ -8,8 +8,8 @@ import mpl_toolkits.axisartist as axisartist -def setup_axes(fig, rect): - ax = fig.add_axes(axisartist.Subplot(fig, rect)) +def setup_axes(fig, pos): + ax = fig.add_subplot(pos, axes_class=axisartist.Axes) ax.set_ylim(-0.1, 1.5) ax.set_yticks([0, 1]) diff --git a/examples/axisartist/demo_axis_direction.py b/examples/axisartist/demo_axis_direction.py index c3ceccdd749d..81fd7a6126bf 100644 --- a/examples/axisartist/demo_axis_direction.py +++ b/examples/axisartist/demo_axis_direction.py @@ -43,11 +43,10 @@ def setup_axes(fig, rect): tick_formatter1=tick_formatter1 ) - ax1 = axisartist.Subplot(fig, rect, grid_helper=grid_helper) + ax1 = fig.add_subplot( + rect, axes_class=axisartist.Axes, grid_helper=grid_helper) ax1.axis[:].toggle(ticklabels=False) - fig.add_subplot(ax1) - ax1.set_aspect(1.) ax1.set_xlim(-5, 12) ax1.set_ylim(-5, 10) diff --git a/examples/axisartist/demo_axisline_style.py b/examples/axisartist/demo_axisline_style.py index 6864de5a2f9c..1427a90952a1 100644 --- a/examples/axisartist/demo_axisline_style.py +++ b/examples/axisartist/demo_axisline_style.py @@ -11,14 +11,13 @@ :doc:`/gallery/ticks_and_spines/centered_spines_with_arrows` example. """ -from mpl_toolkits.axisartist.axislines import SubplotZero +from mpl_toolkits.axisartist.axislines import AxesZero import matplotlib.pyplot as plt import numpy as np fig = plt.figure() -ax = SubplotZero(fig, 111) -fig.add_subplot(ax) +ax = fig.add_subplot(axes_class=AxesZero) for direction in ["xzero", "yzero"]: # adds arrows at the ends of each axis diff --git a/examples/axisartist/demo_curvelinear_grid.py b/examples/axisartist/demo_curvelinear_grid.py index b2fa2bcce5e2..b85991569041 100644 --- a/examples/axisartist/demo_curvelinear_grid.py +++ b/examples/axisartist/demo_curvelinear_grid.py @@ -18,7 +18,7 @@ from matplotlib.transforms import Affine2D from mpl_toolkits.axisartist import ( - angle_helper, Subplot, SubplotHost, ParasiteAxesAuxTrans) + angle_helper, Axes, HostAxes, ParasiteAxesAuxTrans) from mpl_toolkits.axisartist.grid_helper_curvelinear import ( GridHelperCurveLinear) @@ -38,14 +38,12 @@ def inv_tr(x, y): grid_helper = GridHelperCurveLinear((tr, inv_tr)) - ax1 = Subplot(fig, 1, 2, 1, grid_helper=grid_helper) + ax1 = fig.add_subplot(1, 2, 1, axes_class=Axes, grid_helper=grid_helper) # ax1 will have a ticks and gridlines defined by the given # transform (+ transData of the Axes). Note that the transform of # the Axes itself (i.e., transData) is not affected by the given # transform. - fig.add_subplot(ax1) - xx, yy = tr([3, 6], [5, 10]) ax1.plot(xx, yy, linewidth=2.0) @@ -84,7 +82,8 @@ def curvelinear_test2(fig): grid_helper = GridHelperCurveLinear( tr, extreme_finder=extreme_finder, grid_locator1=grid_locator1, tick_formatter1=tick_formatter1) - ax1 = SubplotHost(fig, 1, 2, 2, grid_helper=grid_helper) + ax1 = fig.add_subplot( + 1, 2, 2, axes_class=HostAxes, grid_helper=grid_helper) # make ticklabels of right and top axis visible. ax1.axis["right"].major_ticklabels.set_visible(True) @@ -94,8 +93,6 @@ def curvelinear_test2(fig): # let bottom axis shows ticklabels for 2nd coordinate (radius) ax1.axis["bottom"].get_helper().nth_coord_ticks = 1 - fig.add_subplot(ax1) - ax1.set_aspect(1) ax1.set_xlim(-5, 12) ax1.set_ylim(-5, 10) diff --git a/examples/axisartist/demo_curvelinear_grid2.py b/examples/axisartist/demo_curvelinear_grid2.py index 1f6c7ee69531..9bfb996a2971 100644 --- a/examples/axisartist/demo_curvelinear_grid2.py +++ b/examples/axisartist/demo_curvelinear_grid2.py @@ -17,7 +17,7 @@ GridHelperCurveLinear) from mpl_toolkits.axisartist.grid_finder import ( ExtremeFinderSimple, MaxNLocator) -from mpl_toolkits.axisartist.axislines import Subplot +from mpl_toolkits.axisartist.axislines import Axes def curvelinear_test1(fig): @@ -39,13 +39,11 @@ def inv_tr(x, y): # better tick density grid_locator1=MaxNLocator(nbins=6), grid_locator2=MaxNLocator(nbins=6)) - ax1 = Subplot(fig, 111, grid_helper=grid_helper) + ax1 = fig.add_subplot(axes_class=Axes, grid_helper=grid_helper) # ax1 will have a ticks and gridlines defined by the given # transform (+ transData of the Axes). Note that the transform of the Axes # itself (i.e., transData) is not affected by the given transform. - fig.add_subplot(ax1) - ax1.imshow(np.arange(25).reshape(5, 5), vmax=50, cmap=plt.cm.gray_r, origin="lower") diff --git a/examples/axisartist/demo_floating_axes.py b/examples/axisartist/demo_floating_axes.py index 1994163f0058..6920ddca5233 100644 --- a/examples/axisartist/demo_floating_axes.py +++ b/examples/axisartist/demo_floating_axes.py @@ -39,8 +39,8 @@ def setup_axes1(fig, rect): grid_locator1=MaxNLocator(nbins=4), grid_locator2=MaxNLocator(nbins=4)) - ax1 = floating_axes.FloatingSubplot(fig, rect, grid_helper=grid_helper) - fig.add_subplot(ax1) + ax1 = fig.add_subplot( + rect, axes_class=floating_axes.FloatingAxes, grid_helper=grid_helper) aux_ax = ax1.get_aux_axes(tr) @@ -70,8 +70,8 @@ def setup_axes2(fig, rect): tick_formatter1=tick_formatter1, tick_formatter2=None) - ax1 = floating_axes.FloatingSubplot(fig, rect, grid_helper=grid_helper) - fig.add_subplot(ax1) + ax1 = fig.add_subplot( + rect, axes_class=floating_axes.FloatingAxes, grid_helper=grid_helper) # create a parasite axes whose transData in RA, cz aux_ax = ax1.get_aux_axes(tr) @@ -114,8 +114,8 @@ def setup_axes3(fig, rect): tick_formatter1=tick_formatter1, tick_formatter2=None) - ax1 = floating_axes.FloatingSubplot(fig, rect, grid_helper=grid_helper) - fig.add_subplot(ax1) + ax1 = fig.add_subplot( + rect, axes_class=floating_axes.FloatingAxes, grid_helper=grid_helper) # adjust axis ax1.axis["left"].set_axis_direction("bottom") diff --git a/examples/axisartist/demo_floating_axis.py b/examples/axisartist/demo_floating_axis.py index 276fad0a99e3..36de8ce87dae 100644 --- a/examples/axisartist/demo_floating_axis.py +++ b/examples/axisartist/demo_floating_axis.py @@ -14,7 +14,7 @@ import mpl_toolkits.axisartist.angle_helper as angle_helper from matplotlib.projections import PolarAxes from matplotlib.transforms import Affine2D -from mpl_toolkits.axisartist import SubplotHost +from mpl_toolkits.axisartist import HostAxes from mpl_toolkits.axisartist import GridHelperCurveLinear @@ -42,9 +42,7 @@ def curvelinear_test2(fig): tick_formatter1=tick_formatter1 ) - ax1 = SubplotHost(fig, 1, 1, 1, grid_helper=grid_helper) - - fig.add_subplot(ax1) + ax1 = fig.add_subplot(axes_class=HostAxes, grid_helper=grid_helper) # Now creates floating axis diff --git a/examples/axisartist/demo_parasite_axes.py b/examples/axisartist/demo_parasite_axes.py index d3fe972d4a49..ef7d5ca5268d 100644 --- a/examples/axisartist/demo_parasite_axes.py +++ b/examples/axisartist/demo_parasite_axes.py @@ -23,7 +23,7 @@ fig = plt.figure() -host = HostAxes(fig, [0.15, 0.1, 0.65, 0.8]) +host = fig.add_axes([0.15, 0.1, 0.65, 0.8], axes_class=HostAxes) par1 = ParasiteAxes(host, sharex=host) par2 = ParasiteAxes(host, sharex=host) host.parasites.append(par1) @@ -37,8 +37,6 @@ par2.axis["right2"] = par2.new_fixed_axis(loc="right", offset=(60, 0)) -fig.add_axes(host) - p1, = host.plot([0, 1, 2], [0, 1, 2], label="Density") p2, = par1.plot([0, 1, 2], [0, 3, 2], label="Temperature") p3, = par2.plot([0, 1, 2], [50, 30, 15], label="Velocity") diff --git a/examples/axisartist/demo_ticklabel_alignment.py b/examples/axisartist/demo_ticklabel_alignment.py index 452f88e0046b..14dd6354efaf 100644 --- a/examples/axisartist/demo_ticklabel_alignment.py +++ b/examples/axisartist/demo_ticklabel_alignment.py @@ -10,15 +10,12 @@ import mpl_toolkits.axisartist as axisartist -def setup_axes(fig, rect): - ax = axisartist.Subplot(fig, rect) - fig.add_subplot(ax) - +def setup_axes(fig, pos): + ax = fig.add_subplot(pos, axes_class=axisartist.Axes) ax.set_yticks([0.2, 0.8]) ax.set_yticklabels(["short", "loooong"]) ax.set_xticks([0.2, 0.8]) ax.set_xticklabels([r"$\frac{1}{2}\pi$", r"$\pi$"]) - return ax diff --git a/examples/axisartist/demo_ticklabel_direction.py b/examples/axisartist/demo_ticklabel_direction.py index 1c777c1ec1f0..f9a981f4e398 100644 --- a/examples/axisartist/demo_ticklabel_direction.py +++ b/examples/axisartist/demo_ticklabel_direction.py @@ -9,13 +9,10 @@ import mpl_toolkits.axisartist.axislines as axislines -def setup_axes(fig, rect): - ax = axislines.Subplot(fig, rect) - fig.add_subplot(ax) - +def setup_axes(fig, pos): + ax = fig.add_subplot(pos, axes_class=axislines.Axes) ax.set_yticks([0.2, 0.8]) ax.set_xticks([0.2, 0.8]) - return ax diff --git a/examples/axisartist/simple_axis_direction01.py b/examples/axisartist/simple_axis_direction01.py index 2240ceece7e0..986ea690dfd4 100644 --- a/examples/axisartist/simple_axis_direction01.py +++ b/examples/axisartist/simple_axis_direction01.py @@ -8,7 +8,7 @@ import mpl_toolkits.axisartist as axisartist fig = plt.figure(figsize=(4, 2.5)) -ax1 = fig.add_subplot(axisartist.Subplot(fig, 111)) +ax1 = fig.add_subplot(axes_class=axisartist.Axes) fig.subplots_adjust(right=0.8) ax1.axis["left"].major_ticklabels.set_axis_direction("top") diff --git a/examples/axisartist/simple_axis_direction03.py b/examples/axisartist/simple_axis_direction03.py index e9b758b15817..29033601db3d 100644 --- a/examples/axisartist/simple_axis_direction03.py +++ b/examples/axisartist/simple_axis_direction03.py @@ -9,13 +9,10 @@ import mpl_toolkits.axisartist as axisartist -def setup_axes(fig, rect): - ax = axisartist.Subplot(fig, rect) - fig.add_subplot(ax) - +def setup_axes(fig, pos): + ax = fig.add_subplot(pos, axes_class=axisartist.Axes) ax.set_yticks([0.2, 0.8]) ax.set_xticks([0.2, 0.8]) - return ax diff --git a/examples/axisartist/simple_axis_pad.py b/examples/axisartist/simple_axis_pad.py index f95e2f6e3836..a482c4728ada 100644 --- a/examples/axisartist/simple_axis_pad.py +++ b/examples/axisartist/simple_axis_pad.py @@ -43,11 +43,9 @@ def setup_axes(fig, rect): tick_formatter1=tick_formatter1 ) - ax1 = axisartist.Subplot(fig, rect, grid_helper=grid_helper) + ax1 = fig.add_subplot( + rect, axes_class=axisartist.Axes, grid_helper=grid_helper) ax1.axis[:].set_visible(False) - - fig.add_subplot(ax1) - ax1.set_aspect(1.) ax1.set_xlim(-5, 12) ax1.set_ylim(-5, 10) diff --git a/examples/axisartist/simple_axisartist1.py b/examples/axisartist/simple_axisartist1.py index 3c702c347425..9e49a3b12a71 100644 --- a/examples/axisartist/simple_axisartist1.py +++ b/examples/axisartist/simple_axisartist1.py @@ -9,8 +9,7 @@ fig = plt.figure() fig.subplots_adjust(right=0.85) -ax = axisartist.Subplot(fig, 1, 1, 1) -fig.add_subplot(ax) +ax = fig.add_subplot(axes_class=axisartist.Axes) # make some axis invisible ax.axis["bottom", "top", "right"].set_visible(False) diff --git a/examples/axisartist/simple_axisline.py b/examples/axisartist/simple_axisline.py index 1d48d9f3ff8a..7623763f1ea7 100644 --- a/examples/axisartist/simple_axisline.py +++ b/examples/axisartist/simple_axisline.py @@ -6,13 +6,12 @@ """ import matplotlib.pyplot as plt -from mpl_toolkits.axisartist.axislines import SubplotZero +from mpl_toolkits.axisartist.axislines import AxesZero fig = plt.figure() fig.subplots_adjust(right=0.85) -ax = SubplotZero(fig, 1, 1, 1) -fig.add_subplot(ax) +ax = fig.add_subplot(axes_class=AxesZero) # make right and top axis invisible ax.axis["right"].set_visible(False) diff --git a/examples/axisartist/simple_axisline2.py b/examples/axisartist/simple_axisline2.py index c0523f33da54..ecd49a16de77 100644 --- a/examples/axisartist/simple_axisline2.py +++ b/examples/axisartist/simple_axisline2.py @@ -5,15 +5,14 @@ """ import matplotlib.pyplot as plt -from mpl_toolkits.axisartist.axislines import SubplotZero +from mpl_toolkits.axisartist.axislines import AxesZero import numpy as np fig = plt.figure(figsize=(4, 3)) # a subplot with two additional axis, "xzero" and "yzero". "xzero" is # y=0 line, and "yzero" is x=0 line. -ax = SubplotZero(fig, 1, 1, 1) -fig.add_subplot(ax) +ax = fig.add_subplot(axes_class=AxesZero) # make xzero axis (horizontal axis line through y=0) visible. ax.axis["xzero"].set_visible(True) diff --git a/examples/axisartist/simple_axisline3.py b/examples/axisartist/simple_axisline3.py index c0b8d16b4e0d..41983cc04df3 100644 --- a/examples/axisartist/simple_axisline3.py +++ b/examples/axisartist/simple_axisline3.py @@ -5,12 +5,11 @@ """ import matplotlib.pyplot as plt -from mpl_toolkits.axisartist.axislines import Subplot +from mpl_toolkits.axisartist.axislines import Axes fig = plt.figure(figsize=(3, 3)) -ax = Subplot(fig, 111) -fig.add_subplot(ax) +ax = fig.add_subplot(axes_class=Axes) ax.axis["right"].set_visible(False) ax.axis["top"].set_visible(False) diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index cf820369aecc..1d5d2c4630da 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -1073,7 +1073,8 @@ def fixlist(args): return key def _process_projection_requirements( - self, *args, polar=False, projection=None, **kwargs): + self, *args, axes_class=None, polar=False, projection=None, + **kwargs): """ Handle the args/kwargs to add_axes/add_subplot/gca, returning:: @@ -1081,22 +1082,30 @@ def _process_projection_requirements( which can be used for new axes initialization/identification. """ - if polar: - if projection is not None and projection != 'polar': + if axes_class is not None: + if polar or projection is not None: raise ValueError( - "polar=True, yet projection=%r. " - "Only one of these arguments should be supplied." % - projection) - projection = 'polar' - - if isinstance(projection, str) or projection is None: - projection_class = projections.get_projection_class(projection) - elif hasattr(projection, '_as_mpl_axes'): - projection_class, extra_kwargs = projection._as_mpl_axes() - kwargs.update(**extra_kwargs) + "Cannot combine 'axes_class' and 'projection' or 'polar'") + projection_class = axes_class else: - raise TypeError('projection must be a string, None or implement a ' - '_as_mpl_axes method. Got %r' % projection) + + if polar: + if projection is not None and projection != 'polar': + raise ValueError( + "polar=True, yet projection=%r. " + "Only one of these arguments should be supplied." % + projection) + projection = 'polar' + + if isinstance(projection, str) or projection is None: + projection_class = projections.get_projection_class(projection) + elif hasattr(projection, '_as_mpl_axes'): + projection_class, extra_kwargs = projection._as_mpl_axes() + kwargs.update(**extra_kwargs) + else: + raise TypeError( + f"projection must be a string, None or implement a " + f"_as_mpl_axes method, not {projection!r}") # Make the key without projection kwargs, this is used as a unique # lookup for axes instances @@ -1129,6 +1138,11 @@ def add_axes(self, *args, **kwargs): polar : bool, default: False If True, equivalent to projection='polar'. + axes_class : subclass type of `~.axes.Axes`, optional + The `.axes.Axes` subclass that is instantiated. This parameter + is incompatible with *projection* and *polar*. See + :ref:`axisartist_users-guide-index` for examples. + sharex, sharey : `~.axes.Axes`, optional Share the x or y `~matplotlib.axis` with sharex and/or sharey. The axis will have the same limits, ticks, and scale as the axis @@ -1284,6 +1298,11 @@ def add_subplot(self, *args, **kwargs): polar : bool, default: False If True, equivalent to projection='polar'. + axes_class : subclass type of `~.axes.Axes`, optional + The `.axes.Axes` subclass that is instantiated. This parameter + is incompatible with *projection* and *polar*. See + :ref:`axisartist_users-guide-index` for examples. + sharex, sharey : `~.axes.Axes`, optional Share the x or y `~matplotlib.axis` with sharex and/or sharey. The axis will have the same limits, ticks, and scale as the axis diff --git a/lib/matplotlib/tests/test_figure.py b/lib/matplotlib/tests/test_figure.py index f1abc04ff52e..fbddcfe7876d 100644 --- a/lib/matplotlib/tests/test_figure.py +++ b/lib/matplotlib/tests/test_figure.py @@ -177,6 +177,19 @@ def test_gca(): assert fig.gca() is ax1 +def test_add_subplot_subclass(): + fig = plt.figure() + fig.add_subplot(axes_class=Axes) + with pytest.raises(ValueError): + fig.add_subplot(axes_class=Axes, projection="3d") + with pytest.raises(ValueError): + fig.add_subplot(axes_class=Axes, polar=True) + with pytest.raises(ValueError): + fig.add_subplot(projection="3d", polar=True) + with pytest.raises(TypeError): + fig.add_subplot(projection=42) + + def test_add_subplot_invalid(): fig = plt.figure() with pytest.raises(ValueError, diff --git a/tutorials/toolkits/axisartist.py b/tutorials/toolkits/axisartist.py index a7cbb4b1d14d..2f41d00911e4 100644 --- a/tutorials/toolkits/axisartist.py +++ b/tutorials/toolkits/axisartist.py @@ -52,13 +52,13 @@ import mpl_toolkits.axisartist as AA fig = plt.figure() - ax = AA.Axes(fig, [0.1, 0.1, 0.8, 0.8]) - fig.add_axes(ax) + fig.add_axes([0.1, 0.1, 0.8, 0.8], axes_class=AA.Axes) or to create a subplot :: - ax = AA.Subplot(fig, 111) - fig.add_subplot(ax) + fig.add_subplot(111, axes_class=AA.Axes) + # Given that 111 is the default, one can also do + fig.add_subplot(axes_class=AA.Axes) For example, you can hide the right and top spines using:: @@ -493,7 +493,7 @@ from mpl_toolkits.axisartist.grid_helper_curvelinear \ import GridHelperCurveLinear - from mpl_toolkits.axisartist import Subplot + from mpl_toolkits.axisartist import Axes # from curved coordinate to rectlinear coordinate. def tr(x, y): @@ -507,9 +507,7 @@ def inv_tr(x, y): grid_helper = GridHelperCurveLinear((tr, inv_tr)) - ax1 = Subplot(fig, 1, 1, 1, grid_helper=grid_helper) - - fig.add_subplot(ax1) + fig.add_subplot(axes_class=Axes, grid_helper=grid_helper) You may use Matplotlib's Transform instance instead (but a inverse transformation must be defined). Often, coordinate range in a
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: