Oliver Angelil
Oliver Angelil

Reputation: 1284

something like plt.matshow but with triangles

Basically, I'd like to make something like the following (triangles not squares as is typically used with plt.matshow). enter image description here

One could start with four 2D arrays, each representing the values for the colours of a set of triangles: right, left, bottom, top:

import numpy as np
right=np.random.randn(8, 8)
left=np.random.randn(8, 8)
bottom=np.random.randn(8, 8)
top=np.random.randn(8, 8)

But I have no idea about the plotting...

Upvotes: 3

Views: 1063

Answers (3)

Jared Vargason
Jared Vargason

Reputation: 1

I used ImportanceOfBeingErnest's code to plot the Q-table for a reinforcement learning project- I wanted to understand it so I went through and made it a bit clearer. Just replace the data (up, down, left, right) with your own.

def showQVals(self):
    fig, ax = plt.subplots()

    rows = self.level.NUM_ROWS
    cols = self.level.NUM_COLUMNS

    up = self.q[:,Action.UP].reshape(rows, cols)
    down = self.q[:,Action.DOWN].reshape(rows, cols)
    right = self.q[:,Action.RIGHT].reshape(rows, cols)
    left = self.q[:,Action.LEFT].reshape(rows, cols)

    vertDims = np.array([[0,0],[0,1],[.5,.5],[1,0],[1,1]])
    UP = [1,2,4]
    DOWN = [0,2,3]
    RIGHT = [2,3,4]
    LEFT = [0,1,2]
    triDims = np.array([DOWN, UP, RIGHT, LEFT])

    verts = np.zeros((rows*cols*5,2))
    tris = np.zeros((rows*cols*4,3))

    for row in range(rows): #i
        for col in range(cols): #j
            cell = row*cols+col

            #assign slices to the newly constructed verts and tris
            verts[cell*5:(cell+1)*5,:] = np.c_[vertDims[:,0]+col, vertDims[:,1]+row]
            tris[cell*4:(cell+1)*4,:] = triDims + cell*5

    C = np.c_[ up.flatten(), down.flatten(), 
            right.flatten(), left.flatten()   ].flatten()

    ax.invert_yaxis()
    ax.set_title('Q Values')

    triplot = ax.triplot(verts[:,0], verts[:,1], tris)
    tripcolor = ax.tripcolor(verts[:,0], verts[:,1], tris, facecolors=C)

    fig.colorbar(tripcolor)
    plt.show()

q table figure based off of grid map

Upvotes: -1

ImportanceOfBeingErnest
ImportanceOfBeingErnest

Reputation: 339170

You may indeed use tripcolor to plot a set of triangles. In the code below the function quatromatrix takes 4 2D arrays of values to colormap as input, creates the triangles and rearanges the colors to fit to the respective positions. It is thus very similar to plotting 4 imshow plots.

enter image description here

import matplotlib.pyplot as plt
import numpy as np

def quatromatrix(left, bottom, right, top, ax=None, triplotkw={},tripcolorkw={}):
    if not ax: ax=plt.gca()
    n = left.shape[0]; m=left.shape[1]

    a = np.array([[0,0],[0,1],[.5,.5],[1,0],[1,1]])
    tr = np.array([[0,1,2], [0,2,3],[2,3,4],[1,2,4]])

    A = np.zeros((n*m*5,2))
    Tr = np.zeros((n*m*4,3))

    for i in range(n):
        for j in range(m):
            k = i*m+j
            A[k*5:(k+1)*5,:] = np.c_[a[:,0]+j, a[:,1]+i]
            Tr[k*4:(k+1)*4,:] = tr + k*5

    C = np.c_[ left.flatten(), bottom.flatten(), 
              right.flatten(), top.flatten()   ].flatten()

    triplot = ax.triplot(A[:,0], A[:,1], Tr, **triplotkw)
    tripcolor = ax.tripcolor(A[:,0], A[:,1], Tr, facecolors=C, **tripcolorkw)
    return tripcolor


right=np.random.randn(8, 8)
left=np.random.randn(8, 8)
bottom=np.random.randn(8, 8)
top=np.random.randn(8, 8)

fig, ax=plt.subplots()

quatromatrix(left, bottom, right, top, ax=ax,
             triplotkw={"color":"k", "lw":1},
             tripcolorkw={"cmap": "plasma"}) 

ax.margins(0)
ax.set_aspect("equal")

Upvotes: 3

jonie83
jonie83

Reputation: 1156

See the example matplotlib.pyplot.tripcolor(*args, **kwargs) in the matplotlib documentation here. Here is a simplyfied version of want you need:

import matplotlib.pyplot as plt
import numpy as np

xy = np.asarray([
    [-0.01, 0.872], [-0.080, 0.883], [-0.069, 0.888], [-0.054, 0.890]])

x = xy[:, 0]*180/3.14159
y = xy[:, 1]*180/3.14159

triangles = np.asarray([[3, 2,  0]  , [3,  1, 2],   [ 0, 2,  1] , 
                        [0,  1, 2]])

xmid = x[triangles].mean(axis=1)
ymid = y[triangles].mean(axis=1)
x0 = -5
y0 = 52
zfaces = np.exp(-0.01*((xmid - x0)*(xmid - x0) + 
                (ymid - y0)*(ymid - y0)))


plt.figure()
plt.gca().set_aspect('equal')
plt.tripcolor(x, y, triangles, facecolors=zfaces, edgecolors='k')
plt.colorbar()
plt.title('tripcolor of user-specified triangulation')
plt.xlabel('Longitude (degrees)')
plt.ylabel('Latitude (degrees)')

plt.show()

You should get the following picture: enter image description here

Upvotes: 0

Related Questions