I have two matrix, x and y. x has size of 10 rows and 50 columns, and so is y.
My data is row-to-row paired. It means that the
x[0][:] <-> y[0][:]
x[1][:] <-> y[1][:]
x[2][:] <-> y[2][:]
......
x[49][:] <-> y[0][:]
When I use following command to do the plot, the
plot(x[:][:],y[:][:],'b-o')
or
plot(x,y,'b-o')
to do the plot, the '-' connects the dots in horizontal direction like following:
However, when I do only plot one row of signal:
plot(x[0][:],y[0][:],'b-o')
it looks correct:
I would like for the '-' to connect the dots in a horizontal fashion. Something like this:
in stead of doing a for loop, how do I do it in matrix format? Thanks.
Make some data to demonstrate.
import numpy as np
from matplotlib import pyplot as plt
x = np.matrix(
[
[1, 1, 1, 1],
[2, 2, 2, 2],
[3, 3, 3, 3],
[4, 4, 4, 4]
]
)
y = x.transpose()
# Vertical Lines of grid:
plt.plot(x, y, 'b-o')
plt.show()
# Horizontal Lines
plt.plot(x, y, 'b-o')
plt.show()
# Together (this is what I think you want)
plt.plot(y, x, 'b-o')
plt.plot(x, y, 'b-o')
plt.show()
If you try to concatenate them to do it in one large matrix it does some seemingly silly things by connecting a couple of points that we really do not want connected.
# sillyness
x1 = np.concatenate((x, y), axis=0)
y1 = np.concatenate((y, x), axis=0)
plt.plot(x1, y1, 'b-o')
plt.show()
Related
I am testing the clip_box feature of Artist using the code snippet below:
import matplotlib.pyplot as plt
from matplotlib.transforms import Bbox
import numpy as np
fig = plt.figure()
ax = fig.subplots(1, 2)
x = [1, 2, 3, 4]
y = [3, 8, 5, 2]
line_a, = ax[0].plot(x, y, color='red', linewidth=3.0)
line_b, = ax[1].plot(x, y, color='red', linewidth=3.0)
boundingbox = Bbox(np.array([[0, 0], [3, 9]]))
line_b.set_clip_box(boundingbox)
line_b.set_clip_on(True)
plt.show()
What I expect is the last part of line_b will be cut out by the clip box, and line_b will be a bit shorter than line_a.
It turns out that there's nothing left on the second subplot. It's totally empty. Is my understanding of the clip_box wrong or are there some issues in the code snippet?
The "natural" clip box for the right hand side plot is ax[1].bbox. Finding its extent tells us what units should be used to specify the clip box Bbox.
Since we don't add the Bbox instance to any axes when we create, it could only be relative to the figure. When we print ax[1].bbox, we can see that its size is to be specified in pixels.
It's indeed much simpler to use a Rectangle or Polygon to specify the clip box because they can be added to axes. Using 'none' color for its facecolor could be more convenient because it's figure style-independent.
import matplotlib.pyplot as plt
from matplotlib.transforms import Bbox
fig = plt.figure(dpi=89)
ax = fig.subplots(1, 2)
x = [1, 2, 3, 4]
y = [3, 8, 5, 2]
line_a, = ax[0].plot(x, y, color='red', linewidth=3.0)
line_b, = ax[1].plot(x, y, color='red', linewidth=3.0)
print(ax[1].bbox, '\n', ax[1].bbox.extents)
# the line above prints
# TransformedBbox(
# Bbox(x0=0.5477272727272726, y0=0.10999999999999999, x1=0.8999999999999999, y1=0.88),
# BboxTransformTo(
# TransformedBbox(
# Bbox(x0=0.0, y0=0.0, x1=6.393258426966292, y1=4.797752808988764),
# Affine2D().scale(178.0))))
# [ 623.31363636 93.94 1024.2 751.52 ]
# 178.0 is 2 * dpi, I believe the doubling happens because of what screen I have got
boundingbox = Bbox.from_extents([623.31363636, 93.94, 900.2, 751.52])
print(boundingbox, '\n', boundingbox.extents)
# the line above prints
# Bbox(x0=623.31363636, y0=93.94, x1=900.2, y1=751.52)
# [623.31363636 93.94 900.2 751.52 ]
line_b.set_clip_box(boundingbox)
line_b.set_clip_on(True)
plt.show()
I've spent some time reading about Bboxes in Matplotlib and they are pretty complicated. The set_clip_box method you refer to has not got very helpful documentation, and the examples of its use both use the bbox of an Axes, which is a nested transformation; ie _, ax = plt.subplots(); ax.bbox is a TransformedBbox based on a linear transform of another TransformedBbox based on an Affine2D transform of a plain Bbox! (All of this explained in more detail here.)
It seems that these involve transformations between different sets of co-ordinates; in the case of a regular Axes it is between x- and y-values, pixels, and the specific adaptations to screen size. I would be happy to hear from someone who knows more about Bboxes why your Bbox acts the way it does. But what you want to achieve can be done much more easily, using a FancyBboxPatch (a Rectangle patch would work just as well):
from matplotlib.patches import FancyBboxPatch
f, ax = plt.subplots(1, 2)
x = [1, 2, 3, 4]
y = [3, 8, 5, 2]
line_a, = ax[0].plot(x, y, color='red', linewidth=3.0)
line_b, = ax[1].plot(x, y, color='red', linewidth=3.0)
bb = Bbox([[0, 0], [3, 9]])
ax[1].add_patch(FancyBboxPatch((bb.xmin, bb.ymin), bb.width, bb.height, boxstyle="square",
ec='white', fc='white', zorder=2.1))
(ec and fc are edge colour and fill colour; zorder determines the artist order. Lines are 2, so we just need out Bbox patch to be slightly higher.)
How can I plot line segments in python? Here's an example of the lines I want to plot alongside scatterplot data. However, in this example, the line with slope of 1 should run from 0 to 3 only, and the line with slope of -1 should run from 4 to 8 only. I have the slope and intercept of each line, as well as the starting and ending x values.
plt.scatter(x_1, y_1)
plt.axline((0,9), slope = -1, color = 'black')
plt.axline((0,0), slope = 1, color = 'black')
plt.show()
I'm not sure from your output but it looks like you have maybe two different data sets which you want to plot straight lines through. Below I am breaking 3 of your data points into two lists of x, y coordinates, and the other 4 into two lists of x, y coordinates.
Here is the link for the line of best fit one liner
import matplotlib.pyplot as plt
import numpy
# data which you want to fit lines through
x1 = [0, 1, 3]
y1 = [0, 1, 3]
x2 = [4, 5, 6, 8]
y2 = [5, 4, 3, 2]
# plots the two data set points
plt.scatter(x1, y1, color='black')
plt.scatter(x2, y2, color='blue')
# plot will connect a line between the range of the data
plt.plot(x1, y1, color='black')
plt.plot(x2, y2, color='blue')
# line of best fit one liner
plt.plot(np.unique(x1), np.poly1d(np.polyfit(x1, y1, 1))(np.unique(x1)),color='red')
plt.plot(np.unique(x2), np.poly1d(np.polyfit(x2, y2, 1))(np.unique(x2)), color='red')
plt.ylim([-1, 7])
plt.show()
By knowing both the intercept and the slope of your lines, you can essentially use the equation for a straight line to get the corresponding y-values of your endpoints on the x-axis. Then you can plot these points and style the plot to get a black line between the points. This solution looks like the following
import matplotlib.pyplot as plt
import numpy as np
slope1, intercept1 = 1, 0
slope2, intercept2 = -1, 9
l1x = np.array([0,3])
l1y = l1x*slope1+intercept1
l2x = np.array([4,8])
l2y = np.array(l2x*slope2+intercept2)
plt.plot(l1x, l1y, 'k-', l2x, l2y, 'k-')
# The following two lines are to make the plot look like the image in the question
plt.xlim([0,8])
plt.ylim([0,9])
plt.show()
The line can be defined either by two points xy1 and xy2, or by one point xy1 and a slope.
plt.scatter(x_1, y_1)
plt.axline((4,4), (8,0), color = 'blue')
plt.axline((0,0), (3,3), color = 'black')
plt.show()
I cannot make it clear for me, how pyplot trisurf works. All the examples I have seen on the Internet use numpy, pandas and other stuff impeding understanding this tool
Pyplot docs say it requires X, Y and Z as 1D arrays. But if I try to provide them, it issues a RuntimeError: Error in qhull Delaunay triangulation calculation: singular input data (exitcode=2); use python verbose option (-v) to see original qhull error. I tried using python list and numpy arange
What are exactly those 1D arrays the tool wants me to provide?
plot_trisurf, when no explicit triangles are given, connects nearby 3D points with triangles to form some kind of surface. X is a 1D array (or a list) of the x-coordinates of these points (similar for Y and Z).
It doesn't work too well when all points lie on the same 3D line. For example, setting all X, Y and Z to [1, 2, 3] will result in a line, not a triangle. P1=(1,1,1), P2=(2,2,2), P3=(3,3,3). The n'th point will use the n'th x, the n'th y and the n'th z. A simple example would be ´ax.plot_trisurf([0, 1, 1], [0, 0, 1], [1, 2, 3])`.
Here is an example:
from mpl_toolkits import mplot3d
import matplotlib.pyplot as plt
from math import sin, cos, pi
fig = plt.figure(figsize=(14, 9))
ax1 = fig.add_subplot(1, 2, 1, projection='3d')
ax1.plot_trisurf([0, 1, 1], [0, 0, 1], [1, 2, 3],
facecolor='cornflowerblue', edgecolor='crimson', alpha=0.4, linewidth=4, antialiased=True)
ax2 = fig.add_subplot(1, 2, 2, projection='3d')
N = 12
X = [0] + [sin(a * 2 * pi / N) for a in range(N)]
Y = [0] + [cos(a * 2 * pi / N) for a in range(N)]
Z = [1] + [0 for a in range(N)]
ax2.plot_trisurf(X, Y, Z,
facecolor='cornflowerblue', edgecolor='crimson', alpha=0.4, linewidth=4, antialiased=True)
plt.show()
I tried to make a polygon with this code but it appears me to the polygon. I need one polygon.
import matplotlib.pyplot as plt
x = [4, 1, 2]
y = [1, 2, 1]
z = [0, 2, 1]
plt.fill(x, y, z)
plt.show()
If you run this code, it will print 2 polygons in two colors. I need only one polygon with one color only. can anyone please fix me this issue?
Thanks
Just set the color of the polygons to be the same:
import matplotlib.pyplot as plt
x = [4, 1, 2]
y = [1, 2, 1]
z = [0, 2, 1]
plt.fill(x, y, z, c='C0')
plt.show()
I'm not completely certain why the preceding code works like it does. plt.fill() is used for plotting 2D polygons, and the third argument should be the color, so what you should really write is this:
x = [4, 1, 0, 2]
y = [1, 2, 0, 1]
plt.fill(x, y, c='C0')
plt.show()
(which gives the same plot)
I'm trying to start 2D contour plot for a flow net and I'm having trouble getting the initial grid to show up properly.
Given the number of columns and the number of rows, how can I write a function that will plot a grid so that all points in the given range appear?
I tried plotting for 4 columns and 3 rows of points by doing this:
r = 3
c = 4
x = [i for i in range(c)]
y = [i for i in range(r)]
plot(x,y,'ro')
grid()
show()
and get this error:
'ValueError: x and y must have same first dimension'
So I tried testing it on a 4x4 grid and got this and I get close to what I want, however it only plots points (0,0), (1,1), (2,2), and (3,3)
However, I also want the points (0,0), (1,0), (2,0), (3,0), (1,0), (1,1)...(3,2), (3,3) to appear, as I will later need to plot vectors from this point indicating the direction of flow for my flow net.
Sorry, I know my terminology isn't that great. Does anyone know how to do this and how to make it work for grids that aren't square?
You could use itertools.product to generate the desired points.
Use plt.scatter to plot the points
Use plt.quiver to plot the vector field. (Relevant code taken from these SO answers)
import numpy as np
import matplotlib.pyplot as plt
import itertools
r = 3
c = 4
x = np.linspace(0, c, c+1)
y = np.linspace(0, r, r+1)
pts = itertools.product(x, y)
plt.scatter(*zip(*pts), marker='o', s=30, color='red')
X, Y = np.meshgrid(x, y)
deg = np.arctan(Y**3 - 3*Y-X)
QP = plt.quiver(X, Y, np.cos(deg), np.sin(deg))
plt.grid()
plt.show()
r = 3
c = 4
x = [i % c for i in range(r*c)]
y = [i / c for i in range(r*c)]
print x
print y
Gives:
[0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3]
[0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2]
When used to draw graph as you did it produces desired result.
The first two arguments specify your x and y components. So the number of points must match. I think what you want is something like:
from itertools import product
import matplotlib.pyplot as plt
points = np.array(list(product(range(3),range(4))))
plt.plot(points[:,0],points[:,1],'ro')
plt.show()