How to display more than 10 images in Tensorboard? - python-3.x

I noticed that it doesn't matter how many image I save to the tensorboard log file, tensorboard will only ever show 10 of them (per tag).
How can we increase the number of images or at least select which ones are displayed?
To reproduce what I mean run following MCVE:
import torch
from torch.utils.tensorboard import SummaryWriter
tb = SummaryWriter(comment="test")
for k in range(100):
# create an image with some funny pattern
b = [n for (n, c) in enumerate(bin(k)) if c == '1']
img = torch.zeros((1,10,10))
img[0, b, :] = 0.5
img =img + img.permute([0, 2, 1])
# add the image to the tensorboard file
tb.add_image(tag="test", img_tensor=img, global_step=k)
This creates a folder runs in which the data is saved. From the same folder execute tensorboard --logdir runs, open the browser and go to localhost:6006 (or replace 6006 with whatever port tensorboard happens to display after starting it). Then go to the tab called "images" and move the slider above the grayscale image.
In my case it only displayed the images from steps
k = 3, 20, 24, 32, 37, 49, 52, 53, 67, 78
which isn't even an nice even spacing, but looks pretty random. I'd prefer to have
see more than just 10 of the images I saved, and
have a more even spacing of number of steps between each image displayed.
How can I achieve this?
EDIT: I just found the option --samples_per_plugin and tried tensorboard --logdir runs --samples_per_plugin "images=100". This indeed increased the number of images, but it only showed the images from steps k = 0,1,2,3....,78, but none from above 78.

You probably have to wait a little bit longer to wait for all the data to be loaded, but this is indeed the correct solution, see --help:
--samples_per_plugin: An optional comma separated list of plugin_name=num_samples pairs to explicitly specify how many samples
to keep per tag for that plugin. For unspecified plugins, TensorBoard
randomly downsamples logged summaries to reasonable values to prevent
out-of-memory errors for long running jobs. This flag allows fine
control over that downsampling. Note that 0 means keep all samples of
that type. For instance, "scalars=500,images=0" keeps 500 scalars and
all images. Most users should not need to set this flag. (default: '')
Regarding the random samples: This is also true, there is some sort of randomness to it, from the the FAQ:
Is my data being downsampled? Am I really seeing all the data?
TensorBoard uses reservoir sampling to downsample your data so that it
can be loaded into RAM. You can modify the number of elements it will
keep per tag in tensorboard/backend/application.py.

Related

pytorch make_grid (from torchvision.utils import make_grid) behaves different then I expect

trying to run the visualization utils tutorial from pytorch, I tried it with some images of dogs found on the internet. the images used in the tutorial are not distributed for use.. making the gris and showing the result behaves funny - it shows each channel as a separate image (I guess this is what I see)
so - from the tutorial
but here is what I get from the images I got:
I was expecting to see the two images in their original colors in a grid.
Another step I tried following Ivan's comment:
tutorial: https://pytorch.org/vision/master/auto_examples/plot_visualization_utils.html
I would like to know how to fix this (and use make_grid correctly)
For the output you got, I would assume the correct shape is (height, width, channels) instead of (channels, height, width). You can correct this with torch.permute. The following should provide the desired result:
>>> grid = make_grid(torch.stack([transformed_dog1, transformed_dog2]).permute(0,3,1,2))
>>> show(grid)

gmplot Marker does not work after it marks 256 points

I am trying to mark a bunch of points on the map with gmplot and observed that after a certain point it stops marking and wipes out all the previously marked points. I debugged the gmplot.py module and saw that when the length of points array exceeds 256 this is happening without giving any error and warning.
self.points = [] on gmplot.py
Since I am very new to Python and OOPs concept, is there a way to override this and mark more than 256 points?
Are you using gmplot.GoogleMapPlotter.Scatter or gmplot.GoogleMapPlotter.Marker. I used either and was able to get 465 points for a project that I was working on. Is it possible it is an API key issue for you?
partial snippet of my code
import gmplot
import pandas as pd
# df is the database with Lat, Lon and formataddress columns
# change to list, not sure you need to do this. I think you can cycle through
# directly using iterrows. I have not tried that though
latcollection=df['Lat'].tolist()
loncollection=df['Lon'].tolist()
addcollection=df['formataddress'].tolist()
# center map with the first co-ordinates
gmaps2 = gmplot.GoogleMapPlotter(latcollection[0],loncollection[0],13,apikey='yourKey')
for i in range(len(latcollection)):
gmaps2.marker(latcollection[i],loncollection[i],color='#FF0000',c=None,title=str(i)+' '+ addcollection[i])
gmaps2.draw(newdir + r'\laplot_marker_full.html')
I could hover over the 465th point since I knew approximately where it was and I was able to get the title with str(464) <formataddress(464)>, since my array is indexed from 0
Make sure you check the GitHub site to modify your gmplot file, in case you are working with windows.

