Reputation: 461
I am new to plotting with Python and can't really find an answer to the question: How can I get Cartesian coordinate plane in matplotlib? By this I mean perpendicular reference lines (coordinate axis) ended up with arrows, intersecting at the origin, (0,0), with the origin at the center of the plot.
Think about a a plane for doing high school geomtery, the following is a perfect example of what I need to achieve:
Upvotes: 35
Views: 67338
Reputation: 3630
Here is another way to draw a Cartesian coordinate system, built on the answers that have already been given.
import numpy as np # v 1.19.2
import matplotlib.pyplot as plt # v 3.3.2
# Enter x and y coordinates of points and colors
xs = [0, 2, -3, -1.5]
ys = [0, 3, 1, -2.5]
colors = ['m', 'g', 'r', 'b']
# Select length of axes and the space between tick labels
xmin, xmax, ymin, ymax = -5, 5, -5, 5
ticks_frequency = 1
# Plot points
fig, ax = plt.subplots(figsize=(10, 10))
ax.scatter(xs, ys, c=colors)
# Draw lines connecting points to axes
for x, y, c in zip(xs, ys, colors):
ax.plot([x, x], [0, y], c=c, ls='--', lw=1.5, alpha=0.5)
ax.plot([0, x], [y, y], c=c, ls='--', lw=1.5, alpha=0.5)
# Set identical scales for both axes
ax.set(xlim=(xmin-1, xmax+1), ylim=(ymin-1, ymax+1), aspect='equal')
# Set bottom and left spines as x and y axes of coordinate system
ax.spines['bottom'].set_position('zero')
ax.spines['left'].set_position('zero')
# Remove top and right spines
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
# Create 'x' and 'y' labels placed at the end of the axes
ax.set_xlabel('x', size=14, labelpad=-24, x=1.03)
ax.set_ylabel('y', size=14, labelpad=-21, y=1.02, rotation=0)
# Create custom major ticks to determine position of tick labels
x_ticks = np.arange(xmin, xmax+1, ticks_frequency)
y_ticks = np.arange(ymin, ymax+1, ticks_frequency)
ax.set_xticks(x_ticks[x_ticks != 0])
ax.set_yticks(y_ticks[y_ticks != 0])
# Create minor ticks placed at each integer to enable drawing of minor grid
# lines: note that this has no effect in this example with ticks_frequency=1
ax.set_xticks(np.arange(xmin, xmax+1), minor=True)
ax.set_yticks(np.arange(ymin, ymax+1), minor=True)
# Draw major and minor grid lines
ax.grid(which='both', color='grey', linewidth=1, linestyle='-', alpha=0.2)
# Draw arrows
arrow_fmt = dict(markersize=4, color='black', clip_on=False)
ax.plot((1), (0), marker='>', transform=ax.get_yaxis_transform(), **arrow_fmt)
ax.plot((0), (1), marker='^', transform=ax.get_xaxis_transform(), **arrow_fmt)
plt.show()
Notice that I have not added annotations displaying the coordinates of the points as in my experience, it requires a lot more code to position them nicely and have minimal overlapping. To get annotations, it is probably best to use the adjustText package or an interactive graphing library such as Plotly.
Upvotes: 24
Reputation: 1263
This is an old question, but I think with today's matplotlib versions, the keyword is spines. You would do:
ax = plt.gca()
ax.spines['top'].set_color('none')
ax.spines['bottom'].set_position('zero')
ax.spines['left'].set_position('zero')
ax.spines['right'].set_color('none')
The link provides more examples.
Upvotes: 24
Reputation: 144
The code below will give you a Cartesian plane.
import matplotlib.pyplot as plt
def build_cartesian_plane(max_quadrant_range):
""" The quadrant range controls the range of the quadrants"""
l = []
zeros = []
plt.grid(True, color='b', zorder=0,)
ax = plt.axes()
head_width = float(0.05) * max_quadrant_range
head_length = float(0.1) * max_quadrant_range
ax.arrow(0, 0, max_quadrant_range, 0, head_width=head_width, head_length=head_length, fc='k', ec='k',zorder=100)
ax.arrow(0, 0, -max_quadrant_range, 0, head_width=head_width, head_length=head_length, fc='k', ec='k', zorder=100)
ax.arrow(0, 0, 0, max_quadrant_range, head_width=head_width, head_length=head_length, fc='k', ec='k', zorder=100)
ax.arrow(0, 0, 0, -max_quadrant_range, head_width=head_width, head_length=head_length, fc='k', ec='k', zorder=100)
counter_dash_width = max_quadrant_range * 0.02
dividers = [0,.1,.2,.3,.4, .5, .6, .7, .8, .9, 1]
for i in dividers:
plt.plot([-counter_dash_width, counter_dash_width], [i*max_quadrant_range, i*max_quadrant_range], color='k')
plt.plot([i * max_quadrant_range, i*max_quadrant_range], [-counter_dash_width, counter_dash_width], color='k')
plt.plot([-counter_dash_width, counter_dash_width], [-i * max_quadrant_range, -i * max_quadrant_range], color='k')
plt.plot([-i * max_quadrant_range, -i * max_quadrant_range], [-counter_dash_width, counter_dash_width], color='k')
l.append(i * max_quadrant_range)
l.append(-i * max_quadrant_range)
zeros.append(0)
zeros.append(0)
build_cartesian_plane(10)
plt.show()
Upvotes: 1
Reputation: 68116
I think this example in the matplotlib gallery should get you close enough: http://matplotlib.org/examples/axes_grid/demo_axisline_style.html
Upvotes: 7
Reputation: 11002
If you just want to plot some dots, scatter is what you want
from pylab import *
x = [0,2,-3,-1.5]
y = [0,3,1,-2.5]
color=['m','g','r','b']
scatter(x,y, s=100 ,marker='o', c=color)
show()
For pretty printing ( with arrows and dashed lines ) :
from pylab import *
import matplotlib.pyplot as plt
x = [0,2,-3,-1.5]
y = [0,3,1,-2.5]
color=['m','g','r','b']
fig = plt.figure()
ax = fig.add_subplot(111)
scatter(x,y, s=100 ,marker='o', c=color)
[ plot( [dot_x,dot_x] ,[0,dot_y], '-', linewidth = 3 ) for dot_x,dot_y in zip(x,y) ]
[ plot( [0,dot_x] ,[dot_y,dot_y], '-', linewidth = 3 ) for dot_x,dot_y in zip(x,y) ]
left,right = ax.get_xlim()
low,high = ax.get_ylim()
arrow( left, 0, right -left, 0, length_includes_head = True, head_width = 0.15 )
arrow( 0, low, 0, high-low, length_includes_head = True, head_width = 0.15 )
grid()
show()
There is still some work to do, but it is not far from the result :
Upvotes: 12