Shallow Thoughts : : Jan
Akkana's Musings on Open Source Computing and Technology, Science, and Nature.
Fri, 27 Jan 2017
A web page I maintain (originally designed by someone else) specifies
Times font. On all my Linux systems, Times displays impossibly
tiny, at least two sizes smaller than any other font that's ostensibly
the same size. So the page is hard to read. I'm forever tempted to
get rid of that font specifier, but I have to assume that other people
in the organization like the professional look of Times, and that this
pathologic smallness of Times and Times New Roman is just a Linux font quirk.
In that case, a better solution is to alias it, so that pages that use
Times will choose some larger, more readable font on my system.
How to do that was in this excellent, clear post:
How To Set Default Fonts and Font Aliases on Linux .
It turned out Times came from the gsfonts package, while
Times New Roman came from msttcorefonts:
$ fc-match Times
n021003l.pfb: "Nimbus Roman No9 L" "Regular"
$ dpkg -S n021003l.pfb
gsfonts: /usr/share/fonts/type1/gsfonts/n021003l.pfb
$ fc-match "Times New Roman"
Times_New_Roman.ttf: "Times New Roman" "Normal"
$ dpkg -S Times_New_Roman.ttf
dpkg-query: no path found matching pattern *Times_New_Roman.ttf*
$ locate Times_New_Roman.ttf
/usr/share/fonts/truetype/msttcorefonts/Times_New_Roman.ttf
(
dpkg -S
doesn't find the file because msttcorefonts
is a package that downloads a bunch of common fonts from Microsoft.
Debian can't distribute the font files directly due to licensing
restrictions.)
Removing gsfonts fonts isn't an option; aside from some documents and web
pages possibly not working right (if they specify Times or Times New Roman
and don't provide a fallback), removing gsfonts takes gnumeric and abiword
with it, and I do occasionally use gnumeric. And I like having the
msttcorefonts installed (hey, gotta have Comic Sans! :-) ).
So aliasing the font is a better bet.
Following Chuan Ji's page, linked above,
I edited ~/.config/fontconfig/fonts.conf (I already had one,
specifying fonts for the fantasy and cursive web families),
and added these stanzas:
<match>
<test name="family"><string>Times New Roman</string></test>
<edit name="family" mode="assign" binding="strong">
<string>DejaVu Serif</string>
</edit>
</match>
<match>
<test name="family"><string>Times</string></test>
<edit name="family" mode="assign" binding="strong">
<string>DejaVu Serif</string>
</edit>
</match>
The page says to log out and back in, but I found that restarting
firefox was enough. Now I could load up a page that specified Times
or Times New Roman and the text is easily readable.
Tags: linux, fonts
[
14:47 Jan 27, 2017
More linux |
permalink to this entry |
]
Mon, 23 Jan 2017
Several times recently I've come across someone with a useful fix
to a program on GitHub, for which they'd filed a GitHub pull request.
The problem is that GitHub doesn't give you any link on the pull
request to let you download the code in that pull request. You can
get a list of the checkins inside it, or a list of the changed files
so you can view the differences graphically. But if you want the code
on your own computer, so you can test it, or use your own editors and
diff tools to inspect it, it's not obvious how. That this is a problem
is easily seen with a web search for something like
download github pull request
-- there are huge numbers
of people asking how, and most of the answers are vague unclear.
That's a shame, because it turns out it's easy to pull a pull request.
You can fetch it directly with git into a new branch as long as you
have the pull request ID. That's the ID shown on the GitHub pull
request page:
Once you have the pull request ID, choose a new name for your branch,
then fetch it:
git fetch origin pull/PULL-REQUEST_ID/head:NEW-BRANCH-NAME
git checkout NEW-BRANCH-NAME
Then you can view diffs with something like
git difftool NEW-BRANCH-NAME..master
Easy! GitHub should give a hint of that on its pull request pages.
Fetching a Pull Request diff to apply it to another tree
But shortly after I learned how to apply a pull request, I had a
related but different problem in another project. There was a pull
request for an older repository, but the part it applied to had since
been split off into a separate project. (It was an old pull request
that had fallen through the cracks, and as a new developer on the
project, I wanted to see if I could help test it in the new
repository.)
You can't pull a pull request that's for a whole different repository.
But what you can do is go to the pull request's page on GitHub.
There are 3 tabs: Conversation, Commits, and Files changed.
Click on Files changed to see the diffs visually.
That works if the changes are small and only affect a few files
(which fortunately was the case this time).
It's not so great if there are a lot of changes or a lot of files affected.
I couldn't find any "Raw" or "download" button that would give me a
diff I could actually apply. You can select all and then paste
the diffs into a local file, but you have to do that separately for
each file affected. It might be, if you have a lot of files, that the
best solution is to check out the original repo, apply the pull request,
generate a diff locally with git diff
, then apply that
diff to the new repo. Rather circuitous. But with any luck that
situation won't arise very often.
Update: thanks very much to Houz for the solution! (In the comments, below.)
Just append .diff or .patch to the pull request URL, e.g.
https://github.com/OWNER/REPO/pull/REQUEST-ID.diff
which you can view in a browser or fetch with wget or curl.
Tags: programming, git, github
[
14:34 Jan 23, 2017
More programming |
permalink to this entry |
]
Thu, 19 Jan 2017
In my article on
Plotting election (and other county-level) data with Python Basemap,
I used ESRI shapefiles for both states and counties.
But one of the election data files I found, OpenDataSoft's
USA 2016 Presidential Election by county
had embedded county shapes,
available either as CSV or as GeoJSON. (I used the CSV version, but
inside the CSV the geo data are encoded as JSON so you'll need JSON
decoding either way. But that's no problem.)
Just about all the documentation
I found on coloring shapes in Basemap assumed that the shapes were
defined as ESRI shapefiles. How do you draw shapes if you have
latitude/longitude data in a more open format?
As it turns out, it's quite easy, but it took a fair amount of poking
around inside Basemap to figure out how it worked.
In the loop over counties in the US in the previous article,
the end goal was to create a matplotlib Polygon
and use that to add a Basemap patch
.
But matplotlib's Polygon wants map coordinates, not latitude/longitude.
If m is your basemap (i.e. you created the map with
m = Basemap( ... )
, you can translate coordinates like this:
(mapx, mapy) = m(longitude, latitude)
So once you have a region as a list of (longitude, latitude) coordinate
pairs, you can create a colored, shaped patch like this:
for coord_pair in region:
coord_pair[0], coord_pair[1] = m(coord_pair[0], coord_pair[1])
poly = Polygon(region, facecolor=color, edgecolor=color)
ax.add_patch(poly)
Working with the OpenDataSoft data file was actually a little harder than
that, because the list of coordinates was JSON-encoded inside the CSV file,
so I had to decode it with json.loads(county["Geo Shape"])
.
Once decoded, it had some counties as a Polygon
list of
lists (allowing for discontiguous outlines), and others as
a MultiPolygon
list of list of lists (I'm not sure why,
since the Polygon format already allows for discontiguous boundaries)
And a few counties were missing, so there were blanks on the map,
which show up as white patches in this screenshot.
The counties missing data either have inconsistent formatting in
their coordinate lists, or they have only one coordinate pair, and
they include Washington, Virginia; Roane, Tennessee; Schley, Georgia;
Terrell, Georgia; Marshall, Alabama; Williamsburg, Virginia; and Pike
Georgia; plus Oglala Lakota (which is clearly meant to be Oglala,
South Dakota), and all of Alaska.
One thing about crunching data files
from the internet is that there are always a few special cases you
have to code around. And I could have gotten those coordinates from
the census shapefiles; but as long as I needed the census shapefile
anyway, why use the CSV shapes at all? In this particular case, it
makes more sense to use the shapefiles from the Census.
Still, I'm glad to have learned how to use arbitrary coordinates as shapes,
freeing me from the proprietary and annoying ESRI shapefile format.
The code:
Blue-red
map using CSV with embedded county shapes
Tags: elections, politics, visualization, programming, data, open data, data, matplotlib, government, transparency
[
09:36 Jan 19, 2017
More programming |
permalink to this entry |
]
Sat, 14 Jan 2017
After my
arduous
search for open 2016 election data by county, as a first test I
wanted one of those red-blue-purple charts of how Democratic or
Republican each county's vote was.
I used the Basemap package for plotting.
It used to be part of matplotlib, but it's been split off into its
own toolkit, grouped under mpl_toolkits: on Debian, it's
available as python-mpltoolkits.basemap, or you can find
Basemap on GitHub.
It's easiest to start with the
fillstates.py
example that shows
how to draw a US map with different states colored differently.
You'll need the three shapefiles (because of ESRI's silly shapefile format):
st99_d00.dbf, st99_d00.shp and st99_d00.shx, available
in the same examples directory.
Of course, to plot counties, you need county shapefiles as well.
The US Census has
county
shapefiles at several different resolutions (I used the 500k version).
Then you can plot state and counties outlines like this:
from mpl_toolkits.basemap import Basemap
import matplotlib.pyplot as plt
def draw_us_map():
# Set the lower left and upper right limits of the bounding box:
lllon = -119
urlon = -64
lllat = 22.0
urlat = 50.5
# and calculate a centerpoint, needed for the projection:
centerlon = float(lllon + urlon) / 2.0
centerlat = float(lllat + urlat) / 2.0
m = Basemap(resolution='i', # crude, low, intermediate, high, full
llcrnrlon = lllon, urcrnrlon = urlon,
lon_0 = centerlon,
llcrnrlat = lllat, urcrnrlat = urlat,
lat_0 = centerlat,
projection='tmerc')
# Read state boundaries.
shp_info = m.readshapefile('st99_d00', 'states',
drawbounds=True, color='lightgrey')
# Read county boundaries
shp_info = m.readshapefile('cb_2015_us_county_500k',
'counties',
drawbounds=True)
if __name__ == "__main__":
draw_us_map()
plt.title('US Counties')
# Get rid of some of the extraneous whitespace matplotlib loves to use.
plt.tight_layout(pad=0, w_pad=0, h_pad=0)
plt.show()
Accessing the state and county data after reading shapefiles
Great. Now that we've plotted all the states and counties, how do we
get a list of them, so that when I read out "Santa Clara, CA" from
the data I'm trying to plot, I know which map object to color?
After calling readshapefile('st99_d00', 'states'), m has two new
members, both lists: m.states and m.states_info.
m.states_info[] is a list of dicts mirroring what was in the shapefile.
For the Census state list, the useful keys are NAME, AREA, and PERIMETER.
There's also STATE, which is an integer (not restricted to 1 through 50)
but I'll get to that.
If you want the shape for, say, California,
iterate through m.states_info[] looking for the one where
m.states_info[i]["NAME"] == "California"
.
Note i; the shape coordinates will be in m.states[i]
n
(in basemap map coordinates, not latitude/longitude).
Correlating states and counties in Census shapefiles
County data is similar, with county names in
m.counties_info[i]["NAME"]
.
Remember that STATE integer? Each county has a STATEFP,
m.counties_info[i]["STATEFP"]
that matches some state's
m.states_info[i]["STATE"]
.
But doing that search every time would be slow. So right after calling
readshapefile for the states, I make a table of states. Empirically,
STATE in the state list goes up to 72. Why 72? Shrug.
MAXSTATEFP = 73
states = [None] * MAXSTATEFP
for state in m.states_info:
statefp = int(state["STATE"])
# Many states have multiple entries in m.states (because of islands).
# Only add it once.
if not states[statefp]:
states[statefp] = state["NAME"]
That'll make it easy to look up a county's state name quickly when
we're looping through all the counties.
Calculating colors for each county
Time to figure out the colors from the Deleetdk election results CSV file.
Reading lines from the CSV file into a dictionary is superficially easy enough:
fp = open("tidy_data.csv")
reader = csv.DictReader(fp)
# Make a dictionary of all "county, state" and their colors.
county_colors = {}
for county in reader:
# What color is this county?
pop = float(county["votes"])
blue = float(county["results.clintonh"])/pop
red = float(county["Total.Population"])/pop
county_colors["%s, %s" % (county["name"], county["State"])] \
= (red, 0, blue)
But in practice, that wasn't good enough, because the county names
in the Deleetdk names didn't always match the official Census county names.
Fuzzy matches
For instance, the CSV file had no results for Alaska or Puerto Rico,
so I had to skip those. Non-ASCII characters were a problem:
"Doña Ana" county in the census data was "Dona Ana" in the CSV.
I had to strip off " County", " Borough" and similar terms:
"St Louis" in the census data was "St. Louis County" in the CSV.
Some names were capitalized differently, like PLYMOUTH vs. Plymouth,
or Lac Qui Parle vs. Lac qui Parle.
And some names were just different, like "Jeff Davis" vs. "Jefferson Davis".
To get around that I used SequenceMatcher to look for fuzzy matches
when I couldn't find an exact match:
def fuzzy_find(s, slist):
'''Try to find a fuzzy match for s in slist.
'''
best_ratio = -1
best_match = None
ls = s.lower()
for ss in slist:
r = SequenceMatcher(None, ls, ss.lower()).ratio()
if r > best_ratio:
best_ratio = r
best_match = ss
if best_ratio > .75:
return best_match
return None
Correlate the county names from the two datasets
It's finally time to loop through the counties in the map to color and
plot them.
Remember STATE vs. STATEFP? It turns out there are a few counties in
the census county shapefile with a STATEFP that doesn't match any
STATE in the state shapefile. Mostly they're in the Virgin Islands
and I don't have election data for them anyway, so I skipped them for now.
I also skipped Puerto Rico and Alaska (no results in the election data)
and counties that had no corresponding state: I'll omit that code here,
but you can see it in the final script, linked at the end.
for i, county in enumerate(m.counties_info):
countyname = county["NAME"]
try:
statename = states[int(county["STATEFP"])]
except IndexError:
print countyname, "has out-of-index statefp of", county["STATEFP"]
continue
countystate = "%s, %s" % (countyname, statename)
try:
ccolor = county_colors[countystate]
except KeyError:
# No exact match; try for a fuzzy match
fuzzyname = fuzzy_find(countystate, county_colors.keys())
if fuzzyname:
ccolor = county_colors[fuzzyname]
county_colors[countystate] = ccolor
else:
print "No match for", countystate
continue
countyseg = m.counties[i]
poly = Polygon(countyseg, facecolor=ccolor) # edgecolor="white"
ax.add_patch(poly)
Moving Hawaii
Finally, although the CSV didn't have results for Alaska, it did have
Hawaii. To display it, you can move it when creating the patches:
countyseg = m.counties[i]
if statename == 'Hawaii':
countyseg = list(map(lambda (x,y): (x + 5750000, y-1400000), countyseg))
poly = Polygon(countyseg, facecolor=countycolor)
ax.add_patch(poly)
The offsets are in map coordinates and are empirical; I fiddled with
them until Hawaii showed up at a reasonable place.
Well, that was a much longer article than I intended. Turns out
it takes a fair amount of code to correlate several datasets and
turn them into a map. But a lot of the work will be applicable
to other datasets.
Full script on GitHub:
Blue-red
map using Census county shapefile
Tags: elections, politics, visualization, programming, python, mapping, GIS, data, open data, matplotlib, government, transparency
[
15:10 Jan 14, 2017
More programming |
permalink to this entry |
]
Thu, 12 Jan 2017
Back in 2012, I got interested in fiddling around with election data
as a way to learn about data analysis in Python. So I went searching
for results data on the presidential election. And got a surprise: it
wasn't available anywhere in the US. After many hours of searching,
the only source I ever found was at the UK newspaper, The Guardian.
Surely in 2016, we're better off, right? But when I went looking,
I found otherwise. There's still no official source for US election
results data; there isn't even a source as reliable as The Guardian
this time.
You might think Data.gov would be the place to go for official
election results, but no:
searching
for 2016 election on Data.gov yields nothing remotely useful.
The Federal
Election Commission has an election results page, but it only goes
up to 2014 and only includes the Senate and House, not presidential elections.
Archives.gov
has popular vote totals for the 2012 election but not the current one.
Maybe in four years, they'll have some data.
After striking out on official US government sites, I searched the web.
I found a few sources, none of them even remotely official.
Early on I found
Simon
Rogers, How to Download County-Level Results Data,
which leads to GitHub user tonmcg's
County
Level Election Results 12-16. It's a comparison of Democratic vs.
Republican votes in the 2012 and 2016 elections (I assume that means votes
for that party's presidential candidate, though the field names don't
make that entirely clear), with no information on third-party
candidates.
KidPixo's
Presidential Election USA 2016 on GitHub is a little better: the fields
make it clear that it's recording votes for Trump and Clinton, but still
no third party information. It's also scraped from the New York Times,
and it includes the scraping code so you can check it and have some
confidence on the source of the data.
Kaggle
claims to have election data, but you can't download their datasets
or even see what they have without signing up for an account.
Ben Hamner
has some publically available Kaggle data on GitHub, but only for the primary.
I also found several companies selling election data,
and several universities that had datasets available
for researchers with accounts at that university.
The most complete dataset I found, and the only open one that included
third party candidates, was through
OpenDataSoft.
Like the other two, this data is scraped from the NYT.
It has data for all the minor party candidates as well as the majors,
plus lots of demographic data for each county in the lower 48, plus
Hawaii, but not the territories, and the election data for all the
Alaska counties is missing.
You can get it either from a GitHub repo,
Deleetdk's
USA.county.data (look in inst/ext/tidy_data.csv.
If you want a larger version with geographic shape data included,
clicking through several other opendatasoft pages eventually gets
you to an export page,
USA 2016 Presidential Election by county,
where you can download CSV, JSON, GeoJSON and other formats.
The OpenDataSoft data file was pretty useful, though it had gaps
(for instance, there's no data for Alaska). I was able to make
my own red-blue-purple plot of county voting results (I'll write
separately about how to do that with python-basemap),
and to play around with statistics.
Implications of the lack of open data
But the point my search really brought home: By the time I finally
found a workable dataset, I was so sick of the search, and so
relieved to find anything at all, that I'd stopped being picky about
where the data came from. I had long since given up on finding
anything from a known source, like a government site or even a
newspaper, and was just looking for data, any data.
And that's not good. It means that a lot of the people doing
statistics on elections are using data from unverified sources,
probably copied from someone else who claimed to have scraped it,
using unknown code, from some post-election web page that likely no
longer exists. Is it accurate? There's no way of knowing.
What if someone wanted to spread news and misinformation? There's a
hunger for data, particularly on something as important as a US
Presidential election. Looking at Google's suggested results and
"Searches related to" made it clear that it wasn't just me: there are
a lot of people searching for this information and not being able to
find it through official sources.
If I were a foreign power wanting to spread disinformation, providing
easily available data files -- to fill the gap left by the US
Government's refusal to do so -- would be a great way to mislead
people. I could put anything I wanted in those files: there's no way
of checking them against official results since there are no official
results. Just make sure the totals add up to what people expect to
see. You could easily set up an official-looking site and put made-up
data there, and it would look a lot more real than all the people
scraping from the NYT.
If our government -- or newspapers, or anyone else -- really wanted to
combat "fake news", they should take open data seriously. They should
make datasets for important issues like the presidential election
publically available, as soon as possible after the election -- not
four years later when nobody but historians care any more.
Without that, we're leaving ourselves open to fake news and fake data.
Tags: elections, politics, programming, data, open data, fake news, government, transparency
[
16:41 Jan 12, 2017
More politics |
permalink to this entry |
]
Sun, 08 Jan 2017
The snowy days here have been so pretty, the snow contrasting with the
darkness of the piñons and junipers and the black basalt.
The light fluffy crystals sparkle in a rainbow of colors when they
catch the sunlight at the right angle, but I've been unable to catch
that effect in a photo.
We've had some unusual holiday visitors, too, culminating in this
morning's visit from a huge bull elk.
Dave came down to make coffee and saw the elk in the garden right next
to the window. But by the time I saw him, he was farther out in the
yard. And my DSLR batteries were dead, so I grabbed the point-and-shoot
and got what I could through the window.
Fortunately for my photography the elk wasn't going anywhere in any hurry.
He has an injured leg, and was limping badly.
He slowly made his way down the hill and into the neighbors' yard.
I hope he returns. Even with a limp that bad, an elk that size
has no predators in White Rock, so as long as he stays off the nearby
San Ildefonso reservation (where hunting is allowed) and manages to
find enough food, he should be all right. I'm tempted to buy some
hay to leave out for him.
Some of the sunsets have been pretty nice, too.
A few more photos.
Tags: nature, photography
[
19:48 Jan 08, 2017
More photo |
permalink to this entry |
]
Python's installation tool, pip, has some problems on Debian.
The obvious way to use pip is as root:
sudo pip install packagename
.
If you hang out in Python groups at all, you'll quickly find that this
is strongly frowned upon. It can lead to your pip-installed packages
intermingling with the ones installed by Debian's apt-get,
possibly causing problems during apt system updates.
The second most obvious way, as you'll see if you read pip's man page,
is
pip --user install packagename
.
This installs the package with only user permissions, not root,
under a directory called ~/.local. Python automatically checks
.local as part of its PYTHONPATH, and you can add ~/.local/bin to
your PATH, so this makes everything transparent.
Or so I thought until recently, when I discovered that
pip install --user
ignores system-installed packages
when it's calculating its dependencies, so you could end up with a
bunch of incompatible versions of packages installed. Plus it takes
forever to re-download and re-install dependencies you already had.
Pip has a clear page describing
how
pip --user is supposed to work, and that isn't what it's doing.
So I filed
pip bug 4222;
but since pip has 687 open bugs filed against it, I'm not terrifically
hopeful of that getting fixed any time soon. So I needed a workaround.
Use virtualenv instead of --user
Fortunately, it turned out that pip install works correctly in a
virtualenv if you include the --system-site-packages option.
I had thought virtualenvs were for testing, but quite a few people
on #python said they used virtualenvs all the time, as part of their
normal runtime environments. (Maybe due to pip's deficiencies?)
I had heard people speak deprecatingly of --user in favor of
virtualenvs but was never clear why; maybe this is why.
So, what I needed was to set up a virtualenv that I can keep around
all the time and use by default every time I log in. I called it
~/.pythonenv when I created it:
virtualenv --system-site-packages $HOME/.pythonenv
Normally, the next thing you do after creating a virtualenv is to
source a script called bin/activate inside the venv.
That sets up your PATH, PYTHONPATH and a bunch of other variables
so the venv will be used in all the right ways. But activate
also changes your prompt, which I didn't want in my normal runtime
environment. So I stuck this in my .zlogin file:
VIRTUAL_ENV_DISABLE_PROMPT=1 source $HOME/.pythonenv/bin/activate
Now I'll activate the venv once, when I log in (and once in every xterm
window since I set XTerm*loginShell: true in my .Xdefaults.
I see my normal prompt, I can use the normal Debian-installed Python
packages, and I can install additional PyPI packages with
pip install packagename
(no --user, no sudo).
Tags: python
[
11:37 Jan 08, 2017
More programming |
permalink to this entry |
]
Wed, 04 Jan 2017
A couple of days ago I blogged about using
Firefox's
"Delete Node" to make web pages more readable.
In a
subsequent Twitter
discussion someone pointed out that if the goal is to make a web
page's content clearer, Firefox's relatively new "Reader Mode" might be
a better way.
I knew about Reader Mode but hadn't used it. It only shows up on some
pages. as a little "open book" icon to the right of the URLbar just
left of the Refresh/Stop button. It did show up on the Pogue Yahoo article;
but when I clicked it, I just got a big blank page with an icon of a
circle with a horizontal dash; no text.
It turns out that to see Reader Mode content in noscript, you must
explicitly enable javascript from about:reader.
There are some reasons it's not automatically whitelisted:
see discussions in
bug 1158071
and
bug 1166455
-- so enable it at your own risk.
But it's nice to be able to use Reader Mode, and I'm glad the Twitter
discussion spurred me to figure out why it wasn't working.
Tags: firefox, web
[
11:37 Jan 04, 2017
More tech/web |
permalink to this entry |
]
Mon, 02 Jan 2017
It's trendy among web designers today -- the kind who care more about
showing ads than about the people reading their pages -- to use fixed
banner elements that hide part of the page. In other words, you have
a header, some content, and maybe a footer; and when you scroll the
content to get to the next page, the header and footer stay in place,
meaning that you can only read the few lines sandwiched in between them.
But at least you can see the name of the site no matter how far you
scroll down in the article! Wouldn't want to forget the site name!
Worse, many of these sites don't scroll properly. If you Page Down,
the content moves a full page up, which means that the top of the new
page is now hidden under that fixed banner and you have to scroll back
up a few lines to continue reading where you left off.
David Pogue wrote about that problem recently and it got a lot of play
when Slashdot picked it up:
These 18 big websites fail the space-bar scrolling test.
It's a little too bad he concentrated on the spacebar. Certainly it's
good to point out that hitting the spacebar scrolls down -- I was
flabbergasted to read the Slashdot discussion and discover that lots
of people didn't already know that, since it's been my most common way
of paging since browsers were invented. (Shift-space does a Page Up.)
But the Slashdot discussion then veered off into a chorus of "I've
never used the spacebar to scroll so why should anyone else care?",
when the issue has nothing to do with the spacebar: the issue is
that Page Down doesn't work right, whichever key you use to
trigger that page down.
But never mind that. Fixed headers that don't scroll are bad even
if the content scrolls the right amount, because it wastes precious
vertical screen space on useless cruft you don't need.
And I'm here to tell you that you can get rid of those annoying fixed
headers, at least in Firefox.
Let's take Pogue's article itself, since Yahoo is a perfect example of
annoying content that covers the page and doesn't go away. First
there's that enormous header -- the bottom row of menus ("Tech Home" and
so forth) disappear once you scroll, but the rest stay there forever.
Worse, there's that annoying popup on the bottom right ("Privacy | Terms"
etc.) which blocks content, and although Yahoo! scrolls the right
amount to account for the header, it doesn't account for that privacy
bar, which continues to block most of the last line of every page.
The first step is to call up the DOM Inspector. Right-click on the
thing you want to get rid of and choose Inspect Element:
That brings up the DOM Inspector window, which looks like this
(click on the image for a full-sized view):
The upper left area shows the hierarchical structure of the web page.
Don't Panic! You don't have to know HTML or understand any of
this for this technique to work.
Hover your mouse over the items in the hierarchy. Notice that as you
hover, different parts of the web page are highlighted in translucent blue.
Generally, whatever element you started on will be a small part of the
header you're trying to eliminate. Move up one line, to the element's
parent; you may see that a bigger part of the header is highlighted.
Move up again, and keep moving up, one line at a time, until the whole
header is highlighted, as in the screenshot. There's also a dark grey
window telling you something about the HTML, if you're interested;
if you're not, don't worry about it.
Eventually you'll move up too far, and some other part of the page,
or the whole page, will be highlighted. You need to find the element
that makes the whole header blue, but nothing else.
Once you've found that element, right-click on it to get a context menu,
and look for Delete Node (near the bottom of the menu).
Clicking on that will delete the header from the page.
Repeat for any other part of the page you want to remove, like that
annoying bar at the bottom right. And you're left with a nice, readable
page, which will scroll properly and let you read every line,
and will show you more text per page so you don't have to scroll as often.
It's a useful trick.
You can also use Inspect/Delete Node for many of those popups that
cover the screen telling you "subscribe to our content!" It's
especially handy if you like to browse with NoScript, so you
can't dismiss those popups by clicking on an X.
So happy reading!
Addendum on Spacebars
By the way, in case you weren't aware that the spacebar did a page
down, here's another tip that might come in useful: the spacebar also
advances to the next slide in just about every presentation program,
from PowerPoint to Libre Office to most PDF viewers. I'm amazed at how
often I've seen presenters squinting with a flashlight at the keyboard
trying to find the right-arrow or down-arrow or page-down or whatever
key they're looking for. These are all ways of advancing to the next
slide, but they're all much harder to find than that great big
spacebar at the bottom of the keyboard.
Tags: web, firefox
[
16:23 Jan 02, 2017
More tech/web |
permalink to this entry |
]