Conditional bipolar inside table bar chart - pandas - css - html

for my html representation of a pandas dataframe (python), I'd like to create something that resembles as much as possible the image below (created with Excel), that is, given a sequence of numbers, create INSIDE A TABLE, some horizontal bar charts that become green if the value is greater than zero, red if they are below zero and with the "zero" point in the axis which dynamically rescales according to the data provided. the closest I got to was by using pandas native instruments is given by the code below (http://pandas.pydata.org/pandas-docs/stable/style.html)
#done in Jupyter
from pandas import DataFrame
df = pd.DataFrame([-0.02, 0.03, 0.04, -0.05], columns=['A'])
more_than_zero = df.loc[df.loc[:,'A'] >= 0].index.values.tolist()
less_than_zero = df.loc[df.loc[:,'A'] < 0].index.values.tolist()
df.style.bar(subset=pd.IndexSlice[more_than_zero,'A'], color='#d65f5f')
#df.style.bar(subset=pd.IndexSlice[less_than_zero, 'B'], color='#7fff00')

Update: This answer lead to a pull request pandas-dev/pandas#14757 that got accepted in Pandas v0.20.0. The documentation can be found on Pandas website at style.html#Bar-charts
There's no way to do this out of the box using pandas right now (I'll try to implement that soon), but for now here's a monkey-patching solution:
def _bar_center_zero(self, s, color_positive, color_negative, width):
# Either the min or the max should reach the edge (50%, centered on zero)
m = max(abs(s.min()),abs(s.max()))
normed = s * 50 * width / (100 * m)
base = 'width: 10em; height: 80%;'
attrs_neg = (base+ 'background: linear-gradient(90deg, transparent 0%, transparent {w}%, {c} {w}%, '
'{c} 50%, transparent 50%)')
attrs_pos = (base+ 'background: linear-gradient(90deg, transparent 0%, transparent 50%, {c} 50%, {c} {w}%, '
'transparent {w}%)')
return [attrs_pos.format(c=color_positive, w=(50+x)) if x > 0
else attrs_neg.format(c=color_negative, w=(50+x))
for x in normed]
def bar_excel(self, subset=None, axis=0, color_positive='#5FBA7D',
color_negative='#d65f5f', width=100):
"""
Color the background ``color`` proptional to the values in each column.
Excludes non-numeric data by default.
.. versionadded:: 0.17.1
Parameters
----------
subset: IndexSlice, default None
a valid slice for ``data`` to limit the style application to
axis: int
color_positive: str
color_negative: str
width: float
A number between 0 or 100. The largest value will cover ``width``
percent of the cell's width
Returns
-------
self : Styler
"""
#subset = _maybe_numeric_slice(self.data, subset)
#subset = _non_reducing_slice(subset)
self.apply(self._bar_center_zero, axis=axis, subset=subset,
color_positive=color_positive, color_negative=color_negative,
width=width)
return self
Monkey-patch this to the Styler class:
pd.formats.style.Styler._bar_center_zero = _bar_center_zero
pd.formats.style.Styler.bar_excel = bar_excel
Now you can use it:
df = pd.DataFrame([-0.02, 0.03, 0.04, -0.05], columns=['A'])
df.style.bar_excel(color_positive='#5FBA7D', color_negative='#d65f5f')
Update:
I since then created a pull request on GitHub where I implemented this as well as the option of centering 'dynamically' (align='mid').
The resulting bar you can get by specifying options align and depending on the type of your data are represented below:

Related

Shadows not showing up in Pybullet getCameraImage

I am trying to produce shadows in a captured image in the Pybullet simulator. The shadows show up in the debugGUI mode but are not visible when calling p.getCameraImage even with shadow=True.
Something else I noticed is when shadow=True in p.getCameraImage there is a large shadow as if there is a tall object blocking the light rather than a small shadow corresponding to the object.
The issue persists whether connected to direct (p.connect(p.DIRECT)) or to GUI (p.connect(p.GUI)) as suggested here: https://github.com/bulletphysics/bullet3/issues/2610 and I have attached a minimum code sample below needed to reproduce the issue.
import pybullet as p
import pybullet_data
from PIL import Image
import math
physicsClient = p.connect(p.DIRECT)
p.setAdditionalSearchPath(pybullet_data.getDataPath())
p.configureDebugVisualizer(p.COV_ENABLE_SHADOWS, 1) # Shadows on/off
planeId = p.loadURDF("plane.urdf")
p.loadURDF("sphere_small.urdf",[0,0,0.2])
projectionMatrix = p.computeProjectionMatrixFOV(
fov=90.0,
aspect=16. / 9.,
nearVal=0.1,
farVal=30)
for i in range(360):
viewMatrix = p.computeViewMatrix(
cameraEyePosition=[2*math.cos(math.radians(i)), 2*math.sin(math.radians(i)),2],
cameraTargetPosition=[0.0, 0, 0],
cameraUpVector=[0, 0, 1])
width, height, rgbImg, depthImg, segImg = p.getCameraImage(
width=int(1280),
height=int(720),
viewMatrix=viewMatrix,
projectionMatrix=projectionMatrix,
shadow=True
)
im = Image.fromarray(rgbImg)
im.save('imgs/test/' + str(i) + ".png")

