Tuesday, May 19, 2020

Robincam setup


Introduction

I wanted a remote webcam for watching the robin that lives around my apple tree. Trailcams are a bit pricey and I had an old android phone with a half decent  camera laying around doing nothing.

The Phone...

...s a very battered Blu Vivi 6. The screen is broken, the USB C port is loose and the battery lasts about 30 minutes because it has been frozen a few times..

The USB C port is fixed by gluing in a magnetic connector which also seals the port somewhat against the weather.



 I've installed IP Webcam on it from the play store. You can find it here https://play.google.com/store/apps/details?id=com.pas.webcam

I've gone for the Pro version but everything here works with the free one. The only limitations are Tasker integration and the ability to customise the UI. We are not going to use either of those here. I upgraded because I think the developer deserved a coffee (or Russian tea) on me.

Installing it is straightforward and I've also put it on a couple of old HTC mobiles that are being security cams.

To do everything in this article you are going to need a bit of memory. The Blu has 64GB and I'm using about half of it. That's about 1200 jpgs and several hours of mp4s.

I'll talk about how to get the images off to a pc and get the memory back later.

You'll also need a wifi signal where your camera is sited. You can use broadband and access your through the lvideon cloud see here https://www.ivideon.com/

I haven;t got a sim in the Blu so that's not an option.

I use this https://www.amazon.co.uk/NETGEAR-Wi-Fi-Range-Extender-EX2700/dp/B00NIUHAG6/ref=sr_1_5 network extender to get to the shed so I have coverage over all of my garden. Cheaper wifi extenders are available but this one works for me.

IP Webcam Setup

When you start IP Webcam it shows the setup screen. For plain vanilla you can just jump to the last item and it will work.

Before you set up anything you have to give IP Webcam some permissions to photos and sound.


For a start set up the Video Preferences I use the highest resolution possible and lock the camera in Landscape mode.

The other important settings are the motion and sound detection. I have motion detection on and sound detection off. I was getting a lot of false positives from the wind blowing across the camera. Getting the optimum sensitivity will take trial and error and you can play around with this in the web interface.

Starting the Webcam Server

IP Webcam comes with its own webserver so you can connect to it with a browser. When you start the server it tells you the web address that you need to type in to your browser.

The first thing you should do is configure your router to make this a address permanent. I have a BT Home Hub and the important bit of the settings screen looks like this:


If you find this doesn't work and the assigned ip address changes it could be that your phone is registered on the network more than once. Have a look for duplicate names or MAC addresses in your connected devices and remove the ones you are not using.

Power Management

Even with the all the power management options available the application is power hungry, especially if you opt for aggressive focusing which keeps the camera focused constantly so you can take a still image instantly. Note that if you want to record stills automatically you are going to need the IP Webcam add in. I'll blog about that later. If I'm out of reach of mains power, I use an external battery pack. A big RAV 280000mah battery pack like this https://www.amazon.co.uk/RAVPower-Portable-Charger-26800mAh-External-Black/dp/B012V9H3WA/ in a margarine tub with a hole for the power cable.

Weatherproofing

The Blu comes with a silicone case which is sealed except for the camera, headset and power sockets sealed. I've covered the headphone socket with tape. I wouldn't trust it in a raging storm but it has managed the odd shower without coming to any harm. I'm considering sealing it in a food box with only a hole for the camera lens which I can seal with elefant snot (that really is what Blue Tack is called in Danish)

All that is left is to site your camera in an appropriate place and wait for the motion sensors to pick stuff up. The video will record in a local file which you can watch on your phone. Until you get the motion sensitivity fine tuned, expect a lot of false positives. Especially if there is foliage in your camera field. You'll get a video every time the wind blows.

Uploading to cloud storage 

I use google photos to backup and manage the pictures. You can do this through the IP Webcam web interface but the google photos interface is a bit nicer and when they are on the cloud you can safely delete them from the phone.

First make sure you have recorded at least one video.

Setting up photos is pretty straightforward.go to Settings -> Backup and Sync --> Backup device folders and you should see a folder called 'modet.' Add that to the folders backed up and that's it. There's a bit of a lag between recording and the videos appearing in in Photos so be patient.

Expect to be clearing out the false positives frequently. The free allowance for original size photos is 50GB. You'll go through that quite quickly. The great thing is that deleting from Photos also deletes on your device so it keeps it cleaned up reasonably cleaned up.

