Question on Pyomo Transport/Shipping issue - pyomo

I am learning pyomo and practicing an exercise about shipping problem with conditions below:
The shipment can either directly deliver from source cities to the destination or through a depot (source city -> depot -> destination)
The way of shipping will be selected based on least cost consumed
Every Depot has its own capacity limitation
I tried to use pyomo to solve this question, however, no solution can be figured out.
Please give me some advice and direction why the codes didnt work. Thank you!
import pyomo.environ as pyomo
import numpy as np
supply = dict({'Liverpool': 150000,
'Brighton': 200000})
through = dict({'Newcastle': 70000,
'Birmingham': 50000,
'London': 100000,
'Exeter': 40000,
'Liverpool': 150000,
'Brighton': 200000
})
demand = dict({'C1': 50000,
'C2': 10000,
'C3': 40000,
'C4': 35000,
'C5': 60000,
'C6': 20000})
cost = dict({
('Liverpool', 'Newcastle'): 0.5,
('Liverpool', 'Birmingham'): 0.5,
('Liverpool', 'London'): 1.0,
('Liverpool', 'Exeter'): 0.2,
('Liverpool', 'C1'): 1.0,
('Liverpool', 'C3'): 1.5,
('Liverpool', 'C4'): 2.0,
('Liverpool', 'C6'): 1.0,
('Brighton', 'Birmingham'): 0.3,
('Brighton', 'London'): 0.5,
('Brighton', 'Exeter'): 0.2,
('Brighton', 'C1'): 2.0,
('Newcastle', 'C2'): 1.5,
('Newcastle', 'C3'): 0.5,
('Newcastle', 'C5'): 1.5,
('Newcastle', 'C6'): 1.0,
('Birmingham', 'C1'): 1.0,
('Birmingham', 'C2'): 0.5,
('Birmingham', 'C3'): 0.5,
('Birmingham', 'C4'): 1.0,
('Birmingham', 'C5'): 0.5,
('London', 'C2'): 1.5,
('London', 'C3'): 2.0,
('London', 'C5'): 0.5,
('London', 'C6'): 1.5,
('Exeter', 'C3'): 0.2,
('Exeter', 'C4'): 1.5,
('Exeter', 'C5'): 0.5,
('Exeter', 'C6'): 1.5
})
cost_total = {}
for city_from in supply.keys():
for city_through in through.keys():
for city_to in demand.keys():
if city_from == city_through:
cost_total[(city_from , city_through , city_to)] = 0 + cost.get((city_through , city_to) , 9999)
else:
cost_total[(city_from , city_through , city_to)] = cost.get((city_from , city_through) , 9999) + cost.get((city_through , city_to) , 9999)
supplier = supply.keys()
througher = through.keys()
demander = demand.keys()
model = pyomo.ConcreteModel()
model.i = pyomo.Set(initialize = supplier , doc = 'City From')
model.j = pyomo.Set(initialize = througher , doc = 'City Through')
model.k = pyomo.Set(initialize = demander , doc = 'City To')
model.s = pyomo.Param(model.i , initialize=supply, doc='Supply by City')
model.t = pyomo.Param(model.j , initialize = through , doc = 'through / warehouse')
model.d = pyomo.Param(model.k , initialize=demand , doc='Demand by City')
model.cost = pyomo.Param(model.i , model.j , model.k , initialize=cost_total , doc = 'total cost')
model.x = pyomo.Var(model.i , model.j , model.k , bounds = (0 , None))
def supply_rule(model, i):
return sum(model.x[i,j,k] for j in model.j for k in model.k) <= model.s[i]
model.supply = pyomo.Constraint(model.i, rule=supply_rule, doc='Observe supply limit at plant i')
def demand_rule(model, k):
return sum(model.x[i,j,k] for i in model.i for j in model.j) == model.d[k]
model.demand = pyomo.Constraint(model.k, rule=demand_rule, doc='Satisfy demand at market j')
def depot_cont(model , j):
return sum(model.x[i , j , k] for i in model.i for k in model.k) <= model.t[j]
model.through_cont2 = pyomo.Constraint(model.j , rule = depot_cont)
def objective_rule(model):
return sum(model.cost[i,j,k]*model.x[i,j,k] for i in model.i for j in model.j for k in model.k)
model.objective = pyomo.Objective(rule=objective_rule, sense=pyomo.minimize, doc='Define objective function')

