Imshow differs drastically from applying matplolib.cm to a segmented image - matplotlib

Hi and thanks for reading.
What I am trying to do is to make a web app that would take an image, run it through the model and return a segmented version. I can not use imshow in the webapp though. So I tried adding colormap through matplolib.cm.viridis however it returns a much darker image.
Here are some code and images for refernce:
pred = new_model.predict(np.expand_dims(img, 0))
pred_mask = np.argmax(pred, axis=-1)
pred_mask = pred_mask[0]
This returns me a 2D grayscale image, which when put into matplolib imshow looks like this.(last picture on the right is the output of the model). Code and image below.
axs[0].imshow(m1)
axs[0].set_title('Image')
axs[1].imshow(test_label1)
axs[1].set_title('Ground Truth')
axs[2].imshow(new_pred)
axs[2].set_title('Prediction')
However, when applying colormap to an image using matplolib.cm (something I have to do for app to function) I get this image. Code and image presented below.
Adding colormap. (Viridis, as far as I know is default one from matplolib 3.5)
from matplotlib import cm
pred_mask = cm.viridis(pred_mask / 255)*255
pred_mask = np.asarray(pred_mask, dtype='uint8')
Plotting Image
fig, axs = plt.subplots(1, 3, figsize=(20, 10))
axs[0].imshow(m1)
axs[0].set_title('Image')
axs[1].imshow(test_label1)
axs[1].set_title('Ground Truth')
axs[2].imshow(pred_mask)
axs[2].set_title('Prediction')
But as you can see image is much darker, without even a hint of lighter blue or yellow, i.e. worse. How can I make it closer to imshow output?
PS. Thank you very much for reading and hope that someone has an answer to that. Any suggestions would be much appreciated though.

This is most likely related to the number range of the image or colormap, respectively.
As the prediction mask can be faintly seen my money would be on either multiplying the prediction data with 255 or to set the vmax of imshow to a smaller value. In any case, it would be useful to know the min/max value of pred_mask and additionally show a colorbar for the right plot.
I hope that gets you on the right track.

Related

Plotting xarray.DataArray and Geopandas together - aspect ratio errors

I am trying to create two images side by side: one satellite image alone, and next to it, the same satellite image with outlines of agricultural fields. My raster data "raster_clip" is loaded into rioxarray (original satellite image from NAIP, converted from .sid to .tif), and my vector data "ag_clip" is in geopandas. My code is as follows:
fig, (ax1, ax2) = plt.subplots(ncols = 2, figsize=(14,8))
raster_clip.plot.imshow(ax=ax1)
raster_clip.plot.imshow(ax=ax2)
ag_clip.boundary.plot(ax=ax1, color="yellow")
I can't seem to figure out how to get the y axes in each plot to be the same. When the vector data is excluded, then the two plots end up the same shape and size.
I have tried the following:
Setting sharey=True in the subplots method. Doesn't affect shape of resulting images, just removes the tic labels on the second image.
Setting "aspect='equal'" in the imshow method, leads to an error, which doesn't make sense because the 'aspect' kwarg is listed in the documentation for xarray.plot.imshow.
plt.imshow's 'aspect' kwarg is not available in xarray
Removing the "figsize" variable, doesn't affect the ratio of the two plots.
not entirely related to your question but i've used cartopy before for overlaying a GeoDataFrame to a DataArray
plt.figure(figsize=(16, 8))
ax = plt.subplot(projection=ccrs.PlateCarree())
ds.plot(ax=ax)
gdf.plot(ax=ax)

How do I stretch our the horizontal axis of a matplotlib pyplot?

I'm creating a colour map which has 64 horizontal data points and 3072 vertical. When I plot it, the scaling on both axes is the same and so the horizontal axis is super squished and tiny, and I can't get any information from it. I've tried changing the figsize parameter but nothing changes the actual plot, only the image that contains it. Any ideas on how to change my plot so that the actual length of the axes are the same? Below is my plotting code:
def plot_plot(self, data, title="Pixel Plot"):
pixel_plot = plt.imshow(data)
plt.title(title)
plt.colorbar(pixel_plot)
plt.show(pixel_plot)
thanks in advance!
I think you want the aspect option in plt.imshow().
So something like plt.imshow(data, aspect=0.1) or plt.imshow(data, aspect='equal')
See this solution: https://stackoverflow.com/a/13390798/12133280