There is a Dropbox plug in for IP Webcam but I seem to have broken it. I've emailed the developer to see what I've done wrong.

Coming Soon

Next article "Setting up IP Webcam to take still images" coming soon.



































Tuesday, May 12, 2020

Underwhelmed

Data and Methodology


If he lockdown was intended to protect the NHS then it might have worked a bit too well. We were told we had to flatten the curve and we did. But by how much? We've seen the stories of empty hospitals and because elective and non urgent surgery cancelled.

Here's a chart generated from https://www.england.nhs.uk/statistics/statistical-work-areas/covid-19-daily-deaths/. I haven't done anything with it except cut and paste the totals of daily deaths by age into Libreoffice calc, Transform it from columns to rows and then copy it to Google sheets, which I've used for all the other manipulation.




And here's a chart I made from publically available data.



The blue bars are daily hospitalisations derived from 

The red line is:
That's all data. I'm now going to step into the realm of models and speculation.

The big surprise came when I came to construct a tall thin bell curve with the same area which just failed to breach the capacity line.

The tall thin curve came later with a slower incremental part.

I know this can't be right. But as they say, "all models are wrong and some are useful."

This one is obviously wrong and not very useful. If you think you can improve it please do.

If I get the time and the inclination I will generate some numbers from my RCalc program to try to make a different shaped curve. I'll need to make a branch of the code so I can add add some fudge factors (something I  because the aim of the code was to find the bell curve, not fit it to real life) the results of R0=3 has 70 million people infected in 17 iterations and the opportunity factor doesn't get a chance to pull the curve down. The spreadsheet calculations are obviously crude and somehow wrong. My focus was to get a bell curve with the right shape and the same end total. The fact it had the same width is a mystery to me. It is not designed in to the formula. And I messed up the horizontal axis labels.

As ever all source data is on github here:

https://github.com/davidsinfield/RValue/blob/master/Underwhelmed.ods

It's freely available, do with it what you will.


Before you comment

  • There is no doubt that this is a dangerous disease to the vulnerable. I am not trivialising it.
  • The hospitals have done a grand job and the lack of masks and gowns was a fiasco. I'm not sure what could have been done about it. And I have no intention of being drawn in to a recriminations.
  • I have no wish to kill you or your granny. I'm a grandad I'm well into the age danger zone with a highish BMI and I would be considered quite vulnerable. 
  • The third chart is very definitely wrong. I don't need to be told I am open to suggestions as to how it can be improved.

Tuesday, May 5, 2020

Covid-19 Correlations

Where I started

I was thinking about why there was such a wide spread of values of deaths per million from or of Coronaviris across the 48 countries of Europe so I decided to look at some correlations. It's important to note these are not direct country to country comparisons, I think we all know by now they are very dangerous. Rather they are a statistical method to see what the possibility that a pair of sets of values are somehow linked. The strength of a correlation is measured in the P (for Pearson) value and they range form -1 negative correlation through 0 (no correlation) to +1 positive correlation. A negative correlation means that as one value gets bigger, the other value gets smaller. A positive correlation means that the values increase or decrease together. I used to do rank correlations by hand for my OPen University courses but that is hard work and we now have computers that can do that stuff for us. I used LibreOffice calc and it a matter of fractions of a second to get an answer that would certainly taken hours using the old pen and paper method.

"Correlation is not causation" is a very important concept. It might be that there is a spurious correlations. There are some great spurious correlations of time series here:

https://www.tylervigen.com/spurious-correlations

However given a strong correlation of P>.5 it is certainly legitimate to hypothesise for causation.

Population Density

My first instinct was that it was due to population densities. It seems obvious that if you cram people together the spread of disease will be faster and you may get a higher mortality per capita than more sparsely populated countries. So what does the correlation look like?

The P value is 0.234105007129706 which represents a weak positive correlation. Not very much above chance. I was surprised.

That is certainly not a good enough correlation warrant searching to hard for a causation

Life Expectancy

We generally think of Life expectancy as an indicator of the quality if health and social care and general health of the population. The longer the live expectancy the better we were doing. So you'd expect the longer the live expectancy, the better the health and social care available and there should be a negaitive correlation, that is as life expectancy goes up, mortality goes down.

