3

How can I read in four columns of data to create a surface plot which is colored by the fourth variable? In my case, the data was generated using four nested for loops, so the rightmost columns change most frequently while the leftmost columns change least frequently.

Here is what I've tried so far. It is creating a solid colored graph but the coloring is wrong.

import numpy as np
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
from matplotlib import cm
from mpl_toolkits.mplot3d import Axes3D
import pylab
from scipy.interpolate import griddata

dat = open('ex.csv', 'w')
dat.write('x,y,z,c\n')
for x in range(20):
    for y in range(20):
             dat.write(','.join([str(s) for s in [x,y,x+y,x+y,'\n']]))
dat.close()

fig = matplotlib.pyplot.gcf()
subdat = np.genfromtxt('ex.csv', delimiter=',',skiprows=1)
X = subdat[:,0]
Y = subdat[:,1]
Z = subdat[:,2]
C = subdat[:,3]

xi = np.linspace(X.min(),X.max(),100)
yi = np.linspace(Y.min(),Y.max(),100)

zi = griddata((X, Y), Z, (xi[None,:], yi[:,None]), method='cubic')
ci = griddata((X, Y), C, (xi[None,:], yi[:,None]), method='cubic')

ax1 = fig.add_subplot(111, projection='3d')

xig, yig = np.meshgrid(xi, yi)
surf = ax1.plot_surface(xig, yig, zi,facecolors=cm.rainbow(ci))

m = cm.ScalarMappable(cmap=cm.rainbow)
m.set_array(ci)
col = plt.colorbar(m)
plt.show()

enter image description here (coloring is wrong, should be the same as elevation value with continuous gradient)

kilojoules
  • 9,768
  • 18
  • 77
  • 149
  • Are you sure that the x,y,z point form a single surface? And you say, "unstructured data", but that data looks highly structured. What are you referring to? – tom10 Feb 22 '16 at 23:08
  • What I meant is that it's not arranged in a grid. I'll take that out I see that it's confusing. – kilojoules Feb 22 '16 at 23:11
  • Make sure the new size after reshape is compatible with the old data. In this case the size of your `dat['var1']` is 11 and you are trying to reshape it into 3X5. May be you need to fill in missing values for some combination of 'var1' and 'var2'. – hashmuke Feb 23 '16 at 00:02
  • @hashmuke sorry I edited my question so heavily your comment no longer appears relevant. Thank you for this comment it helped me develop my question. – kilojoules Feb 23 '16 at 23:12

1 Answers1

2

The problem here is that the facecolors aren't normalizing as might be expected. Try this, which does the normalizing explicitely:

norm = matplotlib.colors.Normalize()
surf = ax1.plot_surface(xig, yig, zi, facecolors=cm.rainbow(norm(ci)))

enter image description here

tom10
  • 67,082
  • 10
  • 127
  • 137
  • Thanks! Why are the j's here: `grid_x, grid_y = np.mgrid[0:1:100j, 0:1:100j]`? Is there a way this can be done for any X,Y data? It looks like your solution is limited to the bounds of my example. – kilojoules Feb 24 '16 at 01:30
  • Thanks again for your answer. I am leaving it un-checked, as I am looking for a solution to the general problem. – kilojoules Feb 24 '16 at 02:48
  • Also your color bar is off by a factor of 20 for some reason – kilojoules Feb 24 '16 at 03:21
  • @kilojoules: I've updated my answer. In my update, everything in the code is as is in your code except for the displayed lines. (In particular, your term `(xi[None,:], yi[:,None])`, which I first thought was the problem, seems to be fine.) – tom10 Feb 24 '16 at 04:25