Related
I have made a pbiviz custom visual using developer tools of Normal distribution curve over a Histogram plot with R - ggplot2 and plotly libraries in a pbiviz.package
The visual works fine. Now I want to add interactivity of the Histogram with other Power BI visuals.
i.e. If user clicks on a bar of the Histogram, it should filter out a Table on my PBI report with rows relevant to the histogram bar data.
Considering the limitations of using R script with Power BI, I do not know if it is possible with my current visual as I am new to scripting.
Is there a better way (Typescript, JS, Python, etc.) other than what I have done to make an Interactive Histogram & Distribution Curve in Power BI?
This is the R script along with sample data and Visual Image
Histogram represents the projects falling in different durations
There are two bell curves - One for closed projects and Other for Active Projects
source('./r_files/flatten_HTML.r')
############### Library Declarations ###############
libraryRequireInstall("ggplot2");
libraryRequireInstall("plotly");
libraryRequireInstall("tidyverse");
libraryRequireInstall("scales");
libraryRequireInstall("htmlwidgets");
library(ggplot2)
library(tidyverse)
library(scales)
library(plotly)
theme_set(theme_bw())
##### Making DataSet for All Selected Projects #####
Duration <- dataset$Duration
Status <- (rep(dataset$ProjectStatus))
da <- data.frame(Duration,Status)
lenx <- length(Duration)
meanall <- mean(da$Duration)
sdx <- sd(da$Duration)
binwidth <- 30
font_label <- list(family = "Segoe UI", size = 21, colour = "black")
hovlabel <- list(bordercolor = "black", font = font_label)
#Filtering Out Closed Projects from Dataset
#Creating Data Frame for Closed Projects
closedproj <- dataset %>%
select(Duration,ProjectStatus) %>%
filter(ProjectStatus == "Closed")
closed <- closedproj$Duration
df <- data.frame(closed)
xclosed <- closedproj$
df2 <- data.frame(xclosed)
lenc <- length(xclosed)
mean_closed <- mean(df2$xclosed)
sdc <- sd(df2$xclosed)
a <-
(ggplot(da,aes(x=Duration, fill = Status, text = paste("Duration: ",x,"-", x + binwidth,"<br />Project Count", ..count..)))+
#Histogram
geom_histogram(aes(y=..count..),alpha=0.5, position='identity',binwidth = binwidth)+
# #Distribution Curve
annotate(
geom = "line",
x = da$Duration,
y = dnorm(da$Duration, mean = meanall, sd = sdx) * lenx * binwidth,
width = 3,
color = "red"
) +
annotate(
geom = "line",
x = df2$xclosed,
y = dnorm(df2$xclosed, mean = mean_closed, sd = sdc)* lenc * binwidth,
width = 3,
color = "blue"
) +
labs(
x = "Project Duration (Days)",
y = "Project_Count",
fill = "Project Status")+
#Mean
geom_vline(aes(xintercept=meanall),color="red",linetype="dashed",size = 0.8,label=paste("Mean :",round(meanall,0)))+
geom_vline(aes(xintercept=mean_closed),color="blue",linetype="dashed",size = 0.8,label=paste("Mean (Closed):",round(mean_closed,0)))+
# 1 Sigma
geom_vline(aes(xintercept = (meanall + sdx)), color = "red", size = 1, linetype = "dashed") +
geom_vline(aes(xintercept = (meanall - sdx)), color = "red", size = 1, linetype = "dashed")+
geom_vline(aes(xintercept = (mean_closed + sdc)), color = "blue", size = 1, linetype = "dashed") +
geom_vline(aes(xintercept = (mean_closed - sdc)), color = "blue", size = 1, linetype = "dashed")+
# Theme
theme(
plot.background = element_rect(fill = "transparent"),
legend.background = element_rect(fill = "lightgray"),
axis.title.x = element_text(colour = "Black",size = 18,face = "bold"),
axis.title.y = element_text(colour = "Black",size = 18,face = "bold"),
axis.text.x = element_text(colour = "Black",size = 15),
axis.text.y = element_text(colour = "Black",size = 15),
panel.grid.major = element_blank(), panel.grid.minor = element_blank())+
scale_x_continuous(labels = comma,
breaks = seq(0, max(Duration),50)) +
scale_y_continuous(labels = comma,
breaks = seq(0,max(Duration),10)))
############# Create and save widget ###############
p = ggplotly(a, tooltip = c("text")) %>%
style(hoverlabel = hovlabel) %>%
layout(legend = list(
orientation = "h",
x = 0,
y = 1.13,
title = list(text = "Project Status",font = list(family = "Segoe UI", size = 23)),
font = font_label
),
yaxis = list(title = list(standoff = 25L)),
xaxis = list(title = list(standoff = 25L)),
annotations = list(showarrow=FALSE,align = "left",valign = "top",x = 0.95, xref = "paper",yref = "paper",y = 0.955,
font = list(family = "Segoe UI", size = 22, color = "#cc0000"),
text = paste("Max Duration: ", comma(round(max(da$Duration),0)),
"<br>Mean (Closed): ", comma(round(mean_closed,0)),
"<br>Mean (All) : ", comma(round(meanall,0))))
) %>%
config(modeBarButtonsToRemove = c("select2d","hoverClosestCartesian", "lasso2d","hoverCompareCartesian","toggleSpikelines"), displaylogo = FALSE);
internalSaveWidget(p, 'out.html');
}
####################################################
################ Reduce paddings ###################
ReadFullFileReplaceString('out.html', 'out.html', ',"padding":[0-5]*,', ',"padding":0,')
What I expect is -- If user clicks on a bar of the Histogram, it should reflect on a Table visual on my PBI report with rows relevant to the histogram bar data.
Any help will be highly appreciated !
Regards
I'd like to understand why, when I convert the PIL image imageRGB to a float array arrayRGB_f and use matplotlib's imshow() without a cmap it looks either black, or strange and unreadable, even though PIL's imageRGB.show() looks fine, and each of the individual r, g, b channels shown with cmap='gray' look okay as well.
I have workarounds, but I just don't understand why this happens.
matplotlib.__version__ returns '2.0.2' and I'm using MacOS with an Anaconda installation.
See this answer for more on the conversion of a ttf rendering to a 1bit.
fyi the output of the print statements are:
float64 (41, 101, 3)
int64 (41, 101, 3)
int64 (41, 101)
int64 (41, 101)
fontname = 'default'
imageRGB.show()
plt.imshow()
fontname = 'Arial Unicode.ttf'
imageRGB.show()
plt.imshow()
font = ImageFont.truetype(fontname, 20)
imageRGB.show()
plt.imshow()
from PIL import Image, ImageDraw, ImageFont
import numpy as np
import matplotlib.pyplot as plt
# fontname = 'Arial Unicode.ttf'
fontname = 'default'
if fontname == 'default':
font = ImageFont.load_default()
else:
font = ImageFont.truetype(fontname, 12)
string = "Hello " + fontname[:6]
ww, hh = 101, 41
threshold = 80 # https://stackoverflow.com/a/47546095/3904031
imageRGB = Image.new('RGB', (ww, hh))
draw = ImageDraw.Draw(imageRGB)
image8bit = draw.text((10, 12), string, font=font,
fill=(255, 255, 255, 255)) # R, G, B alpha
image8bit = imageRGB.convert("L")
image1bit = image8bit.point(lambda x: 0 if x < threshold else 1, mode='1') # https://stackoverflow.com/a/47546095/3904031
arrayRGB = np.array(list(imageRGB.getdata())).reshape(hh, ww, 3)
arrayRGB_f = arrayRGB.astype(float)
array8bit = np.array(list(image8bit.getdata())).reshape(hh, ww)
array1bit = np.array(list(image1bit.getdata())).reshape(hh, ww)
for a in (arrayRGB_f, arrayRGB, array8bit, array1bit):
print a.dtype, a.shape
imageRGB.show()
if True:
plt.figure()
a = arrayRGB_f
plt.subplot(2, 2, 1)
plt.imshow(a) # , interpolation='nearest', cmap='gray',
for i in range(3):
plt.subplot(2, 2, 2+i)
plt.imshow(a[:, :, i], cmap='gray')
plt.suptitle('arrayRGB_f, fontname = ' + fontname)
plt.show()
I can't find an ideal duplicate so I'll post an answer.
As #ImportanceOfBeingErnest mentions when .imshow() is given an n x m x 3 or n x m x 4 array, it is expecting a normalized array between 0.0 and 1.0.
Best way to do this is:
arrayRGB_f = arrayRGB.astype(float)/255.
though this seems to work as well:
arrayRGB_f = arrayRGB.astype(float)
arrayRGB_f = arrayRGB_f / arrayRGB_f.max()
For longer discussions, see this and this.
I am using wx.python along with VPython to make an orbit simulator, however i'm having trouble trying to get the sliders in the GUI to effect the simulation, I assume it's because I am trying to get the number associated with the slider button to go into a while loop when it is running.
So my question is, how do i get the function SetRate to update in the while loop located at the bottom of the code? (I have checked to see that the slider is retuning values)
Here is my code for reference:
Value = 1.0
dt = 100.0
def InputValue(Value):
dt = Value
def SetRate(evt):
global Value
Value = SpeedOfSimulation.GetValue()
return Value
w = window(menus=True, title="Planetary Orbits",x=0, y=0, width = 1000, height = 1000)
Screen = display(window = w, x = 30, y = 30, width = 700, height = 500)
gdisplay(window = w, x = 80, y = 80 , width = 40, height = 20)
p = w.panel # Refers to the full region of the window in which to place widgets
SpeedOfSimulation = wx.Slider(p, pos=(800,10), size=(200,100), minValue=0, maxValue=1000)
SpeedOfSimulation.Bind(wx.EVT_SCROLL, SetRate)
TestData = [2, 0, 0, 0, 6371e3, 5.98e24, 0, 0, 0, 384400e3, 0, 0, 1737e3, 7.35e22, 0, 1e3, 0]
Nstars = TestData[0] # change this to have more or fewer stars
G = 6.7e-11 # Universal gravitational constant
# Typical values
Msun = 2E30
Rsun = 2E9
vsun = 0.8*sqrt(G*Msun/Rsun)
Stars = []
colors = [color.red, color.green, color.blue,
color.yellow, color.cyan, color.magenta]
PositionList = []
MomentumList = []
MassList = []
RadiusList = []
for i in range(0,Nstars):
s=i*8
x = TestData[s+1]
y = TestData[s+2]
z = TestData[s+3]
Radius = TestData[s+4]
Stars = Stars+[sphere(pos=(x,y,z), radius=Radius, color=colors[i % 6],
make_trail=True, interval=10)]
Mass = TestData[s+5]
SpeedX = TestData[s+6]
SpeedY = TestData[s+7]
SpeedZ = TestData[s+8]
px = Mass*(SpeedX)
py = Mass*(SpeedY)
pz = Mass*(SpeedZ)
PositionList.append((x,y,z))
MomentumList.append((px,py,pz))
MassList.append(Mass)
RadiusList.append(Radius)
pos = array(PositionList)
Momentum = array(MomentumList)
Mass = array(MassList)
Mass.shape = (Nstars,1) # Numeric Python: (1 by Nstars) vs. (Nstars by 1)
Radii = array(RadiusList)
vcm = sum(Momentum)/sum(Mass) # velocity of center of mass
Momentum = Momentum-Mass*vcm # make total initial momentum equal zero
Nsteps = 0
time = clock()
Nhits = 0
while True:
InputValue(Value) #Reprensents the change in time
rate(100000) #No more than 100 loops per second on fast computers
# Compute all forces on all stars
r = pos-pos[:,newaxis] # all pairs of star-to-star vectors (Where r is the Relative Position Vector
for n in range(Nstars):
r[n,n] = 1e6 # otherwise the self-forces are infinite
rmag = sqrt(sum(square(r),-1)) # star-to-star scalar distances
hit = less_equal(rmag,Radii+Radii[:,newaxis])-identity(Nstars)
hitlist = sort(nonzero(hit.flat)[0]).tolist() # 1,2 encoded as 1*Nstars+2
F = G*Mass*Mass[:,newaxis]*r/rmag[:,:,newaxis]**3 # all force pairs
for n in range(Nstars):
F[n,n] = 0 # no self-forces
Momentum = Momentum+sum(F,1)*dt
# Having updated all momenta, now update all positions
pos = pos+(Momentum/Mass)*dt
# Update positions of display objects; add trail
for i in range(Nstars):
Stars[i].pos = pos[i]
I know nothing about vpython but in a normal wxPython app, you will use wx.Timer instead of while loop.
here is an example of wx.Timer modified from https://www.blog.pythonlibrary.org/2009/08/25/wxpython-using-wx-timers/
You will want to separate the while loop part from your SetRate class method and put it in update.
import wx
class MyForm(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, wx.ID_ANY, "Timer Tutorial 1",
size=(500,500))
# Add a panel so it looks the correct on all platforms
panel = wx.Panel(self, wx.ID_ANY)
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.update, self.timer)
SpeedOfSimulation = wx.Slider(p, pos=(800,10), size=(200,100), minValue=0, maxValue=1000)
SpeedOfSimulation.Bind(wx.EVT_SCROLL, SetRate)
self.SpeedOfSimulation = SpeedOfSimulation
def update(self, event):
# Compute all forces on all stars
SpeedOfSimulation = self.SpeedOfSimulation.GetValue()
I have 2 listboxes (which are connected so that items can move from one to the other) and at the end I would like to get all the entries in the second listbox by using a 'Ok' button (or simply closing the frame). I could add/remove values to a list every time an item is selected (as shown in the commented section of the code below) but I would rather have a single line of code along the lines of [master.selected.get(idx) for idx in master.selected.curselection()] in the close function but I am unable to get it working.
Code:
def measurementPopup(self,master):
self.chargeCarrier = StringVar()
self.massModifiers = StringVar()
self.chargeCarrier.set("[M+xH]")
def onselect1(evt):
w = evt.widget
index = int(w.curselection()[0])
value = w.get(index)
# My Dirty fix -> Here I could enter the selected value to a buffer list (to be returned in the ok function).
master.selected.insert(END,value)
master.avail.delete(index)
def onselect2(evt):
w = evt.widget
index = int(w.curselection()[0])
value = w.get(index)
# My Dirty fix -> Here I could remove the selected value from a buffer list (to be returned in the ok function).
master.selected.delete(index)
master.avail.insert(END,value)
def close(self):
# Here I would return the buffer list and close the window
master.measurementWindow = 0
top.destroy()
if master.measurementWindow == 1:
return
master.measurementWindow = 1
top = self.top = Toplevel()
top.protocol( "WM_DELETE_WINDOW", lambda: close(self))
self.charge = Label(top, text = "Charge", width = 10)
self.charge.grid(row = 0, column = 0, sticky = W)
self.min = Label(top, text = "Min", width = 5)
self.min.grid(row=0, column = 1, sticky = W)
self.minCharge = Spinbox(top, from_= 1, to = 3, width = 5)
self.minCharge.grid(row = 0, column = 2, sticky = W)
self.max = Label(top, text = "Max", width = 5)
self.max.grid(row = 0, column = 3, sticky = W)
self.maxCharge = Spinbox(top, from_ = 1, to=3, width=5)
self.maxCharge.grid(row = 0, column = 4, sticky = W)
self.chargeCarrier = OptionMenu(top, self.chargeCarrier, "[M+xH]", "[M+xNa]")
self.chargeCarrier.grid(row = 0, column = 5, sticky = W)
self.availMass = Label(top, text = "Available")
self.availMass.grid(row = 1, column = 1, sticky = W)
self.selectMass = Label(top, text = "Selected")
self.selectMass.grid(row = 1, column = 3, sticky = W)
self.massMod = Label(top, text = "Mass Mods")
self.massMod.grid(row = 2, column = 0, sticky = W)
self.avail = Listbox(top)
for i in UNITS:
if BLOCKS[i]['available'] == 1:
self.avail.insert(END,BLOCKS[i]['human_readable_name'])
self.avail.grid(row = 2, column = 1, columnspan = 2, sticky = W)
self.avail.bind('<<ListboxSelect>>',onselect1)
self.selected = Listbox(top)
self.selected.grid(row = 2, column = 3, columnspan = 2, sticky = W)
self.selected.bind('<<ListboxSelect>>',onselect2)
self.ok = Button(top,text = 'Ok',command = lambda: close(self))
self.ok.grid(row = 3, column = 0, sticky = W)
I have tried to use the following small snippet in the close function:
values = [master.selected.get(idx) for idx in master.selected.curselection()]
print ', '.join(values)
However, the for segment doesn't return anything. I would expect that this is due to the fact that nothing is actually selected but that I would need something opposite, along the lines of master.selected.allitems() (if it exists and if I understand it correctly).
Summary
How would one get all the items in 1 specific listbox?
The .get() function for the Listbox widget allows you to specify a range of items, which can be specified as 0 to END to return a tuple of all the items.
Example:
from Tkinter import *
root = Tk()
l = Listbox(root, width = 15)
l.pack()
l.insert(END, "Hello")
l.insert(END, "world")
l.insert(END, "here")
l.insert(END, "is")
l.insert(END, "an")
l.insert(END, "example")
def close():
global l, root
items = l.get(0, END)
print(items)
root.destroy()
b = Button(root, text = "OK", command = close).pack()
root.mainloop()
I hope this helps, if it's not what you were looking for let me know in a comment and I can try expand my answer.
from Tkinter import *
import tkFileDialog
import sys
def openwindows():
eText.set(open.show())
def loadfiles():
filedirectory=eText.get()
f=file(filedirectory)
lines = f.readlines()
length=len(lines)
#vertex=[]
#face=[]
for x in range(0,length):
print (x)
Root=Tk()
RTitle=Root.title("Assignment_2")
RWidth=Root.winfo_screenwidth()
RHeight=Root.winfo_screenheight()
Root.geometry("%dx%d+%d+%d" % (RWidth/3,RHeight/3*2,RWidth/2-RWidth/6, RHeight/2-RHeight/3))
frame1 = Frame(Root)
frame1.pack()
Label(frame1, text="Filename: ").pack(side = LEFT)
eText = StringVar()
statusbar = Entry(frame1, state="readonly", textvariable=eText)
eText.set("pyramid.txt")
statusbar.pack(side = LEFT)
myfiletypes = [('text files', '*.txt'), ('All files', '*')]
open = tkFileDialog.Open(frame1, filetypes = myfiletypes)
Button(frame1, text="Browse", fg = "Blue", command=openwindows).pack(side = LEFT)
Button(frame1, text = "Load", fg = "red", command=loadfiles).pack(side=LEFT)
frame2 = Frame(Root)
frame2.pack()
Label(frame2, text="Rotation Axis: ").pack(side=LEFT)
r1 = IntVar()
r1.set(3)
Radiobutton(frame2, text="X", variable=r1, value=1).pack(side=LEFT)
Radiobutton(frame2, text="Y", variable=r1, value=2).pack(side=LEFT)
Radiobutton(frame2, text="Z", variable=r1, value=3).pack(side=LEFT)
Radiobutton(frame2, text="Line AB", variable=r1, value=4).pack(side=LEFT)
Label(frame2, text="A:").pack(side=LEFT)
pointA = Entry(frame2, width=10)
pointA.insert(0, "[0.0,0.0,0.0]")
pointA.pack(side=LEFT)
Label(frame2, text="B:").pack(side=LEFT)
pointB = Entry(frame2, width=10)
pointB.insert(0, "[1.0,1.0,1.0]")
pointB.pack(side=LEFT)
var1 = StringVar(Root)
var1.set("90")
Label(frame2, text="Degree:").pack(side=LEFT)
Spinbox(frame2, width=3, from_=0, to=350, increment=10, textvariable=var1).pack(side=LEFT)
var2 = StringVar(Root)
var2.set("5")
Label(frame2, text="Steps:").pack(side=LEFT)
Spinbox(frame2, width=3, from_= 1, to = 10, textvariable=var2).pack(side=LEFT)
Button(frame2, text = "Rotate", fg = "Blue").pack(side=LEFT)
frame3 = Frame(Root)
frame3.pack()
Label(frame3, text="Scale Ratio: ").pack(side=LEFT)
r2 = IntVar()
r2.set(1)
Radiobutton(frame3, text="All", variable=r2, value=1).pack(side=LEFT)
var3 = StringVar(Root)
var3.set("1")
Spinbox(frame3, width=4, from_= 0.25, to = 4, textvariable=var3, increment=0.25, format='%3.2f').pack(side=LEFT)
Radiobutton(frame3, text="[Sx,Sy,Sz]", variable=r2, value=2).pack(side=LEFT)
scaleamount = Entry(frame3, width=10)
scaleamount.insert(0, "[1,1,1]")
scaleamount.pack(side=LEFT)
var4 = StringVar(Root)
var4.set("4")
Label(frame3, text="Steps:").pack(side=LEFT)
Spinbox(frame3, width=3, from_= 1, to = 10, textvariable=var4).pack(side=LEFT)
Button(frame3, text = "Scale", fg = "Blue").pack(side=LEFT)
separator = Frame(height=2, bd=1, relief=SUNKEN)
separator.pack(fill=X, padx=5, pady=5)
Canvas(Root, bg="Blue").pack(fill="both", expand=True)
mainloop()
when you click Load, its suppose to read the file and display this.
0
1
2
3
4
5
6
7
.....
whatever number of lined you have in the txt file.
But the problem is that, it only displays this
0
which means the for loop only ran one time and thats it.
if I close the program, then the rest of the numbers will show in the command prompt.
really weird... doesnt make sense.
the loadfiles() itself works perfectly fine.
It just wont work with the button
The issue has to do with how the UI is processing.
Try replacing print (x) with
sys.stdout.write(str(x) + '\n') # or "{}\n".format(x)
sys.stdout.flush()
If you search for tkinter and flush you will find plenty of conversations to read.