Your code (unmodified) appears to be working for me.
Realize there are a couple ways to set this up, which is a larger discussion... In your case you enumerated all possible routes, and snuck in a zero-cost option for the direct routes and added high cost for infeasible routes, which is fine. On a larger problem, or more complicated network, the standard way to approach this is as a network flow problem with flow-balance constraints at all the nodes (cities).
Anyhow, your question isn't too clear on what "isn't working". I added this to the end of your code:
solver = pyomo.SolverFactory('glpk')
result = solver.solve(model)
print(result)
for ijk in model.x.index_set():
if model.x[ijk]:
print(f'ship : {ijk} qty: {model.x[ijk].value}')
and it produced this result, which passes 1st level sanity check, but I didn't look at it too closely...
Problem:
- Name: unknown
Lower bound: 198500.0
Upper bound: 198500.0
Number of objectives: 1
Number of constraints: 15
Number of variables: 73
Number of nonzeros: 217
Sense: minimize
Solver:
- Status: ok
Termination condition: optimal
Statistics:
Branch and bound:
Number of bounded subproblems: 0
Number of created subproblems: 0
Error rc: 0
Time: 0.007380008697509766
Solution:
- number of solutions: 0
number of solutions displayed: 0
ship : ('Liverpool', 'Liverpool', 'C1') qty: 50000.0
ship : ('Liverpool', 'Liverpool', 'C6') qty: 20000.0
ship : ('Brighton', 'Birmingham', 'C2') qty: 10000.0
ship : ('Brighton', 'Birmingham', 'C4') qty: 35000.0
ship : ('Brighton', 'Birmingham', 'C5') qty: 5000.0
ship : ('Brighton', 'London', 'C5') qty: 55000.0
ship : ('Brighton', 'Exeter', 'C3') qty: 40000.0
[Finished in 579ms]

Related

TypeError: '_SumExpression' object is not iterable