Setting axes to semilog with Mayavi 3D plot

I'm sucessfully generating a 3D plot with Mayavi, but can't find any way to rescale the axes to a semilog representation.
Is this possible?
I also tried taking a screenshot (as suggested by another answer I read before), which I placed after my mayavi code
arr = mayavi.mlab.screenshot()
fig = plt.figure(figsize=(5, 5))
pylab.imshow(arr)
plt.semilogx()
plt.show()
However this just produces a segmentation fault.
Thanks in advance!

How to export svg in matplotlib with correct mm scale

I am trying to export a figure from matplotlib for laser cutting. The figure is plotted with millimeters as the units.
I'm tying to ensure the correct scale by getting the bounding box in inches and then setting the figure size to that value:
import matplotlib.pyplot as plt
ax = plt.subplot(111)
<snipped for brevity...plotting of lines and paths>
x_bound = map(mm_to_inch, ax.get_xbound())
y_bound = map(mm_to_inch, ax.get_ybound())
plt.gcf().set_size_inches(x_bound[1] - x_bound[0], y_bound[1] - y_bound[0])
plt.axis('off')
plt.savefig('{0}.svg'.format(self.name, format='svg'))
The exported .svg is ~2/3rds of the intended scale and I'm not familiar enough with axes and figures to know why. Additionally, there is a black border around the intended geometry. Here is some example output:
.svg output (converted to .png)
How should I remove the black border and scale the .svg correctly?
You probably want to remove the margins around the axes completely,
plt.gcf().subplots_adjust(0,0,1,1)
I might note however that the result may not be precise enough for the application. Definitely also consider creating the figure with a CAD program.
Based off of ImportanceOfBeingErnest's answer and some responses to other stackoverflow questions, the following solution works:
plt.axis('off')
plt.margins(0, 0)
plt.gca().xaxis.set_major_locator(plt.NullLocator())
plt.gca().yaxis.set_major_locator(plt.NullLocator())
plt.subplots_adjust(top=1, bottom=0, right=1, left=0, hspace=0, wspace=0)
x_bound = map(mm_to_inch, self._ax.get_xbound())
y_bound = map(mm_to_inch, self._ax.get_ybound())
plt.gcf().set_size_inches(x_bound[1] - x_bound[0], y_bound[1] - y_bound[0])

Matplotlib annotate doesn't work on log scale?

I am making log-log plots for different data sets and need to include the best fit line equation. I know where in the plot I should place the equation, but since the data sets have very different values, I'd like to use relative coordinates in the annotation. (Otherwise, the annotation would move for every data set.)
I am aware of the annotate() function of matplotlib, and I know that I can use textcoords='axes fraction' to enable relative coordinates. When I plot my data on the regular scale, it works. But then I change at least one of the scales to log and the annotation disappears. I get no error message.
Here's my code:
plt.clf()
samplevalues = [100,1000,5000,10^4]
ax = plt.subplot(111)
ax.plot(samplevalues,samplevalues,'o',color='black')
ax.annotate('hi',(0.5,0.5), textcoords='axes fraction')
ax.set_xscale('log')
ax.set_yscale('log')
plt.show()
If I comment out ax.set_xcale('log') and ax.set_ycale('log'), the annotation appears right in the middle of the plot (where it should be). Otherwise, it doesn't appear.
Thanks in advance for your help!
It may really be a bug as pointed out by #tcaswell in the comment but a workaround is to use text() in axis coords:
plt.clf()
samplevalues = [100,1000,5000,10^4]
ax = plt.subplot(111)
ax.loglog(samplevalues,samplevalues,'o',color='black')
ax.text(0.5, 0.5,'hi',transform=ax.transAxes)
plt.show()
Another approach is to use figtext() but that is more cumbersome to use if there are already several plots (panels).
By the way, in the code above, I plotted the data using log-log scale directly. That is, instead of:
ax.plot(samplevalues,samplevalues,'o',color='black')
ax.set_xscale('log')
ax.set_yscale('log')
I did:
ax.loglog(samplevalues,samplevalues,'o',color='black')