Array is not iterable, but how to use as argument in zip()? - matplotlib

I want to plot 3D visualizations of DICOM Scans, but I am stuck on this error.
I am using the marching cubes method. First from mesh verts and faces and returned then passed into plt_3d. Modules imported:
import numpy as np
import pydicom as pyd
import os
import matplotlib.pyplot as plt
from glob import glob
from mpl_toolkits.mplot3d.art3d import Poly3DCollection
import scipy.ndimage
from skimage import morphology
from skimage import measure
from skimage.transform import resize
from sklearn.cluster import KMeans
from plotly import version
from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
from plotly.tools import FigureFactory as FF
from plotly.graph_objs import *
init_notebook_mode(connected=True)
imgs_after_resamp is the pixel array(3d) which contains the DICOM Data
def make_mesh(image, threshold=-300, step_size=1):
p = image.transpose(2,1,0)
verts, faces, norm, val = measure.marching_cubes_lewiner(p, threshold,
step_size=step_size, allow_degenerate=True)
print(verts)
return verts, faces
def plotly_3d(verts, faces):
x,y,z = zip(*verts)
fig = FF.create_trisurf(x=x,
y=y,
z=z,
plot_edges=False,
colormap=colormap,
simplices=faces,
backgroundcolor='rgb(64, 64, 64)',
title="Interactive Visualization")
iplot(fig)
def plt_3d(verts, faces):
print(“Drawing”)
x,y,z = zip(*verts)
fig = plt.figure(figsize=(10, 10))
ax = fig.add_subplot(111, projection='3d')
mesh = Poly3DCollection(verts[faces], linewidths=0.05, alpha=1)
face_color = [1, 1, 0.9]
mesh.set_facecolor(face_color)
ax.add_collection3d(mesh)
ax.set_xlim(0, max(x))
ax.set_ylim(0, max(y))
ax.set_zlim(0, max(z))
ax.set_axis_bgcolor((0.7, 0.7, 0.7))
plt.show()
v, f = make_mesh(imgs_after_resamp, 350)
new3d=np.vectorize(plt_3d)
new3d(v,f)
ValueError Traceback (most recent call last)
in
----> 1 plot_ve(imgs_re,400)
TypeError: type object argument after * must be an iterable, not numpy.float32

Related

how to display netcdf raster values over map?

I'm trying to plot netcdf raster values of snowfall data in a text format overlaying what I currently have (mentioned further below). Example, something like this below:
Example
This is all the relevant code I have so far. I excluded the non relevant code. I tried plt.text and it gave me "ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()"
What I have plotted so far
import numpy
from datetime import datetime
import cartopy.crs as ccrs
import cartopy.feature as cfeature
import cartopy.mpl.ticker as cticker
import matplotlib.pyplot as plt
from matplotlib import ticker, patheffects
from metpy.units import units
import numpy as np
import numpy.ma as ma
from scipy.ndimage import gaussian_filter, maximum_filter, minimum_filter
import xarray as xr
from metpy.plots import USCOUNTIES
from gradient import Gradient
import pandas as pd
import matplotlib.colors as col
#Open NOAA Snowfall dataset
ds = xr.open_dataset('sfav2_CONUS_2021093012_to_2022042512.nc')
ds
lat = ds.lat
lon = ds.lon
#converts snowfall data to inches
snowdata = ds['Data'] * 39
plt.text(lon, lat, snowdata, transform=datacrs)
As far as I know there isn't a vectorized way of plotting text (plt.text or plt.annotated). So you'll have to loop over the arrays and plot each point.
import matplotlib.pyplot as plt
import matplotlib.patheffects as PathEffects
import cartopy.crs as ccrs
import numpy as np
data = np.random.rand(18, 9)
lons, lats = np.mgrid[-17:18:2, 8:-9:-2]
lons = lons * 10
lats = lats * 10
fig, ax = plt.subplots(figsize=(10, 5), dpi=86, facecolor="w", subplot_kw=dict(projection=ccrs.EqualEarth()))
ax.pcolormesh(lons, lats, data, cmap="coolwarm", alpha=.2, transform=ccrs.PlateCarree())
ax.coastlines()
for val, lat, lon in zip(data.flat, lats.flat, lons.flat):
ax.text(
lon, lat, f"{val:1.1f}", ha="center", va="center", transform=ccrs.PlateCarree(),
path_effects=[PathEffects.withStroke(linewidth=3, foreground="w", alpha=.5)],
)

"im2col_out_cpu" not implemented for 'Byte'

