Let me see if I have understood you correctly: you are constructing a surface with some 400x300 (=120,000) tiles, each of which could be any one of as many as 800 different images. Once assembled, your surface is static and unchanging, but may be panned and zoomed considerably.
What I would do, then, is render each of these images out to a separate bitmap, then use a tool like egg-texture-cards to construct a big egg file that references all of them individually.
Then pass that egg file through egg-palettize to group those ~800 images into as few individual images as possible (egg-palettize does this by assembling multiple images onto a larger palette of images, and then changing the model to index into that palette). Depending on your graphics hardware and the number of pixels you need to keep in each image, you may be able to get away with very few individual images indeed.
Then, in Python code, load up your egg-texture-cards model, find all of the individual tiles within it, and assemble them according to your needs. Then call flattenStrong() on the whole mess to flatten it into as few objects as possible (presumably no more objects than your individual number of images produced by egg-palettize).
This may or may not give you adequate performance. Whether it does or not depends largely on the number of individual images you were able to reduce it to, which is based on the maximum size you need for your individual images. If you need to be able to zoom these images to fullscreen and maintain full clarity, you may need a different trick (perhaps switching in a full-resolution image based on LOD).
Then again, you may not–even with 800 different full-resolution images, you might do OK with the just the flattenStrong(), omitting the egg-palettize step. Again, this depends on your hardware and your performance needs.
Resizing is absolutely and completely free, in the sense that it costs the same to draw the reduced image as it costs to draw it in full size. Actually, it’s a tiny bit faster to draw it reduced, because you get better caching on your memory. This all works because your graphics card has special vector hardware to scan pixels really, really fast, and when you’re running a 3-D engine like Panda3D, it uses this hardware all the time, whether you’re drawing the image full-resolution or some other scale (or at any rotation and shear, for that matter). So it all costs the same, no matter what transform you apply. (Think about it a minute–this is an essential requirement for rendering 3-D scenes, where almost no polygons are directly facing the camera, and all of your textures will be scaled and skewed in some way or another.)
I think at this point you should just try some of this stuff out and see what you find. It will perhaps help you to understand how the world of 3-D graphics is different from what you might be used to.
David