The European values range from 71.72  to 85.42 a pretty wide range for what we would all expect to be developed industrial countries.

I tried life expectancy against deaths per million. P value is 0.529. That is certainly more significant. Yes, thats a positive correlation. as life expectancy goes up so does a country's mortality rate for the Chinese Cough.

It seems therefore that a high life expectancy is a disadvantage where it comes to mortality from this virus. So maybe it is not a good indicator of the quality of health, social care and fitness after all. Maybe it's just an indicator that we can keep sick people alive longer. I'm not that sure that's a good thing when a pandemic strikes.

There is an alternative explanation. It could be that the reporting in countries with a lower life expectancy is less accurate and they are underreporting deaths from or with to coronavirus.

I'll let you decide.

Data


I did this a while ago and the data is from Worldometer from Wednesday 29th April. The Uk has changed its reporting method since then to include non NHS deaths. I don't know whether this has a large effect but I'll do a revision if I get a chance.

The spreadsheet of values I have used is here 







Risk takers and risk averse

Over the two hundred thousand years of the human race we have evolved a strategy for the survival of the species. It's worked pretty well. One of the cornerstones of the strategy finding a balance between the risk takers and the risk averse. The argument about whether this is nature or nurture is

Here's a very quickly drawn diagram (I have a love hate relationship with Inkscape.)


There's no scale and no attempt at quantifying it. The numbers might be distributed differently but it is what it is.

The important parts as is very often the case are the two edge cases.

The red zone are the risk takers, this is where innovation comes from. The first person to tame a horse, Montgolfier, the Wright Brothers, Edmund Hillary are all in the the red zone. So are all all the entrepreneurs and small businesses. This is the source of all innovation. Some fail. But the ones that succeed make the leaps forward that eventually filter up the other groups.

The green zone are the risk averse. They like the status quo. New ideas and things will only filter down to them after the early adopters and late adopter have proven them. It's very difficult to name them individually because their impact on the species is taken for granted. They take the absolutely safe path. They will survive. They will breed, they will continue the species. Luckily they will breed some a few more risk taker than risk averse because some of the risk takers fail in a spectacular fashion.

Over most of the 200,000 years of the human race this balance has been maintained successfully.  We have thrived. The risk takers have given us innovation and the risk averse have ensured we haven't entirely wiped ourselves out.

The reason for the balance is that we have been allowed to make our own risk assessments.

Consider what happens when we are forced by regulation to be come risk averse....


Tuesday, April 14, 2020

Playing with Reproduction Value

Background

When the chart of infection spread for CoronaVirus was published it intrigued me that both the tall thin curve representing unrestricted spread and the short fat curve representing controlled spread were normal distribution bell curves.



I wanted to know why the curves rose and fell and in particular what made the curves fall in such a symmetrical way. Particularly what caused them to fall. I decided the best way was to make my own model so I can play with it.



When I started reading I realised Basic Reproduction Value, R0 (are-nought) was the most important factor. It's pretty well the only property of the spread of the virus that at this time we are able to control.

The tall thin curve is the number of hospitalisations with time with no intervention. The native property of the virus.

The short fat curve is the number of hospitalisations if the R0 value is attenuated by reducing the opportunity to spread. But why the bell? Why not an ever increasing exponential curve until everyone who will be hospitalised is?

Assumptions

The charts use hospitalisations. That's so the dotted line (available hospital resources) is relatable to the numbers. I have assumed that infections follow that curve. There is a skewing factor that Is not taken into account in those curves and in my calculations and that is that there should be more hospitalisations (though not infections) in as the more vulnerable will be hospitalised early.

I have used a simple model for the reproduction value iteration time. In reality the virus is infectious for a long period. I have seen number like 7-10 days in the incubation period and up to several weeks in the symptomatic period. I haven't modelled for this. For convenience I've called an iteration period a day.

The model uses a chance or opportunity factor. I have assumed that the opportunity factor is linear with the number of people who have been infected. There has been some talk of a small number of reinfections in South Korea. If infection does not confer immunity in the vast number of cases then all bets are off and we are all dead.

Population density will have a huge effect on R value (more specifically on oportunity factor.) I haven't even attempted to model how high density areas within the same population affect the overall shape of the curve. My speculation is that there will be a much longer tail as more isolated communities become infected over time.

