概要
pythonを使ってグラフをいっぱい書くプログラムを試しているのですが.
RuntimeError: Can not put single artist in more than one figure
というエラーが起きて困っています.
問題箇所
https://stackoverrun.com/ja/q/12300089
こちらのリンクでplt.figureを複数設定して解決されている話はあるのですが,
今のプログラムでうまくplt.figureを複数生成する方法が思いつきません.
def evalOneMax(ind): """Objective function.""" evaluation = 0 for dish in ind: evaluation += dish.calorie # TODO:グラフ領域を設定 #TODO:いい感じにトレーのサイズを外から引数として撮ってくるやり方がわからない直接書いた tray_size = np.array([370, 260]) fig = plt.figure() axis = fig.add_subplot(1, 1, 1, xlim=tray_size[0], ylim=tray_size[1], aspect='equal') for dish in ind: axis.add_patch(dish.fig)#<-----ここでエラーが発生 axis.axis("off") plt.savefig('tmp.png') fig.delaxes(axis) plt.clf() plt.cla() plt.close() del axis gray_img = cv2.imread('tmp.png') ind.img = gray_img ret, dishes_area_image = cv2.threshold(gray_img, 200, 255, cv2.THRESH_BINARY)#図形がある dishes_area = cv2.countNonZero(cv2.bitwise_not(cv2.cvtColor(dishes_area_image, cv2.COLOR_RGB2GRAY))) cv2.imwrite('dishes_area.png',dishes_area_image) ret, dishes_overlap_area_image = cv2.threshold(gray_img, 100, 255, cv2.THRESH_BINARY)#重なってて黒い cv2.imwrite('dishes_overlap_area.png',dishes_overlap_area_image) dishes_overlap_area = cv2.countNonZero(cv2.bitwise_not(cv2.cvtColor(dishes_overlap_area_image, cv2.COLOR_RGB2GRAY))) overlap_per = 1 - dishes_overlap_area/dishes_area return evaluation * overlap_per
プログラム全体
import random import numpy as np from operator import attrgetter import csv import matplotlib import matplotlib.pyplot as plt import cv2 # def main(): n_gene = 4 # The number of genes. n_ind = 300 # The number of individuals in a population. CXPB = 0.5 # The probability of crossover. MUTPB = 0.2 # The probability of individdual mutation. MUTINDPB = 0.05 # The probability of gene mutation. NGEN = 40 # The number of generation loop. dish_types= DishTypes() dish_types.load_file() random.seed(64) # --- Step1 : Create initial generation. pop = create_pop(n_ind, n_gene, dish_types) set_fitness(evalOneMax, pop) best_ind = max(pop, key=attrgetter("fitness")) # --- Generation loop. print("Generation loop start.") print("Generation: 0. Best fitness: " + str(best_ind.fitness)) fig_save(best_ind, '{:0=5}'.format(0)) for g in range(NGEN): # --- Step2 : Selection. offspring = selTournament(pop, n_ind, tournsize=3) # --- Step3 : Crossover. crossover = [] for child1, child2 in zip(offspring[::2], offspring[1::2]):# (偶数個目,奇数個目)で子孫を作成 if random.random() < CXPB: child1, child2 = cxTwoPointCopy(child1, child2) # child1.fitness = None # child2.fitness = None crossover.append(child1) crossover.append(child2) offspring = crossover[:] # --- Step4 : Mutation. mutant = [] for mut in offspring: if random.random() < MUTPB: mut = mutFlipBit(dish_types, mut, indpb=MUTINDPB) # mut.fitness = None mutant.append(mut) offspring = mutant[:] # --- Update next population. pop = offspring[:] set_fitness(evalOneMax, pop) # --- Print best fitness in the population. best_ind = max(pop, key=attrgetter("fitness")) print("Generation: " + str(g + 1) + ". Best fitness: " + str(best_ind.fitness)) fig_save(best_ind, dish_types, '{:0=5}'.format(g + 1)) print("Generation loop ended. The best individual: ") print(best_ind) class DishTypes: def __init__(self): self.num=0 self.type=[] self.size=[] self.name=[] self.calorie=[] self.protein=[] self.lipid=[] self.carbohydrate=[] self.calcium=[] self.price=[] self.tray_size=np.array([370, 260]) def load_file(self): with open('dish.csv') as f: reader = csv.reader(f) for row in reader: self.name.append(row[0]) self.type.append(int(row[1])) self.size.append(int(row[2])) self.calorie.append(float(row[3])) self.protein.append(float(row[4])) self.lipid.append(float(row[5])) self.carbohydrate.append(float(row[6])) self.calcium.append(float(row[7])) self.price.append(float(row[8])) self.num = len(self.name) class Dish: def __init__(self, id, dish_types): self.figure_type=dish_types.type[id] self.fig=create_figure(dish_types.type[id],dish_types.size[id],dish_types.tray_size) self.name=dish_types.name[id] self.calorie=dish_types.calorie[id] self.protein=dish_types.protein[id] self.lipid=dish_types.lipid[id] self.carbohydrate=dish_types.carbohydrate[id] self.calcium=dish_types.calcium[id] self.price=dish_types.price[id] class IndividualTray(list): """Container of a individual.""" fitness = None img = None def __new__(cls, a): return list.__new__(cls, a) def create_figure(fig_type, size, tray_size): x = random.randrange(size, tray_size[0] - size) y = random.randrange(size, tray_size[1] - size) if fig_type == 0: return matplotlib.patches.Rectangle((x, y), size, size, facecolor='black', alpha=0.5) if fig_type == 1: return matplotlib.patches.Circle((x, y), radius=size, facecolor='black', alpha=0.5) def create_ind(n_gene, dish_types): """Create a individual.""" return IndividualTray([Dish(random.randint(0, dish_types.num-1), dish_types) for i in range(n_gene)]) def create_pop(n_ind, n_gene, dish_types): """Create a population.""" pop = [] for i in range(n_ind): ind = create_ind(n_gene, dish_types) pop.append(ind) return pop def set_fitness(eval_func, pop): """Set fitnesses of each individual in a population.""" for i, fit in zip(range(len(pop)), map(eval_func, pop)): pop[i].fitness = fit def evalOneMax(ind): """Objective function.""" evaluation = 0 for dish in ind: evaluation += dish.calorie # TODO:グラフ領域を設定 #TODO:いい感じにトレーのサイズを外から引数として撮ってくるやり方がわからない直接書いた tray_size = np.array([370, 260]) fig = plt.figure() axis = fig.add_subplot(1, 1, 1, xlim=tray_size[0], ylim=tray_size[1], aspect='equal') for dish in ind: axis.add_patch(dish.fig) axis.axis("off") plt.savefig('tmp.png') fig.delaxes(axis) plt.clf() plt.cla() plt.close() del axis gray_img = cv2.imread('tmp.png') ind.img = gray_img ret, dishes_area_image = cv2.threshold(gray_img, 200, 255, cv2.THRESH_BINARY)#図形がある dishes_area = cv2.countNonZero(cv2.bitwise_not(cv2.cvtColor(dishes_area_image, cv2.COLOR_RGB2GRAY))) cv2.imwrite('dishes_area.png',dishes_area_image) ret, dishes_overlap_area_image = cv2.threshold(gray_img, 100, 255, cv2.THRESH_BINARY)#重なってて黒い cv2.imwrite('dishes_overlap_area.png',dishes_overlap_area_image) dishes_overlap_area = cv2.countNonZero(cv2.bitwise_not(cv2.cvtColor(dishes_overlap_area_image, cv2.COLOR_RGB2GRAY))) overlap_per = 1 - dishes_overlap_area/dishes_area return evaluation * overlap_per def selTournament(pop, n_ind, tournsize): """Selection function.""" chosen = [] for i in range(n_ind): aspirants = [random.choice(pop) for j in range(tournsize)]#適当にtournsizeこだけ個体を選ぶ chosen.append(max(aspirants, key=attrgetter("fitness")))#fitness属性の一番大きいものを選ぶ return chosen def cxTwoPointCopy(ind1, ind2): """Crossover function.""" size1 = len(ind1) size2 = len(ind2) tmp1 = ind1.copy() tmp2 = ind2.copy() cxpoint1 = int(size1/2) cxpoint2 = int(size2/2) tmp1, tmp2 = tmp2[:cxpoint2].copy()+tmp1[cxpoint1:].copy(), tmp1[:cxpoint1].copy()+tmp2[cxpoint2:].copy() return tmp1, tmp2 def mutFlipBit(dish_types, ind, indpb): """Mutation function.""" tmp = ind.copy() for i in range(len(ind)): if random.random() < indpb: rand = random.randint(0, 2) # 増やす if rand == 0: tmp[i] = ind.append(Dish(random.randint(0, dish_types.num-1), dish_types)) break # へらす if rand == 1: tmp[i] = ind.pop(random.randint(0,len(ind)-1)) break # 変える if rand == 2: randopos = random.randint(0, len(ind) - 1) tmp[i] = ind.pop(randopos) tmp[i] = ind.insert(randopos, random.randint(0, len(ind) - 1)) break return tmp def fig_save(ind, file_name): cv2.imwrite(',/img/'+file_name+'.png', ind.img) if __name__ == "__main__": main()
このままではコードが読めないので、質問を編集し、<code>ボタンを押し、出てくる’’’の枠の中にコードを貼り付けてください
ありがとうございます.
listで作ったらどうかと思ったのですが変わらずでした.
エラー発生箇所はどこですか?
```
for dish in ind:
axis.add_patch(dish.fig)#ここでエラーが発生
```
```
File "/Users/hoge/Desktop/hoge/fig_ga.py", line 161, in evalOneMax
axis.add_patch(dish.fig)
File "/usr/local/lib/python3.7/site-packages/matplotlib/axes/_base.py", line 1916, in add_patch
self._set_artist_props(p)
File "/usr/local/lib/python3.7/site-packages/matplotlib/axes/_base.py", line 905, in _set_artist_props
a.set_figure(self.figure)
File "/usr/local/lib/python3.7/site-packages/matplotlib/artist.py", line 712, in set_figure
raise RuntimeError("Can not put single artist in "
RuntimeError: Can not put single artist in more than one figure
```
エラーはこんな感じでした
・質問のプログラムは複雑そうですが、質問者さんご自身が作成されたものですか?
・問題を簡単にするためにもっと簡単なグラフから試された方が良いかと思います。(参考サイトのコードは動かしてみましたか?)
あなたの回答
tips
プレビュー