Please I am new to Pyomo. I have tried to run the following codes:
from pyutilib.misc import import_file
from pyomo.environ import *
model = ConcreteModel()
model.name = "Transmission Investment planning problem_"
#Sets
#Epoch
model.E = RangeSet(0,3) #No. of Epochs
#System nodes
model.N = ['N1', 'N2', 'N3'] #Names of Bus nodes
#model.n_name= Param(model.N)
model.G = ['G1', 'G2', 'G3'] #Names of generators
model.LI = ['L1', 'L2', 'L3'] #Nnames of Transmission lines
#Scalar Parameters
model.int_rate = 0.05 #interest rate
model.vll = 3000 #value of loss load(£/MWh)
model.tau_period = 8760 #Time duration of demand period (hours)
model.base = 100 #MVA base
model.ref = {'N3'} #reference node
model.vadegree = 0 #phase angle of reference node
#Discount factors
L = 5
Y= len(model.E)*L
irate = range(0,(Y-1))
def disc_factor(i):
disc = [1/((1 + model.int_rate)**i) for i in irate]
return disc
model.cum_disc_inv_cost = [sum(disc_factor(i)[(i*L):]) for i in model.E] #investment discount factor
model.cum_disc_op_cost = [sum(disc_factor(i)[(i*L):((i+1)*L)]) for i in model.E] #operation discount factor
#Demand Periods
model.t_demand = {'N1': 105, 'N2': 210, 'N3': 735} #demand at nodes (MW)
model.demand_curtailed = Var(model.E, model.N, initialize = 0) #curtailed demand (MW)
#Generation Units
model.ge_max = {'G1': 200, 'G2': 200, 'G3': 1000} #maximum stable power generation(MW)
model.ge_marginal_cost = {'G1': 30, 'G2': 35, 'G3': 40} #marginal cost of generation units (£/MWh)
#Bus to generation incidence matrix
model.B = {('N1','G1'): 1, ('N1','G2'): 0, ('N1','G3'): 0, ('N2','G1'): 0, ('N2','G2'): 1, ('N2','G3'): 0, ('N3','G1'): 0, ('N3','G2'): 0, ('N3','G3'): 1,}
#Transmission lines
model.li_x = {'L1': 0.2, 'L2': 0.2, 'L3': 0.2} #reactance of transmission line(p.u)
model.li_max_f = 150 #maximum capaciy provided for line expansion (MW)
model.li_f = {'L1': 100, 'L2': 100, 'L3': 100} #initial capacity for line l (MW)
model.li_sending_bus = {'L1': 'N1', 'L2': 'N1', 'L3': 'N2'} #sending bus for line l
model.li_receiving_bus = {'L1': 'N2', 'L2': 'N3', 'L3': 'N3'} #receiving bus for line l
model.li_length = {'L1': 100, 'L2': 100, 'L3': 100} #length of line l (km)
#Expansion Options
model.inv_cost_var = 4000000 #Annuitized variable investment cost for line l (£/MW.km.yr)
#Bus to line incidence matrix
model.I = {('N1','L1'): 1, ('N1','L2'): 1, ('N1','L3'): 0, ('N2','L1'): -1, ('N2','L2'): 0, ('N2','L3'): 1, ('N3','L1'): 0, ('N3','L2'): -1, ('N3','L3'): -1,}
#Variables
#Transmission line power flow limits
def fl_inv(model, i, l):
return (0, model.li_max_f)
model.li_f_inv = Var(model.E, model.LI, bounds = fl_inv) #transmission capacity to be built for line l (MW)
#Transmission line investment and operation contraints
model.f = Var(model.LI, model.E, initialize=0)
def fl_rule(model, l, j, i):
if i:
return model.f[l,j] >= -(model.li_f_inv[j,l] + model.li_f[l])
else:
return model.f[l,j] <= (model.li_f_inv[j,l] + model.li_f[l])
model.bound_f = Constraint(model.LI, model.E, [0,1], rule=fl_rule)
##generation limit
def fg(model, i, g):
return (0, model.ge_max[g])
model.ge_output = Var(model.E, model.G, initialize = 0, bounds = fg)
#phase angles for the nodes
def theta(model, e, n):
for n in model.N:
if n == model.ref:
model.theta[e, n].fixed = True
return model.vadegree
else: return 0
model.theta = Var(model.E, model.N, initialize = theta)
def line_equation(model, l, e):
return model.f[l, e] == model.base/model.li_x[l] *(sum(model.theta[e, n] for n in model.N if n == model.li_sending_bus[l]) - sum(model.theta[e, n] for n in model.N if n == model.li_receiving_bus[l]))
model.line_equation = Constraint(model.LI, model.E, rule = line_equation)
def system_balance(model, e, n):
return sum(model.B[n, g] * model.ge_output[e, g] for g in model.G) \
+ sum(model.I[n, l] * model.f[l, e] for l in model.LI) \
- model.t_demand[n] + model.demand_curtailed[e, n] == 0
model.SystemBalance = Constraint(model.E, model.N, rule=system_balance)
#OBJECTIVE FUNCTION
def objective_mincost(model):
for i in model.E:
return sum(model.cum_disc_inv_cost[i] * sum(model.li_f_inv[i, l] * model.inv_cost_var * model.li_length[l] for l in model.LI) + model.cum_disc_op_cost[i] * (model.tau_period * (sum(model.ge_max[g] * (model.ge_marginal_cost[g]) for g in model.G) + sum(model.demand_curtailed[i, n] for n in model.N * model.vll))))
model.objective = Objective(rule = objective_mincost, sense = minimize)
opt = SolverFactory('gurobi')
results = opt.solve(model) # solves and updates instance
model.display()
I got the following errorcodes:
ERROR: Rule failed when generating expression for objective objective:
TypeError: '_SumExpression' object is not iterable ERROR: Constructing component 'objective' from data=None failed:
TypeError: '_SumExpression' object is not iterable
Please any suggestions on where the problem might be and possible solution?
Thank you.
You have two places where model.E is multiplied by something that is not a set. You probably meant to parenthesize your sums differently (i.e., this is mostly a problem with how your sums are organized)