The model has no 'fudge factors' to aim to give a preconceived result. The R based calculations are taken directly from the definition of R

Method

The model is very simple. Day zero there are n infectious cases. Which means on day two there will be n*R. The total infected is n+(n*R)* The next day the infections are the (total infected on the previous day) * RO. They are added to the running total. 

I then apply an opportunity factor which is the chance of encountering RO number of people who are do not have acquired immunity. Which is the population/the running total of infected people.

The model runs until the number of new infections is zero or given number of iteraterations or a target number of infections has been reached
.

I have pasted the code after the footnotes. It runs under Python 3. I use version 3.6 on various versions of Ubuntu. This has been tested on 18.04.

Results

I'm presenting the results in a standard form:

  • Parameters
  • Raw output
  • csv
  • chart
  • analysis
The charts are created using LibreOffice Calc

Run one

I wanted a picture of how the tall thin curve might look so I used the profile for infecting the whole population at R0=3.

The parameters for my first run were:

population = 70m
day zero infections = 1
iterations 100
R value = 3

I chose the R0 value because Niall Ferguson had revised his estimate of 200-500k deaths to 20k based on a R) value of "probably greater than 3."

Here are the results. 
If you want the comma separated values to load into a spreadsheet you can cut and paste these:

=================================================================

day,infected,todaysinfections, opportunityfactor
1,4.0,3.0,1.0
2,12.999999614285715,8.999999614285715,0.9999999571428572
3,39.99999382857178,26.999994214286065,0.9999998285714341
4,120.99993134287536,80.99993751430358,0.999999442857231
5,363.99932731491725,242.9993959720419,0.9999982857152666
6,1092.9937348617311,728.9944075468138,0.999994814295324
7,3279.942840759639,2186.9491058979074,0.999984400089502
8,9840.48283497705,6560.539994217413,0.9999531579594177
9,29519.33628960095,19678.8534546239,0.9998594359595003
10,88531.0014957269,59011.66520612595,0.9995783094815771
11,265342.09842229204,176811.09692656514,0.9987352856929181
12,793764.7356017698,528422.6371794777,0.9962094128796816
13,2361056.530291741,1567291.794689971,0.9886605180628318
14,6904340.644671642,4543284.114379901,0.9662706352815467
15,19189833.989471916,12285493.344800275,0.9013665765046909
16,45942461.21758762,26752627.228115708,0.7258595287218298
17,73525420.95292085,27582959.73533324,0.3436791397487483

==============================================================

The chart of iterations v infections is:


Definitely starting to get a bell curve. The exponential part works. And the opportunity factor starts to kick in but doesn't have chance to pull the curve down before the target infections is reached.

The code seems to work as expected although I was surprise the opportunity factor didn't get a chance to kick in.

Run 2

For this run I wanted to try to get the full bell curve. And I did with these parameters.

population = 70m
day zero infections = 1
iterations 100
R value = 2

Raw output:


I was quite pleased to see the bell in the results.

If you want to play with them in a spreadsheet, here are the comma separated values:

