Tooltip of highchart is not displaying properly - highcharts

I am trying to generate column chart of highcharts using rchart library. Spline and pie chart worked me fine. But column chart's tooltip is not rendering properly
I am using following code to generate it
res <- getForumNumDiscussionsData()
h1 <- Highcharts$new()
h1$chart(type = "column")
res <- getForumNumDiscussionsData()
h1 <- Highcharts$new()
h1$chart(type = "column")
#axis
h1$xAxis(title=list(text="Number of Discussions"),categories=res$categories)
h1$yAxis(title=list(text="Number of students"))
#plot options
h1$plotOptions(column=list(pointPadding=0,borderWidth=0))
#series
h1$series(data = res$count,name="students")
#export
h1$exporting(sourceWidth = 1000, sourceHeight = 400)
and data frame : res
categories count
1 < 13 12
2 < 24 121
3 < 39 13
Can anybody help me to render tooltip text properly

Related

Constrain axis limits in chordDiagram (circlize) when making gifs

I hope somebody will be able to help me with this chordDiagram visualisation I am trying to create. I am well aware that maybe this visualization type was not suitable for this particular data, but somehow it was something I had in my head (or how I wanted to visualize this data) and what I wanted to create, and now I think it is too late to give it up :) too curious how one can fix it. It is my first real post here, though I am an active user of stackoverflow and I genuinely admire the audience here.
So I have this data on the change in the size of area in km2 over time (d0) and I am trying to create a GIF out of it using example here: https://guyabel.com/post/animated-directional-chord-diagrams/
The data "d0":
Time <- as.numeric(c(10,10,10,100,100,100,200,200,200,5,5,5,50,50,50,0,0,0))
Year <- as.character(c(2050,2100,2200,2050,2100,2200,2050,2100,2200,2050,2100,2200,2050,2100,2200,2050,2100,2200))
Area_km2 <- as.numeric(c(4.3075211,7.1672926,17.2780622,5.9099250,8.2909189,16.9748961,6.5400554,8.9036313,16.5627228,3.0765610,6.3929883,18.0708108,5.3520782,8.4503856,16.7938196,0.5565978,1.8415855,12.5089476))
(d0 <- as.data.frame(cbind(Time,Year,Area_km2)))
I also have the color codes stored in a separate dataframe (d1) following the above mentioned example.
The data "d1":
year <- as.numeric(c(2050,2100,2200))
order1 <- as.character(c(1,2,3))
col1 <- c("#40A4D8","#33BEB7","#0C5BCE")
(d1 <- as.data.frame(cbind(year,order1,col1)))
So the idea was to have self-linking flows within each sector increasing in size over time, which will look like just growing segments in a final animated GIF (or like growing pie segments), but I noticed that regardless how hard I try I can't seem to manage to constrain the axis of each segment to limits of that particular year in an every single frame. It seems that the axis is being added on and keeps on adding over time, which is not what I want.
Like for example in the first figure (figure0) or "starting frame" the size of the links matches well the dataframe:
figure0
So it is
orig_year
Area_km2
.frame
2050
0.557
0
2100
1.84
0
2200
12.5
0
But when one plots next figure (figure1), the axis seems to have taken the values from the starting frame and added on the current values (4, 7.4 and 19 respectively) instead of (3.08, 6.39 and 18.1) or what should have been the values according the data frame:
figure1
orig_year
Area_km2
.frame
2050
3.08
1
2100
6.39
1
2200
18.1
1
And it keep on doing so as one loops through the data and creates new plots for the next frames. I wonder whether it is possible to constrain the axis and create the visualization in a way that the links just gradually increase over time and the axis is, so to say, following the increase or does also increase gradually following the data???
Any help is highly appreciated!
Thanks.
My code:
Sort decreasing
(d0 <- arrange(d0,Time))
Copy columns
(d0$Dest_year <- d0$Year)
Re-arrange data
library(tweenr)
(d2 <- d0 %>%
mutate(corridor=paste(Year,Dest_year,sep="->")) %>%
dplyr::select(Time,corridor,Area_km2) %>%
mutate(ease="linear") %>%
tweenr::tween_elements('Time','corridor','ease',nframes=30) %>%
tibble::as_tibble())
(d2 <- d2 %>%
separate(col=.group,into=c("orig_year","dest_year"),sep="->") %>%
dplyr::select(orig_year,dest_year,Area_km2,everything()))
d2$Time <- NULL
Create a directory to store the individual plots
dir.create("./plot-gif/")
Fixing scales
scale_gap <- function(Area_km2_m,Area_km2_max,gap_at_max=1,gaps=NULL) {
p <- Area_km2_m/Area_km2_max
if(length(gap_at_max)==1 & !is.null(gaps)) {
gap_at_max <- rep(gap_at_max,gaps)
}
gap_degree <- (360-sum(gap_at_max))*(1-p)
gap_m <- (gap_degree + sum(gap_at_max))/gaps
return(gap_m)
}
Function to derive the size of gaps in each frame for an animated GIF
(d3 <- d2 %>% group_by(orig_year) %>% mutate(gaps=scale_gap(Area_km2_m=Area_km2,Area_km2_max=max(.$Area_km2),gap_at_max=4,gaps=9)))
library(magrittr)
Get the values for axis limits
(axmax <- d2 %>% group_by(orig_year,.frame) %>% mutate(max=mean(Area_km2)))
Creating unique chordDiagrams for each frame
library(circlize)
for(f in unique(d2$.frame)){
png(file=paste0("./plot-gif/figure",f,".png"),height=7,width=7,units="in",res=500)
circos.clear()
par(mar=rep(0,4),cex=1)
circos.par(start.degree=90,track.margin=c(-0.1,0.1),
gap.degree=filter(d3,.frame==f)$gaps,
points.overflow.warning=FALSE)
chordDiagram(x=filter(d2,.frame==f),directional=2,order=d1$year,
grid.col=d1$col1,annotationTrack=c("grid","name","axis"),
transparency=0.25,annotationTrackHeight=c(0.05,0.1),
direction.type=c("diffHeight"),
diffHeight=-0.04,link.sort=TRUE,
xmax=axmax$max)
dev.off()
}
Now make a GIF
library(magick)
img <- image_read(path="./plot-gif/figure0.png")
for(f in unique(d2$.frame)[-1]){
img0 <- image_read(path=paste0("./plot-gif/figure",f,".png"))
img <- c(img,img0)
message(f)
}
img1 <- image_scale(image=img,geometry="720x720")
ani0 <- image_animate(image=img1,fps=10)
image_write(image=ani0,path="./plot-gif/figure.gif")
I will start with your d0 object. I first construct the d0 object but I do not convert everything to characters, just put them as the original numeric format. Also I reorder d0 by Time and Year:
Time = c(10,10,10,100,100,100,200,200,200,5,5,5,50,50,50,0,0,0)
Year = c(2050,2100,2200,2050,2100,2200,2050,2100,2200,2050,2100,2200,2050,2100,2200,2050,2100,2200)
Area_km2 = c(4.3075211,7.1672926,17.2780622,5.9099250,8.2909189,16.9748961,6.5400554,8.9036313,16.5627228,3.0765610,6.3929883,18.0708108,5.3520782,8.4503856,16.7938196,0.5565978,1.8415855,12.5089476)
d0 = data.frame(Time = Time,
Year = Year,
Area_km2 = Area_km2,
Dest_year = Year)
d0 = d0[order(d0$Time, d0$Year), ]
The key thing is to calculate proper values for "gaps" between sectors so that the same unit from data corresponds to the same degree in different plots.
We first calculate the maximal total width of the circular plot:
width = tapply(d0$Area_km2, d0$Time, sum)
max_width = max(width)
We assume there are n sectors (where n = 3 in d0). We let the first n-1 gaps to be 2 degrees and we dynamically adjust the last gap according to the total amount of values in each plot. For the plot with the largest total value, the last gap is also set to 2 degrees.
n = 3
degree_per_unit = (360 - n*2)/max_width
Now degree_per_unit can be shared between multiple plots. Every time we calculate the value for last_gap:
for(t in sort(unique(Time))) {
l = d0$Time == t
d0_current = d0[l, c("Year", "Dest_year", "Area_km2")]
last_gap = 360 - (n-1)*2 - sum(d0_current$Area_km2)*degree_per_unit
circos.par(gap.after = c(rep(2, n-1), last_gap))
chordDiagram(d0_current, grid.col = c("2050" = "red", "2100" = "blue", "2200" = "green"))
circos.clear()
title(paste0("Time = ", t, ", Sum = ", sum(d0_current$Area_km2)))
Sys.sleep(1)
}

