RuntimeError: Can not put single artist in more than one figureの解決の仕方がわからないです.
- 評価
- クリップ 0
- VIEW 363
概要
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()
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
まだ回答がついていません
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.33%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
質問への追記・修正の依頼
y_waiwai
2020/08/03 11:01
このままではコードが読めないので、質問を編集し、<code>ボタンを押し、出てくる’’’の枠の中にコードを貼り付けてください
RyosukeSHIBATA
2020/08/03 11:05
ありがとうございます.
RyosukeSHIBATA
2020/08/03 11:06
listで作ったらどうかと思ったのですが変わらずでした.
meg_
2020/08/03 12:43
エラー発生箇所はどこですか?
RyosukeSHIBATA
2020/08/03 14:18
```
for dish in ind:
axis.add_patch(dish.fig)#ここでエラーが発生
```
RyosukeSHIBATA
2020/08/03 14:35
```
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
```
RyosukeSHIBATA
2020/08/03 14:36
エラーはこんな感じでした
meg_
2020/08/03 17:09
・質問のプログラムは複雑そうですが、質問者さんご自身が作成されたものですか?
・問題を簡単にするためにもっと簡単なグラフから試された方が良いかと思います。(参考サイトのコードは動かしてみましたか?)