I am trying to create a colored line with certain conditions. Basically I would like to have the line colored red when pointing down on the y axis, green when pointing up and blue when neither.
I played around with some similar examples I found but I have never been able to convert them to work with plot() on an axis. Just wondering how this could be done.
Here is some code that I have come up with so far:
#create x,y coordinates
x = numpy.random.choice(10,10)
y = numpy.random.choice(10,10)
#create an array of colors based on direction of line (0=r, 1=g, 2=b)
colors = []
#create an array that is one position away from original
#to determine direction of line
yCopy = list(y[1:])
for y1,y2 in zip(y,yCopy):
if y1 > y2:
colors.append(0)
elif y1 < y2:
colors.append(1)
else:
colors.append(2)
#add tenth spot to array as loop only does nine
colors.append(2)
#create a numpy array of colors
categories = numpy.array(colors)
#create a color map with the three colors
colormap = numpy.array([matplotlib.colors.colorConverter.to_rgb('r'),matplotlib.colors.colorConverter.to_rgb('g'),matplotlib.colors.colorConverter.to_rgb('b')])
#plot line
matplotlib.axes.plot(x,y,color=colormap[categories])
Not sure how to get plot() to accept an array of colors. I always get an error about the format type used as the color. Tried heximal, decimal, string and float. Works perfect with scatter().
I don't think that you can use an array of colors in plot (the documentation says that color can be any matlab color, while the scatter docs say you can use an array).
However, you could fake it by plotting each line separately:
import numpy
from matplotlib import pyplot as plt
x = range(10)
y = numpy.random.choice(10,10)
for x1, x2, y1,y2 in zip(x, x[1:], y, y[1:]):
if y1 > y2:
plt.plot([x1, x2], [y1, y2], 'r')
elif y1 < y2:
plt.plot([x1, x2], [y1, y2], 'g')
else:
plt.plot([x1, x2], [y1, y2], 'b')
plt.show()
OK. So I figured out how to do it using LineCollecion to draw the line on a axis.
import numpy as np
import pylab as pl
from matplotlib import collections as mc
segments = []
colors = np.zeros(shape=(10,4))
x = range(10)
y = np.random.choice(10,10)
i = 0
for x1, x2, y1,y2 in zip(x, x[1:], y, y[1:]):
if y1 > y2:
colors[i] = tuple([1,0,0,1])
elif y1 < y2:
colors[i] = tuple([0,1,0,1])
else:
colors[i] = tuple([0,0,1,1])
segments.append([(x1, y1), (x2, y2)])
i += 1
lc = mc.LineCollection(segments, colors=colors, linewidths=2)
fig, ax = pl.subplots()
ax.add_collection(lc)
ax.autoscale()
ax.margins(0.1)
pl.show()
There is an example on the matplotlib page showing how to use a LineCollection to plot a multicolored line.
The remaining problem is to get the colors for the line collection. So if y are the values to compare,
cm = dict(zip(range(-1,2,1),list("gbr")))
colors = list( map( cm.get , np.sign(np.diff(y)) ))
Complete code:
import numpy as np; np.random.seed(5)
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
x = np.arange(10)
y = np.random.choice(10,10)
points = np.array([x, y]).T.reshape(-1, 1, 2)
segments = np.concatenate([points[:-1], points[1:]], axis=1)
cm = dict(zip(range(-1,2,1),list("rbg")))
colors = list( map( cm.get , np.sign(np.diff(y)) ))
lc = LineCollection(segments, colors=colors, linewidths=2)
fig, ax = plt.subplots()
ax.add_collection(lc)
ax.autoscale()
ax.margins(0.1)
plt.show()
Related
Disclaimer: I'm a total newb to this, 2nd day so pls bear with me, thank you in advance!
So, I managed to get my 3D plot to have multiple lines, but I would like to give them some color gradients. I've managed to get it onto one example line, but I cannot convert it to my own plots.
My plots come from a .csv
I followed this question for the gradients: https://stackoverflow.com/a/8505774/20387853 (Answer by Yann) but I can't seem to understand how to merge the two for i in range bits (one from my old code with the new code) (if it even can be?)
I also dont understand ax.plot(x[i:i+2],y[i:i+2]) so I couldn't adjust this like I thought I could.
SO ATM i have two scripts
Script 1 - in which I'm trying to merge my two data sets.
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import sys
import pandas
points = pandas.read_csv('D:Documents\PYTHON_FILES/test3d.csv')
def highResPoints(x,y,factor=10):
# r is the distance spanned between pairs of points
r = [0]
for i in range(1,len(x)):
dx = x[i]-x[i-1]
dy = y[i]-y[i-1]
r.append(np.sqrt(dx*dx+dy*dy))
r = np.array(r)
# rtot is a cumulative sum of r, it's used to save time
rtot = []
for i in range(len(r)):
rtot.append(r[0:i].sum())
rtot.append(r.sum())
dr = rtot[-1]/(NPOINTS*RESFACT-1)
xmod=[x[0]]
ymod=[y[0]]
rPos = 0 # current point on walk along data
rcount = 1
while rPos < r.sum():
x1,x2 = x[rcount-1],x[rcount]
y1,y2 = y[rcount-1],y[rcount]
dpos = rPos-rtot[rcount]
theta = np.arctan2((x2-x1),(y2-y1))
rx = np.sin(theta)*dpos+x1
ry = np.cos(theta)*dpos+y1
xmod.append(rx)
ymod.append(ry)
rPos+=dr
while rPos > rtot[rcount+1]:
rPos = rtot[rcount+1]
rcount+=1
if rcount>rtot[-1]:
break
return xmod,ymod
#CONSTANTS
NPOINTS = 10
COLOR='red'
RESFACT=10
MAP='winter' # choose carefully, or color transitions will not appear smoooth
cm = plt.get_cmap(MAP)
################ These are old data sets, just to use for this example
x = points['x'].values
y = points['y'].values
z = points['z'].values
x2 = points['x2'].values
y2 = points['y2'].values
z2 = points['z2'].values
fig = plt.figure()
#ax1 = fig.add_subplot(111,projection='3d') # regular resolution color map
ax = fig.add_subplot(111, projection='3d')
ax.plot(x, y, z, c='red',marker='v', linewidth=1.0, markersize=2)
ax.plot(x2, y2, z2, c='blue', marker='o', linewidth=1.0, markersize=2)
ax.set_prop_cycle(color=[cm(1.*i/(NPOINTS-1)) for i in range(NPOINTS-1)])
for i in range(NPOINTS-1):
#ax1.plot(x[i:i+2],y[i:i+2])
ax.plot(x[i:i+2],y[i:i+2])
########################The part I want to merge in
#for i in range(1, 5):
#if i == 1: i = '' #x is your first value not x1
#ax.plot(points[f"x{i}"], points[f"y{i}"], points[f"z{i}"], c='red', marker='o', linewidth=1.0, markersize=2)
#########################
fig.savefig('colorgradienttest.png')
plt.show()
[Link to Image]
I want to make the blue and red lines have a color gradient like the example 3rd line (markers are not important)
Script 2 - to which I want to apply the gradient (the one with the .csv)
from mpl_toolkits.mplot3d import Axes3D
import sys
import matplotlib.pyplot as plt
import pandas
import numpy as np
points = pandas.read_csv('D:Documents\PYTHON_FILES/test3d.csv')
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
#OPTION 1 - not sure why this isn't working for me so Im not using it yet
#for idx in range(29):
# suffix = '' if idx == 0 else str(idx + 1) # ranges start at 0
# x = points[f"x{suffix}"].values
# y = points[f"y{suffix}"].values
# z = points[f"z{suffix}"].values
#ax.plot(x, y, z, c='red', marker='o', linewidth=1.0, markersize=2)
#OPTION 2 - current approach <<<<<<<<<<<<<<<< want to apply gradient to this segment
for i in range(1, 5):
if i == 1: i = '' #x is your first value not x1
ax.plot(points[f"x{i}"], points[f"y{i}"], points[f"z{i}"], c='red', marker='o', linewidth=1.0, markersize=2)
plt.show()
I am trying to 3d plot below data, with height being the respecitive joint probability from probability mass function. The idea is to visualize covariance. I had to go 3D because, the probabilities varies for different combinations of sample. The bars or boxes overlap each other in weird ways that I am unable to infer a proper 3d perspective in different angles. If you look at below gif you will know (box suddenly grows over each other at few angles out of nowhere). Kindly help how to resolve this issue. Also alpha is not working.
Issues:
1. Weird 3d boxes rendering
2. Alpha also not working
Problematic output:
MWE (jupyter):
%matplotlib inline
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from itertools import product
from mpl_toolkits.mplot3d import Axes3D
X , Y = [100,250], [0,100,200]
xb, yb = 175, 125
import pandas as pd
matrix = np.array([
[0.20, 0.10, 0.20],
[0.05, 0.15, 0.30]
])
df = pd.DataFrame(matrix, columns=Y)
df.index = [100, 250]
top = 1
fig = plt.figure(figsize=(15,5))
ax1 = fig.add_subplot(121)
for xy in product(X,Y):
x,y = xy[0], xy[1]
z = df.loc[x,y]
d1, d2 = xb - x, yb - y
color = 'green' if d1*d2 > 0 else 'red'
ax1.add_patch(patches.Rectangle((x, y), d1, d2, alpha=z, facecolor=color))
ax1.scatter(x,y,color='black')
ax1.axvline(x=Xb, ls=':', color='blue')
ax1.axhline(y=Yb, ls=':', color='blue')
ax1.set_xticks(X)
ax1.set_yticks(Y)
ax1.set_xlim([min(X)-50,max(X)+50])
ax1.set_ylim([min(Y)-50,max(Y)+50])
ax2 = fig.add_subplot(122, projection='3d')
ax2.view_init(elev=30., azim=-50)
for xy in product(X,Y):
x ,y = xy[0], xy[1]
z = df.loc[x,y]
# print(x, y, z)
width = x - 175
depth = y - 125
pro = width*depth
top = z
bottom = np.zeros_like(top)
if pro > 0: #positive
color='#B9F6CA'
else:
color='#EF9A9A'
ax2.bar3d(x, y, bottom, -width, -depth, top, color=color)
ax2.scatter(x, y, z, color='blue')
def rotate(angle):
ax2.view_init(azim=angle)
from matplotlib import animation
ani = animation.FuncAnimation(fig, rotate, frames=np.arange(0,362,2),interval=100)
from IPython.display import HTML
plt.close()
HTML(ani.to_jshtml())
Related math problem:
I am trying to create a colored line with certain conditions. Basically I would like to have the line colored red when pointing down on the y axis, green when pointing up and blue when neither.
I played around with some similar examples I found but I have never been able to convert them to work with plot() on an axis. Just wondering how this could be done.
Here is some code that I have come up with so far:
#create x,y coordinates
x = numpy.random.choice(10,10)
y = numpy.random.choice(10,10)
#create an array of colors based on direction of line (0=r, 1=g, 2=b)
colors = []
#create an array that is one position away from original
#to determine direction of line
yCopy = list(y[1:])
for y1,y2 in zip(y,yCopy):
if y1 > y2:
colors.append(0)
elif y1 < y2:
colors.append(1)
else:
colors.append(2)
#add tenth spot to array as loop only does nine
colors.append(2)
#create a numpy array of colors
categories = numpy.array(colors)
#create a color map with the three colors
colormap = numpy.array([matplotlib.colors.colorConverter.to_rgb('r'),matplotlib.colors.colorConverter.to_rgb('g'),matplotlib.colors.colorConverter.to_rgb('b')])
#plot line
matplotlib.axes.plot(x,y,color=colormap[categories])
Not sure how to get plot() to accept an array of colors. I always get an error about the format type used as the color. Tried heximal, decimal, string and float. Works perfect with scatter().
I don't think that you can use an array of colors in plot (the documentation says that color can be any matlab color, while the scatter docs say you can use an array).
However, you could fake it by plotting each line separately:
import numpy
from matplotlib import pyplot as plt
x = range(10)
y = numpy.random.choice(10,10)
for x1, x2, y1,y2 in zip(x, x[1:], y, y[1:]):
if y1 > y2:
plt.plot([x1, x2], [y1, y2], 'r')
elif y1 < y2:
plt.plot([x1, x2], [y1, y2], 'g')
else:
plt.plot([x1, x2], [y1, y2], 'b')
plt.show()
OK. So I figured out how to do it using LineCollecion to draw the line on a axis.
import numpy as np
import pylab as pl
from matplotlib import collections as mc
segments = []
colors = np.zeros(shape=(10,4))
x = range(10)
y = np.random.choice(10,10)
i = 0
for x1, x2, y1,y2 in zip(x, x[1:], y, y[1:]):
if y1 > y2:
colors[i] = tuple([1,0,0,1])
elif y1 < y2:
colors[i] = tuple([0,1,0,1])
else:
colors[i] = tuple([0,0,1,1])
segments.append([(x1, y1), (x2, y2)])
i += 1
lc = mc.LineCollection(segments, colors=colors, linewidths=2)
fig, ax = pl.subplots()
ax.add_collection(lc)
ax.autoscale()
ax.margins(0.1)
pl.show()
There is an example on the matplotlib page showing how to use a LineCollection to plot a multicolored line.
The remaining problem is to get the colors for the line collection. So if y are the values to compare,
cm = dict(zip(range(-1,2,1),list("gbr")))
colors = list( map( cm.get , np.sign(np.diff(y)) ))
Complete code:
import numpy as np; np.random.seed(5)
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
x = np.arange(10)
y = np.random.choice(10,10)
points = np.array([x, y]).T.reshape(-1, 1, 2)
segments = np.concatenate([points[:-1], points[1:]], axis=1)
cm = dict(zip(range(-1,2,1),list("rbg")))
colors = list( map( cm.get , np.sign(np.diff(y)) ))
lc = LineCollection(segments, colors=colors, linewidths=2)
fig, ax = plt.subplots()
ax.add_collection(lc)
ax.autoscale()
ax.margins(0.1)
plt.show()
I am trying to create a colored line with certain conditions. Basically I would like to have the line colored red when pointing down on the y axis, green when pointing up and blue when neither.
I played around with some similar examples I found but I have never been able to convert them to work with plot() on an axis. Just wondering how this could be done.
Here is some code that I have come up with so far:
#create x,y coordinates
x = numpy.random.choice(10,10)
y = numpy.random.choice(10,10)
#create an array of colors based on direction of line (0=r, 1=g, 2=b)
colors = []
#create an array that is one position away from original
#to determine direction of line
yCopy = list(y[1:])
for y1,y2 in zip(y,yCopy):
if y1 > y2:
colors.append(0)
elif y1 < y2:
colors.append(1)
else:
colors.append(2)
#add tenth spot to array as loop only does nine
colors.append(2)
#create a numpy array of colors
categories = numpy.array(colors)
#create a color map with the three colors
colormap = numpy.array([matplotlib.colors.colorConverter.to_rgb('r'),matplotlib.colors.colorConverter.to_rgb('g'),matplotlib.colors.colorConverter.to_rgb('b')])
#plot line
matplotlib.axes.plot(x,y,color=colormap[categories])
Not sure how to get plot() to accept an array of colors. I always get an error about the format type used as the color. Tried heximal, decimal, string and float. Works perfect with scatter().
I don't think that you can use an array of colors in plot (the documentation says that color can be any matlab color, while the scatter docs say you can use an array).
However, you could fake it by plotting each line separately:
import numpy
from matplotlib import pyplot as plt
x = range(10)
y = numpy.random.choice(10,10)
for x1, x2, y1,y2 in zip(x, x[1:], y, y[1:]):
if y1 > y2:
plt.plot([x1, x2], [y1, y2], 'r')
elif y1 < y2:
plt.plot([x1, x2], [y1, y2], 'g')
else:
plt.plot([x1, x2], [y1, y2], 'b')
plt.show()
OK. So I figured out how to do it using LineCollecion to draw the line on a axis.
import numpy as np
import pylab as pl
from matplotlib import collections as mc
segments = []
colors = np.zeros(shape=(10,4))
x = range(10)
y = np.random.choice(10,10)
i = 0
for x1, x2, y1,y2 in zip(x, x[1:], y, y[1:]):
if y1 > y2:
colors[i] = tuple([1,0,0,1])
elif y1 < y2:
colors[i] = tuple([0,1,0,1])
else:
colors[i] = tuple([0,0,1,1])
segments.append([(x1, y1), (x2, y2)])
i += 1
lc = mc.LineCollection(segments, colors=colors, linewidths=2)
fig, ax = pl.subplots()
ax.add_collection(lc)
ax.autoscale()
ax.margins(0.1)
pl.show()
There is an example on the matplotlib page showing how to use a LineCollection to plot a multicolored line.
The remaining problem is to get the colors for the line collection. So if y are the values to compare,
cm = dict(zip(range(-1,2,1),list("gbr")))
colors = list( map( cm.get , np.sign(np.diff(y)) ))
Complete code:
import numpy as np; np.random.seed(5)
import matplotlib.pyplot as plt
from matplotlib.collections import LineCollection
x = np.arange(10)
y = np.random.choice(10,10)
points = np.array([x, y]).T.reshape(-1, 1, 2)
segments = np.concatenate([points[:-1], points[1:]], axis=1)
cm = dict(zip(range(-1,2,1),list("rbg")))
colors = list( map( cm.get , np.sign(np.diff(y)) ))
lc = LineCollection(segments, colors=colors, linewidths=2)
fig, ax = plt.subplots()
ax.add_collection(lc)
ax.autoscale()
ax.margins(0.1)
plt.show()
I've looked at the documentation, but I can't seem to figure out if this is possible -
I have a dataset, with x and y values and discrete z values. Multiple pairs of (x,y) share the same z value. What I want to do is when I mouseover one point with a particular z value, the alpha of all the points with the same z values goes to 1 - i.e., If all the alpha values are initially 0.5, I'd like only the points with the same z value to go to 1.
Here's a minimal working example to illustrate what I'm talking about :
#! /usr/bin/env python
import numpy as np
import matplotlib.pyplot as plt
x = np.random.randn(100)
y = np.random.randn(100)
z = np.arange(0, 10, 1)
z = np.repeat(z, 10)
im = plt.scatter(x, y, c=z, alpha = 0.5)
plt.colorbar(im)
plt.show()
You can probably fake what you want to achieve using a second plot:
import numpy as np
import matplotlib.pyplot as plt
Z = np.zeros(1000, dtype = [("Z", int), ("P", float, 2)])
Z["P"] = np.random.uniform(0.0,1.0,(len(Z),2))
Z["Z"] = np.random.randint(0,50,len(Z))
def on_pick(event):
z = Z[event.ind[0]]['Z']
P = Z[np.where(Z["Z"] == z)]["P"]
selection_plot.set_data(P[:,0],P[:,1])
plt.draw()
fig = plt.figure(figsize=(10,10), facecolor='white')
fig.canvas.mpl_connect('pick_event', on_pick)
ax = plt.subplot(111, aspect=1)
ax.plot(Z['P'][:,0], Z['P'][:,1], 'o', color='k', alpha=0.1, picker=5)
selection_plot, = ax.plot([],[], 'o', color='black', alpha=1.0, zorder=10)
plt.show()