I have a set of points, that I am plotting currently with matplotlib:
x_points = [82,92,90,90,83,74,36,36,36]
y_points = [67,67,66,73,71,69,56,57,57]
import matplotlib.pyplot as plt
plt.plot(x_points, y_points, 'ro')
plt.axis([0, 160, 0, 120])
plt.show()
The goal is to indicate somehow in the plot their order. For example, a different color or a line between two points with an arrow, would indicate that (82,67) came before (92,67). How can this be done?
The generic goal is to plot a directed path on a x-y chart, given a set of input points.
You can use matplotlib.pyplot.arrow
Please see this post:
Draw arrows between 3 points
Related
There are previous questions about quiver plots on polar axes in matplotlib, however they concern vector fields. I'm interested in drawing arbitrary vectors on polar axes. If there is a genuine duplicate, please link it.
I'm writing some software which concerns a circular world. I'm plotting an agent's trajectory from the centre of a circular arena to the edge. This is visualised by drawing a vector from the centre of the circle to the edge. I'm trying to use matplotlib's quiver plot to plot vectors on a set of polar axes. Here's a minimum working example:
import matplotlib.pyplot as plt
import numpy as np
if __name__ == '__main__':
fig = plt.figure()
ax = fig.add_subplot(111, projection='polar')
# Plot origin (agent's start point)
ax.plot(0, 0, color='black', marker='o', markersize=5)
# Plot agent's path
ax.quiver((0, 0), (0, 1), color='black')
# Example of where (0, 1) should be
ax.plot(0, 1, color='black', marker='o', markersize=5)
# Plot configuration
ax.set_rticks([])
ax.set_rmin(0)
ax.set_rmax(1)
ax.set_thetalim(-np.pi, np.pi)
ax.set_xticks(np.linspace(np.pi, -np.pi, 4, endpoint=False))
ax.grid(False)
ax.set_theta_direction(-1)
ax.set_theta_zero_location("N")
plt.show()
If you run the code, you get this plot
The plot shows the origin plotted correctly, an example point at (0, 1) to show where the vector should end, then the vector itself which appears far too short (though the direction is correct). From the docs, I understand that quiver takes cartesian coordinates (x,y) denoting the start point of the vector and (u,v) denoting the vector's direction. In my previous experience with quiver (u,v) essentially denotes where the vector's tip will be, so in this case we'd expect the vector to be drawn from (0,0) to (0,1) which isn't the case and I don't know why.
In short, I want to be able to draw arbitrary vectors on a set of polar axes and quiver isn't working as I expected. Three questions:
Is my code actually sensible given my goal? I want to draw a unit vector from the origin to the edge of the polar plot.
Am I completely misunderstanding how to use quiver?
How can I draw arbitrary vectors on polar axes in matplotlib? I know about arrow and I'm going to give that a try though initial attempts were unsuccessful.
Short of using a standard plot and just defining my own polar system within it I'm completely stumped.
You did not specify u and v in ax.quiver(x,y,u,v). To make sure the arrow is 1 unit long you will need to set the scale und units as well.
ax.quiver(0,0,0,1, color='black', angles="xy", scale_units='xy', scale=1.)
I want to draw Grid of Bar graph/Histogram for my data.My Data contains 1 NUMERIC and 3 CATEGORICAL Column
PAIRGraph is not suitable for my purpose as my purpose as I have only 1 Numeric and 3 Categorical Column
Tried to Refer Documentation https://matplotlib.org/api/_as_gen/matplotlib.pyplot.subplots.html
However, I am unable to find exact way to fulfill my requirement.
Using Demo code I am able to draw only LineGraph. However, I am required to draw Bar Graph.
fig, axes = plt.subplots(1, 2, figsize=(10,4))
x = np.linspace(0, 5, 11)
axes[0].plot(x, x**2, x, np.exp(x),x,20*x)
axes[0].set_title("Normal scale")
axes[0].plot
axes[1].plot(x, x**2, x, np.exp(x))
axes[1].set_yscale("log")
axes[1].set_title("Logarithmic scale (y)");
Please feel free to correct my approach or guide me as I have just started learning.
If you specify exactly what you want to use for the bar and hist, I can modify, but generally it is simply changing the plot to the type of chart you need
import matplotlib.pyplot as plt
import numpy as np
fig, axes = plt.subplots(1, 2, figsize=(10,4))
x = np.linspace(0, 5, 11)
axes[0].bar(x,x**2) # bar plot
axes[0].set_title("Normal scale")
axes[0].plot
axes[1].hist(x) # histogram
axes[1].set_yscale("log")
axes[1].set_title("Logarithmic scale (y)");
plt.show()
After going through the API documentation from Matplotlip Subplot Axes, I found ways to draw different graph not just Line graph.
https://matplotlib.org/api/axes_api.html
DEFAULT:-
axes[0].plot by-default draws line graph.
CUSTOM GRAPH:-
axes[0].bar can be used to draw BAR graph in selected Subplot
axes[0].scatter can be used to draw Scatter graph in selected Subplot
axes[0].hist can be used to draw a histogram. in selected Subplot
Like above example more graph can be drawn with below API:-
What I'm trying to achieve: a plot with two axhline horizontal lines, with the area between them shaded.
The best so far:
ax.hline(y1, color=c)
ax.hline(y2, color=c)
ax.fill_between(ax.get_xlim(), y1, y2, color=c, alpha=0.5)
The problem is that this leaves a small amount of blank space to the left and right of the shaded area.
I understand that this is likely due to the plot creating a margin around the used/data area of the plot. So, how do I get the fill_between to actually cover the entire plot without matplotlib rescaling the x-axis after drawing? Is there an alternative to get_xlim that would give me appropriate limits of the plot, or an alternative to fill_between?
This is the current result:
Note that this is part of a larger grid layout with several plots, but they all leave a similar margin around these shaded areas.
Not strictly speaking an answer to the question of getting the outer limits, but it does solve the problem. Instead of using fill_between, I should have used:
ax.axhspan(y1, y2, facecolor=c, alpha=0.5)
Result:
ax.get_xlim() does return the limits of the axis, not that of the data:
Axes.get_xlim()
Returns the current x-axis limits as the tuple (left, right).
But Matplotlib simply rescales the x-axis after drawing the fill_between:
import matplotlib.pylab as pl
import numpy as np
pl.figure()
ax=pl.subplot(111)
pl.plot(np.random.random(10))
print(ax.get_xlim())
pl.fill_between(ax.get_xlim(), 0.5, 1)
print(ax.get_xlim())
This results in:
(-0.45000000000000001, 9.4499999999999993)
(-0.94499999999999995, 9.9449999999999985)
If you don't want to manually set the x-limits, you could use something like:
import matplotlib.pylab as pl
import numpy as np
pl.figure()
ax=pl.subplot(111)
pl.plot(np.random.random(10))
xlim = ax.get_xlim()
pl.fill_between(xlim, 0.5, 1)
ax.set_xlim(xlim)
It is very straight forward to plot a line between two points (x1, y1) and (x2, y2) in Matplotlib using Line2D:
Line2D(xdata=(x1, x2), ydata=(y1, y2))
But in my particular case I have to draw Line2D instances using Points coordinates on top of the regular plots that are all using Data coordinates. Is that possible?
As #tom mentioned, the key is the transform kwarg. If you want an artist's data to be interpreted as being in "pixel" coordinates, specify transform=IdentityTransform().
Using Transforms
Transforms are a key concept in matplotlib. A transform takes coordinates that the artist's data is in and converts them to display coordinates -- in other words, pixels on the screen.
If you haven't already seen it, give the matplotlib transforms tutorial a quick read. I'm going to assume a passing familiarity with the first few paragraphs of that tutorial, so if you're
For example, if we want to draw a line across the entire figure, we'd use something like:
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
# The "clip_on" here specifies that we _don't_ want to clip the line
# to the extent of the axes
ax.plot([0, 1], [0, 1], lw=3, color='salmon', clip_on=False,
transform=fig.transFigure)
plt.show()
This line will always extend from the lower-left corner of the figure to the upper right corner, no matter how we interactively resize/zoom/pan the plot.
Drawing in pixels
The most common transforms you'll use are ax.transData, ax.transAxes, and fig.transFigure. However, to draw in points/pixels, you actually want no transform at all. In that case, you'll make a new transform instance that does nothing: the IdentityTransform. This specifies that the data for the artist is in "raw" pixels.
Any time you'd like to plot in "raw" pixels, specify transform=IdentityTransform() to the artist.
If you'd like to work in points, recall that there are 72 points to an inch, and that for matplotlib, fig.dpi controls the number of pixels in an "inch" (it's actually independent of the physical display). Therefore, we can convert points to pixels with a simple formula.
As an example, let's place a marker 30 points from the bottom-left edge of the figure:
import matplotlib.pyplot as plt
from matplotlib.transforms import IdentityTransform
fig, ax = plt.subplots()
points = 30
pixels = fig.dpi * points / 72.0
ax.plot([pixels], [pixels], marker='o', color='lightblue', ms=20,
transform=IdentityTransform(), clip_on=False)
plt.show()
Composing Transforms
One of the more useful things about matplotlib's transforms is that they can be added to create a new transform. This makes it easy to create shifts.
For example, let's plot a line, then add another line shifted by 15 pixels in the x-direction:
import matplotlib.pyplot as plt
from matplotlib.transforms import Affine2D
fig, ax = plt.subplots()
ax.plot(range(10), color='lightblue', lw=4)
ax.plot(range(10), color='gray', lw=4,
transform=ax.transData + Affine2D().translate(15, 0))
plt.show()
A key thing to keep in mind is that the order of the additions matters. If we did Affine2D().translate(15, 0) + ax.transData instead, we'd shift things by 15 data units instead of 15 pixels. The added transforms are "chained" (composed would be a more accurate term) in order.
This also makes it easy to define things like "20 pixels from the right hand side of the figure". For example:
import matplotlib.pyplot as plt
from matplotlib.transforms import Affine2D
fig, ax = plt.subplots()
ax.plot([1, 1], [0, 1], lw=3, clip_on=False, color='salmon',
transform=fig.transFigure + Affine2D().translate(-20, 0))
plt.show()
You can use the transform keyword to change between data coordinate (the default) and axes coordinates. For example:
import matplotlib.pyplot as plt
import matplotlib.lines as lines
plt.plot(range(10),range(10),'ro-')
myline = lines.Line2D((0,0.5,1),(0.5,0.5,0),color='b') # data coords
plt.gca().add_artist(myline)
mynewline = lines.Line2D((0,0.5,1),(0.5,0.5,0),color='g',transform=plt.gca().transAxes) # Axes coordinates
plt.gca().add_artist(mynewline)
plt.show()
I would like to plot a circle on an auto-scaled pyplot-generated graphic. When I run
ax.get_aspect()
hoping for a value with which I could manipulate the axes of a ellipse, pyplot returns:
auto
which is less than useful. What methods would you suggest for plotting a circle on a pyplot plot with unequal axes?
This question is more than one year old, but I too just had this question. I needed to add circles to a matplotlib plot and I wanted to be able to specify the circle's location in the plot using data coordinates, and I didn't want the circle radius to change with panning/zooming (or worse the circle turning into an ellipse).
The best and most simple solution that I've found is simply plot a curve with a single point and include a circle marker:
ax.plot(center_x,center_y,'bo',fillstyle='none',markersize=5)
which gives a nice, fixed-size blue circle with no fill!
It really does depend what you want it for.
The problem with defining a circle in data coordinates when aspect ratio is auto, is that you will be able to resize the figure (or its window), and the data scales will stretch nicely. Unfortunately, this would also mean that your circle is no longer a circle, but an ellipse.
There are several ways of addressing this. Firstly, and most simply, you could fix your aspect ratio and then put a circle on the plot in data coordinates:
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = plt.axes()
ax.set_aspect(1)
theta = np.linspace(-np.pi, np.pi, 200)
plt.plot(np.sin(theta), np.cos(theta))
plt.show()
With this, you will be able to zoom and pan around as per usual, but the shape will always be a circle.
If you just want to put a circle on a figure, independent of the data coordinates, such that panning and zooming of an axes did not effect the position and zoom on the circle, then you could do something like:
import matplotlib.patches as mpatches
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = plt.axes()
patch = mpatches.Circle((325, 245), 180, alpha=0.5, transform=None)
fig.artists.append(patch)
plt.show()
This is fairly advanced mpl, but even so, I think it is fairly readable.
HTH,
Building on #user3208430, if you want the circle to always appear at the same place in the axes (regardless of data ranges), you can position it using axes coordinates via transform:
ax.plot(.94, .94, 'ro', fillstyle='full', markersize=5, transform=ax.transAxes)
Where x and y are between [0 and 1]. This example places the marker in the upper right-hand corner of the axes.