Search code examples
pythonmatplotlibplotfigures

Python plotting to different figures fails


EDIT: I figured out that the Problem always occours if one tries to plot to two different lists of figures. Does that mean that one can not do plots to different figure-lists in the same loop? See latest code for much simpler sample of a problem.

I try to analyze a complex set of data which consists basically about measurements of electric devices under different conditions. Hence, the code is a bit more complex but I tried to strip it down to a working example - however it is still pretty long. Hence, let me explain what you see: You see 3 classes with Transistor representing an electronic device. It's attribute Y represents the measurement data - consisting of 2 sets of measurements. Each Transistor belongs to a group - 2 in this example. And some groups belong to the same series - one series where both groups are included in this example.

The aim is now to plot all measurement data for each Transistor (not shown), then to also plot all data belonging to the same group in one plot each and all data of the same series to one plot. In order to program it in an efficent way without having a lot of loops my idea was to use the object orientated nature of matplotlib - I will have figures and subplots for each level of plotting (initialized in initGrpPlt and initSeriesPlt) which are then filled with only one loop over all Transistors (in MainPlt: toGPlt and toSPlt). In the end it should only be printed / saved to a file / whatever (PltGrp and PltSeries).

The Problem: Even though I specify where to plot, python plots the series plots into the group plots. You can check this yourself by running the code with the line 'toSPlt(trans,j)' and without. I have no clue why python does this because in the function toSPlt I explicetly say that python should use the subplots from the series-subplot-list. Would anyone have an idea to why this is like this and how to solve this problem in an elegent way?

Read the code from the bottom to the top, that should help with understanding.

Kind regards

# -*- coding: utf-8 -*-


import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np

maxNrVdrain = 2


X = np.linspace(-np.pi, np.pi, 256,endpoint=True)
A = [[1*np.cos(X),2*np.cos(X),3*np.cos(X),4*np.cos(X)],[1*np.tan(X),2*np.tan(X),3*np.tan(X),4*np.tan(X)]]
B = [[2* np.sin(X),4* np.sin(X),6* np.sin(X),8* np.sin(X)],[2*np.cos(X),4*np.cos(X),6*np.cos(X),8*np.cos(X)]]

class Transistor(object):
    _TransRegistry = []

    def __init__(self,y1,y2):
        self._TransRegistry.append(self)
        self.X = X
        self.Y = [y1,y2]
        self.group = ''

class Groups():
    _GroupRegistry = []

    def __init__(self,trans):
        self._GroupRegistry.append(self)
        self.transistors = [trans]
        self.figlist = []
        self.axlist = []

class Series():
    _SeriesRegistry = []

    def __init__(self,group):
        self._SeriesRegistry.append(self)
        self.groups = [group]
        self.figlist = []
        self.axlist = []


def initGrpPlt():
    for group in Groups._GroupRegistry:
        for j in range(maxNrVdrain):
            group.figlist.append(plt.figure(j))
            group.axlist.append(group.figlist[j].add_subplot(111))
    return

def initSeriesPlt():
    for series in Series._SeriesRegistry:
        for j in range(maxNrVdrain):
            series.figlist.append(plt.figure(j))
            series.axlist.append(series.figlist[j].add_subplot(111))
    return

def toGPlt(trans,j):
    colour = cm.rainbow(np.linspace(0, 1, 4))
    group = trans.group
    group.axlist[j].plot(trans.X,trans.Y[j], color=colour[group.transistors.index(trans)], linewidth=1.5, linestyle="-")
    return

def toSPlt(trans,j):
    colour = cm.rainbow(np.linspace(0, 1, 2))
    series = Series._SeriesRegistry[0]
    group = trans.group
    if group.transistors.index(trans) == 0:
        series.axlist[j].plot(trans.X,trans.Y[j],color=colour[series.groups.index(group)], linewidth=1.5, linestyle="-", label = 'T = nan, RH = nan' )
    else:
        series.axlist[j].plot(trans.X,trans.Y[j],color=colour[series.groups.index(group)], linewidth=1.5, linestyle="-")
    return

def PltGrp(group,j):
    ax = group.axlist[j]
    ax.set_title('Test Grp')
    return

def PltSeries(series,j):
    ax = series.axlist[j]
    ax.legend(loc='upper right', frameon=False)
    ax.set_title('Test Series')
    return


def MainPlt():
    initGrpPlt()
    initSeriesPlt()
    for trans in Transistor._TransRegistry:
        for j in range(maxNrVdrain):
            toGPlt(trans,j)
            toSPlt(trans,j)#plots to group plot for some reason
    for j in range(maxNrVdrain):
        for group in Groups._GroupRegistry:
            PltGrp(group,j)
    plt.show()
    return

def Init():
    for j in range(4):
        trans = Transistor(A[0][j],A[1][j])
        if j == 0:
            Groups(trans)
        else:
            Groups._GroupRegistry[0].transistors.append(trans)
        trans.group = Groups._GroupRegistry[0]
    Series(Groups._GroupRegistry[0])
    for j in range(4):
        trans = Transistor(B[0][j],B[1][j])
        if j == 0:
            Groups(trans)
        else:
            Groups._GroupRegistry[1].transistors.append(trans)
        trans.group = Groups._GroupRegistry[1]
    Series._SeriesRegistry[0].groups.append(Groups._GroupRegistry[1])
    return

def main():
    Init()
    MainPlt()
    return


main()

latest example that does not work:

import matplotlib.pyplot as plt
import matplotlib.cm as cm
import numpy as np



X = np.linspace(-np.pi, np.pi, 256,endpoint=True)

Y1 = np.cos(X)
Y2 = np.sin(X)

figlist1 = []
figlist2 = []

axlist1 = []
axlist2 = []



for j in range(4):
    figlist1.append(plt.figure(j))
    axlist1.append(figlist1[j].add_subplot(111))
    figlist2.append(plt.figure(j))#this should be a new set of figures!
    axlist2.append(figlist2[j].add_subplot(111))
    colour = cm.rainbow(np.linspace(0, 1, 4))
    axlist1[j].plot(X,j*Y1, color=colour[j], linewidth=1.5, linestyle="-")
    axlist1[j].set_title('Test Grp 1')
    colour = cm.rainbow(np.linspace(0, 1, 4))
    axlist2[j].plot(X,j*Y2, color=colour[int(j/2)], linewidth=1.5, linestyle="-")
    axlist2[j].set_title('Test Grp 2')
plt.show()

Solution

  • Ok, stupid mistake if one thinks of the Background but maybe someone has a similar Problem and is unable to see the cause as I was first. So here is the solution:

    The Problem is that the Name of the listobjects like figlist1[j] do not define the figure - they are just pointers to the actual figure object. and if such an object is created by plt.figure(j) one has to make sure that j is different for each figure - hence, in a Loop where multiple figures shall be initialized one Needs to somehow Change the number of the figure or the first object will be overwritten. Hope that helps! Cheers.