I am trying to generate overlap patches from image size (112,112) but i am unable to do so. I have already tried a lot but it didn't work out.
**Code**
import torch
import numpy as np
import torch.nn as nn
from torch import nn
from PIL import Image
import cv2
import os
import math
import torch.nn.functional as F
import torchvision.transforms as T
from timm import create_model
from typing import List
import matplotlib.pyplot as plt
from torchvision import io, transforms
from utils_torch import Image, ImageDraw
from torchvision.transforms.functional import to_pil_image
IMG_SIZE = 112
# PATCH_SIZE = 64
resize = transforms.Resize((IMG_SIZE, IMG_SIZE))
img = resize(io.read_image("Adam_Brody_233.png"))
img = img.to(torch.float32)
image_size = 112
patch_size = 28
ac_patch_size = 12
pad = 4
img = img.unsqueeze(0)
soft_split = nn.Unfold(kernel_size=(ac_patch_size, ac_patch_size), stride=(patch_size, patch_size), padding=(pad, pad))
patches = soft_split(img).transpose(1, 2)
fig, ax = plt.subplots(16, 16)
for i in range(16):
for j in range(16):
sub_img = patches[:, i, j]
ax[i][j].imshow(to_pil_image(sub_img))
ax[i][j].axis('off')
plt.show()
Traceback
Traceback (most recent call last):
File "/home/cvpr/Documents/OPVT/unfold_ours.py", line 32, in <module>
patches = soft_split(img).transpose(1, 2)
File "/home/cvpr/anaconda3/envs/OPVT/lib/python3.7/site-packages/torch/nn/modules/module.py", line 727, in _call_impl
result = self.forward(*input, **kwargs)
File "/home/cvpr/anaconda3/envs/OPVT/lib/python3.7/site-packages/torch/nn/modules/fold.py", line 295, in forward
self.padding, self.stride)
File "/home/cvpr/anaconda3/envs/OPVT/lib/python3.7/site-packages/torch/nn/functional.py", line 3831, in unfold
_pair(dilation), _pair(padding), _pair(stride))
RuntimeError: "im2col_out_cpu" not implemented for 'Byte'
Yes this is an open issue in PyTorch. A simple fix is just to convert your image tensor from ints to floats you can do it like this:
img = img.to(torch.float32)
This should solve your problem

How to plot pointcloud2 in matplotlib

I have a sensor_msgs/PointCloud2 with [x,y,z] and how can I plot it in real-time in matplotlib like this code here. I already changed the type from Odometry to pointcloud2 but I don't know what to change in odom_callback or how to change the code in order to plot it in matplotlib. Can someone has an idea how to plot pointcloud2 in matplotlib
import matplotlib.pyplot as plt
import rospy
import tf
from sensor_msgs.msg import PointCloud2
from tf.transformations import quaternion_matrix
import numpy as np
from matplotlib.animation import FuncAnimation
class Visualiser:
def __init__(self):
self.fig, self.ax = plt.subplots()
self.ln, = plt.plot([], [], 'ro')
self.x_data, self.y_data = [] , []
def plot_init(self):
self.ax.set_xlim(0, 10000)
self.ax.set_ylim(-7, 7)
return self.ln
def getYaw(self, pose):
quaternion = (pose.orientation.x, pose.orientation.y, pose.orientation.z,
pose.orientation.w)
euler = tf.transformations.euler_from_quaternion(quaternion)
yaw = euler[2]
return yaw
def odom_callback(self, msg):
yaw_angle = self.getYaw(msg.pose.pose)
self.y_data.append(yaw_angle)
x_index = len(self.x_data)
self.x_data.append(x_index+1)
def update_plot(self, frame):
self.ln.set_data(self.x_data, self.y_data)
return self.ln
rospy.init_node('publisher_node')
vis = Visualiser()
sub = rospy.Subscriber('/scan3dd', PointCloud2, vis.odom_callback)
ani = FuncAnimation(vis.fig, vis.update_plot, init_func=vis.plot_init)
plt.show(block=True)

Simple logistic regression with Statsmodels: Adding an intercept and visualizing the logistic regression equation