=====================================================================
day,infected,todaysinfections, opportunityfactor
1,3.0,2.0,1.0
2,6.999999885714286,3.9999998857142858,0.9999999714285714
3,14.999998971428605,7.999999085714319,0.999999914285716
4,30.99999394285784,15.999994971429238,0.9999998000000146
5,62.99997017143768,31.999976228579836,0.9999995714286578
6,126.99986594295245,63.999895771514765,0.9999991142861404
7,254.99942708660234,127.99956114364987,0.999998200001915
8,510.99762046489644,255.9981933782941,0.999996371436756
9,1022.9902769794999,511.9926565146035,0.9999927143197077
10,2046.9606399653685,1023.9703629858686,0.9999854001389004
11,4094.8415087068443,2047.8808687414755,0.9999707719908576
12,8190.363711912501,4095.5222032056563,0.9999415165498757
13,16380.449840583464,8190.086128670962,0.9998830090898299
14,32756.789266355827,16376.339425772363,0.9997660078594202
15,65494.14183438098,32737.35256802515,0.9995320601533376
16,130907.58776828786,65413.44593390688,0.9990643836880803
17,261489.82103606238,130582.23326777453,0.9981299058890245
18,521678.6934508844,260188.87241482205,0.9962644454137707
19,1038178.3031141586,516499.6096632741,0.9925474615221302
20,2055857.003245857,1017678.7001316986,0.9851688956697977
21,4031437.2359366487,1975580.2326907916,0.9706306285250591
22,7755042.680259095,3723605.444322446,0.9424080537723336
23,14377204.556859408,6622161.876600313,0.8892136902820129
24,24901294.90187841,10524090.345019003,0.7946113777591514
25,38461947.971023865,13560653.069145458,0.6442672299731655
26,50681279.27394551,12219331.302921642,0.4505436146996591
27,57425903.87736294,6744624.60341743,0.2759817389436356
28,59848977.1579086,2423073.2805456645,0.1796299588948152
29,60551739.29053585,702762.1326272473,0.14501462631559137
30,60741450.163351946,189710.87281609673,0.13497516727805925
31,60791634.38507288,50184.22172093443,0.13226501195211507
32,60804837.662555486,13203.277482604371,0.13154809449895885
33,60808306.413785264,3468.751229775726,0.13135947624920735
34,60809217.37669668,910.9629114187214,0.13130992266021052
35,60809456.589925475,239.21322879153985,0.1312969089043331
36,60809519.40420555,62.81428007674185,0.1312934915724932
37,60809535.898305126,16.494099571382108,0.13129259422563497
38,60809540.2294036,4.331098471276219,0.13129235859564106
39,60809541.366683334,1.137279731252975,0.1312922967228057
40,60809541.665315434,0.29863209891056264,0.13129228047595237

=================================================================

As you can see the run ended because there were no new infections. There were still ~10 million uninfected.

I had acheived my bell curve:


Run 3

For run 3 I wanted to find an R0 value that gave me bell curve and infected every one.

I could have added some goal seeking to my code but decided to do it by hand. I knew the value was greater than 2 and less than 3 so I did increments of 0.1. The sensitivity is greater than I expected so I had to go to a second decimal place.

I won't post all the results, just the the one that got me closest:

population = 70m
day zero infections = 1
iterations 100
R value = 2.56


csv:

========================================================
day,infected,todaysinfections, opportunityfactor
1,3.56,2.56,1.0
2,10.113599760325487,6.553599760325486,0.9999999634285714
3,26.89081296246121,16.777213202135727,0.9999998698057176
4,69.84046287418919,42.949649911727974,0.9999996301312434
5,179.79145851842884,109.95099564423965,0.999999016564816
6,461.26528843560914,281.4738299171803,0.9999974458363069
7,1181.8335550987078,720.5682666630987,0.9999934247815937
8,3026.457200181365,1844.6236450826568,0.9999831309492129
9,7748.489632671324,4722.032432489959,0.9999567791828545
10,19835.55473445807,12087.065101786746,0.9998893215766762
11,50769.67370390198,30934.11896944391,0.9997166492180792
12,129903.58341521795,79133.90971131597,0.9992747332328012
13,332110.4489872361,202206.86557201814,0.998144248808354
14,847304.0774886198,515193.6285013837,0.9952555793001824
15,2150235.418221515,1302931.3407328953,0.9878956703215912
16,5383280.8504639575,3233045.4322424424,0.9692823654539783
17,13023373.812327115,7640092.961863157,0.9230960021362292
18,28943162.735471915,15919788.9231448,0.8139518169667554
19,52846840.87116953,23903678.135697614,0.5865262609218297
20,67841990.3561394,14995149.484969873,0.24504514469757815
21,69025430.52783662,1183440.1716972135,0.030828723483722762
22,69067610.03309497,42179.50525835205,0.013922435316619703
23,69069048.30654654,1438.2734515715865,0.01331987095578611
24,69069097.27439271,48.96784616825324,0.0132993241921923
25,69069098.94147752,1.667084815835123,0.013298624651532727
26,69069098.99823245,0.05675493254555362,0.013298600836035396

=======================================================



This is quite a long post so I'll end the results there. 

Conclusions

Whether you call it 'herd immunity' or 'widespread acquired infection' the opportunity factor serves to form the expected bell curve in all cases where R0 is between 1.2 (results not shown here for brevity. No new cases iteration 158, 22602160 infected) and 2.56.

R0 of 2 or less leaves a large population of potential infections if the R0 is increased by removing restrictions unless there are no or very few infections when restrictions are relieved.**