Pyomo KeyError: "Error accessing indexed component: Index '0' is not valid for array component 'li_f_inv'"

I was trying to run the following code on Pyomo. It is a simple Transmission Expansion problem using a concrete model.
Thanks jsiirola. I am actually just learning Pyomo, thats why I might be making silly mistakes. I implemented all you suggested as shown below:
from pyutilib.misc import import_file
from pyomo.environ import *
import networkx as nx
model = ConcreteModel()
model.name = "DTEPM_trial_concrete"
#Sets
#Epoch
model.E = Set(initialize = [0, 1, 2, 3])
model.E_n = Set(model.E, initialize = {0:[1,2,3,4,5], 1:[6,7,8,9,10], 2:[11,12,13,14,15], 3:[16,17,18,19,20]})
#System nodes
model.N = ['N1', 'N2', 'N3']
model.n_name= Param(model.N, within = Integers)
#T = Set()
model.G = ['G1', 'G2', 'G3']
model.LI = ['L1', 'L2', 'L3']
#Scalar Parameters
model.int_rate = 0.05
model.vll = 3000
model.tau_period = 8760
def R_discount_inv_init(model, i):
return sum(1 / (1 + model.int_rate)**(i - 1) for i in model.E)
model.cum_disc_inv_cost = Param(model.E, initialize = R_discount_inv_init)
def R_discount_op_init(model, i):
for index in model.E_n:
return sum(1 / (1 + model.int_rate)**(i - 1) for i in model.E_n[index])
model.cum_disc_op_cost = Param(model.E, initialize = R_discount_op_init)
#Demand Periods
model.t_demand = {'N1': 1.05, 'N2': 2.10, 'N3': 7.35}
model.demand_curtailed = Var(model.E, model.N, within = NonNegativeReals)
#Generation Units
model.ge_max = {'G1': 2.00, 'G2': 2.00, 'G3': 7.35}
model.ge_marginal_cost = {'G1': 30, 'G2': 35, 'G3': 40}
model.B = {('N1','G1'): 1, ('N1','G2'): 0, ('N1','G3'): 0, ('N2','G1'): 0, ('N2','G2'): 1, ('N2','G3'): 0, ('N3','G1'): 0, ('N3','G2'): 0, ('N3','G3'): 1,}
#Transmission lines
model.li_x = {'L1': 0.2, 'L2': 0.2, 'L3': 0.2}
model.li_max_f = 1.50
model.li_f = {'L1': 1.00, 'L2': 1.00, 'L3': 1.00}
model.li_sending_bus = {'L1': 'N1', 'L2': 'N1', 'L3': 'N2'}
model.li_receiving_bus = {'L1': 'N2', 'L2': 'N3', 'L3': 'N3'}
model.li_length = {'L1': 100, 'L2': 100, 'L3': 100}
#Expansion Options
model.inv_cost_var = 4000000
nodes = ['N1', 'N2', 'N3']
edges = [['N1', 'N2'], ['N1', 'N3'], ['N2', 'N3']]
I = nx.DiGraph()
I.add_nodes_from(nodes)
I.add_edges_from(edges)
model.I = -nx.incidence_matrix(I, oriented=True) # this returns a scipy sparse matrix
#Variables
#Transmission line power flow limits
def fl_inv(model, i, l):
return (0, model.li_max_f)
model.li_f_inv = Var(model.E, model.LI, bounds = fl_inv)
#Transmission line investment and operation contraints
model.f = Var(model.LI, model.E, initialize=0)
def fl_rule(model, l, j, i):
if i:
return model.f[l,j] >= -(model.li_f_inv[j,l] + model.li_f[l])
else:
return model.f[l,j] <= (model.li_f_inv[j,l] + model.li_f[l])
model.bound_f = Constraint(model.LI, model.E, [0,1], rule=fl_rule)
#generation limit
def fg(model, i, g):
return (0, model.ge_max[g])
model.ge_output = Var(model.G, model.E, initialize = 0, bounds = fg)
#phase angles for the nodes
model.theta = Var(model.E, model.N, within = NonNegativeReals)
def line_equation(model, e, l):
return model.bound_f[l] == (1/model.li_x(l) for l in model.LI) *(sum(model.theta[n] for n in model.N if model.n_name[n] == model.li_sending_bus[l]) - sum(model.theta[n] for n in model.N if model.n_name[n] == model.li_receiving_bus[l]))
model.line_equation = Constraint(model.LI, model.E, rule = line_equation)
def system_balance(model, e, n):
return sum(model.b[n, g] * model.ge_output[g] for g in model.G) \
+ sum(model.I[n, l] * model.f[l] for l in model.LI) \
- sum(model.t_demand[n] - model.demand_curtailed[n]) == 0
model.SystemBalance = Constraint(model.E, model.N, rule=system_balance)
#OBJECTIVE FUNCTION
def objective_mincost(model):
return sum( model.cum_disc_inv_cost[e] for e in model.E * sum (model.li_f_inv[l] * model.inv_cost_var[l] * model.li_length[l]) + model.cum_disc_op_cost[e] * (model.tau_period * (sum(model.ge_max[g] * (model.ge_marginal_cost[g])) + sum(model.demand_curtailed[n] * model.vll))))
model.objective = Objective(rule = objective_mincost, sense = minimize)
opt = SolverFactory('gurobi')
results = opt.solve(model) # solves and updates instance
model.display()
But received the following new error message:
ERROR: Rule failed when generating expression for constraint line_equation with index ('L3', 0):
KeyError: "Error accessing indexed component: Index 'L3' is not valid for array component 'bound_f'"
ERROR: Constructing component 'line_equation' from data=None failed:
KeyError: "Error accessing indexed component: Index 'L3' is not valid for array component 'bound_f'"
Please what do you think might be wrong?
Thank you
As the error indicates, you are not passing valid indices to model.li_f_inv in the rule for model.f. Your Var model.li_f_inv is declared as:
model.li_f_inv = Var(model.E, model.LI, bounds = fl_inv)
Your current rule for model.f is only passing a single index to model.li_f_inv, which is invalid. That means your rule for model.f needs to be updated to pass the correct indices:
#Transmission line investment and operation contraints
model.f = Var(model.LI, model.E, initialize=0)
def fl_rule(model, l, j, i):
if i:
return model.f[l,j] >= -(model.li_f_inv[j,l] + model.li_f[l])
else:
return model.f[l,j] <= (model.li_f_inv[j,l] + model.li_f[l])
model.bound_f = Constraint(model.LI, model.E, [0,1], rule=fl_rule)
Also note that you are transposing the indexing sets between the definition of model.f and the sets implied by the fl_rule function.
EDIT: I failed to notice that in your original post, you were attempting to use variables (li_f_inv) in the bounds of another variable (f). This isn't a valid math program (not to mention, not valid Pyomo). You need to express the variable bounds as a Constraint. Also, while Pyomo allows you to express range constraints (lb <= body <= ub), both lb and ub must not be potentially variable. Since that is not the case here, you must express the two bounds constraints separately.