How to effectively adjust graph margin or padding in dash plotly

I have plotted two graphs using plotly dash. But when the y-axis / x-axis tick size is more it gets cut off.
Y-axis :
Code :
data = [go.Scatter(x = df[df['S2PName-Category']==category]['S2BillDate'],
y = df[df['S2PName-Category']==category]['totSale'],
mode = 'markers+lines',
name = category) for category in df['S2PName-Category'].unique()]
layout = go.Layout(title='Category Trend',
xaxis = dict(title = 'Time Frame', tickformat = '%d-%b-%y'),
yaxis = dict(tickprefix= '₹', tickformat=',.2f',type='log'),
hovermode = 'closest',
plot_bgcolor = colors['background'],
paper_bgcolor = colors['background'],
font = dict(color = colors['text'])
)
X-Axis :
Code :
data = [go.Scatter(x = df[df['S2PName']==item]['S2BillDate'],
y = df[df['S2PName']==item]['totSale'],
mode = 'markers+lines',
name = item) for item in items]
layout = go.Layout(title='Category Trend',
xaxis = dict(title = 'Time Frame' , tickformat = '%d-%b'),
yaxis = dict(tickprefix= '₹', tickformat=',.2f',type='log',autorange = True),
hovermode = 'closest',
plot_bgcolor = colors['background'],
paper_bgcolor = colors['background'],
font = dict(color = colors['text'])
)
In the above 2 graphs , as the length of the tick value increases, it gets cut off . Is there a better way to handle this ?
Credit for #Flavia Giammarino in comments for the reference to the docs. I'm posting the answer for completeness.
https://plotly.com/python/setting-graph-size/
From that link the example below shows how to set margin:
fig.update_layout(
margin=dict(l=20, r=20, t=20, b=20),
)
Where l r t b correspond to left, right, top, bottom.
I had a similar problem with some Dash/Plotly charts and long y axis labels being truncated or hidden. There didn't seem to be much information or documentation on this issue, so it took a while to solve.
Solution: add this code to the layout settings to prevent truncation of the y axes labels:
fig.update_layout(
yaxis=dict(
automargin=True
)
)
or you can update the yaxes setting specifically:
fig.update_yaxes(automargin=True)
Update: I tried another version of Plotly (5.10 or above) which mentions setting the automargin setting to any combination of automargin=['left+top+right+bottom'] with similar results. This still seems a bit unstable and doesn't solve all possible scenarios or corner cases, but works fine in most cases, especially when the browser window is maximized.

How do I load multiple grayscale images as a single tensor in pytorch?