Even with this simple model the theoretical expected and possibly the real world results for cases/deaths (we wont know until at least one country has fully played out their infection.)

Any discussion of comparison with actual infections is futile because there is no way of telling what they are except other models.

A more valid result might be to take the deaths and compare them to infections calculated by this model to get an estimate of mortality. This might become another blog post at some time maybe.

Comments

Most comments are welcome either here or by mentioning me on  twitter. I will answer as many and as soon as I can.

I will ignore stuff like "my old aunty died of CoronaVirus so you are wrong." Your anecdotes do not interest me.

Or anything which refers to something I didn't actually say.

If you are commenting please be specific. "Cobblers" or any other such stuff will be either ignored or published to show what an idiot I am dealing with.

If you have a set of parameters you wish me to run please send them. Only the parameters show in the results section please.

If you want me to tailor the model or submit change requests then you'd better be ready with some paypal. I might or might not improve, change, remove it at any time. My choice.

You may take what additional inferences from the results. They are not my responsibility.

You use the information here at your own risk. Any decisions you base on it are your problem not mibe.


Footnotes

*The brackets are extraneous but I know a lot of people have problems with operated precedence and I didn't want to use RPN although I'm probably one of the last people alive who can.

** I may revise my model so the R0 value can be changed in the course of the curve. That might  show any subsequent peak(s).


Code:

Also available on GitHub here

If anyone requires the results files or images I can zip them up and make them available.


=========================================================
#---- License ----
"""
This code is the property of David Sinfield (dsinfield6@gmail.com) It is  released under The GNU public license the short version of which is you may copy, 
distribute, amend but this section of header should remain intact.

The long version is at https://www.gnu.org/licenses/gpl-3.0.html
"""

#------------------------------------------------------------------------------------------------------------------------------
# This is a Transmissibility generator V1.0
# The parameters are prompted for on the command line. It takes no command line parameters.
#blog post description is at https://davidsdiamondsandrust.blogspot.com/2020/04/playing-with-reproduceability-value.html
#------------------------------------------------------------------------------------------------------------------------------

#usage
print ("This program models the number of people infected in over a number of days for a given R value.")
print ()
print ("Day Zero are the number of infections on Day 0")
print("The R value is the number of people each infected person can transmit to.")
print(" R may be a decimal value. The result on day N will be rounded up to an integer.")
print("The program assumes that R declines linearly with the number of infections as the chance of contacting R uninfected declines")
print ("the chance parameter calculation may be a little simplistic but is calculated as (population-infected)/population ")
print ("The definition of R does not include a time element so this assumes one iteration a day.")
#functions
#all the get functions require validity checking for input type numeric.
def getpopulation():
    ipopulation=input("Population(default 70m) - ")
    if len(ipopulation) > 0:
        population=int(ipopulation)
    else:
        print("70m used")
        population=70000000
        return population
    
def getdayzero():
    idayzero=input("Day Zero infections (default =1) - ")
    if len(idayzero)>0:
        dayzero=int(idayzero)
    else:
        print ("1 used")
        dayzero=int(1)
    return dayzero
    #ToDo validty check/default
def getdays():
    return int(input("Days - "))
      #ToDo validty check/default
def getrvalue():
    return float(input("R Value - "))
def gettarget():
    itarget=input("Target value (leave blank for population=target) - ")
    if len(itarget)>0:
        target=int(itarget)
    else:
        print(str(population)+" used")
        target=population
    return target
#end functions

#start procedural
population=getpopulation()
dayzero=getdayzero()
days=getdays()
rvalue=getrvalue()
target=gettarget()

infected=dayzero
newcases=dayzero
csv=["day,infected,todaysinfections, opportunityfactor\n"]
for day in range (1, days):
    # calculations
    chance=((population+1)-infected)/population
    todayscases=float((newcases*rvalue)*chance)
    infected=infected+todayscases
    newcases=float(todayscases)
    #show results
    print ("Chance: "+str(chance)+" Day number: " + str(day) + " - Infected: " + str(int(infected))+" Newcases today:"+str(int(todayscases+0.9)))
    csv.append(str(day)+","+str(infected)+","+str(todayscases)+","+str(chance)+"\n")
    #exit conditions
    if target > 0:
        if infected > target: 
            break
    if newcases<1:
        print("No new cases")
        break