Build custom Metric for Loss Function with Keras, with errors

I'm trying to write custom metric function to set in the compile step wrote in this way:
self.model.compile(optimizer=sgd,loss='categorical_crossentropy',metrics=[self.dice_similarity_coefficient_metric,self.positive_predictive_value_metric,self.sensitivity_metric])
I wrote Dice Similarity Coefficient, Positive Predictive Value and Similarity in this way:
FP = false positive
TP = true positive
FN = false negative
def dice_similarity_coefficient_metric(self, y_true, y_pred):
y_true = np.array(K.eval(y_true))
y_pred = np.array(K.eval(y_pred))
FP = np.sum(y_pred & np.logical_not(y_true)).astype(float)
TP = np.sum(y_true & y_pred).astype(float)
FN = np.sum(np.logical_not(y_pred) &
np.logical_not(y_true)).astype(float)
return K.variable(np.array((2 * TP) / (FP + (2 * TP) + FN +
K.epsilon())))
def positive_predictive_value_metric(self, y_true, y_pred):
y_true = np.array(K.eval(y_true))
y_pred = np.array(K.eval(y_pred))
FP = np.sum(y_pred & np.logical_not(y_true)).astype(float)
TP = np.sum(y_true & y_pred).astype(float)
return K.variable(np.array(TP / (FP + TP + K.epsilon())))
def sensitivity_metric(self, y_true, y_pred):
y_true = np.array(K.eval(y_true))
y_pred = np.array(K.eval(y_pred))
TP = np.sum(y_true & y_pred).astype(float)
FN = np.sum(np.logical_not(y_pred) &
np.logical_not(y_true)).astype(float)
return K.variable(np.array(TP / (TP + FN + K.epsilon())))
when i run the code i have the following error:
InvalidArgumentError (see above for traceback): You must feed a value for placeholder tensor 'dense_3_target' with dtype float
[[Node: dense_3_target = Placeholderdtype=DT_FLOAT, shape=[], _device="/job:localhost/replica:0/task:0/cpu:0"]]
Can someone care to explain where is the problem?
Where i'm wrong?
Thank you
Probably, it's better to define metrics using backend functions. For example:
def false_negatives(Y_true, Y_pred):
return K.sum(K.round(K.clip(Y_true - Y_pred, 0, 1)))
It can be checked on an example data with 5 FN:
y_true = np.array([[1.0, 1.0, 0.0, 1.0], [1.0, 1.0, 0.0, 1.0], [1.0, 1.0, 0.0, 1.0]], dtype=np.float32)
y_pred = np.array([[0.3, 0.99, 0.99, 0.1], [0.6, 0.99, 0.99, 0.1], [0.1, 0.99, 0.99, 0.1]], dtype=np.float32)
n_fn = np.sum((y_true - y_pred) > 0.5)
Y_true = K.placeholder((None, 4), dtype=K.floatx())
Y_pred = K.placeholder((None, 4), dtype=K.floatx())
n_fn = false_negatives(Y_true, Y_pred).eval(inputs_to_values={Y_true: y_true, Y_pred: y_pred})
HTH