Using Statsmodels, I am trying to generate a simple logistic regression model to predict whether a person smokes or not (Smoke) based on their height (Hgt).
I have a feeling that an intercept needs to be included into the logistic regression model but I am not sure how to implement one using the add_constant() function. Also, I am unsure why the error below is generated.
This is the dataset, Pulse.CSV: https://drive.google.com/file/d/1FdUK9p4Dub4NXsc-zHrYI-AGEEBkX98V/view?usp=sharing
The full code and output are in this PDF file: https://drive.google.com/file/d/1kHlrAjiU7QvFXF2a7tlTSFPgfpq9bOXJ/view?usp=sharing
import numpy as np
import pandas as pd
import statsmodels.api as sm
import matplotlib.pyplot as plt
import seaborn as sns
sns.set()
raw_data = pd.read_csv('Pulse.csv')
raw_data
x1 = raw_data['Hgt']
y = raw_data['Smoke']
reg_log = sm.Logit(y,x1,missing='Drop')
results_log = reg_log.fit()
def f(x,b0,b1):
return np.array(np.exp(b0+x*b1) / (1 + np.exp(b0+x*b1)))
f_sorted = np.sort(f(x1,results_log.params[0],results_log.params[1]))
x_sorted = np.sort(np.array(x1))
plt.scatter(x1,y,color='C0')
plt.xlabel('Hgt', fontsize = 20)
plt.ylabel('Smoked', fontsize = 20)
plt.plot(x_sorted,f_sorted,color='C8')
plt.show()
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
~/opt/anaconda3/lib/python3.7/site-packages/pandas/core/indexes/base.py in get_value(self, series, key)
4729 try:
-> 4730 return self._engine.get_value(s, k, tz=getattr(series.dtype, "tz", None))
4731 except KeyError as e1:
((( Truncated for brevity )))
IndexError: index out of bounds
Intercept is not added by default in Statsmodels regression, but if you need you can include it manually.
import numpy as np
import pandas as pd
import statsmodels.api as sm
import matplotlib.pyplot as plt
import seaborn as sns
sns.set()
raw_data = pd.read_csv('Pulse.csv')
raw_data
x1 = raw_data['Hgt']
y = raw_data['Smoke']
x1 = sm.add_constant(x1)
reg_log = sm.Logit(y,x1,missing='Drop')
results_log = reg_log.fit()
results_log.summary()
def f(x,b0,b1):
return np.array(np.exp(b0+x*b1) / (1 + np.exp(b0+x*b1)))
f_sorted = np.sort(f(x1,results_log.params[0],results_log.params[1]))
x_sorted = np.sort(np.array(x1))
plt.scatter(x1['Hgt'],y,color='C0')
plt.xlabel('Hgt', fontsize = 20)
plt.ylabel('Smoked', fontsize = 20)
plt.plot(x_sorted,f_sorted,color='C8')
plt.show()
This will also resolve the error as there was no intercept in your initial code.Source

How can Matplotlib axes be scaled hyperbolically?

I have a plot a bit like this:
The differences between the two lines (red and blue) are most important in my actual data (a ROC curve) at say the grid cell 0.2<x<0.4, 0.8<y<1. Now, I could crop for that grid cell, but let's say I'd rather scale both the x and y axes hyperbolically -- where the y-axis hyperbolic curve has its peak at about 0.9 and the x-axis has its peak at about 0.3 -- such that the 2D space gets stretched out for the grid cell of interest and gets compacted elsewhere (and preserving the meaning of the axes tick numbers). How would one accomplish this? The beginnings of my attempt are below. How would my code be modified to implement the axis scaling I described?
from matplotlib import gridspec
from matplotlib import scale as mscale
from matplotlib import transforms as mtransforms
from matplotlib.ticker import FormatStrFormatter
from matplotlib.ticker import NullFormatter, NullLocator, MultipleLocator
import math
import matplotlib
import matplotlib.patches as mpatches
import matplotlib.pylab as plt
import matplotlib.pyplot as plt
import matplotlib.ticker
import numpy as np
import seaborn as sns
sns.set_palette('husl')
sns.set()
plt.rcParams["figure.figsize"] = [5, 5]
x = np.arange(0, 1, step=0.01)
y1 = 1-1/np.exp(10*x)
y2 = 1-1.1/np.exp(10*x)
plt.scatter(x, y1, s=1, facecolor='red')
plt.scatter(x, y2, s=1, facecolor='blue')
plt.show();
class CustomScale(mscale.ScaleBase):
name = 'custom'
def __init__(self, axis, **kwargs):
mscale.ScaleBase.__init__(self)
self.thresh = None #thresh
self.name = 'custom'
def get_transform(self):
return self.CustomTransform(self.thresh)
def set_default_locators_and_formatters(self, axis):
pass
class CustomTransform(mtransforms.Transform):
input_dims = 1
output_dims = 1
is_separable = True
def __init__(self, thresh):
mtransforms.Transform.__init__(self)
self.thresh = thresh
def transform_non_affine(self, a):
#return np.log(1+a)
return np.exp(a)-1
#return 1+(1/2)*a
mscale.register_scale(CustomScale)
plt.scatter(x, y1, s=1, facecolor='red')
plt.scatter(x, y2, s=1, facecolor='blue')
plt.xscale('custom')
plt.show();
You may be able to achieve this using FuncScale (registered as 'function').
f = lambda a: np.exp(a) - 1
g = lambda b: np.log(b + 1)
plt.xscale('function', functions=(f, g))
For hyperbolic scaling, you could use lambda x: 1 / x for both functions.
See the example in the scales documentation: https://matplotlib.org/3.3.4/gallery/scales/scales.html