How to modify orientation of mgh/dicom/nifti file using nibabel

I have a hard time, figuring out a proper affine transformation for 3 different views i.e. coronal, axial and saggital, each having separate issues like below:
1: Axial color map get overlapped with the saggital original view.
2: Similarly Sagittal color map gets overlapped with the axial original image.
3: And everyone has some kind of orientation issues like best visible here when the color map and original image for coronal come correct but with wrong orientation.
I am saving the original file that I am sending to the server for some kind of prediction, which generates a color map and returns that file for visualization, later I am displaying everything together.
In server after prediction, here is the code to save the file.
nifti_img = nib.MGHImage(idx, affine, header=header)
Whereas affine and header are the original affine and header extracted from the file I sent.
I need to process "idx" value that holds the raw data in Numpy array format, but not sure what exactly to be done. Need help here.
Was trying hard to solve the issue using nibabel python library, but due to very limited knowledge of mine about how these files work and about affine transformation, I am having a hard time figuring out what should I do to make them correct.
I am using AMI js with threejs support in the frontend and nibabel with python in the back end. Solution on the frontend or back end anywhere is acceptable.
Please help. Thanks in advance.
img = nib.load(img_path)
# check the orientation you wanna reorient.
# For example, the original orientation of img is RPI,
# you wanna reorient it to RAS, the second the third axes should be flipped
# ornt[P, 1] is flip of axis N, where 1 means no flip and -1 means flip.
ornt = np.array([[0, 1],
[1, -1],
[2, -1]])
img_orient = img.as_reoriented(ornt)
nib.save(img_orient, img_path)
It was simple, using numpy.moveaxis() and numpy.flip() operation on rawdata from nibabel. as below.
# Getting raw data back to process for better orienation and label mapping.
orig_img_data = nib.MGHImage(numpy_arr, affine)
nifti_img = nib.MGHImage(segmented_arr_output, affine)
# Getting original and predicted data to preprocess to original shape and view for visualisation.
orig_img = orig_img_data.get_fdata()
seg_img = nifti_img.get_fdata()
# Placing proper views in proper place and flipping it for a better visualisation as required.
# moveaxis to get original order.
orig_img_ = np.moveaxis(orig_img, -1, 0)
seg_img = np.moveaxis(seg_img, -1, 0)
# Flip axis to overcome mirror image/ flipped view.
orig_img_ = np.flip(orig_img_, 2)
seg_img = np.flip(seg_img, 2)
orig_img_data_ = nib.MGHImage(orig_img_.astype(np.uint8), np.eye(4), header)
nifti_img_ = nib.MGHImage(seg_img.astype(np.uint8), np.eye(4), header)
Note: It's very important to have same affine matrix to wrap both of these array back. A 4*4 Identity matrix is better rather than using original affine matrix as that was creating problem for me.

Scaling a seaborn heatmap .png output file

I have a program that, in a nutshell, connects to a Cisco wireless controller and gathers data about the number of clients per access point. It runs at 'x' intervals at 'y' time between intervals.
The program works fine.
NOTE Both output files presented below show nine passes at 15 seconds between each pass. All you really care about is that I have 9 columns (one per pass) and the rows are the AP's and their connected clients.
My issue is this: when I run it against a small client (93 access points) the output looks exactly the way I want it to:
But when I run it against another client (1840 access points) the output looks like this:
Here is the relevant portion of my program:
df = pd.DataFrame(e, index=index, columns=cols)
df = df.transpose()
my_dpi = 96
sns.set(font_scale=2)
# plt.figure(figsize=(13, 91))
plt.figure(figsize=(2016 / my_dpi, 9120 / my_dpi), dpi=my_dpi)
sns.heatmap(df, cmap='RdYlGn_r', linewidths=0.5, annot=True, annot_kws={"size": 20})
plt.savefig('d:\\python\\projects\\clients_per_ap\\ac.png')
plt.show()
I tried changing 9120 to 912000, but I get an error stating that the value has to be less than 2^16. I tried 65535, but the program fails with a memory error. I tried 54720 and that works -- 54720 produced the output you see here as the second image, but it is unusable.
How can I scale my output file for the client with 1840 AP's to look like the output file for the client wit 93 AP's? Basically I would like the same (or very close) font and width, just 1840 rows long versus 93.
Have you tried outputting the file in vector format? .PDF works well usually. Sure the text will look big when you zoom in, but that's probably your best bet for working with output that is too big to put into memory. Then you can just use any classic PDF to PNG conversion if you just need that for some reason.

