Get a smooth contour out of a width-variant shape? - python

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.

Related

Adding circle to a plot results in a 2nd scale on the axis and nothing being displayed on the plot

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()

Matplotlib plot function creates two lines from one data list, or a triangle, but no normal x y graph [duplicate]

I have the following data set. I would like to use Python or Gnuplot to plot the data. The tuples are of the form (x, y). The Y-axis should be a log axis, that is, log(y). A scatter plot or line plot would be ideal.
How can this be done?
[(0, 6.0705199999997801e-08), (1, 2.1015700100300739e-08),
(2, 7.6280656623374823e-09), (3, 5.7348209304555086e-09),
(4, 3.6812203579604238e-09), (5, 4.1572516753310418e-09)]
If I get your question correctly, you could do something like this.
>>> import matplotlib.pyplot as plt
>>> testList =[(0, 6.0705199999997801e-08), (1, 2.1015700100300739e-08),
(2, 7.6280656623374823e-09), (3, 5.7348209304555086e-09),
(4, 3.6812203579604238e-09), (5, 4.1572516753310418e-09)]
>>> from math import log
>>> testList2 = [(elem1, log(elem2)) for elem1, elem2 in testList]
>>> testList2
[(0, -16.617236475334405), (1, -17.67799605473062), (2, -18.691431541177973), (3, -18.9767093108359), (4, -19.420021520728017), (5, -19.298411635970396)]
>>> zip(*testList2)
[(0, 1, 2, 3, 4, 5), (-16.617236475334405, -17.67799605473062, -18.691431541177973, -18.9767093108359, -19.420021520728017, -19.298411635970396)]
>>> plt.scatter(*zip(*testList2))
>>> plt.show()
which would give you something like
Or as a line plot,
>>> plt.plot(*zip(*testList2))
>>> plt.show()
EDIT - If you want to add a title and labels for the axis, you could do something like
>>> plt.scatter(*zip(*testList2))
>>> plt.title('Random Figure')
>>> plt.xlabel('X-Axis')
>>> plt.ylabel('Y-Axis')
>>> plt.show()
which would give you
In matplotlib it would be:
import matplotlib.pyplot as plt
data = [(0, 6.0705199999997801e-08), (1, 2.1015700100300739e-08),
(2, 7.6280656623374823e-09), (3, 5.7348209304555086e-09),
(4, 3.6812203579604238e-09), (5, 4.1572516753310418e-09)]
x_val = [x[0] for x in data]
y_val = [x[1] for x in data]
print x_val
plt.plot(x_val,y_val)
plt.plot(x_val,y_val,'or')
plt.show()
which would produce:
As others have answered, scatter() or plot() will generate the plot you want. I suggest two refinements to answers that are already here:
Use numpy to create the x-coordinate list and y-coordinate list. Working with large data sets is faster in numpy than using the iteration in Python suggested in other answers.
Use pyplot to apply the logarithmic scale rather than operating directly on the data, unless you actually want to have the logs.
import matplotlib.pyplot as plt
import numpy as np
data = [(2, 10), (3, 100), (4, 1000), (5, 100000)]
data_in_array = np.array(data)
'''
That looks like array([[ 2, 10],
[ 3, 100],
[ 4, 1000],
[ 5, 100000]])
'''
transposed = data_in_array.T
'''
That looks like array([[ 2, 3, 4, 5],
[ 10, 100, 1000, 100000]])
'''
x, y = transposed
# Here is the OO method
# You could also the state-based methods of pyplot
fig, ax = plt.subplots(1,1) # gets a handle for the AxesSubplot object
ax.plot(x, y, 'ro')
ax.plot(x, y, 'b-')
ax.set_yscale('log')
fig.show()
I've also used ax.set_xlim(1, 6) and ax.set_ylim(.1, 1e6) to make it pretty.
I've used the object-oriented interface to matplotlib. Because it offers greater flexibility and explicit clarity by using names of the objects created, the OO interface is preferred over the interactive state-based interface.
You could also use zip
import matplotlib.pyplot as plt
l = [(0, 6.0705199999997801e-08), (1, 2.1015700100300739e-08),
(2, 7.6280656623374823e-09), (3, 5.7348209304555086e-09),
(4, 3.6812203579604238e-09), (5, 4.1572516753310418e-09)]
x, y = zip(*l)
plt.plot(x, y)
With gnuplot using gplot.py
from gplot import *
l = [(0, 6.0705199999997801e-08), (1, 2.1015700100300739e-08),
(2, 7.6280656623374823e-09), (3, 5.7348209304555086e-09),
(4, 3.6812203579604238e-09), (5, 4.1572516753310418e-09)]
gplot.log('y')
gplot(*zip(*l))

Networkx: how to change a color and size of same edges?