I'm currently trying to use a stack a set of images as a single entity for each label to train a CNN on using cross-validation. Given a dataset of 224x224x1 grayscale images sorted by:
Root/
Class0/image0_view0.png
Class0/image0_view1.png
Class0/image0_view2.png
...
Class1/image0_view0.png
Class1/image0_view1.png
Class1/image0_view2.png
How would I go about flowing 3 images (view 0, 1, and 2) as a single tensor with dimensions 224x224x3 (3 grayscale images)? In other words, how would I create a dataset of image stacks in pytorch using ImageFolder/DatasetFolder and DataLoader? Would I have to re-organize my folders and classes, or would it be easier to make the stacks when I make the splits for cross-validation?
Thank you for your time and help! Let me know if I can provide any more info.
I had a very similar task. I needed to load a random sequence of 3 images as an element of a batch for training the network not on separate images but on seq of images. For batch size 8, I have 8 x 3 = 24 images. This seems to be very similar to different views in your case. I used imread_collection functionality from skimage.io. I added such a getitem to the Dataset class:
def __getitem__(self, idx):
idx_q = int(torch.randint(0 + self.boundary, self.length - self.boundary, (1,)))
q = imread_collection([self.image_paths[idx_q-1], self.image_paths[idx_q], self.image_paths[idx_q+1]], conserve_memory=True)
if self.transform:
q = torch.stack([self.transform(img) for img in q])
return q, p, n
Here I generate a random index of an image and then load three consecutive images using imread_collection and self.image_paths, which is the list with paths to all images. Then I do transform of each image and stack them. In your case, you should think about using the right indexes, maybe by applying a sliding window on the length of self.image_paths.
A bit more info could be found on the torch forum. I also tried to ask and find a more elegant solution, but couldn't and successfully trained the model with such an approach.
How do I load multiple grayscale images as a single tensor in pytorch?
In general, the number of channels is not important.
The operation known as "loading a batch of data" is what you need. For this PyTorch has DataLoader class. DataLoader class further needs Dataset class.
If in DataLoader the batch size is 64 (bs=64) you will load 64 images from once as tensor.
If you use ImageFolder this will not return minibatch for you. ImageFolder is a Dataset derived class.
The problem with ImageFolder (if you just use that) is you will get a single image per index. You would combine multiple images to a minibatch then.
Here is one example using ImageFolder with CIFAR10 data.
from torchvision import transforms
imagef = torchvision.datasets.ImageFolder(r'C:\Users\dj\data\cifar10\test', transform=transforms.ToTensor())
print(imagef)
print(imagef.classes)
img, label = imagef[0]
display(img)
print(img.size())
print(label)
Out:
Dataset ImageFolder
Number of datapoints: 10000
Root location: C:\Users\dj\data\cifar10\test
StandardTransform
Transform: ToTensor()
['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']
tensor([[[0.6078, 0.6549, 0.6902, ..., 0.7882, 0.7922, 0.7529],
[0.6000, 0.6392, 0.6706, ..., 0.7922, 0.7961, 0.7412],
[0.6078, 0.6275, 0.6588, ..., 0.8078, 0.8000, 0.7412],
...,
[0.3490, 0.2235, 0.2392, ..., 0.3490, 0.2314, 0.2627],
[0.3490, 0.2353, 0.2471, ..., 0.2235, 0.2392, 0.2941],
[0.3608, 0.2353, 0.2392, ..., 0.2353, 0.2510, 0.2863]], ...
torch.Size([3, 32, 32])
0
The next example is based on DataLoader:
import torch
from torch.utils.data import DataLoader, Dataset
import torchvision
from torchvision import transforms
import PIL.Image as Image
def pil_loader(path):
with open(path, 'rb') as f:
img = Image.open(f)
return img.convert('RGB')
ds = torchvision.datasets.DatasetFolder(r'C:\Users\dj\data\cifar10\test',
loader=pil_loader,
extensions=('.png'),
transform=transforms.ToTensor())
dl = DataLoader(ds, batch_size=2)
len(dl)
for imgs,lbls in dl:
print(imgs.size()) # torch.Size([2, 3, 32, 32])
break
This DataLoader is what you may need. The one I present, has the custom loading function: pil_loader.
You can also use ImageFolder instead of DatasetFolder in the previous example.
That would be something like:
ds = torchvision.datasets.ImageFolder(r'C:\Users\dj\data\cifar10\test', transform=transforms.ToTensor())
dl = DataLoader(ds, batch_size=3)
print(len(dl))
for imgs,lbls in dl:
print(imgs.size())
break

How to rotate text in table cells?

I'm trying to make table like this:
As you can see, the header is vertically orientated.
How can I achieve this using python-docx?
P.S. Sorry for non-translated table.
Snippet for those who are too tired to seek:
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
from docx.table import _Cell
def set_vertical_cell_direction(cell: _Cell, direction: str):
# direction: tbRl -- top to bottom, btLr -- bottom to top
assert direction in ("tbRl", "btLr")
tc = cell._tc
tcPr = tc.get_or_add_tcPr()
textDirection = OxmlElement('w:textDirection')
textDirection.set(qn('w:val'), direction) # btLr tbRl
tcPr.append(textDirection)

Tensorflow: tf.reduce_logsumexp returning negative values

I am new to tensorflow framework. I am using
tf.reduce_logsumexp in my code. But inspecting the output I see that some of the values are negative. How is that possible? I suspected that it might be due to some nans or inf values so I put in a check to remove those values in my input like this(X is my input):
res = tf.where(tf.is_inf(X), tf.zeros_like(X), X)
res = tf.where(tf.is_nan(res), tf.zeros_like(res), res)
output = tf.reduce_logsumexp(res, axis=0)
But even this does not help and I still get some values as negative. Any help appreciated! Thanks
Note that the logarithm is negative, if its argument is smaller than 1. Therefore, you will always get a negative logsumexp output if the sum of the exponentials is smaller than 1. This occurs for example if all of the exponents are much smaller than zero, i.e. you have
res = [-2.5, -1.4, -3.3, -1.65, -2.15], then the corresponding exponentials are
exp(res) = [0.082, 0.247, 0.037, 0.192, 0.116], and their sum
sum(exp(res)) = 0.674 smaller than 1.
If you then take the logarithm, you get
log(sum(exp(res))) = log(0.674) = -0.394.
It simply emerges from the definition of the function that it does not necessarily have a positive output. You can test it with the following program:
import numpy as np
def logsumexp(arr):
summ = 0.0
for i in range(arr.shape[0]):
print(np.exp(arr[i]))
summ += np.exp(arr[i])
print('Sum: {}'.format(summ))
return np.log(np.sum(np.exp(arr)))
arr = np.asarray([-2.5, -1.4, -3.3, -1.65, -2.15])
print('LogSumExp: {}'.format(logsumexp(arr)))