Maximize figures before saving

The question about how to do maximize a window before saving has been asked several times and has several questions (still no one is portable, though), How to maximize a plt.show() window using Python
and How do you change the size of figures drawn with matplotlib?
I created a small function to maximize a figure window before saving the plots. It works with QT5Agg backend.
import matplotlib.pyplot as plt
def maximize_figure_window(figures=None, tight=True):
"""
Maximize all the open figure windows or the ones indicated in figures
Parameters
----------
figures: (list) figure numbers
tight : (bool) if True, applies the tight_layout option
:return:
"""
if figures is None:
figures = plt.get_fignums()
for fig in figures:
plt.figure(fig)
manager = plt.get_current_fig_manager()
manager.window.showMaximized()
if tight is True:
plt.tight_layout()
Problems:
I have to wait for the windows to be actually maximized before using the plt.savefig() command, otherwise it is saved with as not maximized. This is a problem if I simply want to use the above function in a script
(minor problems:)
2. I have to use the above function twice in order to get the tight_layout option working, i.e. the first time tight=True has no effect.
The solution is not portable. Of course I can add all the possible backend I might use, but that's kind of ugly.
Questions:
how to make the script wait for the windows to be maximized? I don't want to use time.sleep(tot_seconds) because tot_seconds would be kind of arbitrary and makes the function even less portable
how to solve problem 2 ? I guess it is related to problem 1.
is there a portable solution to "maximize all the open windows" problem?
-- Edit --
For problem 3. #DavidG suggestion sounds good. I use tkinter to automatically get width and height, convert them to inches, and use them in fig.set_size_inches or directly during the figure creation via fig = plt.figure(figsize=(width, height)).
So a more portable solution is, for example.
import tkinter as tk
import matplotlib.pyplot as plt
def maximize_figure(figure=None):
root = tk.Tk()
width = root.winfo_screenmmwidth() / 25.4
height = root.winfo_screenmmheight() / 25.4
if figure is not None:
plt.figure(figure).set_size_inches(width, height)
return width, height
where I allow the figure to be None so that I can use the function to just retrieve width and height and use them later.
Problem 1 is still there, though.
I use maximize_figure() in a plot function that I created (let's say my_plot_func()) but still the saved figure doesn't have the right dimensions when saved on file.
I also tried with time.sleep(5) in my_plot_func() right after the figure creation. Not working.
It works only if a manually run in the console maximize_figure() and then run my_plot_func(figure=maximized_figure) with the figure already maximized. Which means that dimension calculation and saving parameters are correct.
It does not work if I run in the console maximize_figure() and my_plot_func(figure=maximized_figure) altogether, i.e. with one call the the console! I really don't get why.
I also tried with a non-interactive backend like 'Agg', so that the figure doesn't get actually created on screen. Not working (wrong dimensions) no matter if I call the functions altogether or one after the other.
To summarize and clarify (problem 1):
by running these two pieces of code in console, figure gets saved correctly.
plt.close('all')
plt.switch_backend('Qt5Agg')
fig = plt.figure()
w, h = maximize_figure(fig.number)
followed by:
my_plot_func(out_file='filename.eps', figure=fig.number)
by running them together (like it would be in a script) figure is not saved correctly.
plt.close('all')
plt.switch_backend('Qt5Agg')
fig = plt.figure()
w, h = maximize_figure(fig.number)
my_plot_func(out_file='filename.eps', figure=fig.number)
Using
plt.switch_backend('Agg')
instead of
plt.switch_backend('Qt5Agg')
it does not work in both cases.

Resources