Draw a line chart based on user input

Please help me to draw a simple line chart in python turtle module based on user input. I am able to draw the x and y axis. The x-axis tick is equal to the number of data points. For example, if the user input is 5 then it will be 5 ticks labelled 1 to 5 and so on. However, the tick for y-axis has 6 ticks(fixed) labelled from 0 to 20, increment in 4(0,4,8..20).
I can't figure out the logic for plotting y values based on user input. For example, if the user types 15, it needs to go to the corresponding data point in y axis and put a dot in there. Similarly, if the user types 5 it needs to go the corresponding value in y axis as well plus connecting to the preceding data point(in this case connecting 15 from previous point to 5 in the current point) and so on based on user input. Also, my x and y labeling could be done it in a better way. Here is my code. Any help is much appreciated. Please look at the image description, I am aiming for similar results.
import turtle as t
import time
wn = t.Screen() # create a window for the turtle to draw on
wn.title("Turtle Demo") # the title to show at the top of the window
WINDOW_WIDTH = 500 # size constants for easy changing
WINDOW_HEIGHT = 500
wn.setup(WINDOW_WIDTH, WINDOW_HEIGHT, 200, 10) # specify window size (width, height)
user_input = t.numinput(title='Line graph', prompt='How many data points:')
x_max = user_input
# print(userInput)
# graph window
x_min = 0
y_min = 0
y_max = 5
# tick info
t_l = 0.1
x_t_space = 1
y_t_space = 1
wn.setworldcoordinates(x_min, y_min, x_max, y_max)
# Draw x-axis
t.tracer(10)
t.hideturtle()
t.up()
t.goto(x_min, 0)
t.down()
t.goto(user_input, 0.0)
t.up()
# Draw the y-axis
t.goto(0.0, y_min)
t.down()
t.goto(0.0, y_max)
t.up()
# Draw the x tick marks
n_x_ticks = int((x_max - x_min) / x_t_space) + 1
for tick in range(n_x_ticks):
loc = x_min + tick * x_t_space
t.up()
t.goto(loc, -t_l * 0.4)
t.down()
t.goto(loc, t_l * 0.4)
t.up()
t.write(tick)
# Draw the y tick marks
y_label = range(0, 21, 4)
n_y_ticks = int((y_max - y_min) / y_t_space) + 1
for tick in range(n_y_ticks):
loc = y_min + tick * y_t_space
t.up()
t.goto(-t_l * 0.4, loc)
t.down()
t.goto(t_l * 0.4, loc)
for i in y_label:
tick = i
print(tick)
t.write(tick, align="left", font=("Arial", 8, "normal"))
# get user input and plot the y value as long as user needed.
# the below code marks the value in the x-axis itself, that is not what I want.
#I want the value to get plotted outside the axis as in the normal line chart
t.backward
t.goto(0, 0)
t.tiltangle(45)
user_value = t.numinput(title='Line graph', prompt='Enter the first value:')
t.shape("square")
t.stamp()
t.forward(user_value)
user_value = t.numinput(title='Line graph', prompt='Enter the next value:')
t.shape("square")
t.stamp()
t.forward(user_value)
user_value = t.numinput(title='Line graph', prompt='Enter the next value:')
t.shape("square")
t.stamp()
t.forward(user_value)
Line chart
The input size is defined by the user and you want the same size of y-values.
Do the following:
for i in range (0, int(user_input)):
user_value = t.numinput(title='Line graph', prompt='Enter the value:')
t.shape("square")
t.stamp()
t.forward(user_value)
EDIT:
Just use matplotlib, it is very simple
import numpy as np
import matplotlib.pyplot as plt
user = int(input("Enter number of data: "))
x = np.arange(user)
y = []
for i in range (0, user):
value = int(input("Enter value: "))
y.append(value)
y = np.array(y)
plt.scatter(x, y)
plt.plot(x, y)
plt.show()
Input:
Enter number of data: 9
Enter value: 10
Enter value: 30
Enter value: 20
Enter value: 50
Enter value: 60
Enter value: 35
Enter value: 38
Enter value: 12
Enter value: 31
Output:
which is the same as the chart you provided.