plt.boxplot(data, vert = False) - adding one data point per boxplot - python 2.7, Matplotlib 1.5.3

Have been trying to add one single point to my boxplots. I would like just to add a point as the black ones in the image below.
data_2 = [pd.read_csv(data).values for data in os.listdir(wd)]
bp = plt.boxplot(data_2, labels = labels, vert = False, showfliers = False)
plt.show()
Any ideas for how I should go with that? You can click here to see the pic
You can just plot individual points after the boxplot is finished, just give the appropiate coordinates:
import numpy as np
import matplotlib.pyplot as plt
data = np.array( [
np.random.normal( 0.19, 0.1, 100 ),
np.random.normal( 0.17, 0.1, 100 ),
np.random.normal( 0.11, 0.1, 100 ),
np.random.normal( 0.16, 0.1, 100 ),
np.random.normal( 0.15, 0.1, 100 ) ] ).T
labels = [ 'pred2012', 'pred2007', 'pred2002', 'pred1995', 'pred1988' ]
fig, ax = plt.subplots()
ax.boxplot( data, labels=labels, vert = False, showfliers = False)
ax.plot( -0.1, 4, marker='o' )
ax.plot( 0.3, 3, marker='*', markersize=20 )
plt.savefig( 'boxplot.png' )
plt.show()

How to add a time control panel to a FuncAnimation from matplotlib

