How to draw a line with matplotlib?
I cannot find a way to draw an arbitrary line with matplotlib Python library. It allows to draw horizontal and vertical lines (with matplotlib.pyplot.axhline and matplotlib.pyplot.axvline , for example), but i do not see how to draw a line through two given points (x1, y1) and (x2, y2) . Is there a way? Is there a simple way?
6 Answers 6
This will draw a line that passes through the points (-1, 1) and (12, 4), and another one that passes through the points (1, 3) et (10, 2)
x1 are the x coordinates of the points for the first line, y1 are the y coordinates for the same — the elements in x1 and y1 must be in sequence.
x2 and y2 are the same for the other line.
import matplotlib.pyplot as plt x1, y1 = [-1, 12], [1, 4] x2, y2 = [1, 10], [3, 2] plt.plot(x1, y1, x2, y2, marker = 'o') plt.show()
I suggest you spend some time reading / studying the basic tutorials found on the very rich matplotlib website to familiarize yourself with the library.
What if I don’t want line segments?
As shown by @thomaskeefe, starting with matplotlib 3.3, this is now builtin as a convenience: plt.axline((x1, y1), (x2, y2)) , rendering the following obsolete.
There are no direct ways to have lines extend to infinity. matplotlib will either resize/rescale the plot so that the furthest point will be on the boundary and the other inside, drawing line segments in effect; or you must choose points outside of the boundary of the surface you want to set visible, and set limits for the x and y axis.
import matplotlib.pyplot as plt x1, y1 = [-1, 12], [1, 10] x2, y2 = [-1, 10], [3, -1] plt.xlim(0, 8), plt.ylim(-2, 8) plt.plot(x1, y1, x2, y2, marker = 'o') plt.show()
Yes, matplotlib draws line segments. the way lines are drawn, you can’t extend lines to infinity. I updated my answer to give you two options to work around it.
«the way lines are drawn, you can’t extend lines to infinity» — why not? axhline and axvline create «infinite» lines. The problem with your solution for me is that i most likely need lines that pass through points that are inside the shown region. Of course i can create a long line segment with endpoints outside of the shown region, but this is inconvenient (i need to calculate somehow the endpoints) and ugly (i need a line, but i draw a segment and try to pan to it to make it look like a line, calculating endpoints that i do not need).
This is a question to ask on the matplotlib mailing list, I was only trying to answer your question here. sorry I could not help, but I can’t add features to the product! I tried to tell you the reason by explaining how matplotlib draws: matplotlib mostly draws pixels to render on printed publications; it is not really top of line at other stuff, but tries to make things possible nonetheless. Maybe you need another tool?
Ok, thanks. I was just not sure if matplotlib has this tool or not. In my recent case, i was trying to understand the behavior of some set of pairs of point on a plane, and i wanted to draw lines through them to see where and how those lines intersect.
As of matplotlib 3.3, you can do this with plt.axline((x1, y1), (x2, y2)) .
I was checking how ax.axvline does work, and I’ve written a small function that resembles part of its idea:
import matplotlib.pyplot as plt import matplotlib.lines as mlines def newline(p1, p2): ax = plt.gca() xmin, xmax = ax.get_xbound() if(p2[0] == p1[0]): xmin = xmax = p1[0] ymin, ymax = ax.get_ybound() else: ymax = p1[1]+(p2[1]-p1[1])/(p2[0]-p1[0])*(xmax-p1[0]) ymin = p1[1]+(p2[1]-p1[1])/(p2[0]-p1[0])*(xmin-p1[0]) l = mlines.Line2D([xmin,xmax], [ymin,ymax]) ax.add_line(l) return l
So, if you run the following code you will realize how does it work. The line will span the full range of your plot (independently on how big it is), and the creation of the line doesn’t rely on any data point within the axis, but only in two fixed points that you need to specify.
import numpy as np x = np.linspace(0,10) y = x**2 p1 = [1,20] p2 = [6,70] plt.plot(x, y) newline(p1,p2) plt.show()
Could you please say exactly what are you trying to do that can not be accomplished by previous function?
Based on @Alejandro’s answer:
- if you want to add a line to an existing Axes (e.g. a scatter plot), and
- all you know is the slope and intercept of the desired line (e.g. a regression line), and
- you want it to cover the entire visible X range (already computed), and
- you want to use the object-oriented interface (not pyplot ).
Then you can do this (existing Axes in ax ):
# e.g. slope, intercept, r_value, p_value, std_err = scipy.stats.linregress(xs, ys) xmin, xmax = ax.get_xbound() ymin = (xmin * slope) + intercept ymax = (xmax * slope) + intercept l = matplotlib.lines.Line2D([xmin, xmax], [ymin, ymax]) ax.add_line(l)
Just want to mention another option here.
You can compute the coefficients using numpy.polyfit(), and feed the coefficients to numpy.poly1d(). This function can construct polynomials using the coefficients, you can find more examples here
Let’s say, given two data points (-0.3, -0.5) and (0.8, 0.8)
import numpy as np import matplotlib.pyplot as plt # compute coefficients coefficients = np.polyfit([-0.3, 0.8], [-0.5, 0.8], 1) # create a polynomial object with the coefficients polynomial = np.poly1d(coefficients) # for the line to extend beyond the two points, # create the linespace using the min and max of the x_lim # I'm using -1 and 1 here x_axis = np.linspace(-1, 1) # compute the y for each x using the polynomial y_axis = polynomial(x_axis) fig = plt.figure() axes = fig.add_axes([0.1, 0.1, 1, 1]) axes.set_xlim(-1, 1) axes.set_ylim(-1, 1) axes.plot(x_axis, y_axis) axes.plot(-0.3, -0.5, 0.8, 0.8, marker='o', color='red')
matplotlib.pyplot.plot#
The coordinates of the points or line nodes are given by x, y.
The optional parameter fmt is a convenient way for defining basic formatting like color, marker and linestyle. It’s a shortcut string notation described in the Notes section below.
>>> plot(x, y) # plot x and y using default line style and color >>> plot(x, y, 'bo') # plot x and y using blue circle markers >>> plot(y) # plot y using x as index array 0..N-1 >>> plot(y, 'r+') # ditto, but with red plusses
You can use Line2D properties as keyword arguments for more control on the appearance. Line properties and fmt can be mixed. The following two calls yield identical results:
>>> plot(x, y, 'go--', linewidth=2, markersize=12) >>> plot(x, y, color='green', marker='o', linestyle='dashed', . linewidth=2, markersize=12)
When conflicting with fmt, keyword arguments take precedence.
Plotting labelled data
There’s a convenient way for plotting objects with labelled data (i.e. data that can be accessed by index obj[‘y’] ). Instead of giving the data in x and y, you can provide the object in the data parameter and just give the labels for x and y:
>>> plot('xlabel', 'ylabel', data=obj)
All indexable objects are supported. This could e.g. be a dict , a pandas.DataFrame or a structured numpy array.
Plotting multiple sets of data
There are various ways to plot multiple sets of data.
- The most straight forward way is just to call plot multiple times. Example:
>>> plot(x1, y1, 'bo') >>> plot(x2, y2, 'go')
>>> x = [1, 2, 3] >>> y = np.array([[1, 2], [3, 4], [5, 6]]) >>> plot(x, y)
>>> for col in range(y.shape[1]): . plot(x, y[:, col])
By default, each line is assigned a different style specified by a ‘style cycle’. The fmt and line property parameters are only necessary if you want explicit deviations from these defaults. Alternatively, you can also change the style cycle using rcParams[«axes.prop_cycle»] (default: cycler(‘color’, [‘#1f77b4’, ‘#ff7f0e’, ‘#2ca02c’, ‘#d62728’, ‘#9467bd’, ‘#8c564b’, ‘#e377c2’, ‘#7f7f7f’, ‘#bcbd22’, ‘#17becf’]) ).
Parameters : x, y array-like or scalar
The horizontal / vertical coordinates of the data points. x values are optional and default to range(len(y)) .
Commonly, these parameters are 1D arrays.
They can also be scalars, or two-dimensional (in that case, the columns represent separate data sets).
These arguments cannot be passed as keywords.
fmt str, optional
A format string, e.g. ‘ro’ for red circles. See the Notes section for a full description of the format strings.
Format strings are just an abbreviation for quickly setting basic line properties. All of these and more can also be controlled by keyword arguments.
This argument cannot be passed as keyword.
data indexable object, optional
An object with labelled data. If given, provide the label names to plot in x and y.
Technically there’s a slight ambiguity in calls where the second label is a valid fmt. plot(‘n’, ‘o’, data=obj) could be plt(x, y) or plt(y, fmt) . In such cases, the former interpretation is chosen, but a warning is issued. You may suppress the warning by adding an empty format string plot(‘n’, ‘o’, », data=obj) .
A list of lines representing the plotted data.
Other Parameters : scalex, scaley bool, default: True
These parameters determine if the view limits are adapted to the data limits. The values are passed on to autoscale_view .
**kwargs Line2D properties, optional
kwargs are used to specify properties like a line label (for auto legends), linewidth, antialiasing, marker face color. Example:
>>> plot([1, 2, 3], [1, 2, 3], 'go-', label='line 1', linewidth=2) >>> plot([1, 2, 3], [1, 4, 9], 'rs', label='line 2')
If you specify multiple lines with one plot call, the kwargs apply to all those lines. In case the label object is iterable, each element is used as labels for each set of data.
Here is a list of available Line2D properties:
a filter function, which takes a (m, n, 3) float array and a dpi value, and returns a (m, n, 3) array and two offsets from the bottom left corner of the image