Julia plotting issues: label overlap and LaTeXStings expansion

I am having two mutually exclusive issues with my sample plot below.
The y-axis label and y-tick labels are on top of each other. I have
not been able to find a way to shift either. I would like
the size of the plot to expand to accommodate the necessary spacing.
I want the y-axis label to be sigma with a subscript theta. It looks like Unicode does not allow a subscript theta. I was hoping to get around this limitation by using LaTeXStrings. However, I cannot get the LatexString to expand into the appropriate form on the plot. Note that issue #1 occurs with or without a LatexString as the ylabel and that LatexString expansion is not working for other string values either.
Sample plot, code, and data are provided below to reproduce. I am using the Juno editor with the Plotly backend on Windows.
using Plots, DelimitedFiles, LaTeXStrings
plotly(linewidth=3,titlefont=18,legendfont=16,guidefont=18,tickfont=14,formatter=:plain)
data=readdlm("hoopstress.txt",skipstart=1)
r=data[:,2]
σθ=data[:,end-1:end]
plot(r,σθ,label=["Simplified Vessel" "Full Vessel"],xlabel="r",ylabel=L"\sigma_\theta")
Length Simple Full
1 0. 53280 56859
2 9.4e-2 52158 55405
3 0.1875 51036 53951
4 0.28125 49915 52498
5 0.375 48793 51044
6 0.46875 47671 49590
7 0.5625 46550 48136
8 0.65625 45428 46682
9 0.75 44307 45228
10 0.84375 43185 43774
11 0.9375 42063 42320
12 1.0312 40942 40866
13 1.125 39883 39411
14 1.2187 39256 38780
15 1.3125 38629 38150
16 1.4062 38002 37519
17 1.5 37375 36888
18 1.5938 36748 36257
19 1.6875 36121 35627
20 1.7813 35494 34996
21 1.875 34867 34365
22 1.9688 34239 33735
23 2.0625 33612 33104
24 2.1562 32985 32473
25 2.25 32389 31842
26 2.3437 31998 31441
27 2.4375 31607 31039
28 2.5312 31216 30637
29 2.625 30825 30235
30 2.7187 30434 29833
31 2.8125 30043 29431
32 2.9062 29652 29029
33 3. 29261 28628
34 3.0938 28870 28226
35 3.1875 28479 27824
36 3.2813 28088 27422
37 3.375 27714 27020
38 3.4688 27452 26693
39 3.5625 27190 26367
40 3.6563 26927 26040
41 3.75 26665 25714
42 3.8438 26403 25387
43 3.9375 26141 25061
44 4.0313 25879 24734
45 4.125 25617 24408
46 4.2187 25354 24081
47 4.3125 25092 23755
48 4.4062 24830 23428
49 4.5 24568 23102
I filed a PR to solve the problem, which has just been merged into master :-)
So in the future you will be able to do
plotly(linewidth=3,titlefont=18,legendfont=16,guidefont=18,tickfont=14,formatter=:plain)
r = 1:10
σθ = [100000 ./ (1:10) .+ 10000, 100000 ./ (1:10) .- 1000 .+ 10000]
plot(r , σθ, label=["Simplified Vessel" "Full Vessel"],
xlabel = "r",
ylabel = L"\sigma_\theta\\\color{white}.",
yformatter = :plain,
include_mathjax = "cdn",
extra_kwargs = :plot)
if you are connected to the internet.
For for local use, if Conda and IJulia are installed and the TeX fonts are copied as described in my previous answer, you can do the following.
import Conda.ROOTENV
function local_mathjax()
joinpath(ROOTENV, "Lib", "site-packages", "notebook", "static", "components", "MathJax",
"MathJax.js?config=TeX-AMS-MML_HTMLorMML-full")
end
plotly(linewidth=3,titlefont=18,legendfont=16,guidefont=18,tickfont=14,formatter=:plain)
r = 1:10
σθ = [100000 ./ (1:10) .+ 10000, 100000 ./ (1:10) .- 1000 .+ 10000]
plot(r , σθ, label=["Simplified Vessel" "Full Vessel"],
xlabel = "r",
ylabel = L"\sigma_\theta\\\color{white}.",
yformatter = :plain,
include_mathjax = local_mathjax(),
extra_kwargs = :plot)
The formatting of y-axis numbers is now realised via yformatter = :plain and the space in the y-title was achieved by adding a line with a white-formatted dot.
Of course, you could also place a mathjax copy anwhere on your system and put the link in the includ_mathjax argument.
More details on the usage can be found in the PR.
Happy coding!
Latex output seems to be currently broken in Plotly.
I read, that for some people it depends on the browser. I couldn't get it to work on neither Edge nor Chrome.
Concerning the overlap it is, unfortunately, the standard setting of plotly itself. However, plotly and also the Julia package Plotly provide the yaxis.automargin = true parameter to overwrite this setting.
If you want additional space you can achieve this by adding a non-empty line to your title, which is done by adding the html code <br>
Below I have supplied an example code to achieve this in Plotly. (Currently, the plotly() backend of Plotsdoes not support passing backend-specific parameters. But there is work going on to achieve this.)
using Plotly
trace1 = Plotly.scatter(Dict(
"x" => [1, 2, 3, 4],
"y" => [1, 4, 9, 16] .* 1000000,
"name" => L"\alpha_{1c} = 352 \pm 11 \text{ km s}^{-1}",
"type" => "scatter")
)
trace2 = Plotly.scatter(Dict(
"x" => [1, 2, 3, 4],
"y" => [0.5, 2, 4.5, 8] .* 1000000,
"name" => L"\beta_{1c} = 25 \pm 11 \text{ km s}^{-1}",
"type" => "scatter")
)
data = [trace1, trace2]
# standard layout (shortens numbers by SI prefix)
layout1 = Layout(xaxis = attr(title = L"\sqrt{(n_\text{c}(t|{T_\text{early}}))}"),
yaxis = attr(title = L"$d, r \text{ (solar radius)}")
)
# sets the number format to "0", i.e. without prefixing
layout2 = Layout(xaxis = attr(title = L"\sqrt{(n_\text{c}(t|{T_\text{early}}))}"),
yaxis = attr(title = L"$d, r \text{ (solar radius)}",
tickformat = "0")
)
# forces automargin
layout3 = Layout(xaxis = attr(title = L"\sqrt{(n_\text{c}(t|{T_\text{early}}))}"),
yaxis = attr(title = L"$d, r \text{ (solar radius)}",
tickformat = "0",
automargin = true)
)
# adds an additional space by adding a line to the title
# note that Plotly seems to accept html code ...
layout4 = Layout(xaxis = attr(title = L"\sqrt{(n_\text{c}(t|{T_\text{early}}))}"),
yaxis = attr(title = L"$d, r \text{ (solar radius)}<br> ",
tickformat = "0",
automargin = true)
)
p1 = Plotly.plot(data, layout1)
p2 = Plotly.plot(data, layout2)
p3 = Plotly.plot(data, layout3)
p4 = Plotly.plot(data, layout4)
Switching to the PyPlot backend fixed both problems straight away.
Switching to the GR backend fixed the LaTeX issue, but made the label overlap worse.
I had some success with the Plotly backend by adding using Plots.PlotMeasures to the top of the script and adding left_margin=80px to either the plot or plotly statements. However, the result wasn't really satisfactory. The margin additions did not affect label spacing with the GR backend.
I still would like to find a solution for directly modifying the plot label positioning since plotly has better interactivity.
Currently plotly does not provide the mathjax environment, but Jupyter does. However, Jupyter by default, does not install the TeX fonts, which seem to be Mathjax default fonts by now.
In order to fix this you have to copy the original mathjax distribution to the directory where jupyter keeps its static files.
download MathJax-2.7.7.zip
copy the jax-folder from the MathJax-2.7.7.zip to C:\Users\<username>\.julia\conda\3\Lib\site-packages\notebook\static\components\MathJax or whereever the files are stored on your system. Note that there might be more MathJax folders, e.g. C:\Users\<username>\.julia\conda\3\pkgs\notebook-6.0.3-py36_0\Lib\site-packages\notebook\static\components\MathJax, but only one is the true source for the server.
Now you can either use Plotly
using Plotly
trace1 = Plotly.scatter(Dict(
"x" => [1, 2, 3, 4],
"y" => [1, 4, 9, 16] .* 1000000,
"name" => L"\alpha_{1c} = 352 \pm 11 \text{ km s}^{-1}",
"type" => "scatter")
)
trace2 = Plotly.scatter(Dict(
"x" => [1, 2, 3, 4],
"y" => [0.5, 2, 4.5, 8] .* 1000000,
"name" => L"\beta_{1c} = 25 \pm 11 \text{ km s}^{-1}",
"type" => "scatter")
)
data = [trace1, trace2]
layout = Layout(xaxis = attr(title = L"\sqrt{(n_\text{c}(t|{T_\text{early}}))}"),
yaxis = attr(title = L"\sigma_\theta\\?",
tickformat = "0",
automargin = true)
)
p = Plotly.plot(data, layout)
(I couldn't find a quick solution for a line break in LaTeX syntax. The linebreak was only kept if I added a character. Maybe, someone else can contribute here ;-) )
or Plots:
using Plots, LaTeXStrings
plotly()
Plots.plot(1:4, [[1,4,9,16], [0.5, 2, 4.5, 8]],
labels = [L"\alpha_{1c} = 352 \pm 11 \text{ km s}^{-1}" L"\beta_{1c} = 25 \pm 11 \text{ km s}^{-1}"],
xlabel = L"\sqrt{(n_\text{c}(t|{T_\text{early}}))}",
ylabel = L"d, r \text{ (solar radius)}"
)
In order to make it work in Juno make sure that the Conda package is installed and the mathjax fonts are copied as described above. Then make the following definitions:
import Plots.plotly_html_head
import Conda.ROOTENV
function mathjax()
mathjaxdir = joinpath(ROOTENV, "Lib\\site-packages\\notebook\\static\\components\\MathJax")
mathjaxfile = joinpath(mathjaxdir, "MathJax.js?config=TeX-AMS-MML_HTMLorMML-full")
return """<script type="text/javascript" src="file://$mathjaxfile"></script>"""
end
function plotly_html_head(plt::Plots.Plot)
local_file = ("file://" * Plots.plotly_local_file_path)
plotly = Plots.use_local_dependencies[] ? Plots.local_file : Plots.plotly_remote_file_path
if Plots.isijulia() && !Plots.ijulia_initialized[]
# using requirejs seems to be key to load a js depency in IJulia!
# https://requirejs.org/docs/start.html
# https://github.com/JuliaLang/IJulia.jl/issues/345
display("text/html", """
<script type="text/javascript">
requirejs([$(repr(plotly))], function(p) {
window.Plotly = p
});
</script>
""")
ijulia_initialized[] = true
end
return """$(mathjax())
<script src=$(repr(plotly))></script>"""
end

Highcharts custom pattern fill shows different stroke width

I'm trying to create a custom pattern fill for highcharts.
It's a horizontal dashed line with alternating starting points from one row to another (the first start at 0,0 the second at 3,10 and so on).
I edited the Highcharts JSfiddle example replacing the custom pattern with the following (here you can find my "final" version) :
color: {
pattern: {
path: {
d: 'M 0 0 H 8 M 14 0 H 22 M 3 10 H 19',
strokeWidth: 0.5
},
width: 22,
height: 20
}
}
The problem is the the two rows of lines have different width.
I can't find any parameter in the documentation to fix this.
I don't know if the problem is in my pattern definition or a highcharts bug.
Any thoughts?
The path as-is moves first to 0,0 and then 14,0, and finally 3,10:
d: 'M 0 0 H 8 M 14 0 H 22 M 3 10 H 19'
You can change that to 0,1 and then 14,1, and then 3,11 and the lines are the same width:
d: 'M 0 1 H 8 M 14 1 H 22 M 3 11 H 19'
The lines starting at 0,0 are centred on the boundary meaning that half the line gets cut off, so just moving them all down by 1 ensures that the whole line is visible.
Updated Fiddle

Getting an error with Openpyxl with Kivy

I'm trying to use some my python code I've written using IPython on Kivy, but I'm getting an error that says it cannot import name BUILTIN_FORMATS, which is called from the styleable.py within openpyxl.
BTW I used:
import openpyxl as xl
It works perfectly fine when I run the code within IPython.
Does anyone know how I can fix this.
EDIT: I've already tried reinstalling openpyxl with pip.
EDIT2: I'm on windows 7, and here's my code:
#!/usr/bin/kivy
import kivy
import random
import matplotlib.pyplot as plt
import pandas as pd
import pylab as pl
import requests
import openpyxl as xl
from operator import itemgetter
from collections import Counter
from lxml import html
#function to load the table form the excel file corresponding to the passed sheet name
def loadTable(sheetName):
lotteryData = pd.ExcelFile("Lottery databases.xlsx") #grabs and loads the file into memory
df = lotteryData.parse(sheetName) #loads the data table form the corresponding sheetName into the df data frame
return df
#function to display the table
def showTable(table):
#get the number of rows the table has
no_of_rows = len(table.index)
#display the table
return table.head(no_of_rows)
#function to display pie charts of a specific column within the database
#table is the database that the function will be working with
#and column is a numberical vaule of which column to get the data from
def printPieChart(table, column):
if column == 6:
columnList = table.iloc[:, -1:].values.T.ravel()
else:
columnList = table.iloc[:, (column - 7): (column - 6)].values.T.ravel()
countedList = Counter(columnList)
#set up the size of the pie chart
fig = plt.figure(figsize=[10, 10])
ax = fig.add_subplot(111)
cmap = plt.cm.prism
#input variables for pie function
slices = [float(v) for v in countedList.values()]
colors = cmap(np.linspace(0., 1., len(slices)))
labels = [float(k) for k in countedList]
columnHeaders = list(table.columns.values)
#the pie chart
pie_wedge_collection = ax.pie(slices, colors = colors, labels = labels, labeldistance = 1.05, autopct = '%1.1f%%')
#get rid of the black outlines between the wedges and around the pie
for pie_wedge in pie_wedge_collection[0]:
pie_wedge.set_edgecolor('white')
ax.set_title(columnHeaders[column + 1])
#can't display a Legends as there's too many for plt.legends() too handle
#return pyplot.pie([float(v) for v in countedList.values()], labels = [float(k) for k in countedList])
def updateDatabase():
wb = xl.load_workbook("Lottery databases.xlsx") #load the workbook into memory
#list of the sheet names within the workbook
sheetnames = ["SuperLotto", "MegaMillions", "Powerball"]
days = ["Tue. ", "Wed. ", "Fri. ", "Sat. "] #days the draws on done on
#list of the webpages to use grab the new draws
webPages = ['http://www.calottery.com/play/draw-games/superlotto-plus/winning-numbers', 'http://www.calottery.com/play/draw-games/mega-millions/winning-numbers', 'http://www.calottery.com/play/draw-games/powerball/winning-numbers']
x = 3
while x != 0:
ws = wb.get_sheet_by_name(sheetnames[x-1]) # which sheet to update
rowIndex = ws.get_highest_row() # gets the highest row index in the sheet
lastCellValue = ws.cell(row = rowIndex - 1, column = 0).value #gets the last value in the first column, draw number
page = requests.get(webPages[x-1]) #grabs the webpage needed
tree = html.fromstring(page.text) #puts the webpage into a tree structure to make it easy to traverse
#get the newest draw and date from the webpage for comparasion purposes
draw_and_date = tree.xpath('//*[#id="objBody_content_0_pagecontent_0_objPastWinningNumbers_rptPast_ctl01_lblDrawDateNumber"]/text()')
#if the table is up to date, it will move on to the next table else it will update it
y = int(draw_and_date[0][-4:]) - int(lastCellValue) # checks to see how many draws are missing from the table
if y == 0:
print("The table for " + sheetnames[x-1] + " is up to date.")
x -= 1 #decrement x by 1 to move on to the next table
else:
#while loop to check if the table needs to be updated or not, if yes it will update it
while y != 0:
#grabs the draw and date of the missing draws from the table
draw_and_date = tree.xpath('//*[#id="objBody_content_0_pagecontent_0_objPastWinningNumbers_rptPast_ctl0' + str(y) + '_lblDrawDateNumber"]/text()')
numbers = tree.xpath(".//*[#id='content']/div[3]/table/tr[" + str(y) + "]/td[2]/span/text()") #numbers
numbers = [int(x) for x in numbers] # converts the text to integers
numbers.sort() #sort the number from smallest to largest
mega = tree.xpath(".//*[#id='content']/div[3]/table/tr[" + str(y) + "]/td[3]/text()") #mega number
mega = int(mega[0]) # converts the text to integers
#write to the file
if sheetnames[x-1] == "MegaMillions":
d = 0
else:
d = 1
if int(draw_and_date[0][-4:]) % 2 == 0:
# if the draw date is even then the day is a Friday/Saturday
ws.append([int(draw_and_date[0][-4:]), (days[d+2] + draw_and_date[0][:12]), numbers[0], numbers[1], numbers[2], numbers[3], numbers[4], mega]) # print the draw date
else:
# if the draw date is odd then the day is a Tuesday/Wednesday
ws.append([int(draw_and_date[0][-4:]), (days[d] + draw_and_date[0][:12]), numbers[0], numbers[1], numbers[2], numbers[3], numbers[4], mega])
y -= 1 #decrement y by 1 to get the next missing draw
print("Updated the " + sheetnames[x-1] + " table successfully!")
x -= 1 #decrement x by 1 to move on to the next table
wb.save("Lottery databases.xlsx") #save the workbook
print("Saved the database Sucessfully!")
and so on...

Resources