I am currently using matplotlib.animation.FuncAnimation() to display an animation of my work, on a figure.
It is working very well, and I understand the arguments I am using ( interval, time range , ...) However, I was wondering if there was a way to implement (maybe directly to the figure) a panel containing the animation, a scroll-bar or whatever, which allows me to :
Move forward or backwards quickly to the time zone of interest.
Show at what point of the animation I am ( 10%, then 20%,...).
Basically, is a way to control the animation in python on the figure like the way I would control it as a video file played by a video player?
If needed, this is what looks like the code for this animation :
def init():
im1.set_data(XYslice[0, :, :])
im2.set_data(XZslice[0, Nplans/2:, :])
return([im1, im2])
def animate(t):
im1.set_data(XYslice[t, :, :])
im2.set_data(XZslice[t, Nplans/2:, :])
return [im1, im2]
anim = animation.FuncAnimation(fig, animate, np.arange(Ntime), interval=200,
blit=True, init_func=init, repeat=True)
What you are talking about is a GUI. The simplest example uses the matplotlib inbuilt widgets:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.mlab import bivariate_normal
from matplotlib.widgets import Slider, Button
#Setup figure and data
fig, ax = plt.subplots()
plt.subplots_adjust(bottom=0.25)
delta = 0.5
t = np.arange(0.0, 100.0, 0.1)
x = np.arange(-3.0, 4.001, delta)
y = np.arange(-4.0, 3.001, delta)
X, Y = np.meshgrid(x, y)
Z1 = bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
Z = (Z1 - Z2) * 5.
cmap = plt.cm.rainbow
im = ax.pcolormesh(X, Y, Z, cmap=cmap)
fig.colorbar(im)
axcolor = 'lightgoldenrodyellow'
axtime = plt.axes([0.25, 0.1, 0.65, 0.03], axisbg=axcolor)
stime = Slider(axtime, 'Time', 0.0, 100.0, valinit=50.0)
#Routines to reset and update sliding bar
def reset(event):
stime.reset()
def update(val):
time = stime.val/10.
Z = (Z1 - Z2) * time
im.set_array(Z.ravel())
fig.canvas.draw()
#Bind sliding bar and reset button
stime.on_changed(update)
resetax = plt.axes([0.8, 0.025, 0.1, 0.04])
button = Button(resetax, 'Reset', color=axcolor, hovercolor='0.975')
button.on_clicked(reset)
plt.show()
This should be a start. If you want it to look better (and add more functionality) then you need to go to a GUI framework like wxpython, check out this example.
An example which is more inline with your data-structure would go as follows:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.mlab import bivariate_normal
from matplotlib.widgets import Slider, Button
#Setup figure and data
fig, ax = plt.subplots()
plt.subplots_adjust(bottom=0.25)
delta = 0.5
t = np.linspace(0.0, 100.0, 256)
x = np.linspace(-4.0, 4.001, 512)
y = np.linspace(-4.0, 4.001, 512)
X, Y = np.meshgrid(x, y)
Z1 = bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
XZslice = np.zeros((256,512,512))
for i in range(t.shape[0]):
XZslice[i,:,:] = (Z1 - Z2) * t[i]/10.
cmap = plt.cm.rainbow
im = ax.pcolormesh(XZslice[128,:,:], cmap=cmap)
fig.colorbar(im)
axcolor = 'lightgoldenrodyellow'
axtime = plt.axes([0.25, 0.1, 0.65, 0.03], axisbg=axcolor)
stime = Slider(axtime, 'Time', 0.0, 100.0, valinit=50.0)
#Routines to reset and update sliding bar
def reset(event):
stime.reset()
def update(val):
time = int(stime.val/100.* 256)
im.set_array(XZslice[time,:,:].ravel())
fig.canvas.draw()
#Bind sliding bar and reset button
stime.on_changed(update)
resetax = plt.axes([0.8, 0.025, 0.1, 0.04])
button = Button(resetax, 'Reset', color=axcolor, hovercolor='0.975')
button.on_clicked(reset)
plt.show()