I am struggling with plotting the following dataset (image below). The dataset represents 10 rectangular features in 3D space. Those features are spaced at a distance of 3 cells in the Y axis. The X and Z columns present the range (number of cells) in the X and Z axes. The output should be 10 rectangles spaced at every 3 cells in Y direction. The rectangles can be in any color.
Another piece of infomraiton (not sure if it's relevent), the number of cells in X, Y, Z directions are 50 cells. Each cell represents a 100 ft distance in real life.
I tired numpy.meshgrid, but with no success.
First of all you need to get the corner points of your rectangles - this is fairly straight forward - it's just the 4 combinations of the 2 (x, z) corners, with all of the points having the y-value shown.
The rectangles can then be plotted as:
from mpl_toolkits.mplot3d import Axes3D
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import matplotlib.pyplot as plt
# Corner points of rectangles
feat1 = [(7,6,10),
(7, 6, 20),
(13, 6, 20),
(13, 6, 10)]
feat2 = [(2,9,13),
(2, 9, 17),
(18, 9, 17),
(18, 9, 13)]
feat3 = [(7,12,10),
(7, 12, 20),
(13, 12, 20),
(13, 12, 10)]
features = [feat1, feat2, feat3]
fig = plt.figure()
ax = Axes3D(fig)
facets = Poly3DCollection(features)
facets.set_facecolor(['blue', 'green', 'red'])
ax.add_collection3d(facets)
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
plt.show()
Which returns a plot like:
Related
Once I attempt to add circles to the plot nothing displays on the plot.
Without the circle code, the x and y axis scale has major grid lines 2,3,4,5,6,7,8, and the data displays.
Once I add the circle code it appears the 2nd scale of 0 to 1.0 is added to both axis.
I believe this is why the plot is blank. No data has a value between 0 and 1.
Not sure why the 2nd axis scale is being added.
import matplotlib.pyplot as plt
import matplotlib.path
from matplotlib.patches import Circle
sample = (5, 5)
circles = [(2, 8), (4, 6), (5, 7)]
squares = [(4, 2), (6, 2), (6, 4)]
plt.figure("Concept", (5, 5))
plt.set_cmap('gray')
# plt.axis((0, 10, 0, 10), option='equal')
plt.axis('equal')
plt.scatter(*sample, marker="D", label="??", color='0.0')
plt.scatter([x for x, y in circles], [y for x, y in circles], marker="o", color='.20')
plt.scatter([x for x, y in squares], [y for x, y in squares], marker="s", color='.33')
# k = 3 nearest neighbors
circle3 = Circle((5, 5), 2, facecolor='none',
edgecolor='black', linestyle='--', alpha=0.8)
plt.axes().add_patch(circle3)
# k = 5 nearest neighbors
circle5 = Circle((5, 5), 3.2, facecolor='none',
edgecolor='black', linestyle=':', alpha=1.0)
plt.axes().add_patch(circle5)
plt.grid(True)
plt.show()
I have a dataset of xy coordinates that are used to make a scatter plot. I have setup a 2dhistogram to create a grid that overlays this plot. I want to the bin coordinate when any scatter point is in each bin. The code below displays the scatter plot and highlights the bin when any scatter point is located within it.
Below is an example of what I have thus far:
import random
import matplotlib.pyplot as plt
import numpy as np
x = [random.randrange(1,100,1) for _ in range (10000)]
y = [random.randrange(1,100,1) for _ in range (10000)]
fig, ax = plt.subplots()
ax.set_xlim(0,100)
ax.set_ylim(0,100)
bins = [np.linspace(*ax.get_xlim(), 50),
np.linspace(*ax.get_ylim(), 50)]
zi, xi, yi = np.histogram2d(x, y, bins=bins)
zi = np.ma.masked_equal(zi, 0)
ax.pcolormesh(xi, yi, zi.T)
ax.set_xticks(bins[0], minor=True)
ax.set_yticks(bins[1], minor=True)
ax.grid(True, which='minor')
scat = ax.scatter(x, y, s = 1)
This displays the scatter point and highlights the bin it's in. I'm hoping to return the co-ordinate of each a bin when a scatter point is located within it.
You can just use the x, y, and bins to calculate in what bin each (x, y) pair will be located. Basically, look for a sign change between the x and y bins and the (x, y) pair, and this tells us in what bin the point lies.
import random
import matplotlib.pyplot as plt
import numpy as np
def used_bins(x, y, bins):
bin_idxs = []
for xelem, yelem in zip(x, y):
xbin = ((bins[0] - xelem) < 0).sum()
ybin = ((bins[1] - yelem) < 0).sum()
bin_idxs.append((xbin, ybin))
return bin_idxs
x = [random.randrange(1,100,1) for _ in range (10)]
y = [random.randrange(1,100,1) for _ in range (10)]
fig, ax = plt.subplots()
ax.set_xlim(0,100)
ax.set_ylim(0,100)
bins = [np.linspace(*ax.get_xlim(), 100),
np.linspace(*ax.get_ylim(), 50)]
zi, xi, yi = np.histogram2d(x, y, bins=bins)
zi = np.ma.masked_equal(zi, 0)
ax.pcolormesh(xi, yi, zi.T)
ax.set_xticks(bins[0], minor=True)
ax.set_yticks(bins[1], minor=True)
ax.grid(True, which='minor')
scat = ax.scatter(x, y, s = 1)
# compute the x, y bin index for each x,y element
bin_idxs = used_bins(x, y, bins)
Sample output:
[(85, 45), (74, 27), (65, 43), (8, 49), (8, 19), (89, 25), (51, 30), (38, 17), (98, 12), (24, 6)]
I have a series of lines stored in a list like so:
line_list = [line_1, line_2, line_3, ..., line_M]
where each line_i is a sub-list composed of two sub-sub-lists, one for the x coordinates and the other for the y coordinates:
line_i = [[x_1i, x2_i, .., x_Ni], [y_1i, y_2i, .., y_Ni]]
I also have a list of the same length as line_list composed of floats,:
floats_list = [0.23, 4.5, 1.6, ..., float_M]
I want to plot each line giving it a color taken from a color map and related to the position of its index in the floats_list list. So line_j will have its color determined by the number floats_list[j]. I also need a colorbar shown to the side
The code would like something like this, except it should work :)
import matplotlib.pyplot as plt
line1 = [[0.5,3.6,4.5],[1.2,2.0,3.6]]
line2 = [[1.5,0.4,3.1,4.9],[5.1,0.2,7.4,0.3]]
line3 = [[1.5,3.6],[8.4,2.3]]
line_list = [line1,line2,line3]
floats_list = [1.2,0.3,5.6]
# Define colormap.
cm = plt.cm.get_cmap('RdYlBu')
# plot all lines.
for j,lin in enumerate(line_list):
plt.plot(lin[0], lin[1], c=floats_list[j])
# Show colorbar.
plt.colorbar()
plt.show()
It's easiest to use a LineCollection for this. In fact, it expects the lines to be in a similar format to what you already have. To color the lines by a third variable, just specify the array=floats_list. As an example:
import numpy
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
# The line format you curently have:
lines = [[(0, 1, 2, 3, 4), (4, 5, 6, 7, 8)],
[(0, 1, 2, 3, 4), (0, 1, 2, 3, 4)],
[(0, 1, 2, 3, 4), (8, 7, 6, 5, 4)],
[(4, 5, 6, 7, 8), (0, 1, 2, 3, 4)]]
# Reformat it to what `LineCollection` expects:
lines = [zip(x, y) for x, y in lines]
z = np.array([0.1, 9.4, 3.8, 2.0])
fig, ax = plt.subplots()
lines = LineCollection(lines, array=z, cmap=plt.cm.rainbow, linewidths=5)
ax.add_collection(lines)
fig.colorbar(lines)
# Manually adding artists doesn't rescale the plot, so we need to autoscale
ax.autoscale()
plt.show()
There are two main advantages of this over repeatedly calling plot.
Rendering speed. Collections render much faster than a large number of similar artists.
It's easier to color the data by another variable according to a colormap (and/or update the colormap later).
I have a polygon comprising of 5 edges. Each edge has its own width, which is randomly generated between 0.2 and 0.5 here for illustration purpose.
Code
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib.path import Path
import math as mt
import random
def buildRectPath(edge, width):
theta = mt.atan((edge[1][1]-edge[0][1]) / (edge[1][0]-edge[0][0]+0.0000001)) # avoid ZeroDivisionError
x_left_top = edge[0][0] - mt.sin(theta) * width
y_left_top = edge[0][1] + mt.cos(theta) * width
x_left_bottom = edge[0][0]
y_left_bottom = edge[0][1]
x_right_top = edge[1][0] - mt.sin(theta) * width
y_right_top = edge[1][1] + mt.cos(theta) * width
x_right_bottom = edge[1][0]
y_right_bottom = edge[1][1]
verts = [(x_left_bottom, y_left_bottom), # left, bottom
(x_left_top, y_left_top), # left, top
(x_right_top, y_right_top), # right, top
(x_right_bottom, y_right_bottom), # right, bottom
(x_left_bottom, y_left_bottom),] # ignored
codes = [Path.MOVETO,
Path.LINETO,
Path.LINETO,
Path.LINETO,
Path.CLOSEPOLY,]
path = Path(verts, codes)
return path
fig = plt.figure()
axes = fig.add_axes([0.1, 0.1, 0.8, 0.8])
axes.axis('equal')
poly = [(1, 1), (2, 4), (4, 6), (6, 6), (8, 3), (1, 1)] # construct a random polygon
# expand each edge of the polygon (to different widths)
edges = [[(1, 1), (2, 4)], [(2, 4), (4, 6)], [(4, 6), (6, 6)], [(6, 6), (8, 3)], [(8, 3), (1, 1)]]
widths = [random.uniform(0.2, 0.5) for cnt in xrange(5)] # generate random widths for the 5 edges
for i, edge in enumerate(edges):
axes.plot([edge[0][0], edge[1][0]], [edge[0][1], edge[1][1]], color='b')
rectPath = buildRectPath(edge, widths[i])
rectPatch = patches.PathPatch(rectPath, facecolor='yellow', alpha=0.5)
axes.add_patch(rectPatch)
Output
Goal
I want to get a smooth contour of the shape. Basically, I am expecting two curves, one for inner loop and the other for the outer loop.
Note that
Since the widths of the lines are different, the contour that I am looking for is kind of like a fitting line that considers all the widths.
Currently there exist gaps between the rectangles. The contour should be a continuous curve that is gap-free.
I'm working with broken_barh plots. Is there any way to get a fixed height of a single broken_barh? The image should get bigger vertically, but proportions should stay the same.
Here is a simple example.
import matplotlib.pyplot as plt
import matplotlib as mlp
fig = plt.figure()
ax = fig.add_subplot(111)
broken_barh(self, xranges, yrange, **kwargs)
ax.broken_barh([(110, 30), (150, 10)], (0, 10), facecolors='blue')
ax.broken_barh([(10, 50), (100, 20), (130, 10)] , (10, 10),
facecolors=('red', 'yellow', 'green'))
ax.broken_barh([(50, 30), (85, 10)], (20, 10), facecolors='black')
ax.set_xlim(0,200)
ax.set_xlabel('seconds since start')
ax.set_yticks([0,10,20])
ax.set_yticklabels(['Bill', 'Jim', 'Jeff'])
ax.grid(True)
plt.savefig('broken_barh_example.png', bbox_inches='tight')
plt.show()
If I generate two plots, one with two broken_barh and the other with three, it looks like this:
with 2 broken_barh
http://imageshack.us/a/img195/747/brokenbarhexample2.png
with 3 broken_barh
http://img341.imageshack.us/img341/5650/brokenbarhexamplenoyran.png
The render fits everything into the available space. If you want the size of the figure to grow as you add more rows, you can do it by hand via
fig.set_size_inches(w, h * num_rows, forward=True)
to force a fixed bar height.
(doc)