How to get a unique plot when using matplolib gca()? - python

I am working on a program to add text labels above dots in a matplolib's 3d animation.
However when I use gca() to work on my label's axis (ax); I end up with two figures when calling plt.show().
two figures instead of one
---The program starts here---
import numpy as np
from PyAstronomy import pyasl
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from mpl_toolkits.mplot3d import proj3d
import mpl_toolkits.mplot3d.axes3d as p3
satellites_values = [[1.0, 2.0, 0.50, 0.0, 30.0, 0.0], [1.0, 1.0, 0.20, 0.0, 90.0, 0.0], [10.0, 2.0, 0.39, 0.0, 180.0, 0.0]]
satellites_pos = []
red_dots_pos = []
fig = plt.figure()
ax = plt.figure().gca(projection='3d')
anim = []
def update(i, pos, red_dot, annotation):
red_dot.set_data([pos[i][1], pos[i][0]])
red_dot.set_3d_properties(pos[i][2])
x2, y2, _ = proj3d.proj_transform(pos[i][1], pos[i][0], pos[i][2], ax.get_proj())
annotation.set_position((x2,y2))
return red_dot, annotation
def create_system(satellites_list):
for satellite in satellites_list:
t = np.linspace(0, 4, 200)
orbit = pyasl.KeplerEllipse(a=satellite[0], per=satellite[1], e=satellite[2], Omega=satellite[3], i=satellite[4], w=satellite[5])
pos = orbit.xyzPos(t)
red_dot, = ax .plot(pos[::, 1], pos[::, 0], pos[::, 2], 'ro')
text = 'aaa'
annotation = ax.text2D(pos[::, 1],pos[::, 0], text)
anim.append(animation.FuncAnimation(fig, update, 200, fargs=(pos, red_dot, annotation), interval=100, blit=False))
ax.plot(pos[::, 1], pos[::, 0], pos[::, 2], 'k-')
create_system(satellites_values)
ax.plot([0], [0], [0], 'bo', markersize=20, label="Earth")
# Hide grid lines
ax.grid(False)
# Hide axes ticks
ax.set_xticks([])
ax.set_yticks([])
ax.set_zticks([])
plt.style.use('default')
plt.legend()
plt.show() ```
When I try:
ax = fig.gca(projection='3d')
or
ax = fig.add_subplot(111, projection='3d')
I get the following error:
TypeError: only size-1 arrays can be converted to Python scalars.
I want to have a unique figure because this program is part of a GUI that's supposed to show the dots with their label.
I was wondering if anyone here knew how to fix this.

Related

IDLE isn't plotting some colormap examples that I've searched for online to learn how to use colormaps by myself. Is IDLE the problem or is it my code

I tried 3 examples and none worked:
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
def fig1():
#import data and create dataframe
wine_url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/wine/wine.data'
wine_column_headers = ['Alcohol','Malic acid','Ash','Alcalinity of ash',
'Magnesium','Total phenols','Flavanoids',
'Nonflavanoid phenols','Proanthocyanins','Color intensity',
'Hue','OD280/OD315 of diluted wines' ,'Proline']
wine_df = pd.read_csv(wine_url, names = wine_column_headers)
#figure
fig, ax1 = plt.subplots()
fig.set_size_inches(13, 10)
#labels
ax1.set_xlabel('Alcohol')
ax1.set_ylabel('Color Intensity')
ax1.set_title('Relationship Between Color Intensity and Alcohol Content in Wines')
#c sequence
c = wine_df['Color intensity']
#plot
plt.scatter( wine_df['Alcohol'], wine_df['Color intensity'] , c=c,
cmap = 'RdPu', s = wine_df['Proline']*.5, alpha =0.5)
cbar = plt.colorbar()
cbar.set_label('Color Intensity')
print("fig1 complete")
#############################################################################
def fig2():
x = np.arange(0, 100)
y = x
t = x
df = pd.DataFrame([x,y]).T
df.plot(kind="scatter", x=0, y=1, c=t, cmap="jet")
print("fig2 complete")
#############################################################################
def fig3():
df = pd.DataFrame([[5.1, 3.5, 0], [4.9, 3.0, 0], [7.0, 3.2, 1],
[6.4, 3.2, 1], [5.9, 3.0, 2]],
columns=['length', 'width', 'species'])
ax1 = df.plot.scatter(x='length', y='width', c='DarkBlue')
print("fig3 complete")
fig1()
fig2()
fig3()
It only prints the last lines, so there is a problem with the plots. Am I missing any argument that I've overlooked?
I expected to get the same images as in other people's codes:
pandas.DataFrame.plot showing colormap inconsistently
example 2
https://betterprogramming.pub/how-to-use-colormaps-with-matplotlib-to-create-colorful-plots-in-python-969b5a892f0c
example 1
I don't remember where I got fig3's code from, but I think it was in another example online.

Matplotlib why does colorbar y label disappear with multiple colorbars

Why does my colorbar label "y1" disappear when I add the second colorbar?
If I remove the colorbar for ax2, then the label shows on the first colorbar.
Using Python 3.8
Stand-Alone Code
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
import matplotlib.colors as mcolors
%matplotlib inline
plt.style.use('seaborn-whitegrid')
x = [-15000, -2000, 0, 5000, 6000, 11000, 18000, 21000, 25000, 36000, 62000]
beta = [1000, 200, -800, 100, 1000, -2000, -5000, -5000, -15000, -21000, -1500]
y = [0.01, 0.2, 1.3, 0.35, 0.88, 2.2, 2.5, 1.25, 3.4, 4.1, 2.1]
fig = plt.figure(figsize=(10, 7.5), constrained_layout=True)
gs = fig.add_gridspec(2, 1)
ax1 = fig.add_subplot(gs[0, 0])
ax2 = fig.add_subplot(gs[1, 0], sharex = ax1)
fig.execute_constrained_layout()
fig.suptitle('Suptitle')
vals = ax1.scatter(x, beta, c=y, norm=mcolors.LogNorm(), cmap='rainbow')
ax1.set_title('ax1', style='italic');
cbax1=ax1.inset_axes([1.1, 0, 0.03, 1], transform=ax1.transAxes)
cbar1=fig.colorbar(vals, cax=cbax1, format = '%1.2g', orientation='vertical')
cbar1.ax.set_ylabel('y1')
cbar1.ax.yaxis.set_label_position('left')
ax2.scatter(x, y, c=y, norm=mcolors.LogNorm(), cmap='rainbow')
ax2.set_title('ax2', style='italic');
vals2 = vals
cbax2 = ax2.inset_axes([1.1, 0, 0.03, 1], transform=ax2.transAxes)
cbar2 = fig.colorbar(vals2, cax=cbax2, format = '%1.2g', orientation='vertical')
cbar2.ax.set_ylabel('y2')
cbar2.ax.yaxis.set_label_position('left')
Made two correction in your code. I am also using Python 3.8
# ---> Assign the second scatter plot to vals2
vals2 = ax2.scatter(x, y, c=y, norm=mcolors.LogNorm(), cmap='rainbow')
ax2.set_title('ax2', style='italic');
# ---> comment below line.
#vals2 = vals
result:
In adition, you can add label to colorbar() function like this:
cbar1=fig.colorbar(vals, cax=cbax1, format = '%1.2g', orientation='vertical', label='y1')
cbar2 = fig.colorbar(vals2, cax=cbax2, format = '%1.2g', orientation='vertical', label='y2')
Try restarting the kernel if you still face this issue.
It might be a bug. You can set the labels after plotting:
# Your other codes
# also can use `cbax1` instead of `cbar1.ax`
cbar2.ax.set_ylabel('y2')
cbar2.ax.yaxis.set_label_position('left')
cbar1.ax.set_ylabel('y1')
cbar1.ax.yaxis.set_label_position('left')
Output:

Python Matplotlib, Stem plot not working with FuncAnimation

I am trying to plot live data from incoming data packet. I have four subplots which on one of the subplot, i want to plot data as Stem plot however i am receiving following error:
self.stemlines.set_data(z, y)
AttributeError: 'list' object has no attribute 'set_data'
plt.plot works fine but I am not able to get it to work for plt.steam.
import matplotlib
matplotlib.use('Qt5Agg')
import matplotlib.pyplot as plt
from matplotlib.widgets import TextBox
import matplotlib
class PlotEngine:
def __init__(self, axisChanged):
# plt.style.use('seaborn-whitegrid')
# style.use('fivethirtyeight')
initialMinValue = '14.4'
initialMaxValue = '14.9'
plt.style.use('ggplot')
matplotlib.rc('axes', titlesize=8) # fontsize of the axes title
matplotlib.rc('axes', labelsize=8)
matplotlib.rc('xtick', labelsize=8) # fontsize of the tick labels
matplotlib.rc('ytick', labelsize=8) # fontsize of the tick labels axes.titlesize
matplotlib.rc('figure', titlesize=8)
self.fig, self.ax = plt.subplots(2, 2)
plt.ion()
# plt.subplot(2, 2, 4, polar=True)
self.fig.patch.set_facecolor('gray')
self.axpolar = plt.subplot(2, 2, 4, projection='polar')
self.axpolar.set_facecolor('black')
# self.ax[1, 1] = fig.add_subplot(2, 2, 4, projection='polar')
self.ax[0, 0].set_facecolor('black')
self.ax[0, 1].set_facecolor('black')
self.ax[1, 0].set_facecolor('black')
self.ax[1, 1].set_facecolor('black')
self.axisChanged = axisChanged
self.slider_freq = plt.axes([0.1, 0.01, 0.3, 0.01])
self.slider_azi = plt.axes([0.5, 0.01, 0.3, 0.01])
self.freqAxBoxMin = plt.axes([0.55, 0.33, 0.04, 0.03])
self.freqAxBoxMax = plt.axes([0.55, 0.28, 0.04, 0.03])
self.freqMinValueBox = TextBox(self.freqAxBoxMin, 'Min Freq:', initial=initialMinValue)
self.freqMaxValueBox = TextBox(self.freqAxBoxMax, 'Max Freq:', initial=initialMaxValue)
self.aziAxBoxMin = plt.axes([0.55, 0.18, 0.04, 0.03])
self.aziAxBoxMax = plt.axes([0.55, 0.10, 0.04, 0.03])
self.aziMinValueBox = TextBox(self.aziAxBoxMin, 'Min Dir:', initial='-180')
self.aziMaxValueBox = TextBox(self.aziAxBoxMax, 'Max Dir:', initial='180')
self.zeroOne, = self.ax[0, 1].plot([], [], 'ro')
self.oneOne, = self.axpolar.plot([], [], 'ro')
self.markerline, self.stemlines, self.baseline, = self.ax[1, 0].stem([1], [1], bottom=-140)
self.ax[0, 1].set_xlim([0, 60])
self.ax[0, 1].set_ylim([-140, -40])
self.axpolar.set_yticks(range(-90, -30, 10)) # Define the yticks
# self.axpolar.set_yticklabels(map(str, range(-90, -30, -10))) # Change the labels
self.ax[1, 0].set_xlim([14, 14.8])
self.ax[1, 0].set_ylim([-140, -40])
# self.background = fig.canvas.copy_from_bbox(self.ax.bbox)
def animateZeroOne(self, i, azimuth, rss, freqGhz):
x = azimuth
y = rss
z = freqGhz
self.zeroOne.set_data(x, y)
self.oneOne.set_data(x, y)
self.stemlines.set_data(z, y)
self.markerline.set_data(z, y)
return self.zeroOne, self.oneOne, self.stemlines, self.markerline
According to StemContainer, stemlines is a list (of Line2D), so it does not have attribute set_data, like markerline or baseline (of type Line2D). Maybe you want to apply that function over every member of the list at your animateZeroOne function?:
def animateZeroOne(self, i, azimuth, rss, freqGhz):
x = azimuth
y = rss
z = freqGhz
self.zeroOne.set_data(x, y)
self.oneOne.set_data(x, y)
[x.set_data(z, y) for x in self.stemlines]
self.markerline.set_data(z, y)
return self.zeroOne, self.oneOne, self.stemlines, self.markerline

python2.7 draw simple polygon without self-intersection

I want to draw simple polygon that means there is no self-intersecting in the polygon using x & y locations. But what I got for the result is butterfly shape of polygon.
I know that if I change li_feasible_points to [[0,2],[2,2],[4,0],[2,0]] in order to draw simple polygon IN THIS TIME.
But WHAT I WANT is to draw simple polygon without self-intersecting by ANY list of corner points locations. Is there any way to solve this problem?
Here is my code and my result below.
from matplotlib import pyplot as plt
fig, ax = plt.subplots(figsize=(6, 6))
x_lim = 5
y_lim = 10
x = np.linspace(0, x_lim)
y = np.linspace(0, y_lim)
li_feasible_points = [[0.0, 2.0], [4.0, 0.0], [2.0, 0.0], [2.0, 2.0]]
line = plt.Polygon(li_feasible_points, closed=False, color='r', fill=True, edgecolor='r')
plt.gca().add_line(line)
plt.xlabel(li_var_names[0])
plt.ylabel(li_var_names[1])
plt.xlim(0, x_lim)
plt.ylim(0, y_lim)
plt.show()
I look forward to your help. Thank you.

matplotlib diagram background depending on data

I'm trying to plot some data and want to have a colored background depending on data.
In the following sample I want to have data1 and data2 on the left yaxis and data3 on right yaxis. This is working. But additionally I tried to colorize the background depending on data3.
How do I need to format the data to get it working?
import matplotlib.pyplot as plt
from datetime import datetime as dt
import matplotlib.dates as md
fig, ax1 = plt.subplots(constrained_layout=True)
data1 = [51.2, 51.2, 51.2, 50.7, 50.7, 50.5, 50.4, 50.7, 50.6]
data2 = [46.5, 46.1, 46.2, 46.3, 46.4, 46.3, 46.2, 46.1, 45.5]
data3 = [ 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0]
timestamps = [1524614516, 1524615134, 1524615587, 1524615910, 1524616235, 1524616559, 1524616866, 1524617189, 1524617511]
timestamps_ = [dt.utcfromtimestamp(x) for x in timestamps]
for data in (data1,data2):
ax1.plot(timestamps_, data, marker='.', linestyle='-')
ax1.set_ylabel("degC")
ax2 = ax1.twinx()
ax2.plot(timestamps_, data3, marker='x', linestyle='-')
ax2.pcolor(ax2.get_xlim(), ax2.get_ylim(), zip(timestamps_, data3), cmap='RdGn', alpha=0.3)
ax2.set_ylabel("ON OFF")
ax1.set_title("Mytitle")
for tick in ax1.xaxis.get_major_ticks():
tick.label1.set_horizontalalignment('right')
tick.label1.set_rotation(35)
xfmt = md.DateFormatter('%Y-%m-%d %H:%M:%S')
ax1.xaxis.set_major_formatter(xfmt)
plt.show()
Error message:
Traceback (most recent call last):
File "/home/tobias/workspace/python_pyplot_test/main.py", line 25, in <module>
ax2.pcolor(ax2.get_xlim(), ax2.get_ylim(), zip(timestamps_, data3), cmap='RdGn', alpha=0.3)
File "/usr/local/lib/python2.7/dist-packages/matplotlib/__init__.py", line 1855, in inner
return func(ax, *args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/matplotlib/axes/_axes.py", line 5732, in pcolor
X, Y, C = self._pcolorargs('pcolor', *args, allmatch=False)
File "/usr/local/lib/python2.7/dist-packages/matplotlib/axes/_axes.py", line 5576, in _pcolorargs
C.shape, Nx, Ny, funcname))
TypeError: Dimensions of C (9, 2) are incompatible with X (2) and/or Y (2); see help(pcolor)
Here's a minimal solution to what you want:
import matplotlib.pyplot as plt
from datetime import datetime as dt
import matplotlib.dates as md
import numpy as np
data3 = np.array([ 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0])
x=np.arange(9)
xp,yp=np.meshgrid(x,data3)
xp=xp.astype(float)-0.5
bgcolor=np.ones(xp.shape)*data3[None,:]
plt.pcolor(xp,yp,bgcolor)
plt.plot(x, data3, marker='x', linestyle='-')
I took out the second axis and all the tick stuff as they were not related to the problem itself.
Another option is to use axvspans:
One difference between using axvspan and pcolor is that the vertical span (rectangles) drawn by axvspan are unbounded in the y-direction while the pcolor rectangles are not. So if you use the zoom button to resize the plot, the axvspan rectangles will stretch to infinity (roughly speaking) while zooming out the pcolor rectangles will expose white areas. It's not a big deal, just thought you'd like to know.
Also note that if the vertical spans start at the first data point and extend to the next data point, then the last value in data3 never gets used. (Nine data points make eight vertical spans). If, however, you center the vertical spans around the data points -- so each data point is in the center of a span, then all 9 values in data3 can be used.
Uncomment the commented code below (and comment-out the current definition of timestamps_left and timestamps_right) to see the difference.
import numpy as np
import matplotlib.pyplot as plt
from datetime import datetime as dt
import matplotlib.dates as md
def topydates(timestamps):
return [dt.utcfromtimestamp(x) for x in timestamps]
fig, ax1 = plt.subplots(constrained_layout=True)
data1 = [51.2, 51.2, 51.2, 50.7, 50.7, 50.5, 50.4, 50.7, 50.6]
data2 = [46.5, 46.1, 46.2, 46.3, 46.4, 46.3, 46.2, 46.1, 45.5]
data3 = [ 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0]
timestamps = np.array([1524614516, 1524615134, 1524615587, 1524615910,
1524616235, 1524616559, 1524616866, 1524617189, 1524617511])
timestamps_ = topydates(timestamps)
for data in (data1,data2):
ax1.plot(timestamps_, data, marker='.', linestyle='-')
ax1.set_ylabel("degC")
ax2 = ax1.twinx()
ax2.plot(timestamps_, data3, marker='x', linestyle='-')
# if you want the axvspans to be centered around the data points
# widths = np.diff(timestamps)
# midpoints = timestamps[:-1] + widths/2.0
# timestamps_left = topydates(np.r_[timestamps[0]-widths[0]/2, midpoints])
# timestamps_right = topydates(np.r_[midpoints, timestamps[-1] + widths[-1]/2.0])
# if you uncomment the code above, then comment-out the line below:
timestamps_left, timestamps_right = timestamps_[:-1], timestamps_[1:]
cmap = plt.get_cmap('RdYlGn')
for left, right, val in zip(timestamps_left, timestamps_right, data3):
print(left, right)
color = cmap(val)
ax2.axvspan(left, right, facecolor=color, alpha=0.3)
ax2.set_ylabel("ON OFF")
ax1.set_title("Mytitle")
for tick in ax1.xaxis.get_major_ticks():
tick.label1.set_horizontalalignment('right')
tick.label1.set_rotation(35)
xfmt = md.DateFormatter('%Y-%m-%d %H:%M:%S')
ax1.xaxis.set_major_formatter(xfmt)
plt.show()

Categories