Related
I have to find the optimum cost of building links between nodes. In my objective function, I am trying to minimise the cost. The problem can be solved to determine the variable, however the optimal value of my cost is incorrect as I want it to take the absolute value of each cost. How can I modify my codes as I cannot use abs() in the objective function?
cost+=(model.a[i,k]-model.a[j,k])model.cmodel.d[i,j].
This value can be negative if model.a[j,k]=1 or positive if model.a[i,k]=1
from pyomo.environ import *
# Creation of a Concrete Model
model = ConcreteModel()
# Sets
model.i = Set(initialize=[1,2,3,4,5,6,7,8,9,10,11,12,13], doc='Nodes')
model.k = Set(initialize=['Orange','SFR', 'Bouygues'], doc='Companies')
# Parameters
model.c = Param(initialize=25, doc='Cost of transforming an existing link into a backbone link in euro/km')
links={
(1, 2) : 1.8,
(1, 7) : 1,
(1, 13) : 5.4,
(2, 8) : 2.3,
(2, 3) : 1.7,
(2, 5) : 7,
(2, 7) : 2,
(2, 12) : 3,
(3, 4) : 2,
(3, 10) : 6.5,
(4, 5) : 1,
(4, 6) : 2,
(5, 8) : 5,
(5, 10) : 1,
(5, 11) : 1.5,
(6, 11) : 2.1,
(7, 12) : 2,
(8, 9) : 2,
(8, 13) : 0.7,
(9, 10) : 1.1,
(10, 11) : 1,
(12, 13) : 2.5,
}
model.d=Param(model.i, model.i,default=0, initialize=links, doc='distance in 10 km between nodes')
# Variables
model.a = Var(model.i, model.k, within=Binary, doc='Binary variable indicating whether node i belongs to company k (0 if it does not belong and 1 if it belongs)')
#Contraints#
def allocation_rule(model, i):
return sum(model.a[i,k] for k in model.k) == 1
model.allocation = Constraint(model.i, rule=allocation_rule, doc='Each node can only belong to one company')
def minimum_rule(model, k):
return sum(model.a[i,k] for i in model.i) >= 2
model.minimum = Constraint(model.k, rule=minimum_rule, doc='Each company must have at least 2 nodes')
#objective
def totalcost(model):
cost=0
for i in model.i:
for j in model.i:
if model.d[i,j]!=0:
for k in model.k:
cost+=(model.a[i,k]-model.a[j,k])*model.c*model.d[i,j]
return cost
model.z = Objective(rule=totalcost, sense=minimize, doc='Minimize the cost of implementing a backbone connecting the three sub-networks')
def total(model):
return model.cost_postive-model.cost_negative
## Display of the output ##
optimizer = SolverFactory("glpk",executable='/usr/bin/glpsol') #creates an optimizer object that uses the glpk package installed to your usr/bin.
optimizer.solve(model) #tells your optimizer to solve the model object
model.display()
I have tried using the cost+=abs((model.a[i,k]-model.a[j,k])model.cmodel.d[i,j]) but this makes the problem non-linear so it cannot be solved.
edited to introduce a new variable p, and added 2 constraints to p>=(model.a[i,k]-model.a[j,k])model.cmodel.d[i,j]) and
p>=-(model.a[i,k]-model.a[j,k])model.cmodel.d[i,j]). However, it returns with error: ERROR:pyomo.core:Rule failed for Param 'd' with index (1, 2):
from pyomo.environ import *
# Creation of a Concrete Model
model = ConcreteModel()
# Sets
model.i = Set(initialize=[1,2,3,4,5,6,7,8,9,10,11,12,13],
doc='Nodes')
model.i = Set(initialize=['Orange','SFR', 'Bouygues'],
doc='Companies')
# Parameters
model.c = Param(initialize=25, doc='Cost of transforming an
existing link into a backbone link in euro/km')
links={
(1, 2) : 1.8,
(1, 7) : 1,
(2, 3) : 1.7,
(2, 5) : 7,
(2, 7) : 2,
(2, 12) : 3,
(3, 4) : 2,
(3, 10) : 6.5,
(4, 5) : 1,
(4, 6) : 2,
(5, 8) : 5,
(5, 10) : 1,
(5, 11) : 1.5,
(6, 11) : 2.1,
(7, 12) : 2,
(8, 9) : 2,
(8, 13) : 0.7,
(9, 10) : 1.1,
(10, 11) : 1,
(12, 13) : 2.5,
(1, 13) : 5.4,
(2, 8) : 2.3,
}
model.d=Param(model.i, model.i,default=0, initialize=links, doc='distance in 10 km between nodes')
# Variables
model.a = Var(model.i, model.k, within=Binary, doc='Binary variable indicating whether node i belongs to company k (0 if it does not belong and 1 if it belongs)')
model.p = Var(model.i,model.k, within=(0.0,None), doc='Cost of building backbone link p_ij')
#Contraints#
def allocation_rule(model, i):
return sum(model.a[i,k] for k in model.k) == 1
model.allocation = Constraint(model.i, rule=allocation_rule, doc='Each node can only belong to one company')
def minimum_rule(model, k):
return sum(model.a[i,k] for i in model.i) >= 2
model.minimum = Constraint(model.k, rule=minimum_rule, doc='Each company must have at least 2 nodes')
def absolute_rule1(model):
return model.p >=(model.a[i,k]-
model.a[j,k])*model.c*model.d[i,j]
model.absolute1 = Constraint(model.i, rule=absolute_rule1, doc='To take the positive cost')
def absolute_rule2(model):
for i in model.i:
for j in model.i:
if model.d[i,j]!=0:
for k in model.k:
return model.p >=-(model.a[i,k]-
model.a[j,k])*model.c*model.d[i,j]
model.absolute2 = Constraint(model.i, rule=absolute_rule2, doc='To take the positive cost')
#objective
def totalcost(model):
cost=0
for i in model.i:
for j in model.i:
if model.d[i,j]!=0:
for k in model.k:
cost+=model.p
return cost
model.z = Objective(rule=totalcost, sense=minimize, doc='Minimize the cost of implementing a backbone connecting the three sub-networks')
Below is a slightly modified approach.
You could put in the helper variables to get to absolute value, but I think that might lead you a bit astray in your objective, as I mentioned in the comment. Specifically, if you have 3 companies, the best you could do for "ownership" would be 1 company owning it, so as you summed over all three companies, you would get one "zero" cost and two actual costs, which is probably not desired.
I reformulated a bit to something which kinda does the same thing with a couple new variables. Realize there is "upward pressure" in the model for link ownership... cost is reduced (good) if more links are owned, so the variable I put in assesses each link by company and only allows ownership if they own both nodes.
The other new variable indicates whether a link is owned or not, independent of company. I think you could probably do without that, but it adds a little clarity. You could get the same thing (remove the variable, I think) by observing:
build_link >= 1 - sum(own_link)
Also, a reminder... I didn't see in your original code that you were inspecting the solver results. Always, always, always do that to ensure the status is "optimal" or you are looking at junk response.
Code:
from pyomo.environ import *
links={
(1, 2) : 1.8,
(1, 7) : 1,
(1, 13) : 5.4,
(2, 8) : 2.3,
(2, 3) : 1.7,
(2, 5) : 7,
(2, 7) : 2,
(2, 12) : 3,
(3, 4) : 2,
(3, 10) : 6.5,
(4, 5) : 1,
(4, 6) : 2,
(5, 8) : 5,
(5, 10) : 1,
(5, 11) : 1.5,
(6, 11) : 2.1,
(7, 12) : 2,
(8, 9) : 2,
(8, 13) : 0.7,
(9, 10) : 1.1,
(10, 11) : 1,
(12, 13) : 2.5,
}
# Creation of a Concrete Model
model = ConcreteModel()
# Sets
model.i = Set(initialize=[1,2,3,4,5,6,7,8,9,10,11,12,13], doc='Nodes')
model.k = Set(initialize=['Orange','SFR', 'Bouygues'], doc='Companies')
model.links = Set(within=model.i*model.i, initialize=links.keys())
# Parameters
model.c = Param(initialize=25, doc='Cost of transforming an existing link into a backbone link in euro/km')
model.d = Param(model.links, default=0, initialize=links, doc='distance in 10 km between nodes')
# Variables
model.a = Var(model.i, model.k, within=Binary, doc='Binary variable indicating whether node i belongs to company k (0 if it does not belong and 1 if it belongs)')
model.own_link = Var(model.links, model.k, within=Binary, doc='Own the link')
model.build_link = Var(model.links, within=Binary, doc='build link')
#Contraints#
def allocation_rule(model, i):
return sum(model.a[i,k] for k in model.k) == 1
model.allocation = Constraint(model.i, rule=allocation_rule, doc='Each node can only belong to one company')
def minimum_rule(model, k):
return sum(model.a[i,k] for i in model.i) >= 2
model.minimum = Constraint(model.k, rule=minimum_rule, doc='Each company must have at least 2 nodes')
def link_owner(model, k, n1, n2):
return model.own_link[n1, n2, k] <= 0.5 * (model.a[n1, k] + model.a[n2, k])
model.link1 = Constraint(model.k, model.links, rule=link_owner)
# link the "build link" variable to lack of link ownership
def link_build(model, *link):
return model.build_link[link] >= 1 - sum(model.own_link[link, k] for k in model.k)
model.build_constraint = Constraint(model.links, rule=link_build)
# objective
cost = sum(model.build_link[link]*model.c*model.d[link] for link in model.links)
model.z = Objective(expr=cost, sense=minimize, doc='Minimize the cost of implementing a backbone connecting the three sub-networks')
## Display of the output ##
optimizer = SolverFactory("glpk") #creates an optimizer object that uses the glpk package installed to your usr/bin.
result = optimizer.solve(model) #tells your optimizer to solve the model object
print(result)
print('Link Ownership Plan:')
for idx in model.own_link.index_set():
if model.own_link[idx].value: # will be true if it is 1, false if 0
print(idx, model.own_link[idx].value)
print('\nLink Build Plan:')
for idx in model.build_link.index_set():
if model.build_link[idx].value: # will be true if it is 1, false if 0
print(idx, model.build_link[idx].value)
Output:
Problem:
- Name: unknown
Lower bound: 232.5
Upper bound: 232.5
Number of objectives: 1
Number of constraints: 105
Number of variables: 128
Number of nonzeros: 365
Sense: minimize
Solver:
- Status: ok
Termination condition: optimal
Statistics:
Branch and bound:
Number of bounded subproblems: 2183
Number of created subproblems: 2183
Error rc: 0
Time: 0.21333098411560059
Solution:
- number of solutions: 0
number of solutions displayed: 0
Link Ownership Plan:
(1, 2, 'Orange') 1.0
(1, 7, 'Orange') 1.0
(1, 13, 'Orange') 1.0
(2, 8, 'Orange') 1.0
(2, 5, 'Orange') 1.0
(2, 7, 'Orange') 1.0
(2, 12, 'Orange') 1.0
(3, 10, 'SFR') 1.0
(4, 6, 'Bouygues') 1.0
(5, 8, 'Orange') 1.0
(6, 11, 'Bouygues') 1.0
(7, 12, 'Orange') 1.0
(8, 9, 'Orange') 1.0
(8, 13, 'Orange') 1.0
(12, 13, 'Orange') 1.0
Link Build Plan:
(2, 3) 1.0
(3, 4) 1.0
(4, 5) 1.0
(5, 10) 1.0
(5, 11) 1.0
(9, 10) 1.0
(10, 11) 1.0
I got a list1 which has N items in each item it has (x,y,z). For z in list2, I need to create a new list which has items from list1 with only (x,y) this need to be done for list3, list4 too.
list1 = [(1250, 1442, 0), (1280, 1655, 1), (1029, 1680, 2), (624, 1573, 3), (732, 1159, 4), (1530, 1634, 5), (1885, 1628, 6), (2152, 1834, 7), (1252, 2459, 8), (1309, 3023, 9), (1376, 3585, 10), (1571, 2388, 11), (1682, 2952, 12), (1686, 3579, 13), (1184, 1391, 14), (1291, 1382, 15), (1117, 1440, 16), (1361, 1400, 17)]
list2 = [0,1,14,15,16,17]
list3 = [2,3,4,5,6,7,8,11]
list4 = [9,10,12,13]
For example, list5 which is between list1 and list2 looks like
list5 = [(1250, 1442),(1280, 1655),(1184, 1391)......]
Can anyone suggest a fast way to do it? Thank you
Easy enough:
def getXYfromIndex(l, indexes):
"""Returns x,y from bigger list 'l' containing (x,y,z).
Uses only those elements (by index) of 'l' that are in 'indexes'"""
# list comprehension: returns x,y for each index in 'l' that is in 'indexes'
return [(x,y) for x,y,_ in (l[i] for i in indexes)]
list1 = [(1250, 1442, 0), (1280, 1655, 1), (1029, 1680, 2), (624, 1573, 3), (732, 1159, 4),
(1530, 1634, 5), (1885, 1628, 6), (2152, 1834, 7), (1252, 2459, 8),
(1309, 3023, 9), (1376, 3585, 10), (1571, 2388, 11), (1682, 2952, 12),
(1686, 3579, 13), (1184, 1391, 14), (1291, 1382, 15), (1117, 1440, 16),
(1361, 1400, 17)]
list2 = [0,1,14,15,16,17]
list3 = [2,3,4,5,6,7,8,11]
list4 = [9,10,12,13]
print(getXYfromIndex(list1,list2)) # use list5 = getXYfromIndex(list1,list2)
print(getXYfromIndex(list1,list3)) # to work with those (x,y) - I just print them
print(getXYfromIndex(list1,list4))
Output:
[(1250, 1442), (1280, 1655), (1184, 1391), (1291, 1382), (1117, 1440), (1361, 1400)]
[(1029, 1680), (624, 1573), (732, 1159), (1530, 1634), (1885, 1628), (2152, 1834),
(1252, 2459), (1571, 2388)]
[(1309, 3023), (1376, 3585), (1682, 2952), (1686, 3579)]
I have a data structure defined as follow :
reqList[i] = [multidict({
1: ['type1', randint(1, 5), randint(1, 5), randint(1, 5)],
2: ['type2', randint(1, 5), randint(1, 5), randint(1, 5)],
3: ['type3', randint(1, 5), randint(1, 5), randint(1, 5)],
4: ['type4', randint(1, 5), randint(1, 5), randint(1, 5)]
}),
multidict({
(1, 2): randint(500, 1000),
(2, 3): randint(500, 1000),
(3, 4): randint(500, 1000)
})]
I want to make the creation of this data structure automatic in a for loop for example. I did this:
nodes = {}
for j in range(1, randint(2, 5)):
nodes[j] = ['type%d' % j, randint(1, 5), randint(1, 5), randint(1, 5)]
edges = {}
for kk in range(1, len(nodes)):
edges[(kk, kk + 1)] = randint(500, 1000)
print "EDGES", edges
reqList[i] = [multidict(nodes),
multidict(edges)]
del (nodes, edges)
when I look into the outputed edges the order of the keys is not kept ! For example I am getting this:
EDGES {(1, 2): 583, (3, 4): 504, (2, 3): 993}
I want it to be :
EDGES {(1, 2): 583, (2, 3): 993, (3, 4): 504}
Does the way I am coding it is correct ? if not, could you suggest a better way knowing that I need to get the same result as in the first example?
Dictionary in 2.7 is unordered and you can not keep the order of insert, unless you manually keep a reference on what key got inserted and when in a separate list. The module collections contains a class called OrderedDict that acts like a dictionary but keeps the inserts in ordered, which is what you could use (it also uses a list to keep track of the keys insert but uses a double link list to speed up deletion of keys).
There's no other way other than these two method.
from collections import OrderedDict
nodes = {}
for j in range(1, randint(2, 5)):
nodes[j] = ['type%d' % j, randint(1, 5), randint(1, 5), randint(1, 5)]
edges = OrderedDict()
for kk in range(1, len(nodes)):
edges[(kk, kk + 1)] = randint(500, 1000)
print "EDGES", edges # EDGES OrderedDict([((1, 2), 898), ((2, 3), 814)])
print edges[(1,2)] # still yields the correct number
You can read more about OrderedDict here
I'm trying to plot a lines graph using matplotlib - python.
The graph should look like below image:
I used patches.PathPatch to graph the image above, with specific vertices and codes, but I'm facing some technical issues when trying to plot live data above what the desired graph. For each reading, the graph gets regenerated (I get total of 8 figures for 8 unique readings). How do I stop this from happening? I just need the image above to be my background graph (as index graph), and live data to be plotted above that graph.... Also, any way to simplify below code? Any help would be greatly appreciated
import matplotlib.pyplot as plt
from matplotlib.path import Path
import matplotlib.patches as patches
import serial # import Serial Library
import numpy # Import numpy
from drawnow import *
tempF= []
pressure=[]
arduinoData = serial.Serial('/dev/cu.AdafruitEZ-Link64b9-SPP', 9600) #Creating our serial object named arduinoData
plt.ion() #Tell matplotlib you want interactive mode to plot live data
cnt=0
fig = plt.figure()
ax = fig.add_subplot(111)
def makeFig(): #Create a function that makes our desired plot
codes = [Path.MOVETO,
Path.LINETO,
Path.LINETO,
Path.LINETO,
Path.CLOSEPOLY,
Path.MOVETO,
Path.LINETO,
Path.LINETO,
Path.LINETO,
Path.CLOSEPOLY,
Path.MOVETO,
Path.LINETO,
Path.LINETO,
Path.LINETO,
Path.CLOSEPOLY,
Path.MOVETO,
Path.LINETO,
Path.LINETO,
Path.LINETO,
Path.CLOSEPOLY,
Path.MOVETO,
Path.LINETO,
Path.LINETO,
Path.LINETO,
Path.CLOSEPOLY,
Path.MOVETO,
Path.LINETO,
Path.LINETO,
Path.LINETO,
Path.CLOSEPOLY,
Path.MOVETO,
Path.LINETO,
Path.LINETO,
Path.LINETO,
Path.CLOSEPOLY,
]
verts1 = [
(0, 0), # left, bottom
(0, 23), # left, top
(1, 18), # right, top
(1, 0), # right, bottom
(0, 0), # ignored
(1, 0), # left, bottom
(1, 18), # left, top
(2, 16), # right, top
(2, 0), # right, bottom
(1, 0), # ignored
(2, 0), # left, bottom
(2, 16), # left, top
(3, 15), # right, top
(3, 0), # right, bottom
(2, 0), # ignored
(3, 0), # left, bottom
(3, 15), # left, top
(4, 14), # right, top
(4, 0), # right, bottom
(3, 0), # ignored
(4, 0), # left, bottom
(4, 14), # left, top
(5, 13), # right, top
(5, 0), # right, bottom
(4, 0), # ignored
(5, 0), # left, bottom
(5, 13), # left, top
(6, 12), # right, top
(6, 0), # right, bottom
(5, 0), # ignored
(6, 0), # left, bottom
(6, 12), # left, top
(7, 10), # right, top
(7, 0), # right, bottom
(6, 0), # ignored
]
verts2 = [
(0, 23), # left, bottom
(0, 45), # left, top
(1, 39), # right, top
(1, 18), # right, bottom
(0, 23), # ignored
(1, 18), # left, bottom
(1, 39), # left, top
(2, 38), # right, top
(2, 16), # right, bottom
(1, 18), # ignored
(2, 16), # left, bottom
(2, 38), # left, top
(3, 34), # right, top
(3, 15), # right, bottom
(2, 16), # ignored
(3, 15), # left, bottom
(3, 34), # left, top
(4, 30), # right, top
(4, 14), # right, bottom
(3, 15), # ignored
(4, 14), # left, bottom
(4, 30), # left, top
(5, 23), # right, top
(5, 13), # right, bottom
(4, 14), # ignored
(5, 13), # left, bottom
(5, 23), # left, top
(6, 19), # right, top
(6, 12), # right, bottom
(5, 13), # ignored
(6, 12), # left, bottom
(6, 19), # left, top
(7, 16), # right, top
(7, 10), # right, bottom
(6, 12), # ignored
]
verts3 = [
(0, 45), # left, bottom
(0, 50), # left, top
(1, 50), # right, top
(1, 39), # right, bottom
(0, 45), # ignored
(1, 39), # left, bottom
(1, 50), # left, top
(2, 50), # right, top
(2, 38), # right, bottom
(1, 39), # ignored
(2, 38), # left, bottom
(2, 50), # left, top
(3, 50), # right, top
(3, 34), # right, bottom
(2, 38), # ignored
(3, 34), # left, bottom
(3, 50), # left, top
(4, 46), # right, top
(4, 30), # right, bottom
(3, 34), # ignored
(4, 30), # left, bottom
(4, 46), # left, top
(5, 32), # right, top
(5, 23), # right, bottom
(4, 30), # ignored
(5, 23), # left, bottom
(5, 32), # left, top
(6, 28), # right, top
(6, 19), # right, bottom
(5, 23), # ignored
(6, 19), # left, bottom
(6, 28), # left, top
(7, 24), # right, top
(7, 16), # right, bottom
(6, 19), # ignored
]
verts4 = [
(0, 50), # left, bottom
(0, 60), # left, top
(1, 60), # right, top
(1, 50), # right, bottom
(0, 50), # ignored
(1, 50), # left, bottom
(1, 60), # left, top
(2, 60), # right, top
(2, 50), # right, bottom
(1, 50), # ignored
(2, 50), # left, bottom
(2, 60), # left, top
(3, 60), # right, top
(3, 50), # right, bottom
(2, 50), # ignored
(3, 50), # left, bottom
(3, 60), # left, top
(4, 60), # right, top
(4, 46), # right, bottom
(3, 50), # ignored
(4, 46), # left, bottom
(4, 60), # left, top
(5, 60), # right, top
(5, 32), # right, bottom
(4, 46), # ignored
(5, 32), # left, bottom
(5, 60), # left, top
(6, 60), # right, top
(6, 28), # right, bottom
(5, 32), # ignored
(6, 28), # left, bottom
(6, 60), # left, top
(7, 60), # right, top
(7, 24), # right, bottom
(6, 19), # ignored
]
path = Path(verts1, codes)
path2 = Path(verts2, codes)
path3 = Path(verts3, codes)
path4 = Path(verts4, codes)
patch = patches.PathPatch(path, facecolor='green', alpha=0.8)
patch2 = patches.PathPatch(path2, facecolor='orange', alpha=0.8)
patch3 = patches.PathPatch(path3, facecolor='red', alpha=0.8)
patch4 = patches.PathPatch(path4, facecolor='purple', alpha=0.8)
#ax.axhline(5, linestyle='--', color='k') # horizontal lines
#ax.axvline(0, linestyle='--', color='k') # vertical lines
ax.add_patch(patch)
ax.add_patch(patch2)
ax.add_patch(patch3)
ax.add_patch(patch4)
ax.set_xlim(0,7)
ax.set_ylim(0,60)
plt.grid()
plt.show()
plt.plot(tempF, 'ro-', label='sensor 1') #plot the temperature
plt.legend(loc='upper left') #plot the legend
plt.plot(pressure, 'bo-', label='sensor 2') #plot the temperature
plt.legend(loc='upper left')
while True: # While loop that loops forever
while (arduinoData.inWaiting()==0): #Wait here until there is data
pass #do nothing
arduinoString = arduinoData.readline() #read the line of text from the serial port
dataArray = arduinoString.split(',') #Split it into an array called dataArray
print dataArray[0]
print dataArray[1]
temp = float( dataArray[0]) #Convert first element to floating number and put in temp
P = float( dataArray[1]) #Convert second element to floating number and put in P
tempF.append(temp) #Build our tempF array by appending temp readings
pressure.append(P) #Building our pressure array by appending P readings
drawnow(makeFig) #Call drawnow to update our live graph
plt.pause(.000001) #Pause Briefly. Important to keep drawnow from crashing
cnt=cnt+1
if(cnt>150): #If you have 50 or more points, delete the first one from the array
tempF.pop(0) #This allows us to just see the last 50 data points
pressure.pop(0)
Using how your input is currently styled:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
path1 = pd.DataFrame([(0,0),(0,23),(1,18),(1,0),(0,0),(1,0),(1,18),(2,16),(2,0),(1,0),(2,0),(2,16),(3,15),(3,0),(2,0),(3,0),(3,15),(4,14),(4,0),(3,0),(4,0),(4,14),(5,13),(5,0),(4,0),(5,0),(5,13),(6,12),(6,0),(5,0),(6,0),(6,12),(7,10),(7,0),(6,0),])
path2 = pd.DataFrame([(0,23),(0,45),(1,39),(1,18),(0,23),(1,18),(1,39),(2,38),(2,16),(1,18),(2,16),(2,38),(3,34),(3,15),(2,16),(3,15),(3,34),(4,30),(4,14),(3,15),(4,14),(4,30),(5,23),(5,13),(4,14),(5,13),(5,23),(6,19),(6,12),(5,13),(6,12),(6,19),(7,16),(7,10),(6,12),])
path3 = pd.DataFrame([(0,45),(0,50),(1,50),(1,39),(0,45),(1,39),(1,50),(2,50),(2,38),(1,39),(2,38),(2,50),(3,50),(3,34),(2,38),(3,34),(3,50),(4,46),(4,30),(3,34),(4,30),(4,46),(5,32),(5,23),(4,30),(5,23),(5,32),(6,28),(6,19),(5,23),(6,19),(6,28),(7,24),(7,16),(6,19),])
path4 = pd.DataFrame([(0,50),(0,60),(1,60),(1,50),(0,50),(1,50),(1,60),(2,60),(2,50),(1,50),(2,50),(2,60),(3,60),(3,50),(2,50),(3,50),(3,60),(4,60),(4,46),(3,50),(4,46),(4,60),(5,60),(5,32),(4,46),(5,32),(5,60),(6,60),(6,28),(5,32),(6,28),(6,60),(7,60),(7,24),(6,19),])
p1y = list(path1[1][1::5])
p1y.append(path1[1][32])
p2y = list(path2[1][1::5])
p2y.append(path2[1][32])
p3y = list(path3[1][1::5])
p3y.append(path3[1][32])
p4y = list(path4[1][1::5])
p4y.append(path4[1][32])
xline = np.array(range(len(p1y)))
ax.fill_between(xline, np.zeros(len(p1y)), p1y, facecolor='green', alpha=0.8)
ax.fill_between(xline, p1y, p2y, facecolor='orange', alpha=0.8)
ax.fill_between(xline, p2y, p3y, facecolor='red', alpha=0.8)
ax.fill_between(xline, p3y, p4y, facecolor='purple', alpha=0.8)
ax.set_xlim(0,7)
ax.set_ylim(0,60)
plt.grid()
plt.show()
However, if you can simplify your incoming verts data:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
path1 = [23, 18, 16, 15, 14, 13, 12, 10]
path2 = [45, 39, 38, 34, 30, 23, 19, 16]
path3 = [50, 50, 50, 50, 46, 32, 28, 24]
path4 = [60, 60, 60, 60, 60, 60, 60, 60]
xline = np.array(range(len(path1)))
ax.fill_between(xline, np.zeros(len(path1)), path1, facecolor='green', alpha=0.8)
ax.fill_between(xline, path1, path2, facecolor='orange', alpha=0.8)
ax.fill_between(xline, path2, path3, facecolor='red', alpha=0.8)
ax.fill_between(xline, path3, path4, facecolor='purple', alpha=0.8)
ax.set_xlim(0,7)
ax.set_ylim(0,60)
plt.grid()
plt.show()
A note of difference, you are using Python 2.6 and this was done using Python 3.6.0 and Matplotlib 2.0.0
I am trying to construct a structured array in Python that can be accessed by the names of the columns and rows. Is this possible with the structured array method of numpy?
Example:
My array should have roughly this form:
My_array = A B C
E 1 2 3
F 4 5 6
G 7 8 9
And i want to have the possibility to do the following:
My_array["A"]["E"] = 1
My_array["C"]["F"] = 6
Is it possible to do this in pyhton using structured arrays or is there another type of structure which is more suitable for such a task?
A basic structured array gives you something that can be indexed with one name:
In [276]: dt=np.dtype([('A',int),('B',int),('C',int)])
In [277]: x=np.arange(9).reshape(3,3).view(dtype=dt)
In [278]: x
Out[278]:
array([[(0, 1, 2)],
[(3, 4, 5)],
[(6, 7, 8)]],
dtype=[('A', '<i4'), ('B', '<i4'), ('C', '<i4')])
In [279]: x['B'] # index by field name
Out[279]:
array([[1],
[4],
[7]])
In [280]: x[1] # index by row (array element)
Out[280]:
array([(3, 4, 5)],
dtype=[('A', '<i4'), ('B', '<i4'), ('C', '<i4')])
In [281]: x['B'][1]
Out[281]: array([4])
In [282]: x.shape # could be reshaped to (3,)
Out[282]: (3, 1)
The view approach produced a 2d array, but with just one column. The usual columns are replaced by dtype fields. It's 2d but with a twist. By using view the data buffer is unchanged; the dtype just provides a different way of accessing those 'columns'. dtype fields are, technically, not a dimension. They don't register in either the .shape or .ndim of the array. Also you can't use x[0,'A'].
recarray does the same thing, but adds the option of accessing fields as attributes, e.g. x.B is the same as x['B'].
rows still have to be accessed by index number.
Another way of constructing a structured array is to defined values as a list of tuples.
In [283]: x1 = np.arange(9).reshape(3,3)
In [284]: x2=np.array([tuple(i) for i in x1],dtype=dt)
In [285]: x2
Out[285]:
array([(0, 1, 2), (3, 4, 5), (6, 7, 8)],
dtype=[('A', '<i4'), ('B', '<i4'), ('C', '<i4')])
In [286]: x2.shape
Out[286]: (3,)
ones, zeros, empty also construct basic structured arrays
In [287]: np.ones((3,),dtype=dt)
Out[287]:
array([(1, 1, 1), (1, 1, 1), (1, 1, 1)],
dtype=[('A', '<i4'), ('B', '<i4'), ('C', '<i4')])
I can construct an array that is indexed with 2 field names, by nesting dtypes:
In [294]: dt1=np.dtype([('D',int),('E',int),('F',int)])
In [295]: dt2=np.dtype([('A',dt1),('B',dt1),('C',dt1)])
In [296]: y=np.ones((),dtype=dt2)
In [297]: y
Out[297]:
array(((1, 1, 1), (1, 1, 1), (1, 1, 1)),
dtype=[('A', [('D', '<i4'), ('E', '<i4'), ('F', '<i4')]), ('B', [('D', '<i4'), ('E', '<i4'), ('F', '<i4')]), ('C', [('D', '<i4'), ('E', '<i4'), ('F', '<i4')])])
In [298]: y['A']['F']
Out[298]: array(1)
But frankly this is rather convoluted. I haven't even figured out how to set the elements to arange(9) (without iterating over field names).
Structured arrays are most commonly produced by reading csv files with np.genfromtxt (or loadtxt). The result is a named field for each labeled column, and a numbered 'row' for each line in the file.
With a recarray, you can access columns with dot notation or with specific reference to the column name. For rows, they are accessed by row number. I haven't seen them accessed via a row name, for example:
>>> import numpy as np
>>> a = np.arange(1,10,1).reshape(3,3)
>>> dt = np.dtype([('A','int'),('B','int'),('C','int')])
>>> a.dtype = dt
>>> r = a.view(type=np.recarray)
>>> r
rec.array([[(1, 2, 3)],
[(4, 5, 6)],
[(7, 8, 9)]],
dtype=[('A', '<i4'), ('B', '<i4'), ('C', '<i4')])
>>> r.A
array([[1],
[4],
[7]])
>>> r['A']
array([[1],
[4],
[7]])
>>> r.A[0]
array([1])
>>> a['A'][0]
array([1])
>>> # now for the row
>>> >>> r[0]
rec.array([(1, 2, 3)],
dtype=[('A', '<i4'), ('B', '<i4'), ('C', '<i4')])
>>>
You can specify the dtype and the type at the same time
>>> a = np.ones((3,3))
>>> b = a.view(dtype= [('A','<f8'), ('B','<f8'),('C', '<f8')], type = np.recarray)
>>> b
rec.array([[(1.0, 1.0, 1.0)],
[(1.0, 1.0, 1.0)],
[(1.0, 1.0, 1.0)]],
dtype=[('A', '<f8'), ('B', '<f8'), ('C', '<f8')])
>>> b.A
array([[ 1.],
[ 1.],
[ 1.]])
>>> b.A[0]
array([ 1.])