print("Program end")

#Option to write a file of data
dofile=input("Enter y to write a result file: ")
if dofile=="y" or dofile== "Y":
    filename=input("Filename (exension .csv will be added): ")
    if len(filename)==0:
        print ("No Filename results.csv will be used")
        f=open("results.csv","a")
    else:
        f=open(filename+".csv", "a")
    print ("Writing "+ f.name)
    for x in csv:
        f.write(x)
    f.close
# end procedural
 

===============================================

Saturday, March 25, 2017

Optimists, rationalists and pessimists

Thing change. It's the only constant.

And as things change we like to guess outcomes.

Optimists like to guess things will be fine.

Pessimists guess at bad outcomes.

Rationalists recognise that of the outcomes some are better than others.

On this continuum I sit between rational and optimistic. What steers me from pure rationalism?

1. Faith in human ingenuity to steer the outcomes towards the good.

2. The fact that from a historical perspective optimists are more often proved right. Unless you believe a nasty Brutus and short life is better than we have now, overall things improve.

Tell me I'm wrong.


Tuesday, March 14, 2017

ANSI formatter for python

ANSI formatter

I have been playing around with python and needed something that formatted the terminal output using the ansi codes as described here:

http://pueblo.sourceforge.net/doc/manual/ansi_color_codes.html

Except I can't remember all the escape sequences any more. The last time I used them was about 35 years ago when I was working with serial terminals at Philips in Holland.

I thought it might be useful so here it is. I've put a listing at the end of the post. Feel free do do with it what you will within the terms of the GPL. I'll update this when I get round to putting it on GitHub.

The code has been tested on LXTerminal and xcfe4 on the pi and xterminal on ubuntu and gives expected results on all of them. It won't work if your terminal doesn't recognise ansi codes.

Here's the sample output:



Update: It's also on GitHub here : https://github.com/davidsinfield/ansilib

And here's the function and a bit of sample usage:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  ansidemo.py
#  
#  
#  This program is free software; you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation; either version 2 of the License, or
#  (at your option) any later version.
#
#  https://www.gnu.org/licenses/gpl-3.0.en.html
#  
#  This program is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#  


dictForeBack={
'fore' : 3,
'back' : 4
}
dictColour={
'black' : 0,
'red' : 1,
'green' : 2, 
'yellow' : 3,
'blue' : 4,
'magenta' : 5,
'cyan' : 6,
'white' : 7
}
dictStyle={
'normal' : 0,
'bold': 1,
'italic' : 3,
'underline' :4,
'inverse': 7,
'strikethough' : 9
}
#========================================================================
#GetANSI(text,foreback,colour,style)
#text - text to print
#forecolour - [black|red|green|yellow|blue|magenta|cyan|white]
#backcolour - [black|red|green|yellow|blue|magenta|cyan|white]
#style - [normal|bold|italic|underline|inverse|strikethough]
#
#Returns a string with ansi precursors to set foreground and background
#colours and style. Set to normal after printing.
#
#Out of range parameters throw a dictionary error
#
#Example: set foreground to red
# print GetANSI('this is red text','red','none','none')
#Example: set foreground bold red, background cyan
# print GetANSI('set properties','red','cyan','bold')
#
#Update
# empty string in a parameter is now the same as none.
# Example:
# GetANSI('text','','','bold')
#=========================================================================
def GetANSI(text,forecolour,backcolour,style):
pre="\033["
post="m"
tonormal=pre+'0m'
retval=""
if forecolour != 'none' and forecolour != '':
retval=retval+pre+str(dictForeBack['fore'])+str(dictColour[forecolour])+post
if backcolour != 'none' and backcolour != '':
retval=retval+pre+str(dictForeBack['back'])+str(dictColour[backcolour])+post
if style != 'none' and style != '':
retval=retval+pre+str(dictStyle[style])+post
return (retval+text+tonormal)

def main():
print GetANSI('red text','red','none','none')
print GetANSI('red text cyan bg bold','red','cyan','bold')
print GetANSI('inverse of above','red','cyan','inverse')
print GetANSI('black on white','none','none','inverse')
print GetANSI('black on green','green','none','inverse')
print GetANSI('non explicit green','green','','')
print 'normal text'
return 0

if __name__ == '__main__':
main()