I generated a graph using networkx
import networkx as nx
G = nx.grid_graph(dim=[5,5])
nx.draw(G);
Then I compute the minimal path between two nodes using the astar algorithm
def dist(a, b):
(x1, y1) = a
(x2, y2) = b
return ((x1 - x2) ** 2 + (y1 - y2) ** 2) ** 0.5
nodes = list(G.nodes)
tmp = nx.astar_path(G,nodes[3],nodes[14],dist)
Now I would like to to modify the color and the size of the edges of the path between the nodes, where the nodes are defined by tmp
tmp
[(0, 3), (1, 3), (2, 3), (2, 4)]
You need to plot each of the network's components with its own commands. Here is a working code that demonstrates how to achieve such a plot.
import numpy as np
import matplotlib.pyplot as plt
import networkx as nx
# only relevant part is treated here
G = nx.grid_graph(dim=[5,5])
node_list = [(0, 3), (1, 3), (2, 3), (2, 4)]
edge_list = [[(0, 3), (1, 3)], [(1, 3), (2, 3)], [(2, 3), (2, 4)]]
pos = nx.spring_layout(G)
nx.draw(G, pos=pos, with_labels=True)
# draw selected nodes in green with triangle shape
nx.draw_networkx_nodes(G, pos=pos, nodelist=node_list, node_size=300, node_color='g', node_shape='^')
# draw selected edges in blue with solid line
nx.draw_networkx_edges(G, pos=pos, edgelist=edge_list, width=3.0, edge_color='blue', style='solid')
The output plot:

How do I show legend for different colors in bokeh scatter plot?

This is my plot.
I need to show the legend for the different colors used.
How do I do that?
My code for the plot:
def mscatter(p, x, y, c,typestr,source):
p.scatter(x, y, marker=typestr,
line_color="#6666ee", fill_color=c, fill_alpha=0.5, size=y*1.5,source = source)
p = figure(title="CGPA of 4th year students",tools=[hover])
mscatter(p, xdata, ydata, colors,"circle",source)
show(p)
here is sample bokeh documentation on adding legends
You will have to modify as you see fit
from collections import OrderedDict
from bokeh.charts import Scatter, output_file, show
# (dict, OrderedDict, lists, arrays and DataFrames of (x, y) tuples are valid inputs)
xyvalues = OrderedDict()
xyvalues['python'] = [(1, 2), (3, 3), (4, 7), (5, 5), (8, 26)]
xyvalues['pypy'] = [(1, 12), (2, 23), (4, 47), (5, 15), (8, 46)]
xyvalues['jython'] = [(1, 22), (2, 43), (4, 10), (6, 25), (8, 26)]
scatter = Scatter(xyvalues, title="Scatter", legend="top_left", ylabel='Languages')
output_file('scatter.html')
show(scatter)
the above code will result in the following picture:

why does my pyplot show no lines?

I am new to pyplot and wondering what I'm doing wrong here.
I would like to plot a series of random line segments:
Here's some example code:
import matplotlib.pyplot as plt
def testPlot():
minx = miny = -1
maxx = maxy = 30
# some points randomly generated
points = [((10, 21), (19, 22)), ((11, 9), (22, 27)), ((9, 13), (5, 9)), ((18, 4), (2, 21)), ((25, 27
for pair in points:
print pair
for point in pair: #plot each point with a small dot
x = point[0]
y = point[1]
plt.plot(x,y,'bo')
# draw a line between the pairs of points
plt.plot(pair[0][0],pair[0][1],pair[1][0],pair[1][1],color='r',linewidth=2)
plt.axis([minx,maxx,miny,maxy])
plt.show()
Here is what I get after running that, there should be lines between the points but where are the lines?
((10, 21), (19, 22))
((11, 9), (22, 27))
((9, 13), (5, 9))
((18, 4), (2, 21))
((25, 27), (11, 13))
Thank you for any clues
This is the line of problem:
...
plt.plot(pair[0][0],pair[0][1],pair[1][0],pair[1][1],color='r',linewidth=2)
...
You're trying to draw the referring to x,y,x1,y1, which in fact should be ((x, x1), (y, y1)). Correcting this seems working fine:
def testPlot():
minx = miny = -1
maxx = maxy = 30
# some points randomly generated
points = [((10, 21), (19, 22)), ((11, 9), (22, 27)), ((9, 13), (5, 9)), ((18, 4), (2, 21)), ((25, 27), (11, 13))]
for pair in points:
print pair
for point in pair: #plot each point with a small dot
x = point[0]
y = point[1]
plt.plot(x,y,'bo')
# change this line to ((x, x1), (y, y1))
plt.plot((pair[0][0],pair[1][0]),(pair[0][1],pair[1][1]), color='r',linewidth=2)
plt.axis([minx,maxx,miny,maxy])
plt.show()
Results:

Categories